AI脑洞板
完整教案
自学课件
第 15 课 · 共 15/51 课

声音留声机 录下来,存进卡里,再放出来

课时
待定
器材
ESP32-S3 触摸屏板 + USB 线
前置知识
无
配套代码
见项目 demo 目录

你好,我是吴老师。

这份是给你自己读的——不用等我讲,你一段一段往下看,看到让你停下来的地方,就照着做一遍。

读完之后,你应该能:说清留声机"录 → 存 → 放"三步各在干什么;解释 WAV 文件头为什么必须有;把录 3 秒声音的字节数算出来;说出播放时怎么跳过文件头找到声音。

用时:90 分钟。准备:板子、TF 卡(已格式化)、数据线、已经接入板卡 Skill 的 WorkBuddy。


一、今天做一个"声音留声机"

先看成品长什么样。 下面就是今天要做的东西,你先玩一遍再回来:

请使用课程的 esp32s3-touchboard-hardware-dev Skill,
做一个"声音留声机":
  按一下 BOOT  → 录 3 秒,存进 TF 卡
  再按一下     → 播放刚才录的那段留言
  再按一下     → 又开始录(覆盖上一条)
屏幕上显示现在是"准备/录音中/播放中"。
录音数据放 PSRAM,写完文件记得 close()。
播放前先检查板卡的音频芯片(ES8311)和功放初始化方式。帮我新建程序并烧录。

烧起来先玩一玩,然后记下三件事:

我玩的时候观察
录一段话,再放出来是你的声音吗?有延迟吗?
拔掉电,重新插上,再按一次刚才录的还在吗?为什么?
把 TF 卡拔下来,插到电脑上能找到那个文件吗?能双击播放吗?

第二、三行是这台留声机"值钱"的地方——声音留下来了,不在板子内存里,而在卡里。 电脑都能打开它,说明它不是"板子专用的黑盒",而是一个真正的声音文件。

这台留声机看着神奇,其实只做三件事:录进来 → 存下去 → 放出来。

今天我们就把它拆开,一样一样看清楚。


二、三件会的东西,拼成一件新的

你已经有三个"半成品":

  1. 第 12 课:对着板子说话,麦克风把它变成数字(回声)
  2. 第 14 课:把数字写进 TF 卡,重启还在
  3. 第 11 课:把数字送出去,扬声器就响

回声是"边收边放",停机就没了。但如果把收进来的数字像计数器一样写进 TF 卡呢?

那样你说的话就留下来了——这就是声音留言机。

三、拆开①:录进来的,本来就是一串数字

录音在板子里是一大串数字:一秒 16000 个,每个 2 字节。

所以"存声音"和存 count.txt 是同一件事:把数字一个接一个写进文件。

但文件里只有一串数字,别人怎么知道它是声音、每秒几个、多大、几个声道?

需要"自我介绍"——这就是文件头。

存声音 = 存数字:麦克风声→数字串→写进 TF 卡,和存计数器是同一件事(但要一份文件头自我介绍)

四、拆开②:为什么必须有个「自述信」

我们用的格式叫 WAV:

┌──────────────────────────────┐
│ 文件头(前 44 字节 = 自述信)      │
│  · 我是 WAV/RIFF               │
│  · 采样率:16000               │
│  · 位深:16                    │
│  · 声道:2                     │
│  · 数据多长                     │
├──────────────────────────────┤
│ 声音数据(一串 16 位数字)         │
└──────────────────────────────┘

播放器拿到 WAV,先读 44 字节"自述信",就全明白了。参数改了头就要改,否则按错的节奏读。

亲眼看一看:这 44 个字节长什么样

下面把真实的文件头按字节画出来了(和板子上 writeWavHeader() 写的一模一样)。 把鼠标放到格子上,看这一格是干什么的:

重点看这两件事:

  1. 黄色那两格是"数据长度" —— 一个在前(块大小)、一个在后(数据长度), 而它们都要等录完才知道。所以程序的做法是:先把 44 个字节的位置占住,录完再回头填。 (点「还没录音」那个按钮,你会看到它是 0。)
  2. 点"采样率填错"试试 —— 把 16000 改成 8000,声音数据一个字节都没动, 但播放器照着这封写错的"自述信"读,就会用一半的速度读你的数据: 声音变得又慢又沉,像磁带快没电。

💡 这就解释了第 11 课那句"送得快音调就高":文件头里写着"每秒读几个数", 播放器完全照它执行。头写错了,数据再对也没用。

五、拆开③:录下来怎么存

准备:PSRAM 申请大内存;打开 record.wav;先留出 44 字节头

录音(按 BOOT):从麦克风读数字攒进内存,屏显秒数;录够停

写文件:把内存数字写在头后面;回头填上"数据多长";close()

工程细节:数据长度要录完才知道,所以头先空着,写完回头填。

六、拆开④:放出来怎么读

打开 record.wav
读 44 字节自述信
跳过文件头,从数据开始:读一小段 → 送出去 → 再读 → 再送
到结尾关闭

和回声的区别只有一处:回声送"麦克风收来的数字",播放送"文件里读出来的数字"。

录音存盘先留 44 字节头录完回头填;播放拆包先读自述信再跳过文件头读数据

七、轮到你设计:三个「多久」

  1. 录多久? 3 秒 ≈ 16000×3×2×2 ≈ 192KB → 内存够吗?要 PSRAM
  2. 存几个文件? 覆盖旧的,还是 note_1、note_2 一直加?
  3. 何时算录完? 到秒数自动停,还是再按一次?

没有标准答案,但决定"这台留言机怎么用"。这就是设计取舍,真正的作品从这开始。

八、故障排查

现象先检查
录完没声音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 课,本章收尾。

第 15 课 · 录 3 秒存成 WAV

第 15 课 · 录 3 秒存成 WAV

按 BOOT 录 3 秒,存成 TF 卡里的 rec.wav,拔卡插电脑就能播放。

15录音WAVPSRAMTF卡
第 15 课 · 播放录音

第 15 课 · 播放录音

开机播放 TF 卡里的 rec.wav(要先跑 demo01 录一段)。

15播放WAVTF卡
第 15 课 · 声音留言机

第 15 课 · 声音留言机

按一下 BOOT 录 3 秒存卡,再按一下播放,再按一下又开始录。

15留言机状态机作品