Processing of Microphone Input

user893825 picture user893825 · Aug 14, 2011 · Viewed 15.2k times · Source

I am trying to get audio data from the microphone. I have achieved this by using the AudioRecord class which fills a buffer with type shorts.

Eventually I would like to graph this buffer so that I get an oscilloscope like display (realtime information). The problem is that if I want to display a value (say in text) then I need a different thread to update the UI. Currently I'm doing this by using an AsyncTask and updating the UI with AsyncTasks.publishProgress(). So far I haven't been very successful and would like to know if I'm on the right track? Are handles a better way to go? Is there anyone out there who has done something similar before, and if so what method worked for you? Also, is it at all possible to simply poll the microphone?


Here is my code. It is meant to output every read sample from the MIC. It appears to do this at an acceptable rate but occasionally displays a zero. Why?

package com.ss.audioacquireapp3;

import android.app.Activity;
import android.content.Context;
import android.media.AudioFormat;
import android.media.AudioRecord;
import android.os.AsyncTask;
import android.os.Bundle;
import android.util.Log;
import android.widget.TextView;


public class AudioAcquireApp3Activity extends Activity 
{
        //Properties (AsyncTask)
        protected TextView _percentField;
        protected InitTask _initTask;

        //Properties (MIC)
        public AudioRecord audioRecord; 
        public int mSamplesRead; //how many samples read 
        public int recordingState;
        public int buffersizebytes; 
        public int channelConfiguration = AudioFormat.CHANNEL_IN_MONO; 
        public int audioEncoding = AudioFormat.ENCODING_PCM_16BIT; 
        public static short[] buffer; //+-32767 
        public static final int SAMPPERSEC = 44100; //samp per sec 8000, 11025, 22050 44100 or 48000

    @Override
    public void onCreate( Bundle savedInstanceState ) 
    {
        super.onCreate(savedInstanceState);
        setContentView( R.layout.main );

        _percentField = ( TextView ) findViewById( R.id.percent_field );

        buffersizebytes = AudioRecord.getMinBufferSize(SAMPPERSEC,channelConfiguration,audioEncoding); //4096 on ion 
        buffer = new short[buffersizebytes]; 
        audioRecord = new AudioRecord(android.media.MediaRecorder.AudioSource.MIC,SAMPPERSEC,channelConfiguration,audioEncoding,buffersizebytes); //constructor 

        _initTask = new InitTask();
        _initTask.execute( this );
    }

    /**
     * sub-class of AsyncTask
     */
    protected class InitTask extends AsyncTask<Context, Integer, String>
    {
        // -- run intensive processes here
        // -- notice that the datatype of the first param in the class definition matches the param passed to this method 
        // -- and that the datatype of the last param in the class definition matches the return type of this method
                @Override
                protected String doInBackground( Context... params ) 
                {
                        //-- on every iteration
                        //-- runs a while loop that causes the thread to sleep for 50 milliseconds 
                        //-- publishes the progress - calls the onProgressUpdate handler defined below
                        //-- and increments the counter variable i by one
                        //int i = 0;

                    audioRecord.startRecording();

                        while( true ) 
                        {
                                try{
                                        mSamplesRead = audioRecord.read(buffer, 0, buffersizebytes);

                                        int amp;

                                        for(int i = 0; i < buffersizebytes - 1; i++){
                                            amp = (int)buffer[i];
                                            publishProgress( amp );
                                        }

                                } catch( Exception e ){                        
                                }
                        }
                }

                // -- gets called just before thread begins
                @Override
                protected void onPreExecute() 
                {
                        //Log.i( "makemachine", "onPreExecute()" );
                        super.onPreExecute();

                }

                // -- called from the publish progress 
                // -- notice that the datatype of the second param gets passed to this method
                @Override
                protected void onProgressUpdate(Integer... values) 
                {
                        super.onProgressUpdate(values);
                        //Log.i( "makemachine", "onProgressUpdate(): " +  String.valueOf( values[0] ) );
                        _percentField.setText( String.valueOf(values[0]) );
                }

                // -- called as soon as doInBackground method completes
                // -- notice that the third param gets passed to this method
                @Override
                protected void onPostExecute( String result ) 
                {
                        super.onPostExecute(result);
                        //Log.i( "makemachine", "onPostExecute(): " + result );
                }   


     } 
}

And here is main.xml

<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
    android:orientation="vertical"
    android:layout_width="fill_parent"
    android:layout_height="fill_parent"
    android:gravity="center_vertical|center_horizontal"
    >

<TextView android:id="@+id/percent_field"
          android:layout_width="fill_parent" 
          android:layout_height="wrap_content"
          android:gravity="center_horizontal"/>

</LinearLayout>

Note that you need to add this to AndroidManifest.xml

<uses-permission android:name="android.permission.RECORD_AUDIO" />

I am running this on a LG Optimus Black. Please help me make this code as efficient as possible.

Answer

pkk picture pkk · Aug 14, 2011
  1. If you need to update UI thread from any thread you may always use Activity.runOnUiThread(Runnable action). See Activity class javadoc for details.
  2. I'm not sure what exactly do you mean by 'simpy poll the microphone', but in my opinion AudioRecord is a good way to go, when recording micrphone. Here is a link to example implementation, which reads frequency of recorded audio live: http://www.anddev.org/novice-tutorials-f8/get-frequency-data-from-microphone-in-real-time-t16774.html

Hope this helps.