I am trying to implement an app where I can detect a whistle of a particular frequency (1000Hz - 1500Hz) even if there is environmental background noise and after a doing a lot of research on the net, I've used FFT methods to try and detect to see if the max amplitude that's captured from the mic corresponds with the whistle tone frequency.
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);
}
}
});
}
I've set up a mic recorder already and so forth but I can't understand what the code is doing and I'm getting some errors saying that my fftarray is negative. Could someone help me point in the right direction? Or is there a better way to implement a whistle detection? I'm using code from here. I'm getting a N is not to the power of 2 exception being thrown.