代码之家  ›  专栏  ›  技术社区  ›  P i

C/C++/Obj-C从声调输入中确定音符(非音高)的实时算法

  •  3
  • P i  · 技术社区  · 14 年前

    我想检测的不是音高,而是 沥青课 一首歌的音符

    所以,不管是C4还是C5都不重要:它们都必须被检测为C。

    想象一下12个半音排列在钟面上,指针指向音高等级。这就是我想要的!理想情况下,我想能够分辨出这首歌的音符是现场的还是稍有偏差的。

    这不是先前问题的副本,因为它引入了以下约束:

    1. 声源是一个 单一人声 希望可以忽略背景干扰(尽管我可能需要处理这个问题)

    2. 八度音不重要, 只有球场级别

    编辑链接:
    Real time pitch detection
    Using the Apple FFT and Accelerate Framework

    9 回复  |  直到 8 年前
        1
  •  4
  •   johnwbyrd    9 年前

    在其他答案中引用的大多数频率检测算法对声音都不起作用。为了理解为什么这是如此直观,考虑到一种语言中的所有元音都可以在一个特定的音符上演唱。尽管所有这些元音的频率内容都非常不同,但它们都必须以相同的音符进行检测。任何语音的音符检测算法都必须以某种方式考虑到这一点。此外,人类的语言和歌曲包含许多 fricatives 其中很多都没有隐含的音调。

    在一般(非语音)情况下,您要查找的功能称为 色度特征 关于这个问题有相当多的研究。它被称为 谐波基音级剖面 . 关于这个概念的原始参考文件是藤岛泰玉的 Real-Time Chord Recognition of Musical Sound: A System Using Common Lisp Music “。这个 Wikipedia entry 概述了更现代的算法变体。有很多免费的 papers and MATLAB implementations 色度特征检测。

    然而,由于你只关注人类的声音,而且人类的声音自然包含了大量的泛音,在这个特定的场景中,你实际上需要的是 基频检测算法 f0 detection algorithm . 有几种这样的算法 explicitly tuned for voice . 也, here is a widely cited algorithm 一次可以处理多种声音。然后,您将对照等温标度检查检测到的频率,然后找到最接近的匹配。

    因为我怀疑你在尝试建立一个音调检测器和/或修正自动调谐,你可能想使用M.Morise的优秀 WORLD 实现,允许快速和良好的质量检测和修改语音流上的f0。

    最后,请注意,只有少数声调检测器在“声音片段”寄存器中工作良好。几乎所有的人,包括全世界,都不能用高音唱法,也不能用低音唱法。许多论文称声乐作品为 "creaky voice" 并开发了特定的算法来帮助特定类型的语音输入。

        2
  •  7
  •   Community Dan Abramov    7 年前

    请参阅此处我的答案以获得平滑的频率检测: https://stackoverflow.com/a/11042551/1457445

    至于将这个频率捕捉到最近的音符——这里是我为我的调谐器应用程序创建的一个方法:

    - (int) snapFreqToMIDI: (float) frequencyy {
    
        int midiNote = (12*(log10(frequencyy/referenceA)/log10(2)) + 57) + 0.5;
        return midiNote;
    }
    

    这将返回MIDI音符值( http://www.phys.unsw.edu.au/jw/notes.html )

    要从该MIDI音符值中获取字符串,请执行以下操作:

    - (NSString*) midiToString: (int) midiNote {
        NSArray *noteStrings = [[NSArray alloc] initWithObjects:@"C", @"C#", @"D", @"D#", @"E", @"F", @"F#", @"G", @"G#", @"A", @"A#", @"B", nil];
        return [noteStrings objectAtIndex:midiNote%12];
    }
    

    有关使用输出平滑进行音调检测的示例,请查看musicianskit.com/developer.php

        3
  •  6
  •   hotpaw2    14 年前

    音高是人类的心理知觉现象。峰值频率内容与音高或音高等级不同。FFT和DFT方法不会直接提供螺距,只提供频率。对于人类的声音源来说,零交叉测量也不能很好地工作。尝试AMDF、ASDF、自相关或倒谱方法。关于音高估计的学术论文也很多。

    还有一长串 pitch estimation algorithms here .

    编辑添加:苹果的speakhere和auriotouch示例应用程序(可从iOS开发中心获得)包含示例源代码,用于从iPhone麦克风获取PCM示例块。

        4
  •  3
  •   P i    10 年前

    如果你在找音高类,你应该看一下色度图。( http://labrosa.ee.columbia.edu/matlab/chroma-ansyn/ )

    您还可以简单地检测f0(使用 YIN algorithm )并返回适当的半色调,大多数基频估计算法都存在八度误差。

        5
  •  2
  •   Nick Johnson    14 年前

    表演一个 Discrete Fourier Transfo 对输入波形的样本求Rm,然后求和对应于不同八度音阶的等效音符的值。以最大值为主频。

    您可能会在目标C中找到一些适合您需要的现有DFT代码。

        6
  •  2
  •   P i    14 年前

    在我找到信息的时候…

    Pitch detection algorithm 维基百科是一个很好的起点。它列出了一些无法确定八度的方法,这对我来说是可以的。

    可以找到一个很好的自相关解释。 here (维基百科为什么不能简单地把事情说成那样呢??)

        7
  •  2
  •   P i    14 年前

    最后我结束了这一次,多亏了 this 文章从 DSP Dimension

    文章包含源代码。

    基本上,他执行快速傅立叶变换。然后他解释说,如果频率与垃圾桶的中心位置不一致,它们就会以钟形曲线在附近的垃圾桶上涂抹。他解释了如何在第二遍(第一遍是FFT)中从这些数据中提取准确的频率。

    这篇文章接着进一步讨论了音调变化;我可以简单地删除代码。

    请注意,它们提供了一个商业图书馆,它只做同样的事情(以及更多的事情),而且是超级优化的。图书馆有一个免费的版本,可以做我所需要的一切,尽管我已经完成了iOS音频子系统的工作,我也可以自己实现它。

    为了记录,我找到了另一种方法来提取准确的频率,方法是通过在垃圾桶及其两个邻居上近似二次曲线来提取准确的频率。 here . 我不知道这两种方法的相对准确度是多少。

        8
  •  1
  •   jbarlow    14 年前

    正如其他人提到的,你应该使用一个音调检测算法。既然这一点已经很好地说明了,我将介绍你问题的一些细节。你说你在找音符的音高等级。然而,找到这一点的方法是计算出音符的频率,然后使用一个表格将其转换为音高等级、八度和分。我不知道如何在没有找到基频的情况下获得音高等级。

    你需要一个实时的音调检测算法。在评估算法时,请注意每个算法所隐含的延迟,与您期望的准确性相比。虽然有些算法比其他算法更好,但从根本上讲,你必须用一个算法交换另一个算法,而且不能确定地同时知道这两个算法——有点像海森堡不确定性原理。(当只听到一个周期的一小部分时,你怎么知道音符是C4?)

    你的“平滑”方法相当于 digital filter 这将改变声音的频率特性。简而言之,它可能会干扰你估计音高的尝试。如果你对数字音频感兴趣,数字滤波器是这个领域的基础和有用的工具,也是一个有趣的主题。有很强的数学背景有助于理解他们,但你不一定需要这些来获得基本的想法。

    此外,过零法是一种基本的技术,可以估计波形的周期,从而估计基音。它可以这样做,但只需要大量的启发式和微调。(基本上,发展一些“候选人”的投球,并试图推断出占优势的投球。许多特殊情况会出现,将混淆这一点。一个快速的是较少的“S”。)你会发现它更容易从频域基音检测算法开始。

        9
  •  1
  •   ugur    8 年前

    如果你是初学者,这可能会很有帮助。它在Java和iOS上都是可用的。

    dywapitchtrack for ios

    dywapitchtrack for java