实时音高检测

Posted

技术标签:

【中文标题】实时音高检测【英文标题】:Real time pitch detection 【发布时间】:2010-11-24 03:43:56 【问题描述】:

我正在尝试对用户唱歌进行,但遇到了很多问题。我尝试了很多方法,包括 FFT (FFT Problem (Returns random results)) 和自相关 (Autocorrelation pitch detection returns random results with mic input),但我似乎无法找到任何方法来给出好的结果。谁能建议一种实时音高跟踪的方法或如何改进我已有的方法?我似乎找不到任何用于的好的 C/C++ 方法。

谢谢,

尼尔。

编辑:请注意,我检查了麦克风输入数据是否正确,并且当使用正弦波时,结果或多或少是正确的音高。

编辑:对不起,这已经晚了,但目前,我通过从结果数组和每个索引中取出值来可视化自动收集,并在 X 轴上绘制索引和在 Y 轴上绘制值(两者除以 100000 或其他东西,我使用 OpenGL),将数据插入 VST 主机并使用 VST 插件对我来说不是一个选项。目前,它看起来就像一些随机的点。我做得对吗,或者你能不能给我一些代码来做这件事,或者帮助我理解如何可视化原始音频数据和自相关数据。

【问题讨论】:

我怀疑你一直在“做错事”。你有没有从其他问题中解决过底层问题?整个“随机结果”听起来就像你还没有让这些方法正常工作。 在我看来,这个问题与在“摇滚乐队”游戏中为人声检测音高非常相似——而且他们似乎让它工作得很好。这让我相信一定有办法做到这一点。只是通过阅读有关音高检测的***文章,这似乎不是一个微不足道的问题。如果您找到好的方法,我们希望您能在这里发布答案! 为了调试,试试吹口哨。口哨的声音包含一个非常强的频率,几乎没有泛音。如果您还没有这样做,您还应该可视化 FFT 的输出。 我必须同意 Thomas 关于可视化的观点。绘制图表是了解您正在分析的声音属性的好方法。 ...或者在自相关的情况下,每个可能时期的相关系数。 【参考方案1】:

退后一步...要使这项工作发挥作用,您必须找到一种方法来绘制此过程的中间步骤。您尝试做的事情并不是特别难,但它容易出错且容易出错。削波、窗口化、接线不良、混叠、直流偏移、读取错误的通道、奇怪的 FFT 频率轴、阻抗不匹配、帧尺寸错误……谁知道呢。但是如果你能画出原始数据,然后画出FFT,一切都会变得清晰。

【讨论】:

究竟如何绘制原始数据和 FFT? @Helium3:波形和频谱图 (2D)。检查大胆。 或者,将中间表示输出到 CSV 并在 MATLAB 或 Octave 中查看。 没错。编程是关于问题分解的。你必须想办法把问题分解成更容易解决的部分。【参考方案2】:

我发现了几个实时音高跟踪的开源实现

dywapitchtrack 使用基于小波的算法

“Realtime C# Pitch Tracker”使用修改后的自相关方法现已从 Codeplex 中删除 - 尝试搜索 GitHub

aubio(由 piem 提及;有几种算法可用)

还有一些音高跟踪器可能不是为实时设计的,但据我所知,可能以这种方式可用,并且也可以作为参考来比较您的实时跟踪器:

Praat 是一个开源包,有时被语言学家用于音高提取,您可以在http://www.fon.hum.uva.nl/paul/praat.html 找到记录的算法

Snack and WaveSurfer 还包含一个音高提取器

【讨论】:

【参考方案3】:

我知道这个答案不会让每个人都开心,但还是这样吧。

这东西很难,非常难。首先阅读尽可能多的关于 FFT、自相关、小波的教程。虽然我仍然在 DSP 上苦苦挣扎,但我确实从以下内容中获得了一些见解。

https://www.coursera.org/course/audio课程目前没有运行,但视频仍然可用。

http://miracle.otago.ac.nz/tartini/papers/Philip_McLeod_PhD.pdf关于音高识别算法开发的论文。

http://dsp.stackexchange.com 一个专门用于数字信号处理的网站。

如果你像我一样没有做足够的数学来完全遵循教程,不要放弃,因为一些图表和示例仍然帮助我理解发生了什么。

接下来是测试数据和测试。为自己编写一个库,生成用于检查算法的测试文件。

1) 一个超级简单的纯正弦波发生器。因此,假设您正在考虑编写 YAT(Yet Another Tuner),然后使用您的正弦发生器创建一系列大约 440Hz 的文件,例如从 420-460Hz 以不同的增量,看看您的代码有多灵敏和准确。能分辨到 5Hz、1Hz 以内,更精细吗?

