FFT - 在PCM数据上应用窗口

时间:2012-03-10 11:16:07

标签: c signal-processing fft fmod kissfft

我目前正在尝试重现FMOD音频库的getSpectrum功能。此功能读取当前播放缓冲区的PCM数据,对此数据应用一个窗口并应用FFT来获取频谱。

它返回一个浮点数组,其中每个浮点数介于0和1 dB之间(10.0f * ( float)log10(val) * 2.0f)。

我不确定我做的是我应该做什么,所以我会解释一下:

首先,我在4096字节缓冲区中获取PCM数据,根据文档,PCM数据由左右数据对的样本组成。

data

就我而言,我正在使用16bit样本,如上图所示。因此,如果我只想使用左声道,我将左侧PCM数据保存在一个短阵列中:

short *data = malloc(4096);
FMOD_Sound_ReadData(sound, (void *)data, 4096, &read);  

因此,如果样本= 4个字节,我有1024个样本,即代表左声道的1024个短路和代表右声道的1024个短路。

为了执行FFT,我需要一个float数组并在我的数据上应用一个窗口(Hanning):

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

whew in是输入,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。我得到一个大小为1024/2 + 1 = 513的kiss_fft_cpx *ouput(复数数组)。

我用以下公式计算每个频率的幅度:

kiss_fft_cpx   c = output[i];
float          amp = sqrt(c.r*c.r + c.i*c.i);

以dB为单位计算:

amp = 10.0f * (float)log10(amp) * 2.0f;

amp不在0和1之间。我不知道在哪里我需要规范化我的数据(在PCM数据上或最后)。另外,我不确定我在PCM数据上应用窗口的方式。

这是我从0到20kHz的歌曲得到的结果与getSpectrum函数的结果相比较。 (对于矩形窗口

results

             My Result                         getSpectrum Result

如何获得相同的结果?

1 个答案:

答案 0 :(得分:2)

对于对数(dB)音阶你有点困惑 - 你没有得到0到1 dB的范围,对于16位音频,你得到一个典型的96 dB范围,其中上端和下端有点任意的,例如0至-96 dB,或96 dB至0 dB,或您喜欢的任何其他范围,具体取决于各种因素。您可能只需要通过合适的偏移量和因子来移动和缩放光谱图,以解决这个问题。

(注意:96 dB的范围来自公式20 * log10(2^16),其中16是位数。)