Reputation: 379
I'm trying to realize a guitar tuner in IOS 8 and I got some code from s.o. who already realized it: it deals with the Goertzel algorithm which in short terms compares the magnitudes of fixed frequencies - as defined for the srings E-A-D-G-B-E. - here the routine which is placed in the callback method of CoreAudio:
int currentString(SInt16 *samples, int N) {
int note0 = 82;
int note1 = 110;
int note2 = 147;
int note3 = 196;
int note4 = 247;
int note5 = 330;
int offset = 0.5;
double results[6];
// filter for the six strings
results[0] = (goertzelFilter(samples, note0+offset, N) +goertzelFilter(samples, note0, N) + goertzelFilter(samples, note0-offset, N))/3.0;
results[1] = (goertzelFilter(samples, note1+offset, N) +goertzelFilter(samples, note1, N) + goertzelFilter(samples, note1-offset, N))/3.0;
results[2] = (goertzelFilter(samples, note2+offset, N) +goertzelFilter(samples, note2, N) + goertzelFilter(samples, note2-offset, N))/3.0;
results[3] = (goertzelFilter(samples, note3+offset, N) +goertzelFilter(samples, note3, N) + goertzelFilter(samples, note3-offset, N))/3.0;
results[4] = (goertzelFilter(samples, note4+offset, N) +goertzelFilter(samples, note4, N) + goertzelFilter(samples, note4-offset, N))/3.0;
results[5] = (goertzelFilter(samples, note5+offset, N) +goertzelFilter(samples, note5, NN) + goertzelFilter(samples, note5-offset, N))/3.0;
int maxInd = -1;
double maxVal = 0.0;
for (int i=0; i<6; i++) {
if (results[i] > maxVal) {
if (i==0)
NSLog(@"String %d - value: %f", i+1, results[i]);
maxVal = results[i];
maxInd = i;
}
}
// if all levels are quite low, return -1
if (maxVal < 1) {
maxInd = -1;
}
return maxInd;
}
However, such routine works only for the lower string "D-G-B-E". For the E- and D-strings, I get erroneous results and I believe that such behavior has to do with overtones, as they seem to be stronger than the searched ones - maybe the low "E" has "A" or "D" as overtone, with a greater amplitude.
My question: has s.o. encountered similar problem? And resolved it? Is Goertzel the right algorithm for that, or are FFT or convolution a better solution?
Last here the Goertzel algorithm I use:
double goertzelFilter(SInt16* samples, double freq, int N) {
double s_prev = 0.0;
double s_prev2 = 0.0;
double coeff,normalizedfreq,power,s;
int i;
normalizedfreq = freq / 44100;
coeff = 2*cos(2*M_PI*normalizedfreq);
for (i=0; i<N; i++) {
s = samples[i] + coeff * s_prev - s_prev2;
s_prev2 = s_prev;
s_prev = s;
}
power = s_prev2*s_prev2+s_prev*s_prev-coeff*s_prev*s_prev2;
return power;
}
Upvotes: 0
Views: 779
Reputation: 70733
The Goertzel algorithm measures energy at a specific frequency, not musical pitch (which is a different psycho-acoustic phenomena). The strongest spectral frequencies produced by many stringed instruments and voices are likely to be overtones or harmonics instead of the pitch frequency, and spectral frequency is what a Goertzel filter sees instead of the pitch.
For low frequency string sounds, try using a pitch detection/estimation algorithm (such as autocorrelation, ASDF, AMDF, RAPT, YAAPT, etc.) instead of using a Goertzel filter (or simple DFT magnitude) to estimate the presence of a pitch.
Upvotes: 0