Android app to record sound in real time and identify frequency

user2463212 picture user2463212 · Jun 7, 2013 · Viewed 7.8k times · Source

I need to develop an app to record frequencies in real time using the phone's mic and then display them (in text). I am posting my code here. The FFT and complex classes have been used from http://introcs.cs.princeton.edu/java/97data/FFT.java.html and http://introcs.cs.princeton.edu/java/97data/Complex.java.html .The problem is when i run this on the emulator the frequency starts from some random value and keeps on increasing till 7996. It then repeats the whole process. Can someone plz help me out?

public class Main extends Activity {

TextView disp;
private static int[] sampleRate = new int[] { 44100, 22050, 11025, 8000 };
short audioData[];
double finalData[];
int bufferSize,srate;
String TAG;
public boolean recording;
AudioRecord recorder;
Complex[] fftArray;
float freq;


@Override
protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    disp = (TextView) findViewById(R.id.display);

    Thread t1 = new Thread(new Runnable(){

        public void run() {

            Log.i(TAG,"Setting up recording");
            for (int rate : sampleRate) {
                try{

                    Log.d(TAG, "Attempting rate " + rate);

            bufferSize=AudioRecord.getMinBufferSize(rate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT)*3; //get the buffer size to use with this audio record

            if (bufferSize != AudioRecord.ERROR_BAD_VALUE) {

            recorder = new AudioRecord (MediaRecorder.AudioSource.MIC,rate,AudioFormat.CHANNEL_CONFIGURATION_MONO,
            AudioFormat.ENCODING_PCM_16BIT,2048); //instantiate the AudioRecorder
            Log.d(TAG, "BufferSize " +bufferSize);
            srate = rate;

            }

            } catch (Exception e) {
                Log.e(TAG, rate + "Exception, keep trying.",e);
            }
        }
            bufferSize=2048;
            recording=true; //variable to use start or stop recording
            audioData = new short [bufferSize]; //short array that pcm data is put into.
            Log.i(TAG,"Got buffer size =" + bufferSize);                
            while (recording) {  //loop while recording is needed
                   Log.i(TAG,"in while 1");
            if (recorder.getState()==android.media.AudioRecord.STATE_INITIALIZED) // check to see if the recorder has initialized yet.
            if (recorder.getRecordingState()==android.media.AudioRecord.RECORDSTATE_STOPPED)
            recorder.startRecording();  //check to see if the Recorder has stopped or is not recording, and make it record.

            else {
                   Log.i(TAG,"in else");
                  // audiorecord();
                finalData=convert_to_double(audioData);
                Findfft();
                for(int k=0;k<fftArray.length;k++)
                {
                    freq = ((float)srate/(float) fftArray.length) *(float)k;
                    runOnUiThread(new Runnable(){
                     public void run()
                     {
                         disp.setText("The frequency is " + freq);
                         if(freq>=15000)
                             recording = false;
                     }
                 });


                }


             }//else recorder started

    } //while recording

    if (recorder.getState()==android.media.AudioRecord.RECORDSTATE_RECORDING) 
    recorder.stop(); //stop the recorder before ending the thread
    recorder.release(); //release the recorders resources
    recorder=null; //set the recorder to be garbage collected.

         }//run

    });
    t1.start();
}





private void Findfft() {
    // TODO Auto-generated method stub
    Complex[] fftTempArray = new Complex[bufferSize];
    for (int i=0; i<bufferSize; i++)
    {
        fftTempArray[i] = new Complex(finalData[i], 0);
    }
    fftArray = FFT.fft(fftTempArray);
}


private double[] convert_to_double(short data[]) {
    // TODO Auto-generated method stub
    double[] transformed = new double[data.length];

    for (int j=0;j<data.length;j++) {
    transformed[j] = (double)data[j];
    }

    return transformed;

}


@Override
public boolean onCreateOptionsMenu(Menu menu) {
    // Inflate the menu; this adds items to the action bar if it is present.
    getMenuInflater().inflate(R.menu.main, menu);
    return true;
 }
 }       

Answer

kandinski picture kandinski · Mar 11, 2014

Your question has been succinctly answered, however, to further your objectives and complete the loop...

Yes, FFT is not optimal on limited CPUs for pitch / frequency identification. A more optimal approach is YIN described here. You may find an implementation at Tarsos. Issues you will face are the lack of javax.sound.sampled in the ADK and therefore converting the shorts/bytes from AudioRecord to the floats required for the referenced implementations.