2016-05-01 136 views
3

即使存在環境背景噪音,並且在網上做了大量的研究之後,我試圖實施一個應用程序,在該應用程序中,我可以檢測特定頻率(1000Hz-1500Hz)的哨子,已經使用FFT方法來嘗試並檢測從麥克風捕獲的最大幅度是否與哨音頻率相對應。帶麥克風的Android哨音檢測

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不是被拋出的異常的力量。

+0

你是什麼意思,你不明白代碼在做什麼?這不是你的? – stackoverflowuser2010

+0

如果您試圖確定聲音中是否存在特定頻率,那麼FFT是正確的選擇。你的問題到底是什麼? – stackoverflowuser2010

+0

我在嘗試運行代碼時遇到了一些錯誤。我得到了java.lang.RuntimeException:N對於最終的Complex []來說不是2的乘方[] fftArray = FFT.fft(fftTempArray); –

回答

0

以下行不可靠地工作:

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

bufferSize可以比一個字節和演員大得多則能產生甚至負數,這樣你的循環不執行一次。然後fftTempArray未被初始化。

刪除(byte)將更正此錯誤。

但是至少有第二個錯誤:您的「從短到雙轉換」是錯誤的。它在micBufferData中將兩個連續的16位採樣組合到一個雙採樣中,而每個16位採樣應該對應它自己的雙採樣。

EDIT

誤差從您的評論顯示,您的陣列另外需要具有2^N的大小。因此,找到下一個低於bufferSize的2^N尺寸。

+0

我似乎無法弄清楚爲什麼會出現這種情況?從打印語句中我可以看到,當N = 5時它出錯。我相信它的起始索引是640.這個數字是否有意義? –

+0

原來,我的bufferSize = 640這不是索引2.這很有趣 –

+0

那麼下一個較低的2^N數是512(= 2^9) –