Get frequency data from microphone in real time

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

Re: Get frequency data from microphone in real time

Postby xdebugx » Sat Feb 19, 2011 8:14 am

KeithB wrote:
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.031 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.


I got the 8000 from:

bufferSize=AudioRecord.getMinBufferSize(8000,AudioFormat.CHANNEL_CONFIGURATION_MONO,

Your recording at 8khz so there should be 8000 samples per second. So:

frequency = (8000/buffersize) should give you the period of time for one buffer that we process.
frequency = (8000/buffersize) * (numCrossings/2); should give the period of time, times the number of crossings.

Is this wrong? Is counting the number of samples and multiplying by the number of crossings better?
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 KeithB » Tue Mar 01, 2011 4:20 pm

Hello again xdebug. There is something maybe you can help me with. Im using your zero crossing methods to monitor frequencys from the microphone. But it would seem any frequency I pass in weather it be 250 hrz or 1000 hrz the frequency I get returned is a quater of the frequency I introduced. E.g

1000 hrz = returned value around 250.
575 hrz = returned value around 145.
250 hrz = returned value around 60.

I cant seem to figure out why this is and maybe you could sheed some light. I can only guess its something to do with the buffer size maybe or that im checking the value of frequency roughtly every 200 milliseconds and might that not be enought time to calculate a more accurate frequency?

Thanks again for your time.
KeithB
Freshman
Freshman
 
Posts: 6
Joined: Sat Jan 29, 2011 8:56 pm

Re: Get frequency data from microphone in real time

Postby xdebugx » Tue Mar 29, 2011 7:25 am

KeithB wrote:Hello again xdebug. There is something maybe you can help me with. Im using your zero crossing methods to monitor frequencys from the microphone. But it would seem any frequency I pass in weather it be 250 hrz or 1000 hrz the frequency I get returned is a quater of the frequency I introduced. E.g

1000 hrz = returned value around 250.
575 hrz = returned value around 145.
250 hrz = returned value around 60.

I cant seem to figure out why this is and maybe you could sheed some light. I can only guess its something to do with the buffer size maybe or that im checking the value of frequency roughtly every 200 milliseconds and might that not be enought time to calculate a more accurate frequency?

Thanks again for your time.


Try counting the number of samples, instead of using buffersize for the number of 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 xdebugx » Tue Mar 29, 2011 6:19 pm

I did some testing with a tone generator and was able to determine the frequency almost exactly; for all frequencies between about 300hz-2200hz. The low tones below 300 were detected higher, but it may be because of my microphone or speakers. I counted the exact number of samples and used that to get the frequency, the sample code is below:

Code: Select all
numCrossing=0;
            numSamples=0;
             recorder.read(audioData,0,bufferSize);

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


            frequency=(4000/numSamples)*numCrossing;


Interestingly, I was getting double the frequency at first, so I used 4000/numSamples, instead of 8000/numSamples.
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 » Wed Mar 30, 2011 2:09 pm

I found a mistake I had been making all along. I was doing the loop unrolling technique wrong. Below is the correct way to do it:

Code: Select all
numCrossing=0;
            numSamples=0;
            recorder.read(audioData,0,bufferSize);
            int mod=(int) (bufferSize/4)*4;
            for (p=0;p<mod;p+=4) {
                        if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
                        if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
                        if (audioData[p+1]>0 && audioData[p+2]<=0) numCrossing++;
                        if (audioData[p+1]<0 && audioData[p+2]>=0) numCrossing++;
                        if (audioData[p+2]>0 && audioData[p+3]<=0) numCrossing++;
                        if (audioData[p+2]<0 && audioData[p+3]>=0) numCrossing++;
                        if (audioData[p+3]>0 && audioData[p+4]<=0) numCrossing++;
                        if (audioData[p+3]<0 && audioData[p+4]>=0) numCrossing++;
                        numSamples+=4;
                        }//for p


                           for (p=p;p<bufferSize;p++) {
                           if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
                           if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
                           numSamples++;
                        }


            mGameThread.af=(8000/numSamples)*numCrossing;
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 gregorym » Mon Jan 23, 2012 11:28 am

Independently, I came to the same conclusion. I think this is correct:
Code: Select all
frequency = (8000/bufferSize) * (numCrossing/2);


The performance is somewhat poor, however, relatively speaking it works. Higher tones report higher frequency.
gregorym
Once Poster
Once Poster
 
Posts: 1
Joined: Mon Jan 23, 2012 11:14 am

Top

Re: Get frequency data from microphone in real time

Postby Kieper » Sat Feb 04, 2012 1:18 pm

My first post here, so hello ;).

