识别音频的音调

23 投票
5 回答
27787 浏览
提问于 2025-04-15 16:23

我有把吉他,我希望我的电脑能识别出我在弹什么音符,也就是能听出音调。请问用Python能做到吗?还有用pygame可以实现吗?如果能用pygame就太好了。

5 个回答

1

你需要使用一个音频库,比如内置的 audioop

分析正在播放的具体音符并不简单,但可以通过这些接口来实现。

另外,这个链接也可能对你有帮助: http://wiki.python.org/moin/PythonInMusic

19

我曾经写过一个工具,正好可以分析正在播放的声音。

你可以在这里查看代码 这里(或者你也可以下载整个项目。这个项目和Frets On Fire结合在一起,Frets On Fire是一个开源的吉他英雄游戏,目的是让你体验真正的吉他英雄)。我用吉他、口琴和口哨进行了测试 :) 代码虽然不太好看,但确实能用 :)

我使用了pymedia来录音,使用scipy进行快速傅里叶变换(FFT)。

除了其他人提到的一些基础知识,我还可以给你一些建议:

  1. 如果你是用麦克风录音,会有很多噪音。你需要通过不断尝试来设置阈值和清理声音的方法,才能让它正常工作。一个可能的解决办法是使用电吉他,把它的输出插入音频输入。这对我来说效果最好。
  2. 特别是,50Hz附近会有很多噪音。虽然这不算太糟,但它的谐波(见下文)在100Hz和150Hz,这正好接近吉他的G2和D3音……正如我所说,我的解决办法是换成电吉他。
  3. 声音检测的速度和准确性之间是有权衡的。你采集的样本越多,检测声音所需的时间就越长,但你能更准确地识别出音高。如果你真的想做一个项目,可能需要使用多个时间尺度。
  4. 当一个音符被演奏时,它会有谐波。有时候,几秒钟后,谐波的强度甚至可能超过基础音。如果不处理这个问题,你的程序可能会认为它听到了E2,过了一会儿又是E3。为了解决这个问题,我使用了一个当前正在播放的声音列表,只要这个音符或它的某个谐波有能量,我就认为是同一个音符在演奏……
  5. 特别难的是,当有人连续演奏同一个音符两次(或更多次)时,因为很难区分这和声音水平的随机波动。你会在我的代码中看到,我不得不使用一个常量,这个常量需要根据使用的吉他进行配置(显然每把吉他都有自己特定的功率波动模式)。
21

要识别音频信号的频率,你需要用到一种叫做FFT(快速傅里叶变换)的算法。根据我所了解,PyGame并没有录音的功能,也不支持FFT变换。

首先,你需要从声卡捕获原始的采样数据,这种数据叫做PCM(脉冲编码调制)。在Python中,捕获音频的最简单方法是使用PyAudio库(这是PortAudio的Python接口)。GStreamer也可以做到这一点,不过对于你的需求来说,可能有点过于复杂。一般来说,捕获16位的样本,采样率为48000赫兹是比较常见的,这也是普通声卡能提供的最佳效果。

一旦你获得了原始的PCM音频数据,就可以使用scipy库中的fftpack模块对这些样本进行FFT变换。这会给你一个分析后的音频信号的频率分布,也就是说,可以知道在某些频率范围内信号的强度。接下来,你只需要找到信号最强的频率即可。

可能还需要一些额外的过滤,以避免出现谐波频率,不过我不太确定。

撰写回答