我目前正在尝试重现getSpectrum
FMOD 音频库的功能。此函数读取当前播放缓冲区的 PCM 数据,在此数据上应用一个窗口并应用 FFT 以获取频谱。
它返回一个浮点数组,其中每个浮点数介于 0 和 1 dB ( 10.0f * ( float)log10(val) * 2.0f
) 之间。
我不确定我应该做什么,所以我会解释一下:
首先,我在 4096 字节缓冲区中获取 PCM 数据,根据文档,PCM 数据由左右一对数据的样本组成。
就我而言,我正在使用上图中的 16 位样本。所以,如果我只想使用左声道,我将左 PCM 数据保存在一个短数组中:
short *data = malloc(4096);
FMOD_Sound_ReadData(sound, (void *)data, 4096, &read);
因此,如果一个样本 = 4 个字节,我有 1024 个样本,即代表左通道的 1024 个短路和代表右通道的 1024 个短路。
为了执行 FFT,我需要一个浮点数组并在我的数据上应用一个窗口(汉宁):
float hanningWindow(short in, size_t i, size_t s)
{
return in*0.5f*(1.0f-cos(2.0f*M_PI*(float)(i)/(float)(s-1.0f)));
}
wewin
是输入,i
是数组中的位置和数组s
的大小 (1024)。
仅获取左声道:
float *input = malloc(1024*sizeof(float));
for (i = 0; i < 1024; i++)
input[i] = hanningWindow(data[i*2], i, 1024);
然后我通过kiss_fft(从真实到复杂)执行FFT。我得到一个kiss_fft_cpx *ouput
大小为 1024/2+1 = 513 的(复数数组)。
我计算每个频率的幅度:
kiss_fft_cpx c = output[i];
float amp = sqrt(c.r*c.r + c.i*c.i);
以分贝计算:
amp = 10.0f * (float)log10(amp) * 2.0f;
amp
不在 0 和 1 之间。我不知道我必须在哪里规范化我的数据(在 PCM 数据上或最后)。另外我不确定我在 PCM 数据上应用我的窗口的方式。
这是我从 0 到 20kHz 的歌曲中得到的结果,与 getSpectrum 函数的结果相比。(对于矩形窗口)
My Result getSpectrum Result
我怎样才能达到相同的结果?