如何在WAV文件数据上执行FFT?

我试图通过检测存在的最高频率来分析文件的音频质量(压缩音频通常会被过滤到低于20KHz的值)。

我正在使用soundstretch库中的类来读取WAV文件数据,该类将PCM样本作为浮点数返回,然后使用fftw3库对这些样本执行FFT。 然后对于每个频率(四舍五入到最接近的KHz),我总计该频率的幅度。

因此,对于不包含16KHz以上频率的低质量文件,我预计在16KHz以上没有振幅或振幅很小,但是我没有得到我期望的结果。 以下是我的代码:

#include  #include  #include  #include  #include "include/WavFile.h" using namespace std; using namespace soundtouch; #define BUFF_SIZE 6720 #define MAX_FREQ 22//KHz static float freqMagnitude[MAX_FREQ]; static void calculateFrequencies(fftw_complex *data, size_t len, int Fs) { for (int i = 0; i < len; i++) { int re, im; float freq, magnitude; int index; re = data[i][0]; im = data[i][1]; magnitude = sqrt(re * re + im * im); freq = i * Fs / len; index = freq / 1000;//round(freq); if (index <= MAX_FREQ) { freqMagnitude[index] += magnitude; } } } int main(int argc, char *argv[]) { if (argc < 2) { cout << "Incorrect args" << endl; return -1; } SAMPLETYPE sampleBuffer[BUFF_SIZE]; WavInFile inFile(argv[1]); fftw_complex *in, *out; fftw_plan p; in = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * BUFF_SIZE); out = (fftw_complex*) fftw_malloc(sizeof(fftw_complex) * BUFF_SIZE); p = fftw_plan_dft_1d(BUFF_SIZE, in, out, FFTW_FORWARD, FFTW_ESTIMATE); while (inFile.eof() == 0) { size_t samplesRead = inFile.read(sampleBuffer, BUFF_SIZE); for (int i = 0; i < BUFF_SIZE; i++) { in[i][0] = (double) sampleBuffer[i]; } fftw_execute(p); /* repeat as needed */ calculateFrequencies(out, samplesRead, inFile.getSampleRate()); } for (int i = 0; i < MAX_FREQ; i += 2) { cout << i << "KHz magnitude: " << freqMagnitude[i] << std::endl; } fftw_destroy_plan(p); fftw_free(in); fftw_free(out); } 

可以编译: – (你需要soundtouch库和fftw3库)

 g++ -g -Wall MP3.cpp include/WavFile.cpp -lfftw3 -lm -lsoundtouch -I/usr/local/include -L/usr/local/lib 

这是我正在测试的文件的光谱分析:

Spek截图

你可以看到它的剪辑速度为16KHz,但我的结果如下:

 0KHz magnitude: 4.61044e+07 2KHz magnitude: 5.26959e+06 4KHz magnitude: 4.68766e+06 6KHz magnitude: 4.12703e+06 8KHz magnitude: 12239.6 10KHz magnitude: 456 12KHz magnitude: 3 14KHz magnitude: 650468 16KHz magnitude: 1.83266e+06 18KHz magnitude: 1.40232e+06 20KHz magnitude: 1.1477e+06 

我希望没有超过16KHz的振幅,我这样做对吗? 我的频率计算是否正确? (我把它从另一个stackoverflow回答中抢走了)这可能与2个频道有关并且我没有分离频道吗?

欢呼任何帮助的人。

您可能正在测量两个立体声声道之间的交错差异,这可能包括由于不均匀的混音和声像而导致的高频。 再次尝试将通道分离或混合为单声道,并使用平滑窗口function来减少FFT孔径边缘伪影,这也会因矩形窗口而引入少量高频噪声。

FFT基本要求是样本的时间间隔和它们的一致性。
在您的情况下,FFT算法的立体声信号电源加倍了它们之间不相关的样本数量。 数学上看到的是两个通道之间的自然相位差异,但更重要的是,两个样本由于无关,可能有如此大的差异而错误地表示方波(在时域中它将由极端表示高信号转换速率)。
作为解决方案,您必须将两个通道分开,并对一个采样系列或两个不同的FFT执行FFT。
我不认为可能存在任何混叠问题,因为这通常与采样过程有关,并且使用带通频率<1/2采样频率(奈奎斯特或抗混叠滤波器)的模拟滤波器来执行。 如果错过了这个过滤,那么几乎没有办法去掉鬼魂(别名谱)。

十年前,我作为一个具有非常轻微的实际经验和书本学习的人说话,所以这个答案可能是一些知识是危险的证据,但我认为你看到的问题只是混淆。

想象一下完美的方波。 你从来没有听过一个完美的方波,因为它需要一个声源立即从一个位置转换到另一个位置,同时仍然推动空气粒子。

您也无法描述具有有限数量谐波的方波。 但是,您可以简单地描述具有任何PCM音频频率的方波。 因此,任何源PCM音频都可能包含无限多个谐波。

您可以做的就是坐在Nyquist上面,并说如果输入音频是N Mhz那么可以是实际信号的最高频率部分是N / 2 Mhz; 因此,您可以将输入波重新采样至第一速率的两倍,小于或等于N / 2 Mhz,显示重要信号而不会丢失有意义的内容。