2016-05-01 3 views
3

Ich versuche, eine App zu implementieren, wo ich eine Pfeife einer bestimmten Frequenz (1000Hz - 1500Hz) erkennen kann, auch wenn es Umwelt Hintergrundgeräusche und nach einer Menge Forschung im Netz, ich habe FFT-Methoden verwendet, um zu versuchen, zu erkennen, ob die maximale Amplitude, die vom Mikrofon aufgenommen wird, mit der Frequenz des Pfeiftons übereinstimmt.Android Whistle Erkennung mit Mic

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); 
      } 
     } 
    }); 

} 

Ich habe bereits ein Mikrofon Recorder einrichten und so weiter, aber ich kann nicht verstehen, was der Code tut und ich habe einige Fehler immer sagen, dass mein fftarray negativ ist. Könnte mir jemand helfen, in die richtige Richtung zu zeigen? Oder gibt es einen besseren Weg, eine Pfeifenerkennung zu implementieren? Ich verwende Code von here. Ich bekomme ein N ist nicht auf die Kraft von 2 Ausnahme geworfen wird.

+0

Was meinen Sie verstehen Sie nicht, was der Code tut? Es gehört nicht dir? – stackoverflowuser2010

+0

Wenn Sie herausfinden möchten, ob bestimmte Frequenzen in einem Sound vorhanden sind, ist FFT der richtige Weg. Was genau ist deine Frage? – stackoverflowuser2010

+0

Ich erhalte einige Fehler, wenn ich versuche, den Code auszuführen. Ich bekomme java.lang.RuntimeException: N ist keine Potenz von 2 für den letzten Komplex [] fftArray = FFT.fft (fftTempArray); –

Antwort

0

Die folgende Zeile funktioniert nicht zuverlässig:

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

bufferSize als ein Byte viel größer sein kann und die Besetzung dann kann sogar negative Zahlen erzeugen, so dass Ihre Schleife ein einziges Mal nicht ausgeführt wird. fftTempArray wird dann nicht initialisiert.

Entfernen (byte) wird diesen Fehler korrigieren.

Aber es gibt mindestens einen zweiten Fehler: Ihre "Konvertierung von kurz zu doppelt" ist falsch. Es kombiniert zwei aufeinanderfolgende 16-Bit-Samples zu einem Doppel-Sample in micBufferData, während jedes 16-Bit-Sample seinem eigenen Doppel-Sample entsprechen sollte.

EDIT

Der Fehler aus Ihrem Kommentar zeigt, dass Ihr Array benötigt zusätzlich eine 2^N Größe zu haben. Also, finden Sie die 2^N Größe, die als nächstes unter bufferSize ist.

+0

Ich kann nicht scheinen, herauszufinden, warum dies auftritt? Ich kann aus print-Anweisungen sehen, dass es ausfällt, wenn N = 5. Ich glaube, dass sein Startindex 640 ist. Ist diese Zahl sogar sinnvoll? –

+0

Stellt sich heraus, meine Puffergröße = 640, die nicht Index 2 ist. Das ist interessant –

+0

So ist dann die nächst niedrigere 2^N Nummer 512 (= 2^9) –