音频电平表
我是新来编程,我试图做一个Java应用程序,将“听到”(不一定记录)的声音和显示有多大。我想转换录音到数字,所以我可以看到声音水平的差异。我得到了这段代码,并添加了“getLevel()”方法,该方法返回当前录音的振幅,但每次都返回-1。我想我不是正确使用它。任何想法,我必须调用这种方法?我必须在一周内完成我的项目,所以任何帮助将非常感谢!音频电平表
public class Capture extends JFrame {
protected boolean running;
ByteArrayOutputStream out;
public Capture() {
super("Capture Sound Demo");
setDefaultCloseOperation(EXIT_ON_CLOSE);
Container content = getContentPane();
final JButton capture = new JButton("Capture");
final JButton stop = new JButton("Stop");
final JButton play = new JButton("Play");
capture.setEnabled(true);
stop.setEnabled(false);
play.setEnabled(false);
ActionListener captureListener =
new ActionListener() {
public void actionPerformed(ActionEvent e) {
capture.setEnabled(false);
stop.setEnabled(true);
play.setEnabled(false);
captureAudio();
}
};
capture.addActionListener(captureListener);
content.add(capture, BorderLayout.NORTH);
ActionListener stopListener =
new ActionListener() {
public void actionPerformed(ActionEvent e) {
capture.setEnabled(true);
stop.setEnabled(false);
play.setEnabled(true);
running = false;
}
};
stop.addActionListener(stopListener);
content.add(stop, BorderLayout.CENTER);
ActionListener playListener =
new ActionListener() {
public void actionPerformed(ActionEvent e) {
playAudio();
}
};
play.addActionListener(playListener);
content.add(play, BorderLayout.SOUTH);
}
private void captureAudio() {
try {
final AudioFormat format = getFormat();
DataLine.Info info = new DataLine.Info(
TargetDataLine.class, format);
final TargetDataLine line = (TargetDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runner = new Runnable() {
int bufferSize = (int)format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
out = new ByteArrayOutputStream();
running = true;
try {
while (running) {
int count =
line.read(buffer, 0, buffer.length);
if (count > 0) {
out.write(buffer, 0, count);
System.out.println(line.getLevel()); // |-this is what i added-|
}
}
out.close();
} catch (IOException e) {
System.err.println("I/O problems: " + e);
System.exit(-1);
}
}
};
Thread captureThread = new Thread(runner);
captureThread.start();
} catch (LineUnavailableException e) {
System.err.println("Line unavailable: " + e);
System.exit(-2);
}
}
private void playAudio() {
try {
byte audio[] = out.toByteArray();
InputStream input =
new ByteArrayInputStream(audio);
final AudioFormat format = getFormat();
final AudioInputStream ais =
new AudioInputStream(input, format,
audio.length/format.getFrameSize());
DataLine.Info info = new DataLine.Info(
SourceDataLine.class, format);
final SourceDataLine line = (SourceDataLine)
AudioSystem.getLine(info);
line.open(format);
line.start();
Runnable runner = new Runnable() {
int bufferSize = (int) format.getSampleRate()
* format.getFrameSize();
byte buffer[] = new byte[bufferSize];
public void run() {
try {
int count;
while ((count = ais.read(
buffer, 0, buffer.length)) != -1) {
if (count > 0) {
line.write(buffer, 0, count);
}
}
line.drain();
line.close();
} catch (IOException e) {
System.err.println("I/O problems: " + e);
System.exit(-3);
}
}
};
Thread playThread = new Thread(runner);
playThread.start();
} catch (LineUnavailableException e) {
System.err.println("Line unavailable: " + e);
System.exit(-4);
}
}
private AudioFormat getFormat() {
float sampleRate = 8000;
int sampleSizeInBits = 8;
int channels = 1;
boolean signed = true;
boolean bigEndian = true;
return new AudioFormat(sampleRate,
sampleSizeInBits, channels, signed, bigEndian);
}
@SuppressWarnings("deprecation")
public static void main(String args[]) {
JFrame frame = new Capture();
frame.pack();
frame.show();
}
}
是的,就像@tubro说的那样,它是AudioSystem.NOT_SPECIFIED = -1
。
我在我的程序中使用以下函数通过计算均方根来获得分贝的响度。请注意,我假设归一化样本的值为-1到+1。为此,我写了一个PCM解码器至极支持不同格式的8位,16位,符号,无符号大端等
public final class Loudness {
public static final float evaluate(final float[] window) {
if (window == null) {
throw new NullPointerException();
} else if (window.length == 0) {
throw new IllegalArgumentException("window is empty");
}
float sum = 0.0f;
for (int i = 0; i < window.length; i++) {
assert window[i] >= -1.0f && window[i] <= 1.0f;
sum += (window[i] * window[i]);
}
// Root Mean Square
// 0 <= rms <= 1
final float rms = (float) Math.sqrt(sum/window.length);
// 0 <= decibel
final float decibel = (float) (20 * Math.log10(rms));
return decibel;
}
}
好吧,我设法使它捕获音频并在xls文件上打印当前样本的时间戳和值,但存在一个问题:即使我在时间和值之间放置了一些空格,似乎它们在不同的列中,它们实际上位于xls的同一列,它只是展开并覆盖下一列(如果您不明白,我可以放置一个打印屏幕)。如何使它打印时间和数据振幅在两个不同的列? – xchris
@xchris:在时间和度量值之间放置一个制表符:'System.out.println(time +“\ t”+ value)''。将控制台输出复制并粘贴到excel中的左上角单元格 – Vertex
是的,“\ t”在csv上无法正常工作,但它在xls上正常工作,谢谢! – xchris
你却加上'的System.out.println(line.getLevel()) ;'?请参阅文档:http://docs.oracle.com/javase/7/docs/api/javax/sound/sampled/DataLine.html#getLevel%28%29“返回: 此行中信号的当前幅度,或AudioSystem.NOT_SPECIFIED“所以-1意味着别的东西出错了。 – turbo
请注意,'running'在不同步的线程中被访问,没有同步分配:在UI线程和捕获线程中。通常情况下,你可以确保通过剔除“volatile”来获得'running'的当前值。 – Vertex