我想在真实音频设备上应用FFT并从中计算峰值
这是我的代码..
N=8192
kiss_fft_cpx out[N/2 +1];
int len = fft->N / 2 + 1;
kiss_fft_scalar* samples = &samples2[0]; //inputs from the mic
kiss_fftr(fft->config, samples, out);
for (int i = 0; i < len; i++) {
float re = scale(out[i].r) * N;
float im = scale(out[i].i) * N;
if (i > 0)
spectrum[i] = sqrtf(re * re + im * im) / (N / 2);
else
spectrum[i] = sqrtf(re * re + im * im) / N;
}
现在我使用代码计算选择。但每次它返回0
float peak = 0;
float maxEnergy = 0;
for (int i = 0; i < BUFFER_SIZE / 2 + 1; i++) {
float binEnergy = spectrum.at(i);
if (binEnergy > maxEnergy) {
maxEnergy = binEnergy;
peak = i;
}
}
这里我总是得到峰值= 0。请帮忙
以下是前25个FFT样本的频谱输出:
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[0]: 0.036530
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[1]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[2]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[3]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[4]: 0.040397
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[5]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[6]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[7]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[8]: 0.044121
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[9]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[10]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[11]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[12]: 0.040396
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[13]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[14]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[15]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[16]: 0.116464
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[17]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[18]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[19]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[20]: 0.040397
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[21]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[22]: 0.012086
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[23]: 0.011568
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(257) > specturm[24]: 0.044121
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(267) > peak 2223.000000
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(270) > FREQUENCY 4342.773438
06-05 17:28:34.512 : INFO / HelloWorld ( 3351 : 3351 ) : void GuitarTunerMainForm::calculateFrequency(Tizen::Base::ByteBuffer *)(281) > octave 8
答案 0 :(得分:2)
我怀疑你是(a)未能在FFT之前应用合适的window function和/或(b)你有一个大的直流分量。这将导致在0Hz处可能出现大的,可能是模糊的(由于spectral leakage)峰值。您可以通过打印/绘制光谱阵列来验证这一点。
解决这个问题:
在FFT之前应用合适的窗口函数(例如Hann)
更改峰值查找循环,使其从bin 0上方的某处开始,例如
const int PEAK_MIN = BUFFER_SIZE / 1024;
for (int i = PEAK_MIN; i < BUFFER_SIZE / 2 + 1; i++) {
...
答案 1 :(得分:2)
使用autocorrelation方法对语音进行音高检测有一种相当简单但计算密集的方法。我不明白为什么它也不适用于吉他!但是,当有一个以上的基频时,它会挣扎。但是,我不知道处理它的算法。
你需要采取足够的样本来覆盖至少3个音高周期。然后你自动相关信号(自相关可以有效performed with an FFT)。
如果您有自相关信号,您会发现滞后0处的最大峰值。第二高峰应该是您的音高。
通过在自相关之前使用类似汉明窗口的窗口来输入信号,可以获得更好的效果。
Praat成名的保罗·博尔斯玛(Paul Boersma)还远远地想出了more accurate method of pitch detection。
基本上使用他的计划。您将获取窗口函数的自相关,然后存储以供以后使用。接下来,您将输入信号窗口。自相关信号。现在除以窗口函数的自相关。最后,选择最高峰值,滞后0的偏移量是您的音高检测的样本数量。
值得注意的是,您确实需要插入自相关峰值以获得最佳结果。我个人使用抛物线插值,我获得的精度提高是巨大的。抛物线插值非常简单:
void ParabolicInterpolation( const float kA, const float kB, const float kC, float& p, float& m )
{
p = 0.5f * ((kA - kC) / (kA - (2.0f * kB) + kC));
m = (0.25f * (kA - kC) * p);
}
其中kB是您已经识别的自相关峰,kA是之前的自相关样本,kC是之后的样本。
编辑: 如果您不需要上述方法提供的那种精确度,那么另一种计算基频的简单方法称为谐波产品频谱({ {3}})。基本上你从FFT开始。您将其转换为幅度谱。最后你下采样2x,3x和4x。然后将样本相乘。最大峰值将按您的基频率计算。但是,这会受到FFT分辨率的严重限制。
希望有所帮助!