Autocorrelation on Audio Signals
One of the major confusions surrounding digital signal processing is the assumption that the peak frequency in the frequency domain will give you an indication of the fundamental frequency (or pitch) of the signal. This is wrong, and in fact no Fourier Transform should be done at all for the best results (at least in my opinion). Wikipedia gives you some idea of the kinds of pitch detection algorithms that can be used on sound (http://en.wikipedia.org/wiki/Pitch_detection_algorithm), and although many ideas are discussed there we will only focus on one, Autocorrelation.
Autocorrelation can be best explained by the cross correlation of the signal itself, and is used to weed out randomization in seemingly random data sets (such as an audio signal). To put it basically I've made some C code that calculates the fundamental frequency based on a minimum/maximum frequency lookup, a signal array and its length plus the constant sample rate of the signal (44.1kHz):
#define MIN_FREQ (1.0/(65.406/44100.0)) #define MAX_FREQ (1.0/(1046.502/44100.0)) double autoCorrelation(SInt16* samples,int length) { if(length >= MIN_FREQ) { int lookupCount = MIN_FREQ - MAX_FREQ; double* results = (double*) malloc(sizeof(double)*lookupCount); for(int p=MAX_FREQ;p<MIN_FREQ;p++) { double psum = 0.0; for(int i=0;i<length-p;i++) { psum += samples[i]*samples[i+p]; } results[p-MAX_FREQ] = psum / ((double)length); } double maxFreq = -1.79769313486231E+308; int maxIdx = -1; for(int i=0;i<lookupCount;i++) { if(results[i] > maxFreq) { maxFreq = results[i]; maxIdx = i; } } free(results); return 1.0/((double)(maxIdx+MAX_FREQ)/44100.0); } return 0.0; }
I do not recommend calling this function inside a RemoteIO callback, as you will encounter extreme lag towards the start of the application. Instead store the samples from that callback somewhere globally accessible, and then poll a process function using an NSTimer to return you your frequency results.
Hi,
I am trying to prove your code, but I can“t, might you put the project code to download an test the autocorrelation?
I’m also having trouble with this. Using your RemoteIO code to do the sampling, I always end up with 512 as my “length”. And since that number isn’t greater than the MIN_FREQ, the function never runs. I agree with Ricardo, a simple xcode project that combines the RemoteIO with the autocorrelation would be great to have.
-Rick
Hi.
First of all, I would like to thank you for these tutorials. Apple and iPhone community are not open like some other communities, so guys like you are of great help for newcomers.
I got a question regarding this snippet:
I am using your autocorrelation to get fundamental frequency of guitar tone, and it works great for high pitches. When you get to A string it starts to be less accurate, and E is almost impossible to tune. Do you maybe know why is that?
When I get wider range of octaves to test, i finally get lower harmonics of tone in some other octave, but that gets all system in crazy state – finding tones that aren’t there and other behavior that makes my tuner unusable (yep, I’m using this great code of yours from next entry to find tone)…
What I can’t understand is how can it be that 82 Hz is showing as 225 or 120 or that kind of crazy results, while first four strings are perfect in two decimals sometimes.
Even if you ignore this question – consider me thankful, because I found more useful code snippets here than 10 other sites combined.
Best regards.