使用computeSpectrum()进行音高检测,返回FFT值。

5
  • 我正在使用Actionscript 3.0制作Flash Player 10.3
  • 我在已经加载的.mp3文件上使用computeSpectrum()
  • 使用*Event.ENTER_FRAME*获取byteArray中每个样本的快照
  • ByteArray包含512个值(每个通道256个)。这些值是FFT频谱,范围从0到1。
  • 我不能对每个样本使用峰值频率(正如我发现的那样!)因为最高值不一定是基频!结果,我得到了很多随机值!当然,也有些正确的,但这还不够!

我了解到自相关的信息...
能否举一个例子来说明我如何使用它呢?

或者提供链接、甚至来自其他脚本语言的示例脚本以便于我理解?

问候
initcode


你想在原始波形上进行自相关,还是在FFT上进行? - endolith
我认为我会更喜欢使用FFT,因为我正在尝试检测用户刚刚录制但未保存在任何地方的音频中的音高...它以Flash Player中的ByteArray存在。 - initcode
我的意思是,你可以做1. FFT(信号),2. Autocorr(信号),或3. Autocorr(FFT(信号))。此外,4. FFT(FFT(信号))(“倒谱”)我相信所有这些方法都被用于音高检测,尽管我不知道哪种方法最适合声音。 - endolith
嗨,进展如何?你设法让它工作了吗?我正在做一个非常类似的项目。同样使用这个http://gerrybeauregard.wordpress.com/2010/08/06/real-time-spectrum-analysis/...请分享你在声音领域的发现。谢谢! - bukowski
4个回答

8

听起来你已经知道如何获取FFT频谱了,对吗?

spectrum http://flic.kr/p/7notw6

但是如果您正在寻找基本频率(绿点),您不能仅使用最高峰。它不一定是基音。在我的例子中,实际的基音频率是100 Hz,但最高峰是300 Hz。

有许多不同的方法可以找到真正的基音频率,每种方法在不同的情况下都更有效。comp.dsp上的一个主题提到了“FFT、倒谱、自/互相关、AMDF/ASDF”。

举个简单的例子,每个红点与其相邻点相差100 Hz,因此如果您使用峰值查找算法,然后平均每个谐波与下一个之间的距离,就会找到基音频率,但如果错过任何峰值或包括额外的峰值,或者信号对称且仅包含奇次谐波(1f、3f、5f),则会失败。您需要找到模式,然后丢弃异常值并进行平均。这可能是一种容易出错的方法。

你还可以对原始波形进行自相关处理。从概念上讲,这意味着将波形的副本滑过它本身,并找到最能与自身对齐的延迟(这将是一个完整的周期)。在正常实现中,我们使用FFT来加速处理。自相关基本上是
  • IFFT(FFT(signal)⋅FFT(signal)*)

其中*表示复共轭或时间反转。 例如,在Python中:

correlation = fftconvolve(sig, sig[::-1], mode='full')

而 fftconvolve() 的源代码相对简单:https://github.com/scipy/scipy/blob/master/scipy/signal/signaltools.py#L133


2
那张图片价值1.0E03个单词。 - rajah9
1
假设每个单词平均有6个字符,那么这张48 kB的图片只有12.5%的信息传递效率。 :) - endolith
如果我必须选择一个免费的 C++ 库来应用音高检测,你会建议哪一个呢?目前我正在研究 Adobe Alchemy,它将允许我(理论上)在 C++ 库和 Flash 之间进行通信! - initcode
嗨,endolith,我仍在努力解决检测问题...谢谢你的回答...我的问题是每个人都给我很好的理论,但没有人详细解释,以便我可以开始尝试编写公式...我需要在你上面给我的公式中再问一些细节,并且如果你有时间,你可以向我解释一下吗? - initcode
我有一个FFT数组,每个样本给出512个值,每个通道256个值。在您的公式中,“signal”是这些“样本”之一,对吗?因此,FFT(signal)将被替换为这512个值的数组?FFT(signal)*的公式是什么? 我该如何写下这个公式? 请记住,我没有使用任何C库,所以我必须自己想出来...还有任何IFFT的公式吗?这个公式的结果会是什么? 它将代表基频率的频率吗?提前感谢您。 - initcode
显示剩余2条评论

1

您可以使用谐波产品谱方法来估计频率谱(FFT结果)中泛音峰之间的距离(频率差异),即使一些峰值缺失,只要没有太多杂波频率峰(噪声)。

要进行谐波产品谱分析,请将FFT打印在半透明纸上并将其卷成圆柱形(或在软件中进行等效操作)。将圆柱体越来越紧地包裹,直到最大数量的峰重叠。周长将是音高的良好估计值。这适用于任何具有许多谐波的音乐声音,即使基本音高频率峰缺失或较弱。


0

谢谢www0z0k, 我已经在ByteArray中使用了SampleDataEvent.SAMPLE_DATA! 我正在寻找一种方法来模拟自相关,以检测音高! - initcode

0

你想做什么?

我以前没有使用过computeSpectrum(),但我的职业生涯的前半段是一名DSP工程师。

如果它能够实现文档中所说的功能,那么你就不需要自相关结果。

在你的字节数组中,索引表示频率二进制数,索引值表示该特定频率的幅度。

如果你的意思是通过音高检测找到最强的频率,那么你需要循环遍历字节数组,并为每个索引计算sqrt(left*left+right*right)。找到这些值中的最大值。最大值的索引代表最强的频率。

假设fs=44.1kHz,i是你的索引,那么最强的频率是

f = (i/255) * (44100 / 2);

请记住,你的频率分辨率受到二进制间隔的限制。如果你需要更高的分辨率,你需要对数据进行插值。


1
嗨,MPD,谢谢你的回复...... 我实际上正在尝试检测音高,而不仅仅是在样本中检测峰值频率。 问题是基频不一定是最高频率,因此我必须找到自相关以检测该频率; 然后就容易了; 我已经有函数根据频率返回正确的音符了! - initcode
1
好的,那么您需要进一步了解音高检测算法。有几种方法可以实现。这里有一些相关的问题,但我还没有阅读它们以了解它们的价值。自相关是一个时间域的东西,虽然你可以使用FFT计算它。问题在于computeSpectrum()不会将完整的FFT值返回给你。您可能需要使用原始数据计算FFT,或者使用原始数据在时间域中计算自相关。 - mpdonadio

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接