你好,我是吴老师。
这份是给你自己读的——不用等我讲,你一段一段往下看,看到让你停下来的地方,就照着做一遍。
读完之后,你应该能:说清留声机"录 → 存 → 放"三步各在干什么;解释 WAV 文件头为什么必须有;把录 3 秒声音的字节数算出来;说出播放时怎么跳过文件头找到声音。
用时:90 分钟。准备:板子、TF 卡(已格式化)、数据线、已经接入板卡 Skill 的 WorkBuddy。
一、今天做一个"声音留声机"
先看成品长什么样。 下面就是今天要做的东西,你先玩一遍再回来:
请使用课程的 esp32s3-touchboard-hardware-dev Skill,
做一个"声音留声机":
按一下 BOOT → 录 3 秒,存进 TF 卡
再按一下 → 播放刚才录的那段留言
再按一下 → 又开始录(覆盖上一条)
屏幕上显示现在是"准备/录音中/播放中"。
录音数据放 PSRAM,写完文件记得 close()。
播放前先检查板卡的音频芯片(ES8311)和功放初始化方式。帮我新建程序并烧录。
烧起来先玩一玩,然后记下三件事:
| 我玩的时候 | 观察 |
|---|---|
| 录一段话,再放出来 | 是你的声音吗?有延迟吗? |
| 拔掉电,重新插上,再按一次 | 刚才录的还在吗?为什么? |
| 把 TF 卡拔下来,插到电脑上 | 能找到那个文件吗?能双击播放吗? |
第二、三行是这台留声机"值钱"的地方——声音留下来了,不在板子内存里,而在卡里。 电脑都能打开它,说明它不是"板子专用的黑盒",而是一个真正的声音文件。
这台留声机看着神奇,其实只做三件事:录进来 → 存下去 → 放出来。
今天我们就把它拆开,一样一样看清楚。
二、三件会的东西,拼成一件新的
你已经有三个"半成品":
- 第 12 课:对着板子说话,麦克风把它变成数字(回声)
- 第 14 课:把数字写进 TF 卡,重启还在
- 第 11 课:把数字送出去,扬声器就响
回声是"边收边放",停机就没了。但如果把收进来的数字像计数器一样写进 TF 卡呢?
那样你说的话就留下来了——这就是声音留言机。
三、拆开①:录进来的,本来就是一串数字
录音在板子里是一大串数字:一秒 16000 个,每个 2 字节。
所以"存声音"和存 count.txt 是同一件事:把数字一个接一个写进文件。
但文件里只有一串数字,别人怎么知道它是声音、每秒几个、多大、几个声道?
需要"自我介绍"——这就是文件头。
四、拆开②:为什么必须有个「自述信」
我们用的格式叫 WAV:
┌──────────────────────────────┐
│ 文件头(前 44 字节 = 自述信) │
│ · 我是 WAV/RIFF │
│ · 采样率:16000 │
│ · 位深:16 │
│ · 声道:2 │
│ · 数据多长 │
├──────────────────────────────┤
│ 声音数据(一串 16 位数字) │
└──────────────────────────────┘
播放器拿到 WAV,先读 44 字节"自述信",就全明白了。参数改了头就要改,否则按错的节奏读。
亲眼看一看:这 44 个字节长什么样
下面把真实的文件头按字节画出来了(和板子上 writeWavHeader() 写的一模一样)。
把鼠标放到格子上,看这一格是干什么的:
重点看这两件事:
- 黄色那两格是"数据长度" —— 一个在前(块大小)、一个在后(数据长度), 而它们都要等录完才知道。所以程序的做法是:先把 44 个字节的位置占住,录完再回头填。 (点「还没录音」那个按钮,你会看到它是 0。)
- 点"采样率填错"试试 —— 把 16000 改成 8000,声音数据一个字节都没动, 但播放器照着这封写错的"自述信"读,就会用一半的速度读你的数据: 声音变得又慢又沉,像磁带快没电。
💡 这就解释了第 11 课那句"送得快音调就高":文件头里写着"每秒读几个数", 播放器完全照它执行。头写错了,数据再对也没用。
五、拆开③:录下来怎么存
准备:PSRAM 申请大内存;打开 record.wav;先留出 44 字节头
录音(按 BOOT):从麦克风读数字攒进内存,屏显秒数;录够停
写文件:把内存数字写在头后面;回头填上"数据多长";close()
工程细节:数据长度要录完才知道,所以头先空着,写完回头填。
六、拆开④:放出来怎么读
打开 record.wav
读 44 字节自述信
跳过文件头,从数据开始:读一小段 → 送出去 → 再读 → 再送
到结尾关闭
和回声的区别只有一处:回声送"麦克风收来的数字",播放送"文件里读出来的数字"。
七、轮到你设计:三个「多久」
- 录多久? 3 秒 ≈ 16000×3×2×2 ≈ 192KB → 内存够吗?要 PSRAM
- 存几个文件? 覆盖旧的,还是 note_1、note_2 一直加?
- 何时算录完? 到秒数自动停,还是再按一次?
没有标准答案,但决定"这台留言机怎么用"。这就是设计取舍,真正的作品从这开始。
八、故障排查
| 现象 | 先检查 |
|---|---|
| 录完没声音 | WAV 头写对了吗?字节数填对了吗? |
| 声音变尖变快 | 播放采样率和头里写的一致吗? |
| 断断续续 | 一次读太少了,缓冲大一点 |
| 电脑打不开文件 | 44 字节头写错了 |
九、自检小测
先自己想,再点开对答案。
1. 留声机只做三件事,是哪三件?
录进来 → 存下去 → 放出来。
对应三课:第 12 课(麦克风把声音变数字)、第 14 课(数字写进 TF 卡)、第 11 课(数字送出去就响)。
2. 为什么"存声音"和"存 count.txt"是同一件事?
因为声音在板子里本来就是数字——一秒 16000 个,每个 2 字节。
存声音 = 把这一大串数字一个接一个写进文件,和把计数器的数字写进文件,动作一模一样。
3. 既然都是数字,为什么还要 WAV 文件头?
因为光有一串数字,别人不知道它是什么:
- 每秒几个数字?(采样率)
- 每个数字几位?(位深)
- 一个还是两个声道?
文件头就是那封**"自述信"**:把这几件事说清楚,播放器才知道按什么节奏读。 光给数字不给说明,读到的东西就是噪音。
4. 录 3 秒声音,大约多少字节?为什么要用 PSRAM?
16000 个/秒 × 3 秒 × 4 字节(立体声 16 位 = 左右各 2 字节)
= 192,000 字节 ≈ 192 KB
192 KB 太大了——板子的普通内存(DRAM)装不下这么大的缓冲, 所以要申请 PSRAM(板子上那块 8MB 的"大内存")。
5. 播放时,程序怎么知道从哪儿开始是声音数据?
跳过前面 44 字节。
文件头的长度是固定的 44 字节,所以:
打开文件 → 读掉(或跳过)前 44 字节 → 从第 45 字节开始就是声音数字
6. "数据长度"要先写在文件头里,可它是录完才知道的——怎么办?
先空着,录完回头填。
写文件只能从头往后写,但录的时候还不知道能录多久。所以:
① 先占住 44 字节的位置(随便填)
② 录多少、往后面写多少
③ 录完 → 回到开头,把真实长度补进去
④ close()
这是本课最"工程"的一步:先把位置留出来,事后回去补。 写程序和生活中一样——有些信息,就是得等做完了才知道。
7. 录音存文件和第 12 课的"回声",最大的区别是什么?
回声是"边收边放",不留底;留言机是"先存下来,再放"。
- 回声:麦克风收到数字 → 立刻送出去。停机就没了。
- 留言机:麦克风收到数字 → 攒进内存 → 写进卡里。断电还在,还能拿到电脑上播。
多出来的这一步"存",就是"留言"和"通话"的区别。
十、拓展:让它更像一台留声机
- 多条留言(序号文件、来回切换)
- 变声留言机(播放时隔一取一)
- 会说话的相册(照片配录音)
- 语音小抄(录英语循环播)
下一课反着来:不录只放,放卡里现成的 MP3——第 16 课,本章收尾。