Get the frequency of an audio file in every 1/4 seconds in android

Jani Bela picture Jani Bela · Aug 7, 2012 · Viewed 9.9k times · Source

I have a sound file (.3gp) and its about ~1 min. I would like to get the frequency of this sound file in every 1/4 seconds. My idea is to receive samples in every 1/4 seconds from the audio file and using FFT I might get the frequency values. Is there any way to do this?

Actually I would split the sound file into 1/4sec samples sound files (alwyas overwriting the preveious one), then using FFT algorithm and detect the frequency where the magintude is the bigggest. But there might be easier solutions however I dont have a clue how to do this either.

***UPDATE 2 - new code

I use this code so far:

public class RecordAudio extends AsyncTask<Void, double[], Void> {

    @Override
    protected Void doInBackground(Void... arg0) {

        try {
             int bufferSize = AudioRecord.getMinBufferSize(frequency,
             AudioFormat.CHANNEL_IN_MONO, AudioFormat.ENCODING_PCM_16BIT);


            //int bufferSize = AudioRecord.getMinBufferSize(frequency, 
                  //  channelConfiguration, audioEncoding); 

            AudioRecord audioRecord = new AudioRecord( 
                    MediaRecorder.AudioSource.MIC, frequency, 
                    channelConfiguration, audioEncoding, bufferSize); 

            short[] buffer = new short[blockSize];
            //double[] toTransform = new double[blockSize];


            audioRecord.startRecording();


            // started = true; hopes this should true before calling
            // following while loop

            while (started) {
               sampling++;

               double[] re = new double[blockSize];
               double[] im = new double[blockSize];

               double[] newArray = new double[blockSize*2];
               double[] magns = new double[blockSize];

               double MaxMagn=0;
               double pitch = 0;

               int bufferReadResult = audioRecord.read(buffer, 0,
                        blockSize);


               for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                   re[i] = (double) buffer[i] / 32768.0; // signed   16bit
                   im[i] = 0;
               }    

               newArray = FFTbase.fft(re, im,true);

               for (int i = 0; i < newArray.length; i+=2) {

                   re[i/2]=newArray[i];
                   im[i/2]=newArray[i+1];
                   magns[i/2] = Math.sqrt(re[i/2]*re[i/2]+im[i/2]*im[i/2]);
               }

              // I only need the first half      

              for (int i = 0; i < (magns.length)/2; i++) {
                   if (magns[i]>MaxMagn)
                   {
                       MaxMagn = magns[i];
                       pitch=i;
                   }
               }                                           
                 if (sampling > 50) {
                   Log.i("pitch and magnitude", "" + MaxMagn + "   " + pitch*15.625f);
                   sampling=0;
                   MaxMagn=0;pitch=0;
                   }                   


            }

            audioRecord.stop();

        } catch (Throwable t) {
            t.printStackTrace();
            Log.e("AudioRecord", "Recording Failed");
        }
        return null;
    }

I use this: http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

Guitar strings seem correct, but my own sound is not good because of this:

enter image description here

The magnitude of the two peaks change most of the time and I always find the biggest to get the fundamental frequency.

Answer

Bjorn Roche picture Bjorn Roche · Aug 8, 2012

Pitch tracking with the FFT is asked so often on Stack Overflow I wrote a blog entry with sample code. The code is in C, but with the explanation and links you should be able to do what you want.

As to dividing it up into 1/4 second increments, you could simply take FFTs of 1/4 second segments as you suggested, instead of the default (which I think is about 1 second). If this doesn't give you the frequency resolution you want, you may have to use a different pitch recognition method. Another thing you could do is use overlapping segments that are longer than 1/4 second, but start at intervals that are 1/4 second apart. This method is alluded to the blog entry, but it may not meet your design spec.