0

I am trying to obtain frequency from a Microphone using FFT. Which is given here- http://www.wikijava.org/wiki/The_Fast_Fourier_Transform_in_Java_%28part_1%29

The FFT function takes in three parameters, the real, imaginary and a boolean value. The real and the imaginary portions are obtained from the recorded buffer.

The FFT function returns an array, from which the index of the largest magnitude is calculated. This is used to get the frequency.

But when i run the application I am not getting the desired frequency values. Is there something wrong with my sampling rate/buffersize/blocksize? Or is there something wrong with the calculation itself.

public class MainActivity extends Activity {

int audioSource = MediaRecorder.AudioSource.MIC;    // Audio source is the device MIC
int channelConfig = AudioFormat.CHANNEL_IN_MONO;    // Recording in mono
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit
int blockSize = 1024;                               // deal with this many samples at a time
int sampleRate = 8000;                             // Sample rate in Hz
public double frequency = 0.0;                      // the frequency given
RecordAudio recordTask;                             // Creates a Record Audio command
TextView tv;                                        // Creates a text view for the frequency
boolean started = false;
Button startStopButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv = (TextView) findViewById(R.id.textView1);
    startStopButton = (Button) findViewById(R.id.button1);
    startStopButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick (View v){
            if (started) {
                started = false;
                startStopButton.setText("Start");
                recordTask.cancel(true);
            }
            else{
                started = true;
                startStopButton.setText("Stop");
                recordTask = new RecordAudio();
                recordTask.execute();
            }

        }
    });
}

private class RecordAudio extends AsyncTask<Void, Double, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding);                // Gets the minimum buffer needed
        AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize);   // The RAW PCM sample recording
        short[] buffer = new short[blockSize];          // Save the raw PCM samples as short bytes
        double[] re = new double[blockSize];
        double[] im = new double[blockSize];
        double[] magnitude = new double[blockSize];
        try {
            audioRecord.startRecording();  //Start
        } catch (Throwable t) {
        }
        while (started) {
            int bufferReadResult = audioRecord.read(buffer, 0, blockSize);
            for (int i = 0; i < blockSize && i < bufferReadResult; i++) {
                re[i] =((double) buffer[i] / 32768.0); // signed 16 bit
                im[i]=0;

            }
            double[] newArray = new double[blockSize*2];
            newArray = FFTbase.fft(re, im,true);
            double real;
            double imag;
            for(int i=0;i<(newArray.length/2)-1;i++)
            {
                real=newArray[2*i];
                imag=newArray[2*i+1];
                magnitude[i]=Math.sqrt(real*real+imag*imag);
    }
            double MaxMagn=-1.0;
            int index=0;
            for (int i = 0; i < (magnitude.length); i++) {
                if (magnitude[i]>MaxMagn)
                {
                    MaxMagn = magnitude[i];
                    index=i;
                }
            }
            publishProgress((double)(index * sampleRate)/blockSize);

        }
        return null;
    }
    @Override
    protected void onProgressUpdate(Double... values) {
        TextView display = (TextView) findViewById(R.id.textView1);
        display.setText(String.valueOf(values[0]));
        }
}

This is the zero crossing method which i tried. But this also did not give me the desired frequency.

public class MainActivity extends Activity {

int audioSource = MediaRecorder.AudioSource.MIC;    // Audio source is the device MIC
int channelConfig = AudioFormat.CHANNEL_CONFIGURATION_MONO;    // Recording in mono
int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; // Records in 16bit
int blockSize = 256;                               // deal with this many samples at a time
int sampleRate = 8000;                             // Sample rate in Hz
public double frequency = 0.0;                      // the frequency given
RecordAudio recordTask;                             // Creates a Record Audio command
TextView tv;                                        // Creates a text view for the frequency
boolean started = false;
Button startStopButton;

@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    tv = (TextView) findViewById(R.id.textView1);
    startStopButton = (Button) findViewById(R.id.button1);
    startStopButton.setOnClickListener(new OnClickListener() {

        @Override
        public void onClick (View v){
            if (started) {
                started = false;
                startStopButton.setText("Start");
                recordTask.cancel(true);
            }
            else{
                started = true;
                startStopButton.setText("Stop");
                recordTask = new RecordAudio();
                recordTask.execute();
            }

        }
    });
}

