使用Mic进行Android哨子检测

时间:2016-05-01 05:33:13

标签: java android android-studio fft

我正在尝试实现一个应用程序,我可以检测特定频率(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异常的力量。

1 个答案:

答案 0 :(得分:0)

以下行无法可靠地运行:

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

bufferSize可能远大于一个字节,然后强制转换甚至可以产生负数,这样你的循环就不会被执行一次。 fftTempArray未初始化。

删除(byte)将更正此错误。

但至少有第二个错误:你的“从短到双的转换”是错误的。它将两个连续的16位样本组合成micBufferData中的一个双样本,而每个16位样本应该对应于它自己的双样本。

修改

评论中的错误显示,您的阵列还需要具有2 ^ N的大小。因此,找到下一个低于bufferSize的2 ^ N大小。