我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?

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、...)

【讨论】:

以上是关于我的应用程序“查找麦克风的音频输入频率”总是崩溃。但为啥?的主要内容,如果未能解决你的问题,请参考以下文章

为啥我的 Eclipse 总是崩溃?

进行 API 调用时,应用程序总是崩溃

为啥我的 strlen 函数总是“崩溃”? [关闭]

为啥我的 QThreads 总是让 Maya 崩溃?

C++ 程序在执行 std::string 分配时总是崩溃

Xcode 6 中的应用程序数据包。总是崩溃或显示错误