private class RecordAudio extends AsyncTask<Void, Double, Void> {
    @Override
    protected Void doInBackground(Void... params) {
        int bufferSize = AudioRecord.getMinBufferSize(sampleRate, channelConfig, audioEncoding);                // Gets the minimum buffer needed
        AudioRecord audioRecord = new AudioRecord(audioSource, sampleRate, channelConfig, audioEncoding, bufferSize);   // The RAW PCM sample recording
        short[] buffer = new short[blockSize];          // Save the raw PCM samples as short bytes
        double[] re = new double[blockSize];
        double[] im = new double[blockSize];
        double[] magnitude = new double[blockSize];
        try {
            audioRecord.startRecording();  //Start
        } catch (Throwable t) {
        }
        int sampling=0;
        while (started) {
            sampling++;
            int bufferReadResult = audioRecord.read(buffer, 0, blockSize);




            int numCrossing=0; //initialize your number of zero crossings to 0
            int p=0;
            for (p=0;p<bufferSize/4;p+=4) {
                if (buffer[p]>0 && buffer[p+1]<=0) numCrossing++;
                if (buffer[p]<0 && buffer[p+1]>=0) numCrossing++;
                if (buffer[p+1]>0 && buffer[p+2]<=0) numCrossing++;
                if (buffer[p+1]<0 && buffer[p+2]>=0) numCrossing++;
                if (buffer[p+2]>0 && buffer[p+3]<=0) numCrossing++;
                if (buffer[p+2]<0 && buffer[p+3]>=0) numCrossing++;
                if (buffer[p+3]>0 && buffer[p+4]<=0) numCrossing++;
                if (buffer[p+3]<0 && buffer[p+4]>=0) numCrossing++;
            }//for p

            for (p=(bufferSize/4)*4;p<bufferSize-1;p++) {
                if (buffer[p]>0 && buffer[p+1]<=0) numCrossing++;
                if (buffer[p]<0 && buffer[p+1]>=0) numCrossing++;
            }



            frequency=(sampleRate/bufferSize)*(numCrossing/2);
            if(sampling>20){
            //publishProgress((double)(index * sampleRate)/bufferSize);
            publishProgress((double)frequency);
            sampling=0;
            }}
        return null;
    }
shivram
  • 469
  • 2
  • 10
  • 26
  • Depending on the nature of your audio source the largest peak may not be interesting - it could even just be the DC (0 Hz) value. What kind of audio are you looking at and what information are you trying to determine? If you're looking to identify musical *pitch* then you're probably using the wrong approach. – Paul R Jan 04 '15 at 07:40
  • I am trying to get the pitch of tone, so that i could determine the note which is being played by the piano. I tried the zero crossing method as well. But that is not giving me the desired result as well. I will attach the zero crossing code as well. – shivram Jan 04 '15 at 07:50
  • @PaulR I have attached the zero crossing code. – shivram Jan 04 '15 at 07:53
  • The zero crossing method is pretty much useless for anything but pure sinusoids with perfect SNR. For piano notes, which are complex sounds, you should use a proper pitch detection method, such as harmonic product spectrum. There are lots of good questions and answers about this very subject here on SO already - read a few of these to get a better understanding of how to implement pitch detection properly. – Paul R Jan 04 '15 at 08:58
  • See also the links you were given in response to [your previous question](http://stackoverflow.com/questions/27754810/android-mapping-frequency-obtained-from-fft-to-musical-notes) which you seem to have ignored. – Paul R Jan 04 '15 at 09:01

0 Answers0