首页 > 解决方案 > 如何获取 Python 3.x 中录制的音频的频率和幅度?

问题描述

我正在尝试录制音频并以 1 秒的间隔获取音频的平均频率和幅度,而无需写入文件。如果您使用 pyaudio 从文件中读取,有很多例子可以说明如何做到这一点,尽管任何可用于这种特定情况的东西都使用 Python 2.7 库,而 Python 3.x 似乎不存在这些库。

任何帮助,将不胜感激!

标签: pythonpython-3.xaudio

解决方案


获取音频

我不确定您使用哪个库来录制音频,但实时录制/播放的正常选择(在我看来)是PyAudio(您只提到它是为了从文件中读取)。

他们有一个用于实时处理的阻塞非阻塞音频 I/O 的示例。例如,使用阻塞模式示例,您可以在每次收到新的音频块时执行 DSP 处理。

"""PyAudio Example: Play a wave file."""

import pyaudio
import wave
import sys

CHUNK = 1024

if len(sys.argv) < 2:
    print("Plays a wave file.\n\nUsage: %s filename.wav" % sys.argv[0])
    sys.exit(-1)

wf = wave.open(sys.argv[1], 'rb')

# instantiate PyAudio (1)
p = pyaudio.PyAudio()

# open stream (2)
stream = p.open(format=p.get_format_from_width(wf.getsampwidth()),
                channels=wf.getnchannels(),
                rate=wf.getframerate(),
                output=True)

# read data
data = wf.readframes(CHUNK)

# play stream (3)
while len(data) > 0:
    stream.write(data)
    data = wf.readframes(CHUNK)
    # Do all of your DSP processing here i.e. function call or whatever

# stop stream (4)
stream.stop_stream()
stream.close()

# close PyAudio (5)
p.terminate()

找到幅度

如果您想要任何给定点的信号幅度,那么您所要做的就是获取样本数组中一个样本的绝对值,即从音频块数据中获取第三个样本的幅度。

ampSample3 = abs(data[2])

显然,这通常对单个样本幅度没有那么有用,但最好查看整个块。因此,您可以计算每个值的绝对值,将所有数组相加并除以块大小(平均值)。

blockAmplitudeMean = sum(numpy.absolute(x))/len(x)

但是在处理音频时,我们通常需要块的RMS值。

blockLinearRms= numpy.sqrt(numpy.mean(data**2)) # Linear value between 0 -> 1
blockLogRms = 20 * math.log10(blockLinearRms) # Decibel (dB value) between 0 dB -> -inf dB

获取频率

在您的问题中,您刚刚指定获取音频的频率,这可能意味着两件事之一。

确定频谱

DSP中常用,可以使用DFT(离散傅里叶变换)分析频谱。您通常会在FFT(快速傅里叶变换)的名称下看到它,因为这是 DFT 最流行的实现。已经有 Python 库可以为您实现 FFT 并且易于使用。

请注意,这将为您提供一个包含复杂信息(真实信号+相位信息)即频率信息的块大小长度的数组。这并不意味着您一定可以识别传入音频的音高(您不能直接判断有人在钢琴上弹奏 A1 音符,除非信号质量非常高,并且您仍然具有一些基本的 DSP 处理以及傅立叶变换)。

以供参考:

  • 这是scipy.fft的链接以及如何开始
  • 这是numpy.fft的链接,其中包含几个示例

如果你想对频率信息做一些事情,你可以在你的处理循环中调用这个函数。

确定音高(/音符)

这是许多人试图完成的一项重要任务。大多数算法通常涉及 FFT(如前所述),但在上面还有另一层复杂的处理。除非您想开发自己的算法,否则我建议您使用库:


推荐阅读