您如何分析 PCM 或 WAV 样本的基频? [关闭]
Posted
技术标签:
【中文标题】您如何分析 PCM 或 WAV 样本的基频? [关闭]【英文标题】:How do you analyse the fundamental frequency of a PCM or WAV sample? [closed] 【发布时间】:2010-09-09 01:54:35 【问题描述】:我有一个样本保存在 DirectX 的缓冲区中。这是从乐器演奏和捕捉的音符样本。如何分析样本的频率(就像吉他调音器一样)?我相信涉及到 FFT,但我没有指向 HOWTO。
【问题讨论】:
【参考方案1】:确实会涉及 FFT(快速傅立叶变换)。 FFT 允许您用固定频率和不同幅度的简单正弦波之和来近似任何模拟信号。您实际上要做的是获取样本并将其分解为幅度->频率对,然后获取与最高幅度相对应的频率。
希望另一位 SO 读者可以填补我在理论和代码之间留下的空白!
【讨论】:
这种方法存在严重的准确性问题,尤其是在音乐上下文中。正如 endolith 指出的那样,FFT 可以为您提供一系列频率范围内的强度; FFT 窗口大小越小(越快),范围越大。更糟糕的是,整体范围是 0 到 44100 Hz(对于红皮书音频),而典型的音符几乎总是远低于 1000Hz,因此您拥有的大部分分辨率都浪费在更高的频段上。【参考方案2】:应用DFT,然后从结果中推导出基频。谷歌搜索 DFT 信息将为您提供所需的信息 - 我会为您提供一些链接,但它们对数学知识的期望差异很大。
祝你好运。
【讨论】:
【参考方案3】:吉他调音器不使用 FFT 或 DFT。通常他们只计算零交叉。您可能无法获得基频,因为某些波形的过零次数比其他波形多,但您通常可以通过这种方式获得基频的倍数。尽管您可能会偏离一个或多个八度音阶,但这足以得到音符。
在计算过零之前进行低通滤波通常可以去除多余的过零。调整低通滤波器需要了解您想要检测的频率范围
【讨论】:
我怀疑他们只计算过零。在典型的吉他波形中,每个周期有许多过零。 flickr.com/photos/56868697@N00/4180888094 他们可能做了一个简单的自相关。 对于一个简单的调谐器来说,更多的过零并不重要。请记住,调谐器不需要基频的确切频率。它需要知道注释。通过在每个周期计算更多的零交叉,它可能会锁定到更高的八度音阶,但 Cb 仍将是 Cb,过高 2 美分仍将过高 2 美分。自相关非常适合更高级的处理,但对于调谐器来说它是多余的。【参考方案4】:更具体一点:
如果您从输入数组中的原始 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 ;
【讨论】:
我喜欢简洁明了,但怀疑 for 循环有问题。输出的大小肯定与输入的大小不同 大小一模一样。进行 FFT 是一种权衡 - 只有通过分析大的时间跨度,您才能获得精细的频率分辨率(许多输出箱)。如果将分析限制在非常精确的时间(输入样本量小),您会在频域中获得低分辨率。【参考方案5】:还有其他基于时间的算法,而不是基于频率的算法。 自相关是一种相对简单的音高检测算法。 参考: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 是这个问题的糟糕解决方案。这就像开一辆坦克去杂货店一样。当然,这很酷,但这确实不是最好的方法。自相关通常被认为是解决这个问题的正确方法。即 Autotune/Melodyne/Singstar/你的名字。基于过零的解决方案仅适用于您对蠕虫行为有特定了解的情况。自相关也可以非常有效地实现。 哇,什么?我不同意。频域解决方案绝对不是一个糟糕的解决方案。谐波乘积谱或倒谱方法易于实现且相当稳健。无论如何,自相关一般都不是正确的解决方案;它是几种有效的解决方案之一。没错,不过:过零并不是一个可靠的音高指标。 自相关通常比 FFT 的计算密集度更高。事实上,我们经常使用 FFT 进行自相关,因为它更快。使用 FFT 可以做到的朴素自相关就像驾驶坦克穿过杂货店的墙壁而不是使用前门。【参考方案6】: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 周期。)有很多陷阱,使用正确的方法实际上取决于您的应用程序。
【讨论】:
除了缺少基本原理外,还存在处理弦乐器信号的交感共振问题。特别是在吉他的乐器调音场景中,在任何给定时间未调音的琴弦都是打开的,如果接近调音的音高,则与弹奏的琴弦有重合的部分。 算法大纲的链接已损坏。你会碰巧把它们放在另一个地方吗?提前致谢! @RafaelB 谢谢我修好了gist.github.com/endolith/255291【参考方案7】:检索 PCM 音频信号中的基频是一项艰巨的任务,并且有很多要讨论的内容...
无论如何,通常基于时间的方法不适用于复音信号,因为由多个基频引起的不同谐波分量之和给出的复波具有仅取决于最低频率分量的过零率。 . 同样在频域中,FFT 也不是最合适的方法,因为音符之间的频率间隔遵循指数比例,而不是线性的。这意味着如果时域分析窗口的大小不够大,FFT 方法中使用的恒定频率分辨率可能不足以解析低频音符。
更合适的方法是常数 Q 变换,它是在对信号进行低通滤波和 2 抽取(即每步采样频率减半)的过程之后应用 DFT,以获得不同的子带具有不同的频率分辨率。通过这种方式优化了 DFT 的计算。问题是时间分辨率也是可变的,并且对于较低的子带会增加......
最后,如果我们试图估计单个音符的基频,FFT/DFT 方法是可以的。在复音环境中情况会发生变化,其中不同声音的部分重叠并根据它们的相位差求和/抵消它们的幅度,因此单个频谱峰值可能属于不同的谐波内容(属于不同的音符)。在这种情况下,相关性不会给出好的结果...
【讨论】:
以上是关于您如何分析 PCM 或 WAV 样本的基频? [关闭]的主要内容,如果未能解决你的问题,请参考以下文章
如何使用 fread 和 fwrite 从文件中读取 pcm 样本?
音频处理WAV 文件格式分析 ( 逐个字节解析文件头 | 相关字段的计算公式 )
如何使用 java 从 pcm 字节数组 .wav 文件中获取频率和音高?