python - 如何获取 Python 3.x 中录制的音频的频率和幅度?
问题描述
我正在尝试录制音频并以 1 秒的间隔获取音频的平均频率和幅度,而无需写入文件。如果您使用 pyaudio 从文件中读取,有很多例子可以说明如何做到这一点,尽管任何可用于这种特定情况的东西都使用 Python 2.7 库,而 Python 3.x 似乎不存在这些库。
任何帮助,将不胜感激!
解决方案
获取音频
我不确定您使用哪个库来录制音频,但实时录制/播放的正常选择(在我看来)是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 处理以及傅立叶变换)。
以供参考:
如果你想对频率信息做一些事情,你可以在你的处理循环中调用这个函数。
确定音高(/音符)
这是许多人试图完成的一项重要任务。大多数算法通常涉及 FFT(如前所述),但在上面还有另一层复杂的处理。除非您想开发自己的算法,否则我建议您使用库:
- Google 的 REAPER算法(需要封装到 Python中)
- Aubio Python DSP 库
- Librosa Python 音频分析库(这是一个入门示例)
推荐阅读
- r - 在 anaconda 中更新 R 包但出现 clang-12 错误
- interface - 在 Proguard 之后删除了接口实现的方法
- c++ - Eclipse CDT - 如何在同一个项目中配置多个目标
- personalization - 关于谷歌广告个性化
- jboss - Wildfly 生成的密钥库不可读
- asp.net-core - 解码 request_id 参数以访问编码数据的新方法是什么?
- reporting-services - 运行和发布分页报表的区别
- android - 最初如何使用 javascript 函数而不是 URL 加载 android WebView。
- curl - 文件名中带有日文字符的 cURL 文件上传不起作用
- redisson - 在 Tomcat 9 中使用 Redisson java 客户端时遇到的缓慢问题