Get frequency data from microphone in real time

Basic Tutorials concerning: GUI, Views, Activites, XML, Layouts, Intents, ...

Get frequency data from microphone in real time

Postby xdebugx » Sun Aug 08, 2010 9:30 pm

How to get sound frequency data in real time, with android.

The class I use for recording audio in real time is called android.media.AudioRecord.
http://developer.android.com/reference/ ... ecord.html

It can record in real time, the only problem was getting the frequency data from the byte stream it returns. The AudioRecord class PCM encodes the audio data, so you need to decode the PCM format to get the frequency. There are several methods for decoding PCM data, the easiest for me was called Counting Zero Crossings. I've implemented a AudioRecord threaded class below that will update a variable in real time with the frequency currently "heard" in the microphone:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. //Author xdebugx.net (Jeremiah McLeod) 8-8-2010
  2.  
  3. import android.media.AudioRecord;
  4. import android.media.MediaRecorder.AudioSource;
  5. import android.media.AudioFormat;
  6.  
  7.  
  8. class recorderThread extends Thread {
  9. public boolean recording;  //variable to start or stop recording
  10. public int frequency; //the public variable that contains the frequency value "heard", it is updated continually while the thread is running.
  11. public recorderThread () {
  12. }
  13.  
  14. @Override
  15.         public void run() {
  16.                 AudioRecord recorder;
  17.                 int numCrossing,p;
  18.                 short audioData[];
  19.                 int bufferSize;
  20.                
  21.                 bufferSize=AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_CONFIGURATION_MONO,
  22. AudioFormat.ENCDING_PCM_16BIT)*3; //get the buffer size to use with this audio record
  23.  
  24. recorder = new AudioRecord (AudioSource.MIC,8000,AudioFormat.CHANNEL_CONFIGURATION_MONO,
  25. AudioFormat.ENCODING_PCM_16BIT,bufferSize); //instantiate the AudioRecorder
  26.                
  27. recording=true; //variable to use start or stop recording
  28. audioData = new short [bufferSize]; //short array that pcm data is put into.
  29.  
  30.  
  31. while (recording) {  //loop while recording is needed
  32.         if (recorder.getState()==android.media.AudioRecord.STATE_INITIALIZED) // check to see if the recorder has initialized yet.
  33.         if (recorder.getRecordingState()==android.media.AudioRecord.RECORDSTATE_STOPPED)
  34.               recorder.startRecording();  //check to see if the Recorder has stopped or is not recording, and make it record.
  35.                                
  36.         else {
  37.                        
  38.         recorder.read(audioData,0,bufferSize); //read the PCM audio data into the audioData array
  39.                                                
  40.         //Now we need to decode the PCM data using the Zero Crossings Method
  41.                                
  42.         numCrossing=0; //initialize your number of zero crossings to 0
  43.         for (p=0;p<bufferSize/4;p+=4) {
  44.                if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
  45.                 if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
  46.                 if (audioData[p+1]>0 && audioData[p+2]<=0) numCrossing++;
  47.                 if (audioData[p+1]<0 && audioData[p+2]>=0) numCrossing++;
  48.                 if (audioData[p+2]>0 && audioData[p+3]<=0) numCrossing++;
  49.                 if (audioData[p+2]<0 && audioData[p+3]>=0) numCrossing++;
  50.                 if (audioData[p+3]>0 && audioData[p+4]<=0) numCrossing++;
  51.                 if (audioData[p+3]<0 && audioData[p+4]>=0) numCrossing++;
  52.                 }//for p
  53.        
  54.           for (p=(bufferSize/4)*4;p<bufferSize-1;p++) {
  55.                 if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
  56.                 if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
  57.                 }
  58.                                                
  59.                                                
  60.                                                        
  61. frequency=(8000/bufferSize)*(numCrossing/2);  // Set the audio Frequency to half the number of zero crossings, times the number of samples our buffersize is per second.
  62.  
  63.                  }//else recorder started
  64.  
  65.         } //while recording
  66.                                
  67.         if (recorder.getState()==android.media.AudioRecord.RECORDSTATE_RECORDING) recorder.stop(); //stop the recorder before ending the thread
  68.         recorder.release(); //release the recorders resources
  69.         recorder=null; //set the recorder to be garbage collected.
  70.  
  71.         }//run
  72.  
  73.  
  74. }//recorderThread
Parsed in 0.041 seconds, using GeSHi 1.0.8.4


