代码之家  ›  专栏  ›  技术社区  ›  mahboudz

智能手机上音符的音高识别

  •  21
  • mahboudz  · 技术社区  · 15 年前

    由于CPU、代码大小和RAM等资源有限,如何最好地检测音符的音调,类似于电子或软件调谐器的功能?

    我应该使用:

    • 接吻快速傅立叶变换
    • 快速傅立叶变换
    • 离散小波变换
    • 自相关
    • 过零分析
    • 八度间隔滤波器

    其他?

    简而言之,我要做的是识别一个音符,在中C以下两个八度到上两个八度,在任何(合理的)乐器上演奏。我想在半音的20%以内——换句话说,如果用户弹得太平或太尖锐,我需要区分。但是,我不需要调整所需的精度。

    5 回复  |  直到 9 年前
        1
  •  14
  •   beingdevious    9 年前

    如果你不需要那么高的精度,一个快速傅立叶变换就足够了。 Window 首先是音频块,这样可以得到定义明确的峰值,然后找到第一个有效峰值。

    仓宽=采样率/fft大小:

    基本原理 range from 20赫兹到7千赫,所以14千赫的采样率就足够了。下一个“标准”采样率是22050赫兹。

    然后,FFT大小由所需的精度决定。FFT输出的频率是线性的,而音调的频率是对数的,所以最坏的情况下精度将是在低频。对于20赫兹时20%的半音,您需要 1.2 Hz ,这意味着FFT长度为 18545 .二的下一个幂是2 十五 =32768。这是1.5秒的数据,需要我笔记本电脑的处理器3毫秒来计算。

    这不适用于具有 missing fundamental 找到“第一显著”峰有点困难(因为 harmonics are often higher than the fundamental 但是你可以找到一个适合你的情况的方法。

    Autocorrelation and harmonic product spectrum 能更好地找到真正的波的基波,而不是谐波,但我认为它们不能很好地处理 inharmonicity 像钢琴或吉他这样的大多数乐器都不和谐(和声应该是稍微尖锐的)。不过,这取决于你的情况。

    此外,您还可以使用 Chirp-Z transform .

    我已经写好了 a few different methods in Python 用于比较。

        2
  •  13
  •   MusiGenesis    15 年前

    如果你想实时进行音高识别(精确到半色调的1/100以内),你唯一真正的希望就是零交叉法。很抱歉,这是一个微弱的希望。过零可以通过几个波长的数据来估计基音,也可以通过智能手机的处理能力来实现,但是它不是特别精确,因为测量波长的微小误差会导致估计频率的大误差。像吉他合成器这样的设备(它从只有两个波长的吉他弦中推导出音高)是通过将测量值量化成音阶的音符来工作的。这可能适用于您的目的,但请注意,过零对简单的波形非常有效,但对更复杂的仪器声音的效果却越来越差。

    在我的应用程序中(一个在智能手机上运行的软件合成器),我使用单乐器音符的录制作为可波动合成的原材料,为了在特定音高下生成音符,我需要知道录制的基本音高,精确到半色调的1/1000以内(我真的只需要1/100的精度,但我需要CD)。过零法是 许多的 这种方法太不准确,基于FFT的方法要么太不准确,要么太慢(有时两者都是)。

    在本例中,我发现最好的方法是使用自相关。使用自相关,你基本上猜测音调,然后测量你的样品在相应波长的自相关。通过半色调扫描可能的音高范围(比如A=55赫兹到A=880赫兹),我找到了最相关的音高,然后在音高附近进行更精细的扫描,以获得更准确的值。

    最适合你的方法完全取决于你想用它做什么。

        3
  •  6
  •   ire_and_curses    15 年前

    我不熟悉您提到的所有方法,但是您选择什么主要取决于输入数据的性质。你是在分析纯音,还是你的输入源有多个音符?言语是你输入的特征吗?您必须对输入进行采样的时间长度是否有任何限制?你能用一些准确度来换取速度吗?

    在某种程度上,您选择什么也取决于您是否希望在 time 或在 frequency space .转换 time series 对频率的表示需要时间,但在我的经验中往往会给出更好的结果。

    Autocorrelation 比较时域中的两个信号。一个简单的实现是简单的,但计算起来相对昂贵,因为它需要对原始信号和时移信号中的所有点进行差分,然后对自相关函数中的转折点进行微分,然后选择与基频相对应的最小值。还有其他方法。例如, Average Magnitude Differencing 是一种非常便宜的自相关形式,但精度会受到影响。所有的自相关技术都存在着八度误差的风险,因为函数中除了基波之外还存在峰值。

    测量 zero-crossing points 简单明了,但如果信号中存在多个波形,则会遇到问题。

    在频率空间,基于 FFT 可能对你的目的足够有效。一个例子是谐波积谱技术,它将信号的功率谱与每一次谐波的降采样版本进行比较,并通过将频谱相乘来识别基音,从而产生一个清晰的峰值。

    和以往一样,没有什么可以替代测试和分析几种技术,以经验的方式确定哪些技术最适合您的问题和约束。

    这样的答案只能触及这个话题的表面。以及前面的链接,这里有一些相关的参考资料供进一步阅读。

        4
  •  5
  •   dfrankow    15 年前

    在我的项目中 danstuner ,我从 Audacity . 它基本上需要一个快速傅立叶变换,然后通过在快速傅立叶变换上放置一条三次曲线并找到该曲线的峰值来找到峰值功率。工作得很好,尽管我得防止八度跳远。

    Spectrum.cpp .

        5
  •  5
  •   Craig McQueen Dr. Watson    15 年前

    过零不会起作用,因为一个典型的声音有谐波和过零远远超过基频。

    我试验过的(作为家庭项目)是:

    1. 使用ADC以所需的采样率对声音进行采样。
    2. 检测波形(滑动窗口或类似)的短期正负峰值的水平。即信封探测器。
    3. 制作一个方波,当波形在正包线的90%以内时,方波变高;当波形在正包线的90%以内时,方波变低。即具有滞后的跟踪方波。
    4. 通过直接计数/时间计算来测量方波的频率,根据需要使用尽可能多的样本以获得所需的精度。

    然而,我发现,通过我的电子键盘输入,对于某些乐器的声音,它可以获得2_的基频(下一个八度)。这是一个附带的项目,在进行其他事情之前,我从未着手实施解决方案。但我认为它的CPU负载比FFT少得多。