假设我有一个 WAV 文件。在这个文件中,是一系列以精确 1 秒为间隔的正弦音。我想使用 FFTW 库按顺序提取这些音调。这特别难做吗?我该怎么办?
另外,将这种音调写入 WAV 文件的最佳方法是什么?我假设我只需要一个简单的音频库来输出。
我选择的语言是 C
假设我有一个 WAV 文件。在这个文件中,是一系列以精确 1 秒为间隔的正弦音。我想使用 FFTW 库按顺序提取这些音调。这特别难做吗?我该怎么办?
另外,将这种音调写入 WAV 文件的最佳方法是什么?我假设我只需要一个简单的音频库来输出。
我选择的语言是 C
要获取文件部分的功率谱:
收集 N 个样本,其中 N 是 2 的幂 - 例如,如果您的采样率为 44.1 kHz,并且您希望大约每秒采样一次,那么就选择 N = 32768 个样本。
将加窗样本传递给FFT例程 - 理想情况下,您需要实数到复数 FFT,但如果您只有复数 FFT,则为所有虚输入部分传递 0
计算 FFT 输出箱的平方幅度(re * re + im * im)
(可选)计算每个幅度平方输出箱的 10 * log10 以获得以dB 为单位的幅度值
现在您已经有了功率谱,您只需要识别峰值,如果您有合理的 S/N 比,这应该非常简单。请注意,频率分辨率随着 N 的增大而提高。对于上述 44.1 kHz 采样率和 N = 32768 的示例,每个 bin 的频率分辨率为 44100 / 32768 = 1.35 Hz。
您基本上对估计频谱感兴趣 -假设您已经过了读取 WAV 并将其转换为离散时间信号的阶段。
在各种方法中,最基本的是周期图,它相当于采用窗口离散傅里叶变换(使用 FFT)并保持其平方幅度。这对应于保罗的回答。您需要一个跨越要检测的最低频率的几个周期的窗口。示例:如果您的正弦曲线可以低至 10 Hz(周期 = 100 毫秒),您应该采用 200 毫秒或 300 毫秒左右(或更多)的窗口。然而,周期图有一些缺点,虽然它计算简单,如果不需要高精度,它就足够了:
由于频谱偏差以及给定频率的方差不会随着计算中使用的样本数量的增加而减少的事实,原始周期图不是一个好的频谱估计。
周期图可以通过平均几个窗口来更好地执行,并明智地选择宽度(Bartlet 方法)。还有许多其他方法可以估计频谱(AR 建模)。
实际上,您对估计全频谱并不完全感兴趣,而只是对单个频率的位置感兴趣。这可以通过寻找估计频谱的峰值来完成(按照解释完成),也可以通过更具体和更强大(和复杂)的方法(Pisarenko,MUSIC 算法)来完成。在您的情况下,他们可能会矫枉过正。
WAV 文件包含线性脉冲编码调制 (LPCM)数据。这只是意味着它是固定采样率的一系列幅度值。RIFF 标头包含在文件的开头,用于传达诸如采样率和每个样本的位数(例如 8 kHz 有符号 16 位)之类的信息。
格式非常简单,您可以轻松滚动自己的格式。但是,有几个库可用于加速该过程,例如libsndfile。简单直接媒体层 (SDL) / SDL_mixer和PortAudio是两个不错的播放库。
至于将数据输入 FFTW,您需要缓冲 1 秒的块(通过采样率和每个样本的位数确定大小)。然后将所有样本转换为 IEEE 浮点数(即float
或double
取决于 FFTW 配置——libsndfile可以为您执行此操作)。接下来创建另一个数组来保存频域输出。最后,通过将两个缓冲区传递给并使用返回的句柄fftw_plan_dft_r2c_1d
调用来创建并执行一个 FFTW 计划。fftw_execute
fftw_plan