2) 然后升级您的正弦波发生器,以便为信号添加一系列较弱的谐波。

3) 接下来是谐波的真实世界变化。因此,对于大多数弦乐器,您会看到一系列谐波是基频 F0 的简单倍数,但对于单簧管和长笛等乐器,由于室内空气的行为方式,偶次谐波将丢失或非常微弱。对于某些仪器,F0 缺失,但可以从其他谐波的分布中确定。 F0 是人耳感知的音高。

4) 通过以不规则的方式上下移动谐波峰值频率来引发一些故意失真

关键是,如果您正在创建具有已知结果的文件,那么更容易验证您正在构建的内容是否确实有效,当然还有错误。

还有许多包含声音样本的“库”。 https://freesound.org 来自上述 Coursera 系列。 http://theremin.music.uiowa.edu/MIS.html

接下来请注意,您的麦克风并不完美,除非您花费数千美元购买它,否则它将具有相当可变的频率响应范围。特别是如果您使用的是低音,那么便宜的麦克风,阅读您的 PC 或手机中的内置麦克风,从大约 80-100Hz 开始会有显着的衰减。对于相当好的外部设备,您可能会降至 30-40Hz。去寻找你麦克风上的数据。

您还可以通过扬声器播放音调,然后使用您最喜欢的麦克风录音来检查发生了什么。但当然,现在我们谈论的是两组频率响应曲线。

在性能方面,有许多免费可用的库,但请注意各种许可模型。

最重要的是,在您的前几次尝试之后不要放弃。祝你好运。

【讨论】:

【参考方案4】:

这是我设计的一种不寻常的两阶段算法的 C++ 源代码,它可以在 Windows 上播放 polyphonic MP3 文件时进行实时音高检测。这个免费的应用程序(PitchScope Player,可在网络上获得)经常用于检测 MP3 录音中吉他或萨克斯管独奏的音符。该算法旨在检测 MP3 音乐文件中任何给定时刻的最主要音高(音符)。在 MP3 录制期间的任何给定时刻,最主要的音高(一个音符)的显着变化可以准确地推断出音符的开始。

当在钢琴上按下一个键时,我们听到的不仅仅是一个声音振动频率,而是在不同数学相关频率上发生的多个声音振动的复合。这种不同频率的振动复合的元素被称为谐波或分音。例如,如果我们按下钢琴上的中间 C 键,复合谐波的各个频率将从 261.6 Hz 作为基频开始,523 Hz 将是 2 次谐波,785 Hz 将是 3 次谐波,1046 Hz 将是 4 次谐波,等等。后面的谐波是基频 261.6 Hz 的整数倍(例如:2 x 261.6 = 523、3 x 261.6 = 785、4 x 261.6 = 1046)。在底部链接的是实际和声的快照,在吉他独奏的复音 MP3 录音过程中出现。

我没有使用 FFT,而是使用具有对数频率间隔的修改后的 DFT 变换,首先通过寻找具有峰值电平的频率来检测这些可能的谐波(见下图)。由于我为修改后的 Log DFT 收集数据的方式,我不必对信号应用窗口函数,也不必添加和重叠。我已经创建了 DFT,因此它的频率通道以对数方式定位,以便直接与吉他、萨克斯等音符创建谐波的频率对齐。

现在退休了,我决定在一个名为 PitchScope Player 的免费演示应用程序中发布我的音高检测引擎的源代码。 PitchScope Player 可在网络上获得,您可以下载适用于 Windows 的可执行文件,以查看我的算法在您选择的 mp3 文件上的运行情况。以下指向 GitHub.com 的链接将引导您访问我的完整源代码,您可以在其中查看我如何使用自定义对数 DFT 变换检测谐波,然后查找其频率满足定义了正确整数关系的部分(谐波)'音高”。

