0
我对声音数字化知之甚少。我试图表示麦克风输入的即时配置文件。我知道如何从麦克风中获取音乐,但我不知道如何将其解释为配置文件。任何人都可以帮我填补空白吗?绘制麦克风输入配置文件
package test;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Container;
import java.awt.Graphics;
import java.awt.Graphics2D;
import java.awt.RenderingHints;
import java.awt.event.ActionEvent;
import java.io.IOException;
import java.io.OutputStream;
import javax.sound.sampled.AudioFileFormat;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioInputStream;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.TargetDataLine;
import javax.swing.AbstractAction;
import javax.swing.JButton;
import javax.swing.JFrame;
import javax.swing.JPanel;
import javax.swing.SwingUtilities;
/**
*
* @author François Billioud
*/
public class SoundRecorder extends JFrame {
/** JFrame for the GUI **/
public SoundRecorder() {
super("Sound Recorder");
setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
Container pane = getContentPane();
pane.setLayout(new BorderLayout());
pane.add(wavePane = new WavePane(), BorderLayout.CENTER);
pane.add(new JButton(new AbstractAction("ok") {
@Override
public void actionPerformed(ActionEvent e) {
dispose();
}
}), BorderLayout.SOUTH);
setSize(300,300);
setLocationRelativeTo(null);
}
/** Just displays the frame and starts listening **/
public static void main(String[] args) {
SwingUtilities.invokeLater(new Runnable() {
@Override
public void run() {
SoundRecorder rec = new SoundRecorder();
rec.setVisible(true);
rec.listenToMic();
}
});
}
/** Draws the sound read from the mic **/
private static class WavePane extends JPanel {
private final int[] x = new int[0];
private int[] y = new int[0];
private WavePane() {
setOpaque(true);
setBackground(Color.WHITE);
}
/** updates the data to be displayed **/
public void setData(int[] y) {
this.y = y;
int n = y.length;
this.x = new int[n];
float pas = getWidth()/(float)(n-1);
float xCurrent = 0;
for(int i=0; i<n; i++) {
this.x[i] = Math.round(xCurrent);
xCurrent+=pas;
}
repaint();
}
/** Draws a line that represent the mic profile **/
@Override
public void paint(Graphics g) {
super.paint(g);
Graphics2D g2D = (Graphics2D) g;
g2D.setRenderingHint(RenderingHints.KEY_ANTIALIASING,RenderingHints.VALUE_ANTIALIAS_ON);
g2D.setRenderingHint(RenderingHints.KEY_RENDERING, RenderingHints.VALUE_RENDER_QUALITY);
g2D.drawPolyline(x, y, x.length);
}
}
/** Defines the audio format to be used.
* I know nothing about that and am open to suggestions if needed
*/
private static final AudioFormat format = new AudioFormat(
16000, //Sample rate
16, //SampleSizeInBits
2, //Channels
true,//Signed
true //BigEndian
);
/** Creates a thread that will read data from
* the mic and send it to the WavePane
* in order to be painted.
* We should be using a SwingWorker, but it will do
* for the sake of this demo.
**/
private void listenToMic() {
new Thread(new Runnable() {
@Override
public void run() {
try {
//Open the line and read
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format);
//checks if system supports the data line
if (!AudioSystem.isLineSupported(info)) {
System.err.print("Line not supported");
}
//starts listening
TargetDataLine line = (TargetDataLine) AudioSystem.getLine(info);
line.open(format);
line.start();
//sends the stream to the interpreter
AudioInputStream ais = new AudioInputStream(line);
AudioSystem.write(ais, AudioFileFormat.Type.AU, new Interpreter());
} catch (LineUnavailableException | IOException ex) {
System.err.println(ex.getLocalizedMessage());
}
}
}).start();
}
private final WavePane wavePane;
private class Interpreter extends OutputStream {
private int[] y;
@Override
public void write(int b) throws IOException {
//TBD
//Fill y array
}
@Override
public void flush() throws IOException {
//Sends the values found to the panel for drawing
wavePane.setData(y);
}
}
}
我发现this link但它并没有帮助我......
编辑:好了,从我的理解,每个16位是一个频率的幅度。我有2个通道,所以我必须每32位读取16位才能获得第一个通道。现在我需要知道每帧要读取多少个频率。然后我想我可以画出轮廓。任何提示?
感谢您提供非常完整的链接。我想要从麦克风实时获取每个频率的能量。你的链接是好的,但STFT是在将麦克风输入转换成比特时完成的。问题更多的是关于数据如何在流中排列,以及如何重新排列它们以获得我的表示。你明白我的意思吗? – Sharcoux
增加了关于流内容到答案的一些评论。 – astraujums
好的。我想我只有更多的信息,那么我应该如何解读一个负数?能量不能是负面的,所以我猜想-3000意味着3000阶段的PI?那么,我应该只考虑绝对值吗?如果我有一个大字节无符号格式的字节数组byte [16],那么将其转换为数字的正确方法是什么?非常感谢您的帮助! – Sharcoux