我试图实现一个应用程序,我可以检测到一个特定频率(1000hz-1500hz)的哨声,即使有环境背景噪声,在做了大量的网络研究之后,我用了fft方法来试着检测从麦克风捕捉到的最大振幅是否与口哨音频率一致。

public void run() {
    if (ar == null) {
        bufferSize = AudioRecord.getMinBufferSize(8000, AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT);
        ar = new AudioRecord(MediaRecorder.AudioSource.MIC, 8000,AudioFormat.CHANNEL_CONFIGURATION_MONO, AudioFormat.ENCODING_PCM_16BIT,bufferSize);
        audioBuffer = new short[bufferSize];
        ar.startRecording();
        ar.read(audioBuffer, 0, bufferSize);

        //Conversion from short to double
        double[] micBufferData = new double[bufferSize];//size may need to change
        final int bytesPerSample = 2; // As it is 16bit PCM
        final double amplification = 1.0; // choose a number as you like
        for (int index = 0, floatIndex = 0; index < (byte) bufferSize - bytesPerSample + 1; index += bytesPerSample, floatIndex++) {
            double sample = 0;
            for (int b = 0; b < bytesPerSample; b++) {
                int v = audioBuffer[index + b];
                if (b < bytesPerSample - 1 || bytesPerSample == 1) {
                    v &= 0xFF;
                }
                sample += v << (b * 8);
            }
            double sample32 = amplification * (sample / 32768.0);
            micBufferData[floatIndex] = sample32;
        }

        //Create Complex array for use in FFT
        Complex[] fftTempArray = new Complex[bufferSize];
        for (int i=0; i< (byte) bufferSize; i++)
        {
            fftTempArray[i] = new Complex(micBufferData[i], 0);
        }

        //Obtain array of FFT data
        final Complex[] fftArray = FFT.fft(fftTempArray);
        //final Complex[] fftInverse = FFT.ifft(fftTempArray);

        //Create an array of magnitude of fftArray
        double[] magnitude = new double[fftArray.length];
        for (int i=0; i<fftArray.length; i++){
            magnitude[i]= fftArray[i].abs();
        }


        double maxVal = -1.0;
        int maxIndex = 1;
        for( int j=0; j < fftArray.length / 2; ++j ) {
            double v = magnitude[2*j] * magnitude[2*j] + magnitude[2*j+1] * magnitude[2*j+1];
            if( v > maxVal ) {
                maxVal = v;
                maxIndex = j;
            }
        }

        maxFrequency =  ((1.0 * 44100) / (1.0 * bufferSize)) * maxIndex;

    }
    runOnUiThread(new Runnable() {
        @Override
        public void run() {
            if (isRunning) {
                tv2.setText("Frequency Detected: " + maxFrequency);
            }
        }
    });

}

我已经设置了一个麦克风录音机等等,但我不明白代码在做什么,我得到一些错误说我的fftarray是阴性的。有人能帮我指出正确的方向吗?还是有更好的方法来实现哨声探测?我正在使用here中的代码。我得到的n不是抛出2个异常的幂。

最佳答案

以下线路工作不可靠:

for (int i=0; i< (byte) bufferSize; i++)

bufferSize可以比一个字节大得多,然后转换可以产生偶数个负数,这样循环就不会一次执行。fftTempArray未初始化。
删除(byte)将更正此错误。
但至少还有第二个错误:你的“从短到双”的转换是错误的。它在micBufferData中将两个连续的16位样本合并为一个双样本,而每个16位样本应对应于其自身的双样本。
编辑
注释中的错误显示,数组还需要2^n的大小。所以,找到2^n的大小,它的下一个小于bufferSize

10-08 03:40