One thing that might give you a headache, is that the emulator only works with certain settings when instantiating your AudioRecord. There are options you can use for bit-rate, channel, and format. As of now only the ones I used in the example will work on the emulator. Other options should work on phones though.
Last edited by xdebugx on Tue Aug 24, 2010 6:07 am, edited 1 time in total.
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Top

Re: Get frequency data from microphone in real time

Postby nioupy » Sun Aug 22, 2010 5:31 pm

Hi,

thanks for those lines of code: i guess they'll prove handy to me, although at the moment, I'm starting getting that famous headache: for the moment, I cannot get the audio record state_initialised as true on my phone (htc desire)...
I guess I'll have to fiddle with the settings to get it on...
nioupy
Developer
Developer
 
Posts: 36
Joined: Sat Apr 03, 2010 1:34 pm

Re: Get frequency data from microphone in real time

Postby nioupy » Mon Aug 23, 2010 6:27 am

pfff : it took me a bit of fiddling to finally understand this: I am always forgetting the bases. Stupid me.

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. <uses-permission android:name="android.permission.RECORD_AUDIO"></uses-permission>
Parsed in 0.031 seconds, using GeSHi 1.0.8.4


A little of that in my manifest solved my initialisation issue...

Thanks for your class, it'll make a great start for my stuffs :)
nioupy
Developer
Developer
 
Posts: 36
Joined: Sat Apr 03, 2010 1:34 pm

Re: Get frequency data from microphone in real time

Postby xdebugx » Mon Aug 23, 2010 7:15 am

Oh darn, should have mention that before. Glad you found it. Btw, I'm not to sure if the formula I used to get the actuall frequency is correct, it's kind of sporatic. The frequency should be 1 divided by the time for one cycle. So I used 8000 / buffersize for the 1 second. Since in the example we are recording at 8khz. And the (numCrossings/2) should give you how many cycles per buffersize samples. Let me know if it works for you. Also to find the volume I think you multiply the numCrossings times your buffersize. But you have to have a reference to compare it too.
Last edited by xdebugx on Tue Aug 24, 2010 6:13 am, edited 1 time in total.
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Re: Get frequency data from microphone in real time

Postby fbarnard » Mon Aug 23, 2010 8:46 am

Nevermind it was a stupid question

Hi

This is what i was looking for for so long. One question this mite be a stupid question...

Why do you lookp every 4 to find the zero crossing point.
fbarnard
Developer
Developer
 
Posts: 44
Joined: Tue Jun 15, 2010 12:31 pm

Re: Get frequency data from microphone in real time

Postby fbarnard » Mon Aug 23, 2010 10:44 am

Hi

Here is another one :-)

Whats the difference between using Counting Zero Crossings and FFT. I did a quick google search and if i want to do and understand fft i must go to learn some advanced maths because dam its way over my head.


thanks
fbarnard
Developer
Developer
 
Posts: 44
Joined: Tue Jun 15, 2010 12:31 pm

Top

Re: Get frequency data from microphone in real time

Postby xdebugx » Tue Aug 24, 2010 5:46 am

fbarnard wrote:Hi

Here is another one :-)

Whats the difference between using Counting Zero Crossings and FFT. I did a quick google search and if i want to do and understand fft i must go to learn some advanced maths because dam its way over my head.


thanks



Which is why I used zero crossing's method. The main difference is that the FFT will give a more precise and accurate frequency, especially if theres mixed tones. The zero crossing is less precise and gives the overall tone.
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Re: Get frequency data from microphone in real time

Postby xdebugx » Tue Aug 24, 2010 5:51 am

fbarnard wrote:
Nevermind it was a stupid question

Hi

This is what i was looking for for so long. One question this mite be a stupid question...

Why do you lookp every 4 to find the zero crossing point.


Looping every 4 is a technique called loop unrolling. It is a bit faster than looping every 1. It still works the same, as I count each sample. It is faster because you spend less time doing the loops (incrementing and checking for end of loop). The second loop after the first one, is encase the buffersize is not evenly divisible by 4, to process the remaining samples.
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Re: Get frequency data from microphone in real time

Postby fbarnard » Tue Aug 24, 2010 7:40 am

thanks...
fbarnard
Developer
Developer
 
Posts: 44
Joined: Tue Jun 15, 2010 12:31 pm

Re: Get frequency data from microphone in real time

Postby KeithB » Tue Feb 08, 2011 3:36 pm

