【发布时间】:2010-09-09 01:54:35
【问题描述】:
我有一个样本保存在 DirectX 的缓冲区中。这是从乐器演奏和捕捉的音符样本。如何分析样本的频率(就像吉他调音器一样)?我相信涉及到 FFT,但我没有指向 HOWTO。
【问题讨论】:
标签: audio signal-processing fft pitch-tracking
我有一个样本保存在 DirectX 的缓冲区中。这是从乐器演奏和捕捉的音符样本。如何分析样本的频率(就像吉他调音器一样)?我相信涉及到 FFT,但我没有指向 HOWTO。
【问题讨论】:
标签: audio signal-processing fft pitch-tracking
确实会涉及 FFT(快速傅立叶变换)。 FFT 允许您用固定频率和不同幅度的简单正弦波之和来近似任何模拟信号。您实际上要做的是获取样本并将其分解为幅度->频率对,然后获取与最高幅度相对应的频率。
希望另一位 SO 读者可以填补我在理论和代码之间留下的空白!
【讨论】:
应用DFT,然后从结果中推导出基频。谷歌搜索 DFT 信息将为您提供所需的信息 - 我会为您提供一些链接,但它们对数学知识的期望差异很大。
祝你好运。
【讨论】:
吉他调音器不使用 FFT 或 DFT。通常他们只计算零交叉。您可能无法获得基频,因为某些波形的过零次数比其他波形多,但您通常可以通过这种方式获得基频的倍数。尽管您可能会偏离一个或多个八度音阶,但这足以得到音符。
在计算过零之前进行低通滤波通常可以去除多余的过零。调整低通滤波器需要了解您想要检测的频率范围
【讨论】:
更具体一点:
如果您从输入数组中的原始 PCM 开始,您基本上拥有的是波幅与时间的关系图。执行 FFT 会将其转换为频率直方图,频率范围为输入采样率的 0 到 1/2 .结果数组中每个条目的值将是相应子频率的“强度”。
所以要在给定大小为 N 的输入数组以 S 个样本/秒采样的情况下找到根频率:
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 ;
【讨论】:
还有其他基于时间的算法,而不是基于频率的算法。 自相关是一种相对简单的音高检测算法。 参考: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;如果您使用代码,请了解条款)。
【讨论】:
FFT 可以帮助您确定频率在哪里,但它不能准确地告诉您频率是多少。 FFT 中的每个点都是频率的“bin”,因此如果 FFT 中有一个峰值,那么您所知道的就是您想要的频率在该 bin 或频率范围内的某个位置。
如果您希望它真正准确,则需要具有高分辨率和大量 bin(= 大量内存和大量计算)的长 FFT。您还可以使用 quadratic interpolation 在对数标度频谱上从低分辨率 FFT 中猜测真正的峰值,效果出奇的好。
如果计算成本最重要,您可以尝试将信号转换为可以计算过零的形式,然后计算得越多,测量就越准确。
但是,如果fundamental is missing,这些都不起作用。 :)
我已经概述了几种不同的算法 here,插值 FFT 通常是最准确的(尽管这只适用于 when the fundamental is the strongest harmonic - 否则你需要更聪明地找到它),过零接近第二(虽然这只适用于for waveforms with one crossing per cycle)。这两种情况都不是典型的。
请记住,在许多乐器(如钢琴或吉他)中,基频以上的分音不是完美的泛音。每个部分是actually a little bit out of tune,或inharmonic。因此,FFT 中的高频峰值不会正好在基波的整数倍上,而且波形会从一个周期到下一个周期略有变化,这会抛出自相关。
为了获得真正准确的频率读数,我建议使用自相关来猜测基频,然后使用二次插值找到真正的峰值。 (您可以在频域中进行自相关以节省 CPU 周期。)有很多陷阱,使用正确的方法实际上取决于您的应用程序。
【讨论】:
检索 PCM 音频信号中的基频是一项艰巨的任务,并且有很多要讨论的内容...
无论如何,通常基于时间的方法不适用于复音信号,因为由多个基频引起的不同谐波分量之和给出的复波具有仅取决于最低频率分量的过零率。 . 同样在频域中,FFT 也不是最合适的方法,因为音符之间的频率间隔遵循指数比例,而不是线性的。这意味着如果时域分析窗口的大小不够大,FFT 方法中使用的恒定频率分辨率可能不足以解析低频音符。
更合适的方法是常数 Q 变换,它是在对信号进行低通滤波和 2 抽取(即每步采样频率减半)的过程之后应用 DFT,以获得不同的子带具有不同的频率分辨率。通过这种方式优化了 DFT 的计算。问题是时间分辨率也是可变的,并且对于较低的子带会增加......
最后,如果我们试图估计单个音符的基频,FFT/DFT 方法是可以的。在复音环境中情况会发生变化,其中不同声音的部分重叠并根据它们的相位差求和/抵消它们的幅度,因此单个频谱峰值可能属于不同的谐波内容(属于不同的音符)。在这种情况下,相关性不会给出好的结果...
【讨论】: