IOS 中的吉他调音器:Goertzel 算法不适用于 6 弦中的 2 弦

Guitar Tuner in IOS: Goertzel Algorithm doesn't work for 2 of 6 strings

我试图在 IOS 8 中实现一个吉他调音器,我从 s.o 那里得到了一些代码。谁已经意识到这一点:它涉及 Goertzel 算法,该算法在短期内比较固定频率的大小 - 正如为 srings E-A-D-G-B-E 所定义的。 - 这里是放置在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;
}

然而,这样的套路只适用于下弦"D-G-B-E"。 对于 E 弦和 D 弦,我得到了错误的结果,我认为这种行为与泛音有关,因为它们似乎比搜索到的泛音更强——也许低 "E" 有 "A"或 "D" 作为泛音,振幅更大。

我的问题:s.o。遇到类似问题?并解决了? Goertzel 是正确的算法,还是 FFT 或卷积是更好的解决方案?

最后这里是我使用的 Goertzel 算法:

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;
}

Goertzel 算法测量特定频率的能量,而不是音调(这是一种不同的心理声学现象)。许多弦乐器和人声产生的最强频谱频率可能是泛音或谐波而不是音高频率,而频谱频率是 Goertzel 滤波器看到的而不是音高。

对于低频弦乐声音,尝试使用音高detection/estimation算法(例如自相关、ASDF、AMDF、RAPT、YAAPT等)而不是使用Goertzel滤波器(或简单的DFT幅度)来估计音调的存在。