您如何分析PCM或WAV样本的基频?

时间:2008-09-15 18:10:41

标签: audio signal-processing fft pitch-tracking

我有一个样本保存在DirectX的缓冲区中。这是从乐器演奏和捕捉的音符样本。如何分析样本的频率(如吉他调谐器)?我认为涉及到FFT,但我没有指向HOWTO。

7 个答案:

答案 0 :(得分:20)

FFT可以帮助您确定频率的位置,但它无法告诉您正好频率是多少。 FFT中的每个点都是频率的“bin”,所以如果你的FFT中有一个峰值,你所知道的就是你想要的频率在那个bin或频率范围内。

如果你想要它真的准确,你需要一个具有高分辨率和大量垃圾箱的长FFT(=大量内存和大量计算)。您还可以使用对数刻度光谱上的quadratic interpolation从低分辨率FFT中猜测真实峰值,这非常有效。

如果计算成本最重要,您可以尝试将信号转换为可以计算零交叉的形式,然后计算得越多,测量就越准确。

如果fundamental is missing,这些都不会起作用。 :)

我已经概述了一些不同的算法here,内插的FFT通常是最准确的(尽管这仅适用when the fundamental is the strongest harmonic - 否则你需要更聪明地找到它),零-crossings紧接着(尽管这只能起作用for waveforms with one crossing per cycle)。这些条件都不典型。

请记住,在许多乐器(如钢琴或吉他)中,基频以上的部分是完美的谐波。每个部分都是actually a little bit out of tuneinharmonic。因此,FFT中的高频峰值不会精确地位于基波的整数倍上,并且波形将从一个周期稍微改变到下一个周期,这会导致自相关。

为了得到一个非常准确的频率读数,我会说使用自相关来猜测基波,然后使用二次插值找到真正的峰值。 (你可以在频域中进行自相关以节省CPU周期。)有很多问题,正确的使用方法实际上取决于你的应用程序。

答案 1 :(得分:17)

还有其他算法是基于时间的,而不是基于频率的。 自相关是用于音调检测的相对简单的算法。 参考:http://cnx.org/content/m11714/latest/

我编写了自相关的c#实现和其他可读的算法。查看http://code.google.com/p/yaalp/

http://code.google.com/p/yaalp/source/browse/#svn/trunk/csaudio/WaveAudio/WaveAudio 列出文件,PitchDetection.cs就是你想要的那个。

(该项目是GPL;如果您使用该代码,请理解这些条款。)

答案 2 :(得分:6)

吉他调音器不使用FFT或DFT。通常他们只算零过境点。您可能无法获得基频,因为某些波形的交叉点比其他波形更多,但通常可以获得基频的倍数。这足以获得音符,尽管你可能会关闭一个或多个八度音阶。

在计算过零点之前进行低通滤波通常可以消除过多的过零点。调整低通滤波器需要知道您想要检测的频率范围

答案 3 :(得分:5)

确实会涉及FFT(快速傅里叶变换)。 FFT允许您使用固定频率和不同幅度的简单正弦波之和来近似任何模拟信号。您基本上要做的是取样并将其分解为幅度 - >频率对,然后采用与最高幅度相对应的频率。

希望另一位SO读者可以填补我在理论和代码之间留下的空白!

答案 4 :(得分:4)

更具体一点:

如果你从输入数组中的原始PCM开始,你基本上得到的是波幅与时间的关系图。进行FFT会将其转换为频率直方图,输入采样率为0到1/2的频率。结果数组中每个条目的值将是相应子频率的“强度”。

因此,在给定以S样本/秒采样的大小为N的输入数组时找到根频率:

FFT(N, input, output);
max = max_i = 0;
for(i=0;i<N;i++)
  if (output[i]>max) max_i = i;
root = S/2.0 * max_i/N ;

答案 5 :(得分:3)

检索PCM音频信号中的基频是一项艰巨的任务,有很多话题可以讨论......

无论如何,通常基于时间的方法不适用于复音信号,因为由多个基频引起的不同谐波分量之和给出的复数波具有过零率,该过零率仅取决于最低频率分量。 。 同样在频域中,FFT不是最合适的方法,因为音符之间的频率间隔遵循指数标度,而不是线性。这意味着如果时域中分析窗口的大小不够大,则FFT方法中使用的恒定频率分辨率可能不足以解析低频率音符。

更合适的方法是恒定Q变换,它是在低通滤波和信号抽取2(即将采样频率的每一步减半)的过程之后应用的DFT,以便获得不同的子带具有不同的频率分辨率以这种方式,优化了DFT的计算。麻烦的是,时间分辨率也是可变的,而较低的子带也会增加......

最后,如果我们试图估算单个音符的基频,FFT / DFT方法就可以了。对于复音上下文,情况发生变化,其中不同声音的部分重叠并且根据它们的相位差来求和/取消它们的幅度,因此单个频谱峰值可以属于不同的谐波内容(属于不同的音符)。在这种情况下的相关性没有给出好的结果......

答案 6 :(得分:1)

应用DFT,然后从结果中导出基频。在谷歌搜索DFT信息将为您提供所需的信息 - 我会将您链接到一些人,但他们对数学知识的期望差异很大。

祝你好运。