我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?
Posted
技术标签:
【中文标题】我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?【英文标题】:My app "find frequency of audio input from microphone" always crashs. But why?我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为什么? 【发布时间】:2014-09-04 13:20:43 【问题描述】:最后你会发现错误信息!!
import java.nio.ByteBuffer;
import java.nio.ByteOrder;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.Audiosystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.TargetDataLine;
Math3 导入以使用 fft。
import org.apache.commons.math3.complex.Complex;
import org.apache.commons.math3.transform.DftNormalization;
import org.apache.commons.math3.transform.FastFourierTransformer;
import org.apache.commons.math3.transform.TransformType;
public class AudioInput
TargetDataLine microphone;
final int audioFrames= 8196; //power ^ 2
final float sampleRate= 8000.0f;
final int bitsPerRecord= 16;
final int channels= 1;
final boolean bigEndian = true;
final boolean signed= true;
byte byteData[]; // length=audioFrames * 2
double doubleData[]; // length=audioFrames only reals needed for apache lib.
AudioFormat format;
FastFourierTransformer transformer;
public AudioInput ()
byteData= new byte[audioFrames * 2]; //two bytes per audio frame, 16 bits
//doubleData= new double[audioFrames * 2]; // real & imaginary
doubleData= new double[audioFrames]; // only real for apache
transformer = new FastFourierTransformer(DftNormalization.STANDARD);
System.out.print("Microphone initialization\n");
format = new AudioFormat(sampleRate, bitsPerRecord, channels, signed, bigEndian);
DataLine.Info info = new DataLine.Info(TargetDataLine.class, format); // format is an AudioFormat object
if (!AudioSystem.isLineSupported(info))
System.err.print("isLineSupported failed");
System.exit(1);
try
microphone = (TargetDataLine) AudioSystem.getLine(info);
microphone.open(format);
System.out.print("Microphone opened with format: "+format.toString()+"\n");
microphone.start();
catch(Exception ex)
System.out.println("Microphone failed: "+ex.getMessage());
System.exit(1);
public int readPcm()
int numBytesRead=
microphone.read(byteData, 0, byteData.length);
if(numBytesRead!=byteData.length)
System.out.println("Warning: read less bytes than buffer size");
System.exit(1);
return numBytesRead;
public void byteToDouble()
ByteBuffer buf= ByteBuffer.wrap(byteData);
buf.order(ByteOrder.BIG_ENDIAN);
int i=0;
while(buf.remaining()>2)
short s = buf.getShort();
doubleData[ i ] = (new Short(s)).doubleValue();
++i;
//System.out.println("Parsed "+i+" doubles from "+byteData.length+" bytes");
public void findFrequency()
double frequency;
Complex[] cmplx= transformer.transform(doubleData, TransformType.FORWARD);
double real;
double im;
double mag[] = new double[cmplx.length];
for(int i = 0; i < cmplx.length; i++)
real = cmplx[i].getReal();
im = cmplx[i].getImaginary();
mag[i] = Math.sqrt((real * real) + (im*im));
double peak = -1.0;
int index=-1;
for(int i = 0; i < cmplx.length; i++)
if(peak < mag[i])
index=i;
peak= mag[i];
frequency = (sampleRate * index) / audioFrames;
System.out.print("Index: "+index+", Frequency: "+frequency+"\n");
/* * 打印第一个频率区间以了解我们的分辨率 */
public void printFreqs()
for (int i=0; i<audioFrames/4; i++)
System.out.println("bin "+i+", freq: "+(sampleRate*i)/audioFrames);
public static void main(String[] args)
AudioInput ai= new AudioInput();
int turns=10000;
while(turns-- > 0)
ai.readPcm();
ai.byteToDouble();
ai.findFrequency();
//ai.printFreqs();
这是来自控制台的内容以及错误消息:
麦克风初始化 麦克风以格式打开:PCM_SIGNED 8000.0 Hz,16 位,单声道,2 字节/帧,大端
Exception in thread "main" org.apache.commons.math3.exception.MathIllegalArgumentException: 8.196 is not a power of 2, consider padding for fix
at org.apache.commons.math3.transform.FastFourierTransformer.transformInPlace(FastFourierTransformer.java:229)
at org.apache.commons.math3.transform.FastFourierTransformer.transform(FastFourierTransformer.java:375)
at AudioInput.findFrequency(AudioInput.java:88)
at AudioInput.main(AudioInput.java:126)
【问题讨论】:
此代码没有找到输入信号的频率 - 它找到幅度最大的 FFT bin - 这是 bin 覆盖的可能频率范围。面对复杂的信号或噪声,确定信号的实际主频率是一个不同的命题。 【参考方案1】:8196 不是 2 的幂。尝试将变量 audioFrames
更改为 final int audioFrames= 8192;
。 FFT算法只能处理大小为2的数组(2、4、8、16、32、64、128、256、512、1024、2048、4096、8192、...)
【讨论】:
以上是关于我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?的主要内容,如果未能解决你的问题,请参考以下文章