user2212383
user2212383

Reputation: 1

Low pass android PCM audio data

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.

Upvotes: 0

Views: 1936

Answers (3)

hotpaw2
hotpaw2

Reputation: 70743

FFT peak magnitude frequency detection usually won't work for determining guitar pitch, since the peak frequency is often not the frequency of the note pitch. Try using a pitch detection or estimation algorithm instead. See More accurate estimating guitar pitch frequency based on FFT(already) result for some alternatives.

Upvotes: 0

marko
marko

Reputation: 9169

The FFT can be thought of as a series of band-pass filters, with the magnitude of each bin being the power averaged over the window. A LPF upstream of a FFT isn't going to get you very much - you can just discard higher order FFT bins instead - unless you have a requirement for a particularly steep response.

The approach of implementing a guitar tuner with an FFT is problematic (although having implementing a successful tuner this way, they aren't insurmountable).

Finding the peak bin is a naive approach and won't give you precise results. Ever. Each bin is a band-pass filter, so you make the assumption that the measured result is the bin centre frequency. Here's what's wrong:

  • The frequencies of semitones in equal temperament are a geometric progression (the ratio is ~1.06), yet the spacing of FFT bins is linear. If we assume Fs is 44.1k and a 1024 point FFT is used, the bin spacing 44.1Hz. As E2 (the bottom string of a guitar is ~82Hz @A440), it's clear this a tuner using this approach will largely useless. Even trading an extremely large window size for real-time response (and a lot of processing), it's still not very accurate. You're totally screwed trying to tune an electric bass (bottom string: E1, ~41Hz)
  • What happens with frequencies that straddle bins? As it happens the frequencies of C in all octaves are not far from a power of 2. B - a note a guitar tuner does need to perform well on is close too. For these notes, the fundamental's energy is split almost evenly between two bands. It's likely not the largest any more.
  • Is the fundamental even the peak frequency? (Hint: it's often not).
  • Bins overlap. Just how much depends on the window function used.

If you want to persist with FFT solutions, you probably want to be use the STFT. There's a good description of how to do it from DSPDimension.com. The one piece of information missing from that page is that the definition of frequency is as the rate-of-change of phase:

F = dPhi/dt

Consequently, it is possible to estimate F knowing the phase difference between two consecutive windows of results.

Note that windowing is sampling, so sampling theory and the Nyquist rate applies to frequency resolution achievable with it. You need at least 2048-point FFTs for a guitar tuner.

Upvotes: 0

ederwander
ederwander

Reputation: 3478

The Window Function can help increase a bit your results.

The purpose of the window is to decrease the amplitude component of the ends of the window, in order to avoid the appearance of spurious high frequency, this is necessary because the Fourier transform assumes the signal to be infinite, so in case of a window, it is repeated countless times for both sides, causing a discontinuity at the borders!

If you apply one window, this problem is minimized, but still occur to some degree.

If are you working with guitar build a low-pass to filter the highest tuned frequency expected, you need Low-pass before apply your Window Function!

you need to consider the Frequency Response from the microphone, I believe it is not easy for these mobile microphones capture low-frequency of a tuned guitar, we are talk about 82.4Hz

Finding the peak of FFT is not a good idea to do tuners !

Upvotes: 1

Related Questions