:PyAudio 按键录音与回放实战)
IoT-For-Beginners 智能语音定时器Raspberry Pi 篇PyAudio 按键录音与回放实战【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners本篇文章是开源课程项目IoT-For-Beginners第 6 章Consumer 消费类设备第 1 课《用 IoT 设备识别语音》中 Raspberry Pi 分支的实战指南聚焦于如何用按键控制音频采集。你将学会在树莓派上连接 Grove 按键、安装 PyAudio 音频库并编写一段完整的 Python 程序按住按键说话即可录音松开按键自动回放录制内容。这是后续构建智能厨房定时器语音转文字的第一步也是理解以按键替代唤醒词wake word来触发语音采集这一隐私设计模式的最佳入门实践。项目背景为什么用按键触发录音在 课程 README 中本课要构建一个可用语音设定多个定时器的智能厨房定时器。真实的智能音箱如 Alexa、Siri、Google Home通过持续监听唤醒词来触发语音识别但这会带来明显的隐私问题——设备可能把家中私人谈话上传到云端。为了规避训练唤醒词模型的复杂度同时保护用户隐私本课程采用的方案是用一颗物理按键替代唤醒词——只有按下按键时才开始采集音频见 课程 README 中 The smart timer you are building in this lesson will use a button to turn on the speech recognition 一节。本文聚焦 Raspberry Pi 分支的音频采集实现。硬件准备麦克风与扬声器选型Raspberry Pi 没有内置麦克风需要外接常见方案包括USB 麦克风、USB 耳机、USB 一体式扬声器speakerphone、USB 声卡 3.5mm 麦克风或ReSpeaker 2-Mics Pi HAT。Pi 自带 3.5mm 耳机孔可用于接耳机/音箱也可以使用 HDMI 音频、USB 音箱等作为扬声器。完整的连接与配置流程arecord -l/aplay -l查看声卡、修改alsa.conf默认声卡、用arecord/aplay测试录音回放、alsamixer调节音量请参考 pi-microphone.md本文不再赘述。按键Grove 按键 vs ReSpeaker 2-Mics Pi HAT采集音频需要一个按键来控制录音的起止。本课提供两种硬件路径Grove 按键 Grove Base HATGrove 按键是一种数字传感器按下/松开会切换高、低电平信号。它既可配置为按下输出高电平、松开输出低电平也可配置为相反逻辑。使用这条路径时需要在 Grove Base HAT 上单独接线。ReSpeaker 2-Mics Pi HAT该 HAT 自带一颗按键因此无需再外接按键可直接跳转到后续编码环节。使用 ReSpeaker HAT 时需先安装其驱动详见 Seeed 官方入门文档Pi 上需git可用sudo apt install git --yes安装。任务一连接按键如果你使用的是 ReSpeaker 2-Mics Pi HAT按键已在 HAT 上见 pi-respeaker-hat.png请跳过本节。若使用 Grove 按键接线步骤如下对应 pi-audio.md 的 Connect the button 部分将 Grove 线缆的一端插入按键模块的插座有防呆设计只有一个方向能插入。在树莓派断电状态下将 Grove 线缆另一端连接到 Grove Base HAT 上标有D5的数字插座。该插座位于紧邻 GPIO 引脚的那一排插座中从左数第二个。接线完成后上电启动树莓派即可进入编码环节。任务二安装音频依赖PortAudio 与 PyAudioPyAudio 是基于 PortAudio 跨平台音频库的 Python 封装提供录音与回放能力但需要先安装底层系统库。在树莓派终端中依次执行sudo apt update sudo apt install libportaudio0 libportaudio2 libportaudiocpp0 portaudio19-dev libasound2-plugins --yes然后安装 PyAudio 的 pip 包pip3 install pyaudio说明libasound2-plugins提供 ALSAAdvanced Linux Sound Architecture插件支持portaudio19-dev提供开发头文件。命令执行环境为树莓派操作系统Raspberry Pi OS的 apt 包管理。任务三编写录音与回放程序新建一个名为smart-timer的文件夹在其中创建app.py。仓库中该文件的完整实现位于 code-record/pi/smart-timer/app.py下面按模块逐一讲解。模块导入import io import pyaudio import time import wave from grove.factory import Factorypyaudio负责录音与回放的核心模块io、wave标准库用于把录制的裸音频数据封装为 WAV 二进制缓冲区time主循环中用于轮询按键的休眠grove.factory.FactorySeeed Grove 硬件库用于创建按键类实例。创建按键实例根据硬件路径二选一# 使用 ReSpeaker 2-Mics Pi HAT 时 # 该 HAT 上的按键连接到 D17 端口按下时输出低电平 button Factory.getButton(GPIO-LOW, 17)# 使用 Grove 按键接在 Grove Base HAT 的 D5 端口时 # 该按键按下时输出高电平 button Factory.getButton(GPIO-HIGH, 5)Factory.getButton的第一个参数是电平逻辑GPIO-LOW按键按下时引脚为低电平is_pressed()在低电平时返回 TrueGPIO-HIGH按键按下时引脚为高电平is_pressed()在高电平时返回 True。第二个参数是端口号。两个参数必须与实际接线方式和硬件严格对应否则按键状态检测会反向或失效。仓库中的示例代码app.py使用 Grove 按键路径Factory.getButton(GPIO-HIGH, 5)。创建 PyAudio 实例与配置声卡编号audio pyaudio.PyAudio()随后声明麦克风与扬声器的硬件声卡编号——这两个编号来自 pi-microphone.md 中运行arecord -l查看采集设备与aplay -l查看播放设备得到的结果microphone_card_number microphone card number speaker_card_number speaker card number把microphone card number替换为麦克风的声卡号把speaker card number替换为扬声器的声卡号——也就是你在alsa.conf文件中设置的同一个编号若使用板载耳机孔则为 0。采样率 rate 的选择rate 48000 #48KHz采样率越高声音质量越好。如果后续运行时报采样率错误可改为44100或16000。需要说明的是对本项目后续的语音转文字speech-to-text用途而言16KHz 已是足够好的采样率——课程 README 中给出了数据量的估算16-bit 音频在 16KHz 下每秒约产生 32KB 数据16-bit 每采样 2 字节 × 每秒 16000 次采样 32,000 字节/秒。对于像 Wio Terminal 这类仅有 192KB 内存的微控制器这个体量对内存是很大压力而树莓派作为单板计算机拥有充足内存与操作系统层面的音频缓冲可以宽松地使用更高采样率。capture_audio 录音函数定义录音函数按住按键期间持续采集音频def capture_audio(): stream audio.open(format pyaudio.paInt16, rate rate, channels 1, input_device_index microphone_card_number, input True, frames_per_buffer 4096) frames [] while button.is_pressed(): frames.append(stream.read(4096)) stream.stop_stream() stream.close()audio.open各参数含义参数值说明formatpyaudio.paInt16采样格式为 16 位有符号整数PCMWAV 音频的标准格式raterate采样率即上面定义的48000可降为 44100/16000channels1单声道麦克风通常为单声道输入input_device_indexmicrophone_card_number指定使用哪个声卡设备采集inputTrue开启输入采集模式frames_per_buffer4096每次读取的缓冲区大小帧数即 4096 字节这段代码的采集逻辑是只要按键处于按下状态就持续调用stream.read(4096)读取一个 4096 字节缓冲区并追加到frames列表一旦松开按键立即停止并关闭流。这就是以按键替代唤醒词的核心实现——录音窗口完全由用户物理控制不会在未按下按键时采集或上传任何声音。将音频封装为 WAV 缓冲区在capture_audio函数末尾追加如下代码wav_buffer io.BytesIO() with wave.open(wav_buffer, wb) as wavefile: wavefile.setnchannels(1) wavefile.setsampwidth(audio.get_sample_size(pyaudio.paInt16)) wavefile.setframerate(rate) wavefile.writeframes(b.join(frames)) wav_buffer.seek(0) return wav_buffer这里把内存中累积的音频帧写入一个二进制缓冲区封装为标准WAV 文件。WAV 是常见的无压缩音频存储格式文件头部包含采样率如 16000 表示 16KHz、采样位宽16 表示 16-bit、声道数等元信息头部之后是原始音频数据。要点setnchannels(1)单声道setsampwidth(audio.get_sample_size(pyaudio.paInt16))通过 PyAudio 查询 16-bit 整数采样格式对应的字节宽度即 2 字节并写入文件头setframerate(rate)写入采样率writeframes(b.join(frames))把按 4096 字节分块的帧数据拼接后写入wav_buffer.seek(0)将指针复位到缓冲区开头便于后续读取函数返回这个BytesIO缓冲区对象而非磁盘文件——这样既可用于本地回放也可在后续课程中直接作为 HTTP 请求体上传给语音转文字服务。play_audio 回放函数添加如下回放函数把录到的音频播放出来def play_audio(buffer): stream audio.open(format pyaudio.paInt16, rate rate, channels 1, output_device_index speaker_card_number, output True) with wave.open(buffer, rb) as wf: data wf.readframes(4096) while len(data) 0: stream.write(data) data wf.readframes(4096) stream.close()该函数打开一个输出流output True设备编号为speaker_card_number其余参数与输入流一致。随后把capture_audio返回的 WAV 缓冲区以只读方式打开按 4096 帧的块循环读取并写入输出流直到读完所有数据后关闭流完成回放。主循环按下 → 录音 → 回放while True: while not button.is_pressed(): time.sleep(.1) buffer capture_audio() play_audio(buffer)主循环的工作方式外层while True常驻运行内层循环以 0.1 秒为间隔轮询按键time.sleep(.1)避免忙等占用 CPU直到按键被按下才退出随后调用capture_audio()采集音频采集期间按键保持按下松开后得到 WAV 缓冲区再调用play_audio(buffer)回放。至此一个按下即录、松手即放的语音采集闭环完成。任务四运行与故障排查在smart-timer目录下运行python3 app.py按住按键对着麦克风说话说完松开即可听到刚才录音的回放。运行中可能出现如下 ALSA 输出piraspberrypi:~/smart-timer $ python3 app.py ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.front ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.rear ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.center_lfe ALSA lib pcm.c:2565:(snd_pcm_open_noupdate) Unknown PCM cards.pcm.side这些 ALSA 告警是因为树莓派默认配置中声明了一些你并未接入的音频设备可以安全忽略不影响录音与回放功能。若遇到如下错误说明当前采样率不被声卡支持OSError: [Errno -9997] Invalid sample rate此时将代码中的rate改为44100或16000即可注意降低采样率会降低音质但对语音识别足够。仓库源码印证与后续演进上述代码的完整可运行版本保存在课程仓库中code-record/pi/smart-timer/app.py。该文件与本文讲解逐行对应按键创建在 第 7 行PyAudio 实例与声卡/采样率配置在 第 9-12 行capture_audio在 第 14-38 行play_audio在 第 40-54 行主循环在 第 56-61 行。这一录音模块正是后续课程的基石。在 code-speech-to-text/pi/smart-timer/app.py 中可以看到它的自然演进capture_audio()保持完全不变主循环改为把 WAV 缓冲区直接作为请求体上传至 Azure Speech 服务convert_speech_to_text通过 REST 调用获取访问令牌、以audio/wav; codecsaudio/pcm; samplerate{rate}格式发送录音并解析返回的DisplayText从而打通按键录音 → 云端语音识别 → 文本处理的完整链路。这也印证了将录音封装为内存 WAV 缓冲区、而非落盘文件的架构考量——后续可以直接流式上传无需中间文件。小结通过本文你完成了智能语音定时器在树莓派上的第一个里程碑使用 Grove 按键或 ReSpeaker HAT 自带按键作为隐私友好的唤醒词替代方案借助 PortAudio/PyAudio 采集 16-bit 单声道 PCM 音频将其封装为 WAV 缓冲区并回放验证。掌握了声卡编号、采样率、缓冲区大小等关键参数的调优方法以及 ALSA 告警与采样率错误的排查手段。下一步即可基于该录音模块接入语音转文字服务让树莓派真正听懂你的语音指令。【免费下载链接】IoT-For-Beginners12 Weeks, 24 Lessons, IoT for All!项目地址: https://gitcode.com/GitHub_Trending/io/IoT-For-Beginners创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考