## 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

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.011 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

Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

### Re: Get frequency data from microphone in real time

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

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

### Re: Get frequency data from microphone in real time

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

Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

### Re: Get frequency data from microphone in real time

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

Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

### Re: Get frequency data from microphone in real time

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

Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

### Re: Get frequency data from microphone in real time

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

Posts: 1
Joined: Mon Jan 23, 2012 11:14 am

### Re: Get frequency data from microphone in real time

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.014 seconds, using GeSHi 1.0.8.4
Kieper
Once Poster

Posts: 1
Joined: Sat Feb 04, 2012 1:01 pm

### Re: Get frequency data from microphone in real time

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

Posts: 1
Joined: Thu Feb 23, 2012 2:24 pm

### Re: Get frequency data from microphone in real time

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

Posts: 1
Joined: Thu Nov 08, 2012 5:35 am

### Re: Get frequency data from microphone in real time

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.012 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

Posts: 2
Joined: Sat Nov 24, 2012 9:39 am

### Re: Get frequency data from microphone in real time

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

Posts: 2
Joined: Sat Nov 24, 2012 9:39 am

### Re: Get frequency data from microphone in real time

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 sampleif (peaks>peakHeight*.95) peaked=true; //find if sample loudness is greater than past averageelse peaked=false;peakHeight=((peakHeight+peaks)/2); // average current sample loudness with previous loudness.`
xdebugx
Junior Developer

Posts: 24
Joined: Fri Apr 02, 2010 4:06 am

### Re: Get frequency data from microphone in real time

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

Posts: 19
Joined: Wed Nov 21, 2012 6:03 am

Previous

Return to Novice Tutorials

### Who is online

Users browsing this forum: No registered users and 3 guests