Here is some fft code I found, it works pretty good, but you shouldn't use N bigger than 8 192 on slower phones.
x array is your input data from mic, y should be zeros, output is also handled in this arrays(x is real part, and y is imaginary part of complex number).
Bin frequency u get from (Fs*i)/N, Fs - sampling frequency, i - array element, N - total array elements.

Well if I'm wrong correct me ;).

Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.  
  2.     /***************************************************************
  3.      * fft.c
  4.      * Douglas L. Jones
  5.      * University of Illinois at Urbana-Champaign
  6.      * January 19, 1992
  7.      * http://cnx.rice.edu/content/m12016/latest/
  8.      *
  9.      *   fft: in-place radix-2 DIT DFT of a complex input
  10.      *
  11.      *   input:
  12.      * n: length of FFT: must be a power of two
  13.      * m: n = 2**m
  14.      *   input/output
  15.      * x: double array of length n with real part of data
  16.      * y: double array of length n with imag part of data
  17.      *
  18.      *   Permission to copy and use this program is granted
  19.      *   as long as this header is included.
  20.      *
  21.      *
  22.      ****************************************************************/
  23. public final class FFT {
  24.  
  25.     int n, m;
  26.     // Lookup tables.  Only need to recompute when size of FFT changes.
  27.     double[] cos;
  28.     double[] sin;
  29.     double[] window;
  30.  
  31.     public FFT(int n) {
  32.         this.n = n;
  33.         this.m = (int) (Math.log(n) / Math.log(2));
  34.  
  35.         // Make sure n is a power of 2
  36.         if (n != (1 << m)) {
  37.             throw new RuntimeException("FFT length must be power of 2");
  38.         }
  39.  
  40.         // precompute tables
  41.         cos = new double[n / 2];
  42.         sin = new double[n / 2];
  43.  
  44.         for (int i = 0; i < n / 2; i++) {
  45.             cos[i] = Math.cos(-2 * Math.PI * i / n);
  46.             sin[i] = Math.sin(-2 * Math.PI * i / n);
  47.         }
  48.     }
  49.  
  50.     public void fft(double[] x, double[] y) {
  51.         int i, j, k, n1, n2, a;
  52.         double c, s, e, t1, t2;
  53.  
  54.         // Bit-reverse
  55.         j = 0;
  56.         n2 = n / 2;
  57.         for (i = 1; i < n - 1; i++) {
  58.             n1 = n2;
  59.             while (j >= n1) {
  60.                 j = j - n1;
  61.                 n1 = n1 / 2;
  62.             }
  63.             j = j + n1;
  64.  
  65.             if (i < j) {
  66.                 t1 = x[i];
  67.                 x[i] = x[j];
  68.                 x[j] = t1;
  69.                 t1 = y[i];
  70.                 y[i] = y[j];
  71.                 y[j] = t1;
  72.             }
  73.         }
  74.         // FFT
  75.         n1 = 0;
  76.         n2 = 1;
  77.  
  78.         for (i = 0; i < m; i++) {
  79.             n1 = n2;
  80.             n2 = n2 + n2;
  81.             a = 0;
  82.  
  83.             for (j = 0; j < n1; j++) {
  84.                 c = cos[a];
  85.                 s = sin[a];
  86.                 a += 1 << (m - i - 1);
  87.  
  88.                 for (k = j; k < n; k = k + n2) {
  89.                     t1 = c * x[k + n1] - s * y[k + n1];
  90.                     t2 = s * x[k + n1] + c * y[k + n1];
  91.                     x[k + n1] = x[k] - t1;
  92.                     y[k + n1] = y[k] - t2;
  93.                     x[k] = x[k] + t1;
  94.                     y[k] = y[k] + t2;
  95.                 }
  96.             }
  97.         }
  98.     }
  99. }
  100.  
