3、音频采集基础:使用PyAudio库录制麦克风音频,理解采样率、位深度与声道数
好,咱们正式开始动手了。
前面两章我们把摄像头画面搞定了,但一个完整的直播或录制系统,光有画面可不行。你想想看,一个没有声音的监控画面,或者一个只有图像没有讲解的教学视频,是不是总觉得少了点什么?
这一章,我们就来攻克音频采集。我会带你用 PyAudio 这个库,把麦克风的声音抓进来。同时,我会把 采样率、位深度、声道数 这三个最基础也最容易搞混的概念,用最直白的方式讲清楚。
3.1 为什么是PyAudio?
Python里处理音频的库不少,比如 sounddevice、wave、pydub。但我个人习惯用 PyAudio。为什么?
- 跨平台稳定:Windows、macOS、Linux 都能跑,底层用的是 PortAudio,这东西很成熟。
- 底层控制力强:你可以直接操作音频流,拿到最原始的 PCM 数据。这对于我们后面做音视频同步、音频处理来说,太重要了。
- 生态好:很多开源项目都在用,遇到问题网上随便一搜就有答案。
安装也很简单,一行命令搞定:
pip install pyaudio
嗯,这里要注意。如果你在 Windows 上遇到安装失败,别慌。去 https://www.lfd.uci.edu/~gohlke/pythonlibs/ 下载对应版本的 .whl 文件,然后手动安装。我当年第一次装的时候,就被这个坑过。
3.2 三个核心参数:采样率、位深度、声道数
在写代码之前,我们必须先把这三个参数搞明白。说白了,它们决定了你录出来的声音是什么质量。
3.2.1 采样率(Sample Rate)
采样率,就是每秒钟对声音信号采样的次数。单位是 Hz(赫兹)。
- 8000 Hz:电话音质,够用但很糊。
- 44100 Hz:CD 音质,也是我们最常用的。我个人习惯用这个。
- 48000 Hz:DVD/专业音频设备的标准。如果你做专业录音,建议用这个。
为什么会这样?根据奈奎斯特采样定理,采样率必须大于信号最高频率的两倍。人耳能听到的频率范围是 20Hz ~ 20kHz,所以 44100 Hz 刚好能覆盖。
我在项目中遇到过一个问题:录制的语音听起来有点“闷”。排查了半天,发现是采样率设成了 16000 Hz,导致高频信息丢失了。后来改成 44100 Hz,问题解决。
3.2.2 位深度(Bit Depth)
位深度,决定了每个采样点用多少位来表示。它直接影响动态范围。
- 8-bit:256 个等级,噪音大,基本不用。
- 16-bit:65536 个等级,CD 音质,够用。
- 24-bit:16777216 个等级,专业录音棚级别。
你想想看,位深度越大,能记录的细节就越多。但文件体积也会变大。对于一般的网络摄像头应用,16-bit 是性价比最高的选择。
3.2.3 声道数(Channels)
声道数,就是声音的通道数量。
- 1(Mono):单声道,所有声音混在一起。适合语音通话。
- 2(Stereo):双声道,左右声道分开。适合音乐、环境音录制。
我个人建议,如果你只是录人声讲课,用单声道就够了。双声道虽然听起来更立体,但数据量翻倍,处理起来也麻烦一些。
核心公式:
数据量(字节/秒) = 采样率 × 位深度 / 8 × 声道数
举个例子:44100 Hz × 16-bit / 8 × 1(单声道)= 88200 字节/秒 ≈ 86 KB/s
3.3 实战:用PyAudio录制麦克风音频
好了,理论讲完了,咱们直接上代码。我会写一个最简单的录音程序,把麦克风的声音保存成 WAV 文件。
import pyaudio
import wave
# 录音参数
FORMAT = pyaudio.paInt16 # 16-bit 位深度
CHANNELS = 1 # 单声道
RATE = 44100 # 采样率 44100 Hz
CHUNK = 1024 # 每次读取的帧数
RECORD_SECONDS = 5 # 录制时长
# 初始化 PyAudio
p = pyaudio.PyAudio()
# 打开音频流
stream = p.open(format=FORMAT,
channels=CHANNELS,
rate=RATE,
input=True,
frames_per_buffer=CHUNK)
print("开始录音...")
frames = []
# 循环读取音频数据
for i in range(0, int(RATE / CHUNK * RECORD_SECONDS)):
data = stream.read(CHUNK)
frames.append(data)
print("录音结束")
# 关闭流
stream.stop_stream()
stream.close()
p.terminate()
# 保存为 WAV 文件
wf = wave.open("output.wav", 'wb')
wf.setnchannels(CHANNELS)
wf.setsampwidth(p.get_sample_size(FORMAT))
wf.setframerate(RATE)
wf.writeframes(b''.join(frames))
wf.close()
print("文件已保存为 output.wav")
这段代码的逻辑很简单:
- 初始化 PyAudio 对象。
- 打开一个输入流(input=True),指定好参数。
- 在一个循环里不断读取
CHUNK大小的数据,存到列表里。 - 结束后,把数据写入 WAV 文件。
小技巧:
CHUNK 这个值不是随便选的。1024 是一个比较平衡的值。太小了(比如 256)会导致 CPU 占用高,太大了(比如 4096)会增加延迟。我一般用 1024 或 2048。
3.4 避坑指南:我曾经踩过的坑
代码写完了,但直接跑可能会遇到问题。我把自己踩过的坑分享给你:
- 坑一:录音没声音
我曾经遇到过,代码跑起来没报错,但录出来的文件是静音。排查了半天,发现是麦克风被系统静音了。所以,先检查一下系统音量设置。
- 坑二:录音有爆音
如果你录出来的声音有“噼啪”的爆音,大概率是
CHUNK设置得太小,或者 CPU 负载太高,导致数据读取不及时。试着把CHUNK调大一点,比如 2048 或 4096。 - 坑三:采样率不匹配
有些麦克风硬件不支持 44100 Hz,只支持 48000 Hz 或 16000 Hz。你可以用
p.get_device_info_by_index()查看设备支持的采样率。我一般会写一个设备列表打印函数,先看看再动手。
重要提醒:
在 Windows 上,如果你同时打开多个 PyAudio 流,可能会报错。记得每次用完都要 stream.close() 和 p.terminate(),释放资源。
3.5 理解音频数据:PCM 是什么?
你可能会好奇,stream.read(CHUNK) 读出来的 data 到底是什么?
说白了,它就是 PCM(脉冲编码调制) 数据。是一串二进制数字,每个数字代表一个采样点的振幅。
- 如果是 16-bit 单声道,每个采样点占 2 个字节。
- 如果是 16-bit 双声道,每个采样点占 4 个字节(左声道 2 字节 + 右声道 2 字节)。
我们后面做音频处理,比如降噪、音量调整,本质上就是修改这些 PCM 数据。
3.6 本章小结
这一章,我们完成了音频采集的第一步。你学会了:
- 三个核心参数:采样率、位深度、声道数。
- 用 PyAudio 录制麦克风音频并保存为 WAV 文件。
- 避开了我当年踩过的坑。
下一章,我们会把音频和视频结合起来,实现真正的音视频同步采集。嗯,那才是真正的挑战。
课后练习:
1. 修改代码,录制 10 秒的双声道音频,对比文件大小。
2. 尝试用不同的采样率(8000、44100、48000)录制同一段声音,听听区别。
3. 打印出你电脑上所有音频设备的列表,看看你的麦克风支持哪些采样率。