我们说我有一个WAV文件。在此文件中,是精确1秒间隔的一系列正弦音。我想使用FFTW库按顺序提取这些音调。这特别难吗?我该怎么做呢?
另外,将这种音调写入WAV文件的最佳方法是什么?我假设我只需要一个简单的音频库来输出。
我选择的语言是C
答案 0 :(得分:22)
获取文件某部分的power spectrum:
收集N个样本,其中N是2的幂 - 如果你的采样率是44.1 kHz,你想要大约每秒采样一次,那就去说N = 32768个样本。
对样本应用合适的window function,例如Hanning
将窗口样本传递给FFT例程 - 理想情况下,您需要一个真实到复数的FFT,但如果你只有一个是复数到复数的FFT,则为所有虚拟输入传递0份
计算FFT输出区的平方幅度(re * re + im * im)
(可选)计算每个幅度平方输出箱的10 * log10,以获得dB
中的幅度值现在您拥有了功率谱,您只需要确定峰值,如果您有合理的信噪比,这应该非常简单。请注意,频率分辨率随着N的增大而提高。对于上述44.1 kHz采样率和N = 32768的示例,每个箱的频率分辨率为44100/32768 = 1.35 Hz。
答案 1 :(得分:3)
你基本上对estimating a Spectrum感兴趣 - 假设你已经经历了阅读WAV并将其转换为离散时间信号的阶段。
在各种方法中,最基本的是周期图,相当于采用窗口离散傅立叶变换(带FFT)并保持其平方幅度。这符合保罗的答案。您需要一个窗口,该窗口跨越您想要检测的最低频率的几个周期。例如:如果你的正弦曲线可以低至10赫兹(周期= 100毫秒),你应该在200毫秒到300毫秒左右(或更长)的窗口。但是,周期图有一些disadvantages,虽然它很容易计算,如果不需要高精度,它就足够了:
原始周期图并不好 由于光谱的光谱估计 偏见和方差的事实 在给定频率下不会减少 作为使用的样本数量 计算量增加。
通过平均几个窗口,可以更好地选择周期图,并明智地选择宽度(Bartlet method)。还有许多其他估算频谱的方法(AR建模)。
实际上,您并不完全对估计全频谱感兴趣,而只对单一频率的位置感兴趣。这可以通过寻找估计频谱的峰值(如所解释的那样)来完成,但也可以通过更具体和更强大(和复杂)methods(Pisarenko,MUSIC算法)来完成。在你的情况下,他们可能会有点矫枉过正。
答案 2 :(得分:2)
WAV文件包含linear pulse code modulated (LPCM)个数据。这只意味着它是固定采样率的一系列振幅值。文件开头包含RIFF header,以传达sampling rate等信息和每个样本的比特(例如8 kHz带符号的16位)。
格式非常简单,您可以轻松自己动手。但是,有几个库可用于加速此过程,例如libsndfile。 Simple Direct-media Layer (SDL) / SDL_mixer和PortAudio是两个很好的播放库。
至于将数据馈送到FFTW,您需要缓冲1秒的块(通过采样率和每个样本的位确定大小)。然后将所有样本转换为IEEE浮点(即float
或double
,具体取决于FFTW配置 - libsndfile可以为您执行此操作)。接下来创建另一个数组来保存频域输出。最后,通过将两个缓冲区传递到fftw_plan_dft_r2c_1d
并调用fftw_execute
with the returned fftw_plan
handle来创建并执行FFTW计划。