【问题标题】:frequency / pitch detection for dummies假人的频率/音高检测
【发布时间】:2012-07-18 04:15:48
【问题描述】:

虽然我在这个网站上有很多关于音高检测概念的问题...它们都涉及我不熟悉的神奇 FFT。我正在尝试构建一个需要实现音高检测的 Android 应用程序。我完全不了解用于执行此操作的算法。

不可能那么很难吧?毕竟,Android 市场上有大约 80 亿个吉他调音器应用程序。

有人可以帮忙吗?

【问题讨论】:

  • 您需要对快速傅立叶变换有一些基本的了解才能实现您的要求。如果您正在寻找一个 java FFT 库,我无法想象找到一个会很困难。除非您想学习一些信号处理,否则我建议您寻找吉他调音器库。如果没有基本的了解,FFT 将难以实施。

标签: java android audio


【解决方案1】:

FFT 并不是实现音高检测或音高跟踪的最佳方式。一个问题是最响亮的频率并不总是基频。另一个原因是,FFT 本身需要大量数据和处理才能获得调整仪器所需的分辨率,因此它的响应速度可能很慢(即延迟)。另一个问题是,FFT 的结果必然是直观的:你得到一个复数数组,你必须知道如何解释它们。

如果您真的想使用 FFT,这里有一种方法:

  1. 低通您的信号。这将有助于防止噪声和高次谐波产生虚假结果。可以想象,您可以跳过这一步,而是将结果加权到 FFT 的较低值。对于某些具有强基频的仪器,这可能不是必需的。
  2. 窗口化您的信号。 Windows 的大小应至少为 4096。越大越好,因为它可以为您提供更好的频率分辨率。如果你太大,它最终会增加你的计算时间和延迟。 hann 函数是您窗口的不错选择。 http://en.wikipedia.org/wiki/Hann_function
  3. 尽可能频繁地对窗口信号进行 FFT。即使是重叠的窗口也很好。
  4. FFT 的结果是复数。使用 sqrt( real^2 + imag^2 ) 找到每个复数的大小。 FFT 数组中幅度最大的索引是您的峰值频率的索引。
  5. 您可能希望对多个 FFT 进行平均以获得更一致的结果。

如何根据索引计算频率?好吧,假设你有一个大小为 N 的窗口。在你 FFT 之后,你将有 N 个复数。如果您的峰值是第 n 个,并且您的采样率为 44100,那么您的峰值频率将接近 (44100/2)*n/N。为什么近?那么你有一个错误(44100/2)* 1/N。对于 4096 的 bin 大小,这大约是 5.3 Hz——在 A440 上很容易听到。您可以通过 1. 考虑相位来改进这一点(我只描述了如何考虑幅度),2. 使用更大的窗口(这将增加延迟和处理要求,因为 FFT 是 N Log N 算法),或者 3. 使用更好的算法,比如 YIN http://www.ircam.fr/pcm/cheveign/pss/2002_JASA_YIN.pdf

您可以跳过窗口化步骤,只需将音频分解为您想要分析的多个样本的离散块。这相当于使用方形窗口,虽然有效,但您的结果中可能会出现更多噪音。

顺便说一句:许多调谐器应用许可代码来自第三方,例如 z-plane 和 iZotope。

更新:如果您想要 C 源代码和 FFT 方法的完整教程,我已经written one。该代码可以在 Mac OS X 上编译和运行,并且应该可以很容易地转换到其他平台。它的设计目的不是最好的,但它的设计目的是易于理解。

【讨论】:

  • 这似乎正是我需要的,但对我来说没用,因为我不知道什么是“低通”、“窗口”和“汉恩函数”。 (尽管有链接,但我仍然不明白它是如何应用的。)上述建议可能会对了解更多的人有所帮助,但我问这个问题是因为我完全不了解它们。
  • 对于低通过率,我建议了一个替代方案,但如果你不知道它是什么,你可以谷歌它并问另一个问题。这不是另一个问题的子答案。
  • 事实是,您所要求的信息通常在一两个学期的大学水平课程中涵盖,并非所有细节都可以在这里涵盖。
  • 我的伙伴使用他在网上找到的代码在 iPhone 版本上实现了相同的功能。如果我理解数学,我相信我可以通过它编写代码,但是因为我需要完成一个学期的课程才能做到这一点,所以我需要代码。我对这个数学的无知程度不仅仅是不熟悉......我从来没有处理过这个级别的任何事情。谢谢你所做的一切......但我真正需要的是一种方法,我可以传递一个返回值的参数。
  • 谷歌上“音高检测 java”的第三个结果:tarsos.0110.be/artikels/lees/YIN_Pitch_Tracker_in_JAVA
【解决方案2】:

快速傅里叶变换将函数从时域更改为频域。所以不是f(t),其中f是你从麦克风获得的信号,t是那个信号的时间索引,你得到g(θ),其中gf和@的FFT 987654331@ 是频率。一旦你有了g(θ),你只需要找到哪个θ 的幅度最高,这意味着“最大”的频率。这将是您拾取的声音的主要音高。

至于实际实现FFT,如果你google“快速傅立叶变换示例代码”,你会得到一堆例子。

【讨论】:

  • 这个example 可能对测试有用。
  • 我发现了一堆样本,它们都需要值数组,我不知道如何获得或它们的含义。我们正在到达那里。 this 在正确的邮政编码中吗?
  • @brainmurphy1 该链接看起来是正确的。您可以通过从麦克风读取输入来获取阵列。我以前从未这样做过,但谷歌说你想要 AudioRecord 类,这是一个例子:androiddevblog.net/android/android-audio-recording-part-2
  • @Jon Lin 通过这个从 AudioRecord 类运行数组后,我会得到声音的“FFT”吗?我如何把它变成频率?我说得有道理吗?
  • @brainmurphy1 依赖于FFT函数,但一般你通过新数组寻找最大值,索引是频率。
猜你喜欢
  • 2011-07-11
  • 1970-01-01
  • 2010-12-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2021-10-26
相关资源
最近更新 更多