Hello,
Im currently working on a project that requires me to check if a certain frequency tone (Created using the ToneGenerator Class) has been heard on an second android devices microphone. I have currently been researching FFT but I am extremly new to DSP. I have a general understanding of fft but thats all.

Would I be able to use this code to find a certain frequency (I understand there can be inaccuracies due to tones mixing and harmonics)

Thanks very much for your time and apoligies for the poor understanding of DSP.
KeithB
Freshman
Freshman
 
Posts: 6
Joined: Sat Jan 29, 2011 8:56 pm

Re: Get frequency data from microphone in real time

Postby xdebugx » Wed Feb 09, 2011 6:21 am

Hello,
Im currently working on a project that requires me to check if a certain frequency tone (Created using the ToneGenerator Class) has been heard on an second android devices microphone. I have currently been researching FFT but I am extremly new to DSP. I have a general understanding of fft but thats all.

Would I be able to use this code to find a certain frequency (I understand there can be inaccuracies due to tones mixing and harmonics)

Thanks very much for your time and apoligies for the poor understanding of DSP.


This zero-crossings method is not as accurate as FFT, but is alot easier. When I researched how to decode PCM endoding, lots of sites mentioned FFT as a more accurate method, but it was hard to understand how to do it. The zero-crossings method will give you the overall approximate tone in most cases, FFT will be more accurate with mixed tones and harmonics.
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Re: Get frequency data from microphone in real time

Postby KeithB » Fri Feb 11, 2011 10:39 am

thanks xdebugx. Do you have any links that explains how zero crossing works in a simple manner. I cant seem to find any basic guides about it online. Your codes very nice but when it comes to your ForLoops for the numcrossing value i dont no whats being done and would linke to understand whats happening here. If you do have a link that may explain it it would be much appreciated.

Thanks
KeithB
Freshman
Freshman
 
Posts: 6
Joined: Sat Jan 29, 2011 8:56 pm

Re: Get frequency data from microphone in real time

Postby xdebugx » Sat Feb 12, 2011 1:58 am

It was hard to find examples I could understand :D , but this is one of the best: http://www.dsprelated.com/groups/matlab/show/2667.php

Basically your just looping through the data and counting how many times the numeric values cross zero. Or keeping track of when the sign changes. The way I did it was to check for when the data went from greater than zero to less than zero, or less than zero to greater than zero. I've simplified my code, without the for loop optimization below:

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2. numCrossing=0; //initialize your number of zero crossings to 0
  3. for (p=0;p<bufferSize-1;p++) {
  4. if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
  5. if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
  6. }//for p
  7.  
  8.  
Parsed in 0.035 seconds, using GeSHi 1.0.8.4
xdebugx
Junior Developer
Junior Developer
 
Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

Re: Get frequency data from microphone in real time

Postby KeithB » Mon Feb 14, 2011 1:17 pm

Thanks xdebugx. Last question. I understand when your trying to reconstruct the frequency using half the value of numCrossing multiplied by the number of samples your buffer is per second. But how does 8000 fit into this.

For example if I was doing a zero crossings method on a tone that is only one second long and is passed directly to the for loop which calculates the numCrossing value as an array, to reconstruct the frequency would I have

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. frequency = (numSamples) * (numCrossing/2) ;
Parsed in 0.035 seconds, using GeSHi 1.0.8.4

Thanks very much.
KeithB
Freshman
Freshman
 
Posts: 6
Joined: Sat Jan 29, 2011 8:56 pm

Re: Get frequency data from microphone in real time

Postby KeithB » Tue Feb 15, 2011 6:10 pm

KeithB wrote:Thanks xdebugx. Last question. I understand when your trying to reconstruct the frequency using half the value of numCrossing multiplied by the number of samples your buffer is per second. But how does 8000 fit into this.

For example if I was doing a zero crossings method on a tone that is only one second long and is passed directly to the for loop which calculates the numCrossing value as an array, to reconstruct the frequency would I have

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1. frequency = (numSamples) * (numCrossing/2) ;
Parsed in 0.036 seconds, using GeSHi 1.0.8.4

Thanks very much.


Silly me, I figured this out. Looking at code too long really does not make things easier.
KeithB
Freshman
Freshman
 
Posts: 6
Joined: Sat Jan 29, 2011 8:56 pm

Top
Next

Return to Novice Tutorials

Who is online

Users browsing this forum: No registered users and 5 guests