3、音频采集基础:使用PyAudio库录制麦克风音频,理解采样率、位深度与声道数

好,咱们正式开始动手了。

前面两章我们把摄像头画面搞定了,但一个完整的直播或录制系统,光有画面可不行。你想想看,一个没有声音的监控画面,或者一个只有图像没有讲解的教学视频,是不是总觉得少了点什么?

这一章,我们就来攻克音频采集。我会带你用 PyAudio 这个库,把麦克风的声音抓进来。同时,我会把 采样率、位深度、声道数 这三个最基础也最容易搞混的概念,用最直白的方式讲清楚。

3.1 为什么是PyAudio?

Python里处理音频的库不少,比如 sounddevicewavepydub。但我个人习惯用 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")

这段代码的逻辑很简单:

  1. 初始化 PyAudio 对象。
  2. 打开一个输入流(input=True),指定好参数。
  3. 在一个循环里不断读取 CHUNK 大小的数据,存到列表里。
  4. 结束后,把数据写入 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. 打印出你电脑上所有音频设备的列表,看看你的麦克风支持哪些采样率。