我的音高检测算法实际上是一个两阶段的过程:a)首先检测到 ScalePitch('ScalePitch' 有 12 个可能的音高值:E, F, F#, G, G#, A, A#, B, C, C#, D, D# ) b) 并在确定 ScalePitch 之后,通过检查 4 个可能的 Octave-Candidate 音符的所有谐波来计算 Octave。该算法旨在检测和弦 MP3 文件中任何给定时刻的最主要音高(音符)。这通常对应于器乐独奏的音符。那些对我的两阶段音高检测算法的 C++ 源代码感兴趣的人可能希望从 GitHub.com 上的 SPitchCalc.cpp 文件中的 Estimate_ScalePitch() 函数开始。 https://github.com/CreativeDetectors/PitchScope_Player

下面是对数 DFT(由我的 C++ 软件创建)在复音 mp3 录音中吉他独奏 3 秒的图像。它显示了演奏独奏时吉他上各个音符的谐波如何出现。对于这个对数 DFT 上的每个音符,我们可以看到它的多个谐波垂直延伸,因为每个谐波将具有相同的时间宽度。确定音符的八度后,我们就知道了基本音的频率。

【讨论】:

【参考方案5】:

几年前我在一个项目中遇到过类似的麦克风输入问题 - 原来是由于直流偏移造成的。

确保在尝试 FFT 或您使用的任何其他方法之前消除任何偏差。

您也可能遇到余量或削波问题。

图表是诊断大多数音频问题的最佳方式。

【讨论】:

对不起,如果我听起来很愚蠢,但我如何可视化 FFT / 自相关的结果?我会获取结果数组中的每个值,并绘制该值和该值的大小吗? 您可以通过将高通滤波器设置为非常低的截止频率来消除直流偏置。我通常选择 25-30 赫兹,这是基于延长弦(5 或 6 根)贝司吉他的最低结果。 我建议通过主机运行您的输入,并使用免费的 VST Fre(a)koscope 和 s(M)exoscope 以图形方式查看频率响应和波形。 还有其他方法吗? VSTs Fre(a)koscope 和 s(M)exoscope 适用于 windows 和 mac 上的 im。 我认为有一个插件适配器可以让您在英特尔 Mac 上使用 PC VST。绝大多数免费插件都是 PC(这就是为什么我仍然在我的 PC 而不是我的 Mac 上做音乐的原因)。有一些类似的 Mac 工具,但大多数都不是免费的。试试 BlueCat 的东西。他有一个频谱分析仪和一个示波器。或者在 kvraudio 搜索音频插件数据库。或者只是在那里的论坛上提问。【参考方案6】:

查看aubio 和开源库,其中包括几种最先进的音高跟踪方法。

【讨论】:

【参考方案7】:

看看这个示例应用程序:

http://www.codeproject.com/KB/audio-video/SoundCatcher.aspx

我意识到应用程序是 C# 并且您需要 C++,并且我意识到这是 .Net/Windows 并且您在 Mac 上......但我认为他的 FFT 实现可能是一个起始参考点。尝试将您的 FFT 实现与他的进行比较。 (他是 Cooley-Tukey 的 FFT 的迭代、广度优先版本)。它们相似吗?

此外,您所描述的“随机”行为可能是因为您直接抓取声卡返回的数据,而没有正确组合字节数组中的值。您是否要求您的声卡对 16 位值进行采样,然后给它一个字节数组来存储这些值?如果是这样,请记住返回数组中的两个连续字节构成一个 16 位音频样本。

【讨论】:

【参考方案8】:

可在http://code.google.com/p/freqazoid/ 获得用于实时真实检测器的 Java 代码。

它在任何运行 2008 年后实时 Java 的计算机上都运行良好。该项目已被放弃,任何感兴趣的人都可以接手。如果您想了解更多详情,请与我联系。

【讨论】:

【参考方案9】:

我在这里问过类似的问题:

C/C++/Obj-C Real-time algorithm to ascertain Note (not Pitch) from Vocal Input

编辑:

Performous 包含一个用于实时音高检测的 C++ 模块

还有Yin Pitch-Tracking 算法

【讨论】:

哪个问题?还是这个问题接受了答案改变? 对不起,我已经修复了缺少链接的答案。【参考方案10】:

你能适应乐器调音器的任何东西吗?我令人愉悦的紧凑型吉他调音器能够很好地检测琴弦的音高。我看到了对piano tuner 的引用,它在一定程度上解释了一种算法。

【讨论】:

我尝试从一些吉他调音器代码(使用 FFT)中改编一些东西,但结果到处都是。【参考方案11】:

以下是一些实现音高检测的开源库:

WORLD:语音分析/合成工具包。如果您的源信号是语音,这尤其适用。 aubio :音频特征提取库。实现了许多音高检测算法。 Pitch detection:一组用 C++ 实现的音高检测算法。 dywapitchtrack :一种高质量的音高检测算法。 YIN:在单个 C++ 源文件中实现 YIN 算法的另一种实现。

【讨论】:

【参考方案12】:

您可以使用 TarsosDSP 进行实时音高检测,无论是歌手的声音 https://github.com/JorenSix/TarsosDSP 以防万一有人还没有听说过:-)

【讨论】:

这是一个很老的问题了,不知道你的回答是否还有意义。

以上是关于实时音高检测的主要内容,如果未能解决你的问题,请参考以下文章

使用 Swift 使用 AVAudioEngine 实时进行音高转换

iPhone 上的实时音高转换

Python 的实时程序声音?

添加效果后导出音频文件

音频时标音高修改 - 开源示例?

Python改变wav文件的音高[关闭]