【问题标题】:Android whistle detection with Mic带有麦克风的 Android 哨声检测
【发布时间】:2016-08-26 02:17:20
【问题描述】:

我正在尝试实现一个应用程序,即使存在环境背景噪音,我也可以检测到特定频率(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 个异常的力量。

【问题讨论】:

  • 你不明白代码在做什么是什么意思?不是你的吗?
  • 如果您想确定声音中是否存在特定频率,那么 FFT 是正确的方法。你的问题到底是什么?
  • 我在尝试运行代码时遇到了一些错误。我得到 java.lang.RuntimeException: N is not a power of 2 for final Complex[] fftArray = FFT.fft(fftTempArray);
  • 这种东西最好先用更高级的语言(mathematica、matlab、python-numpy)做原型来整理数学。对于 numpy 中的带通,请参见例如stackoverflow.com/questions/36968418/…

标签: java android android-studio fft


【解决方案1】:

以下行不能可靠地工作:

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

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

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

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

编辑

您的评论中的错误表明,您的数组还需要具有 2^N 大小。所以,找到比bufferSize小的2^N大小。

【讨论】:

  • 我似乎无法弄清楚为什么会发生这种情况?我可以从打印语句中看到它在 N = 5 时出错。我相信它的起始索引是 640。这个数字是否有意义?
  • 原来,我的 bufferSize = 640 不是索引 2。这很有趣
  • 那么下一个较低的 2^N 数字是 512 (=2^9)
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2015-11-26
  • 1970-01-01
  • 1970-01-01
  • 2011-09-05
相关资源
最近更新 更多