I'm working on a guitar tuner app, by recording audio, getting an FFT of the audio, and finding the peak magnitude to find the base freq. So far results show my code works, and will give back an accurate frequency when played pure tones, especially at 500+hz, however with the low frequencies of guitar, and the loud harmonics, results are kind of messy.
I believe i need to introduce a window function, as well as a low pass filter to refine my results and help my app detect the right peak, and not a harmonic, but i'm not too sure
I have implemented a window function, although i'm not sure it's affecting final results, and i'm totally stuck on how to implement a low-pass filter.
byte data[] = new byte[bufferSize]; //the audio data read in
...
double[] window = new double[bufferSize]; //window array
//my window function, not sure if correct
for(int i = 0; i< bufferSize-1; ++i){
window[i] = ((1 - Math.cos(i*2*Math.PI/bufferSize-1))/2);
data[i] = (byte) (data[i] * window[i]);
}
DoubleFFT_1D fft1d = new DoubleFFT_1D(bufferSize);
double[] fftBuffer = new double[bufferSize*2];
for(int i = 0; i < bufferSize-1; ++i){
fftBuffer[2*i] = data[i];
fftBuffer[2*i+1] = 0;
}
fft1d.complexForward(fftBuffer);
//create/populate power spectrum
double[] magnitude = new double[bufferSize/2];
maxVal = 0;
for(int i = 0; i < (bufferSize/2)-1; ++i) {
double real = fftBuffer[2*i];
double imaginary = fftBuffer[2*i + 1];
magnitude[i] = Math.sqrt( real*real + imaginary*imaginary );
Log.i("mag",String.valueOf(magnitude[i]) + " " + i);
//find peak magnitude
for(int i = 0; i < (bufferSize/2)-1; ++i) {
if(magnitude[i] > maxVal){
maxVal = (int) magnitude[i];
binNo = i;
}
}
//results
freq = 8000 * binNo/(bufferSize/2);
Log.i("freq","Bin "+String.valueOf(binNo));
Log.i("freq",String.valueOf(freq) + "Hz");
So yeah, not entirely sure if the window function is doing much, power spectrum contains harmonic peaks regardless, and i'm not sure where to begin with using a low pass filter.