Parsed in 0.040 seconds, using GeSHi 1.0.8.4
Kieper
Once Poster
Once Poster
 
Posts: 1
Joined: Sat Feb 04, 2012 1:01 pm

Re: Get frequency data from microphone in real time

Postby iamgood » Thu Feb 23, 2012 2:50 pm

Hello xdebugx, I had used your progrm but the frequency is not accurate and is very difference in reality. Then, I had tried to modified your code, however, it didn't work, either. I don't know what should I do now. Thanks.
iamgood
Once Poster
Once Poster
 
Posts: 1
Joined: Thu Feb 23, 2012 2:24 pm

Re: Get frequency data from microphone in real time

Postby paulergiker » Thu Nov 08, 2012 5:47 am

Hi Kieper,

I tried to implement the fft code you posted but encountered a few problems due to my non-existing knowledge in the area.

I managed to run the FFT calculation but now I'm stuck with the x&y arrays and have no idea how to get the frequency. I understand that in the formula you posted ((Fs*i)/N Fs is my sampling frequency (the n parameter when creating an instance of the FFT class) and N is the length of the x-array. However I'm unclear on what i is. In the provided formula is "i" the complex' number's imaginary part from the y-array or how do I get "i"?

Thanks
paulergiker
Once Poster
Once Poster
 
Posts: 1
Joined: Thu Nov 08, 2012 5:35 am

Re: Get frequency data from microphone in real time

Postby ackblerg » Sat Nov 24, 2012 10:05 am

Hi thanks for the sample code, I was having the same troubles as the posters above when it came to the frequency values being less than expected. With a bit of fiddling around with the code I was able to get it to display the correct values, using 1KHZ and 2KHZ tones from youtube.

Heres the modified code that works.
Syntax: [ Download ] [ Hide ]
Using java Syntax Highlighting
  1.       numCrossing=0; //initialize your number of zero crossings to 0
  2.  
  3.       for (p=0;p<1000;p+=4) {
  4.              if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
  5.               if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
  6.               if (audioData[p+1]>0 && audioData[p+2]<=0) numCrossing++;
  7.               if (audioData[p+1]<0 && audioData[p+2]>=0) numCrossing++;
  8.               if (audioData[p+2]>0 && audioData[p+3]<=0) numCrossing++;
  9.               if (audioData[p+2]<0 && audioData[p+3]>=0) numCrossing++;
  10.               if (audioData[p+3]>0 && audioData[p+4]<=0) numCrossing++;
  11.               if (audioData[p+3]<0 && audioData[p+4]>=0) numCrossing++;
  12.               }//for p
  13.      
  14.         for (p=(bufferSize/4)*4;p<bufferSize-1;p++) {
  15.               if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
  16.               if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
  17.               }
  18.        
  19.                                                    
  20.         frequency=numCrossing*4;
  21. // Sampling at 8KHz and using 1000 samples thus the number of zero crossings
  22. //should be multiplied by 8 in order to get the numCrossings/second.
  23. //This number is divided by 2 to get the frequency(waves/sec) since 1 wave=2 zero crossings.
  24.  
  25.        
  26.  
Parsed in 0.039 seconds, using GeSHi 1.0.8.4


Instead of using all the buffer values ( in my case the min buffer size was round 2300), I only use 1000 of them. This seemed to solve the problem. By changing the buffer to 500, and changing the formula to freq=numCrossings * 8, I got the same accurate results. However when I changed the buffer to 2000, the results became inaccurate again (lower values for numCrossings/freq) . I'll look into it a bit more later, but I can only think of two reasons why this is happening.

1. For loop terminating before has a chance to process all data?
- Is that even possible?

2. Some kind of variable overflow.
-cant think of why, the values all seem to be rather small

Any ideas?
ackblerg
Freshman
Freshman
 
Posts: 2
Joined: Sat Nov 24, 2012 9:39 am

Re: Get frequency data from microphone in real time

Postby ackblerg » Sat Nov 24, 2012 10:35 am

