【问题标题】:How to perform FFT on WAV file data?如何对 WAV 文件数据执行 FFT?
【发布时间】:2016-05-30 19:44:55
【问题描述】:

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

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

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

#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 的幅度,我这样做对吗? 我的频率计算是否正确? (我从另一个stackoverflow答案中抢走了它) 这可能与有 2 个频道有关,而我没有分开频道吗?

为任何帮助的家伙干杯。

【问题讨论】:

  • FFT 需要一个周期信号,而你没有。这需要使用窗口函数来消除伪影。谷歌“fft 窗口功能”,很多点击。并确保正确测试,使用单一或少数频率的测试文件。
  • 我认为,如果您使用的是 2 通道交错部署的立体声信号,则有必要将它们分开。 fft 假定样本是指相同间隔的相同波形,但您有两倍的样本,如果通道之间的信号完全不同,您也会有快速变化(信号转换速率),这会产生错误的高频内容。
  • @Frankie_C :您的评论可能就是答案。将其发布为答案,我将删除我的。

标签: c++ c audio fft wav


【解决方案1】:

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

【讨论】:

    【解决方案2】:

    FFT 的基本要求是样本的相等时间间隔及其全等。
    在您的情况下,为 FFT 算法提供的立体声信号会使它们之间不相关的样本数量增加一倍。数学上看到的是两个通道之间的自然相位差,但更重要的是,两个样本,因为不相关,可能有如此大的差异以错误地表示方波(在时域中,它会用一个极高信号转换率)。
    作为一种解决方案,您必须分离两个通道并对一个系列样本或两个不同的 FFT 执行 FFT。
    我不认为可能存在任何混叠问题,因为这通常与采样过程有关,并且使用带通频率

    【讨论】:

      【解决方案3】:

      我作为一个在十多年前具有非常少的现实世界经验和书籍学习的人发言,所以这个答案可能证明一点知识是一件危险的事情,但我认为你看到的问题只是混叠。

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

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

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

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-09-11
        • 2014-03-16
        • 2014-06-16
        • 2014-09-16
        • 1970-01-01
        • 2018-06-07
        • 2020-01-06
        相关资源
        最近更新 更多