3、Python音频库入门:PyAudio安装与配置、sounddevice库基础、wave模块读写、音频设备枚举
好,咱们进入实战环节。前面聊了那么多音频基础概念,现在该让Python真正“听到”声音了。这一章我会带你搞定三个最常用的音频库——PyAudio、sounddevice和wave。说白了,它们就是Python和音频硬件之间的翻译官。
我个人习惯把这几个库分个工:PyAudio是瑞士军刀,功能全但配置稍麻烦;sounddevice是轻骑兵,API简洁,适合快速原型;wave是后勤兵,专门读写WAV文件。咱们一个一个来。
3.1 PyAudio:安装与配置
PyAudio是对PortAudio的Python封装。PortAudio是个跨平台音频I/O库,几乎所有专业音频软件底层都在用它。嗯,这里要注意——PyAudio的安装曾经是很多初学者的噩梦。
pip install pyaudio 大概率会报错,因为缺少PortAudio的二进制依赖。别慌,有解决方案。
3.1.1 安装方法
不同平台,安装方式不一样。我列个表,你对着自己的系统来:
| 操作系统 | 推荐安装方式 | 备注 |
|---|---|---|
| Windows | pip install pipwin → pipwin install pyaudio |
或者直接下载预编译whl文件 |
| macOS | brew install portaudio → pip install pyaudio |
Homebrew先装依赖 |
| Linux (Ubuntu/Debian) | sudo apt install portaudio19-dev → pip install pyaudio |
开发头文件必须装 |
| Linux (其他发行版) | 安装对应portaudio-dev包 → pip install pyaudio |
包名可能略有不同 |
我曾经在Windows上被这个坑折腾了整整一下午。后来发现,直接用 pipwin 是最省心的——它会自动从Gohlke的仓库拉取编译好的whl文件。
3.1.2 验证安装
装完之后,跑个简单的验证脚本:
import pyaudio
# 创建PyAudio对象
p = pyaudio.PyAudio()
# 获取默认输入设备信息
info = p.get_default_input_device_info()
print(f"默认输入设备: {info['name']}")
print(f"采样率: {info['defaultSampleRate']}")
# 别忘了关闭
p.terminate()
如果没报错,并且打印出了设备信息,恭喜你,PyAudio装好了。
3.2 sounddevice库:轻量级替代方案
说实话,我现在做原型验证时更常用sounddevice。为什么?因为它API设计得更Pythonic,不用手动管理流对象的生命周期。你想想看,PyAudio里你得自己open、start、stop、close,而sounddevice一个函数调用就搞定了。
3.2.1 安装与基础用法
安装简单到离谱:
pip install sounddevice
没有依赖陷阱,没有编译问题。这才是现代Python库该有的样子。
来个最简单的录音示例:
import sounddevice as sd
import numpy as np
# 录制3秒音频,采样率44100Hz
fs = 44100
duration = 3
print("开始录音...")
recording = sd.rec(int(duration * fs), samplerate=fs, channels=1)
sd.wait() # 等待录制完成
print("录音结束")
# recording是一个numpy数组
print(f"数据形状: {recording.shape}")
print(f"数据类型: {recording.dtype}")
看到了吗?三行核心代码就完成了录音。sd.rec()是阻塞式调用,sd.wait()确保数据写满。我在项目中经常用这个组合做快速音频采集验证。
3.2.2 播放音频
播放同样简单:
import sounddevice as sd
import numpy as np
# 生成一个440Hz的正弦波,播放2秒
fs = 44100
t = np.linspace(0, 2, int(fs * 2), endpoint=False)
wave = 0.5 * np.sin(2 * np.pi * 440 * t)
sd.play(wave, samplerate=fs)
sd.wait() # 等待播放完成
3.3 wave模块:读写WAV文件
wave是Python标准库的一部分,不需要额外安装。它只支持WAV格式,但WAV恰恰是音频采集中最常用的无损格式。说白了,你采集到的原始数据,最终大概率要存成WAV。
3.3.1 读取WAV文件
import wave
import numpy as np
# 打开WAV文件
with wave.open('test.wav', 'rb') as wf:
# 获取文件参数
n_channels = wf.getnchannels()
sampwidth = wf.getsampwidth()
framerate = wf.getframerate()
n_frames = wf.getnframes()
print(f"声道数: {n_channels}")
print(f"采样宽度: {sampwidth} 字节") # 1=8bit, 2=16bit, 4=32bit
print(f"采样率: {framerate} Hz")
print(f"总帧数: {n_frames}")
# 读取所有音频数据
raw_data = wf.readframes(n_frames)
# 转为numpy数组(假设是16bit)
audio_data = np.frombuffer(raw_data, dtype=np.int16)
# 如果是多声道,reshape成二维数组
if n_channels > 1:
audio_data = audio_data.reshape(-1, n_channels)
这里有个细节——readframes()返回的是原始字节,你得自己根据采样宽度转成合适的numpy类型。我曾经见过有人直接用int16去读8bit的WAV,结果数据全乱了。
3.3.2 写入WAV文件
import wave
import numpy as np
# 准备数据:2秒的440Hz正弦波,16bit
fs = 44100
t = np.linspace(0, 2, int(fs * 2), endpoint=False)
wave_data = (0.5 * np.sin(2 * np.pi * 440 * t) * 32767).astype(np.int16)
# 写入WAV
with wave.open('output.wav', 'wb') as wf:
wf.setnchannels(1) # 单声道
wf.setsampwidth(2) # 16bit = 2字节
wf.setframerate(fs) # 采样率
wf.writeframes(wave_data.tobytes())
print("WAV文件已保存")
3.4 音频设备枚举
做音频采集的第一步是什么?不是写代码,是搞清楚你的机器上有哪些音频设备。我刚开始做项目时,直接用了默认设备,结果采集到的全是麦克风的底噪——因为我压根没意识到还有别的输入源。
3.4.1 用PyAudio枚举设备
import pyaudio
p = pyaudio.PyAudio()
device_count = p.get_device_count()
print(f"检测到 {device_count} 个音频设备\n")
print(f"{'索引':<6} {'名称':<40} {'输入通道':<10} {'输出通道':<10} {'采样率':<10}")
print("-" * 80)
for i in range(device_count):
info = p.get_device_info_by_index(i)
print(f"{i:<6} {info['name']:<40} {info['maxInputChannels']:<10} "
f"{info['maxOutputChannels']:<10} {info['defaultSampleRate']:<10.0f}")
p.terminate()
3.4.2 用sounddevice枚举设备
sounddevice更简洁:
import sounddevice as sd
# 获取所有设备
devices = sd.query_devices()
print(devices)
# 获取默认设备
default_input = sd.default.device[0]
default_output = sd.default.device[1]
print(f"默认输入设备索引: {default_input}")
print(f"默认输出设备索引: {default_output}")
输出类似这样:
0 MacBook Pro Microphone, Core Audio (1 in, 0 out)
1 MacBook Pro Speakers, Core Audio (0 in, 2 out)
2 USB Audio Device, Core Audio (2 in, 2 out)
3.5 本章知识体系
下面这张图帮你理清三个库的关系和适用场景:
这张图把三个库的定位说得很清楚了。我个人建议的学习路径是:先用sounddevice快速上手录音和播放,再用wave搞定文件读写,最后深入PyAudio做精细的流控制。别一上来就啃PyAudio的复杂API,容易劝退。
3.6 避坑指南
最后,分享几个我踩过的坑:
- 设备被占用:PyAudio打开设备后,如果不调用
close()或terminate(),其他程序就访问不了这个设备。我曾经调试时忘了关流,结果Audacity一直报错说设备不可用。 - 缓冲区大小不匹配:sounddevice的
blocksize参数默认是自动选择的,但在某些USB声卡上会导致爆音。手动设成1024或512帧通常能解决问题。 - 采样率不匹配:不是所有设备都支持所有采样率。枚举设备时记得检查
defaultSampleRate,别想当然地用96000去录一个只支持48000的麦克风。 - 数据类型转换:wave模块读出来的是bytes,sounddevice要的是numpy数组,PyAudio要的是bytes或numpy。这三者之间的转换最容易出bug。我的习惯是统一用numpy做中间格式。