More fiddling and I've worked out the for loop is not terminating early, neither is it some kind of buffer overflow-
however the samples 1000-2000 stored in the buffer contain less zero crossings (77) than the samples from 0-1000(250), for a pure tone, and this is what is causing the inaccurate calculated frequency. So either the microphone stops recording/or something hardware related is happening?

I plan to write a program that can sample the mic as fast as possible and raise a flag when it detects a change in volume in the environment that would be most likely caused by someone speaking, and then use this to trigger google voice recognition. I'll most likely collect and store mic data first so maybe that will make it easier to see whats currently the problem.
ackblerg
Freshman
Freshman
 
Posts: 2
Joined: Sat Nov 24, 2012 9:39 am

Re: Get frequency data from microphone in real time

Postby xdebugx » Sun Nov 25, 2012 3:54 pm

ackblerg wrote:More fiddling and I've worked out the for loop is not terminating early, neither is it some kind of buffer overflow-
however the samples 1000-2000 stored in the buffer contain less zero crossings (77) than the samples from 0-1000(250), for a pure tone, and this is what is causing the inaccurate calculated frequency. So either the microphone stops recording/or something hardware related is happening?

I plan to write a program that can sample the mic as fast as possible and raise a flag when it detects a change in volume in the environment that would be most likely caused by someone speaking, and then use this to trigger google voice recognition. I'll most likely collect and store mic data first so maybe that will make it easier to see whats currently the problem.



Are you testing it on an actual phone? I imagine there could be some anamollys on any number of phones. I tested it on my laptop with the emulator and it gave me pretty close to the frequency I was playing, but I expect my laptop didn't have any mic/buffer problems that a phone could have.

Loudness should be pretty easy to calculate. Take an average of the highs and lows (instead of zero-crossings) from the sample and trigger voice recognition when they spike for more than a second or two.


Here is the code I'm using to find spikes in volume:

Code: Select all
            numCrossing=0;
            numSamples=0;
            peaks=0;
            recorder.read(audioData,0,bufferSize);
            if (mGameThread.updateAF==true) {
            mod=(int) (bufferSize/4)*4;
            for (p=0;p<mod;p+=4) {

peaks = peaks + java.lang.Math.abs (audioData[p]) + java.lang.Math.abs (audioData[p+1]) + java.lang.Math.abs (audioData[p+2]) + java.lang.Math.abs (audioData[p+3]); //add together highes and lowes from each sample

                        if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
                        if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
                        if (audioData[p+1]>0 && audioData[p+2]<=0) numCrossing++;
                        if (audioData[p+1]<0 && audioData[p+2]>=0) numCrossing++;
                        if (audioData[p+2]>0 && audioData[p+3]<=0) numCrossing++;
                        if (audioData[p+2]<0 && audioData[p+3]>=0) numCrossing++;
                        if (audioData[p+3]>0 && audioData[p+4]<=0) numCrossing++;
                        if (audioData[p+3]<0 && audioData[p+4]>=0) numCrossing++;
                        numSamples+=4;
                        }//for p


                           for (;p<bufferSize;p++) {
peaks = peaks + java.lang.Math.abs (audioData[p]); //add together highes and lows from each sample
                           if (audioData[p]>0 && audioData[p+1]<=0) numCrossing++;
                           if (audioData[p]<0 && audioData[p+1]>=0) numCrossing++;
                           numSamples++;
                        }


               peaks = peaks / numSamples; //averge highs and lows from total sample

if (peaks>peakHeight*.95) peaked=true; //find if sample loudness is greater than past average
else peaked=false;

peakHeight=((peakHeight+peaks)/2); // average current sample loudness with previous loudness.

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 Sagar jacky » Wed Nov 28, 2012 11:54 am

I have never thought about this kind of activities like “get frequency data from microphone in real time”. I believe there are more applications are coming from the android developers and hope to see more useful ones from their end. Outlook tech support and troubleshoot help number
Sagar jacky
Junior Developer
Junior Developer
 
Posts: 19
Joined: Wed Nov 21, 2012 6:03 am

Top
Previous

Return to Novice Tutorials

Who is online

Users browsing this forum: No registered users and 6 guests