如何对 WAV 文件数据执行 FFT?
How to perform FFT on WAV file data?
我正在尝试通过检测存在的最高频率来分析文件的音频质量(压缩音频通常会被过滤到低于 20KHz 的频率)。
我正在使用来自 soundstretch 库的 class 读取 WAV 文件数据,其中 returns PCM 采样为浮点数,然后使用 fftw3 库对这些样本执行 FFT。然后对于每个频率(四舍五入到最接近的 KHz),我将计算该频率的振幅。
因此,对于不包含 16KHz 以上频率的低质量文件,我希望在 16KHz 以上会有 none 或非常小的振幅,但是我没有得到我期望的结果。下面是我的代码:
#include <iostream>
#include <math.h>
#include <fftw3.h>
#include <soundtouch/SoundTouch.h>
#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
这是我正在测试的文件的频谱分析:
如您所见,它被削波为 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 的振幅,我这样做对吗?
我的频率计算正确吗? (我从另一个 Whosebug 答案中抢走了它)
会不会是因为有2个频道,我没有分开频道?
为任何帮助的人干杯。
我是作为一个在十年前几乎没有实际经验和书本知识的人发言的,所以这个答案可能证明一点知识是一件危险的事情,但我认为你看到的问题只是混叠。
想象一个完美的方波。您从未听过完美的方波,因为它需要声源立即从一个位置转换到另一个位置,同时仍然推动空气粒子。
您也无法描述具有有限谐波数的方波。但是,您可以简单地描述具有任何频率的 PCM 音频的方波。因此,任何源 PCM 音频都可能包含无限数量的谐波。
你可能做的就是坐在奈奎斯特上面说,如果输入音频是 N Mhz,那么可以是实际信号的最高频率部分是 N/2 Mhz;因此,您可以将输入波重新采样到小于或等于 N/2 Mhz 的第一速率的两倍,这会显示重要信号而不会丢失有意义的内容。
您可能正在测量两个立体声通道之间的交错差异,其中可能包括由于混音和平移不均而导致的高频。再次尝试将通道分离或混合为单声道,并使用平滑 window 函数来减少 FFT 孔径边缘伪影,由于矩形 window,这也会引入少量高频噪声。
FFT 的基本要求是样本的时间间隔相等及其一致性。
在您的情况下,为 FFT 算法提供立体声信号会使它们之间不相关的样本数量加倍。数学上看到的是两个通道之间的自然相位差,但更重要的是,两个样本,因为不相关,可能有如此大的差异以错误地表示方波(在时域中,它会被表示为一个非常高信号转换率)。
作为一种解决方案,您必须将两个通道分开并对一个样本系列或两个不同的 FFT 执行 FFT。
我不认为可能存在任何混叠问题,因为这通常与采样过程有关,并且使用带通频率 < 1/2 采样频率(奈奎斯特或抗混叠滤波器)的模拟滤波器执行。如果错过了这个过滤,那么之后几乎没有办法去除重影(别名频谱)。
我正在尝试通过检测存在的最高频率来分析文件的音频质量(压缩音频通常会被过滤到低于 20KHz 的频率)。
我正在使用来自 soundstretch 库的 class 读取 WAV 文件数据,其中 returns PCM 采样为浮点数,然后使用 fftw3 库对这些样本执行 FFT。然后对于每个频率(四舍五入到最接近的 KHz),我将计算该频率的振幅。
因此,对于不包含 16KHz 以上频率的低质量文件,我希望在 16KHz 以上会有 none 或非常小的振幅,但是我没有得到我期望的结果。下面是我的代码:
#include <iostream>
#include <math.h>
#include <fftw3.h>
#include <soundtouch/SoundTouch.h>
#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
这是我正在测试的文件的频谱分析:
如您所见,它被削波为 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 的振幅,我这样做对吗? 我的频率计算正确吗? (我从另一个 Whosebug 答案中抢走了它) 会不会是因为有2个频道,我没有分开频道?
为任何帮助的人干杯。
我是作为一个在十年前几乎没有实际经验和书本知识的人发言的,所以这个答案可能证明一点知识是一件危险的事情,但我认为你看到的问题只是混叠。
想象一个完美的方波。您从未听过完美的方波,因为它需要声源立即从一个位置转换到另一个位置,同时仍然推动空气粒子。
您也无法描述具有有限谐波数的方波。但是,您可以简单地描述具有任何频率的 PCM 音频的方波。因此,任何源 PCM 音频都可能包含无限数量的谐波。
你可能做的就是坐在奈奎斯特上面说,如果输入音频是 N Mhz,那么可以是实际信号的最高频率部分是 N/2 Mhz;因此,您可以将输入波重新采样到小于或等于 N/2 Mhz 的第一速率的两倍,这会显示重要信号而不会丢失有意义的内容。
您可能正在测量两个立体声通道之间的交错差异,其中可能包括由于混音和平移不均而导致的高频。再次尝试将通道分离或混合为单声道,并使用平滑 window 函数来减少 FFT 孔径边缘伪影,由于矩形 window,这也会引入少量高频噪声。
FFT 的基本要求是样本的时间间隔相等及其一致性。
在您的情况下,为 FFT 算法提供立体声信号会使它们之间不相关的样本数量加倍。数学上看到的是两个通道之间的自然相位差,但更重要的是,两个样本,因为不相关,可能有如此大的差异以错误地表示方波(在时域中,它会被表示为一个非常高信号转换率)。
作为一种解决方案,您必须将两个通道分开并对一个样本系列或两个不同的 FFT 执行 FFT。
我不认为可能存在任何混叠问题,因为这通常与采样过程有关,并且使用带通频率 < 1/2 采样频率(奈奎斯特或抗混叠滤波器)的模拟滤波器执行。如果错过了这个过滤,那么之后几乎没有办法去除重影(别名频谱)。