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

文字转语音 TTS——机器怎样把文字变成声音 让屏幕里的文字开口说话

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

1. 先做一件事:让它开口

烧录 demo01_tts_player(需要 WiFi 和密钥)。屏幕上有四句话,点一下第一句——板子开口了。

先别激动,做三件事:

  1. 把屏幕底部那行小字抄下来:字数 声音 合成 播放,四个数字一个都别漏;
  2. 再点最长的句子,把这四个数字也抄下来;
  3. 对比两行:字多的句子,哪些数字变大了?

这四个数字就是今天的证据链:发出 N 个字 → 收回 N 字节声音 → 云端合成 N 毫秒 → 喇叭播放 N 毫秒。

任务 1:四句证据链表

✏️ 可以直接在表格里填写
句子字数预测(先写:字节和播放会怎么变)实测字节实测播放
今天天气真好6
你好,我是会说话的板子11
床前明月光,疑是地上霜12
现在是下午三点二十五分11

2. 反着用上一课的账:字节能念多久

上一课算过:喇叭吃的数字,每秒 16000 个 × 每个 2 字节 = 每秒 32000 字节。上一课是"说了几秒 → 多少字节",这一课反过来:收回多少字节 → 能念几秒。

算一算(写在纸上): 收回 59200 字节 → 能念 59200 ÷ 32000 = ______ 秒? (答案:约 1.85 秒。对照你抄的实测"播放"数字——板子真的念了差不多这么久。字节就是声音的长度。)

再算一笔:收回 89280 字节能念多久?(答案:约 2.79 秒。)和实测对照,对得上吗?


3. 三步,文字变声音

你点的那一下,背后是一场下行接力。注意和上一课对比——同一条链子,方向反了:

文字变声音的三步:誊写寄出、云端合成、喂喇叭

步骤谁在做在哪里干什么
1 誊写寄出板子板子上文字誊写成安全字符,连同三个旋钮寄给百度
2 合成百度云端把字做成一串声音数字,寄回来
3 喂喇叭板子板子上声音数字存进 pcmBuffer,一勺一勺写进喇叭

两课对偶表(重点,考试就考这个感觉)

第 24 课(上行)第 25 课(下行)
你给板子什么声音文字
板子寄出什么声音数字(base64 装信封)文字(誊写成安全字符)
云端干什么比对猜字照字面做声音
寄回来什么文字声音数字(PCM)
pcmBuffer 的角色装出去的仓库收回来的仓库
会出什么错猜错字做砸生僻字/多音字

注意:全程没有人"念"了这句话。云端不理解句意,它照字面把声音做出来。


4. 喇叭只认数字:喂饭比喻

喇叭是个只认数字的婴儿:喂它数字,它就振动;给它文字,它不张嘴——它不认识字。所以板子要把云端寄回的声音数字一勺一勺喂给它,每次一小块、速度要稳,声音才不抖。

喇叭只认数字:一勺一勺喂,字里没藏声音

云端是照字面做菜的大厨:递字条、收回声音数字。它不理解菜谱(句意),只照字面做。

⚠️ 比喻的边界:字里面没有藏着声音。你没法从"床"这个字里解压出一段声音——文字和声音数字是两种东西,中间隔着云端的"制作"。 想通了这一点,两个现象就通了:

  • 为什么必须联网? 声音要云端现做,本地没得解压。
  • 为什么同一句话每次念得几乎一样? 大厨每次用同一套做法,不是放同一盘录音。

5. 动手做实验

实验一:五种声音(demo02)

烧录 demo02_voice_knob。固定念"床前明月光,疑是地上霜",拧旋钮,每次先预测再听:

三个旋钮:发音人、语速、音调

✏️ 可以直接在表格里填写
旋钮组合预测(和上一行比哪里变)实测听感实测字节
女声 · 正常 · 正常
男声 · 正常 · 正常
女声 · 快 · 正常
女声 · 慢 · 正常
女声 · 正常 · 高

盯住第三、四行的字节:同一句 12 个字,念得快,字节数明显变少。念得快 = 声音短 = 字节少——上一课的账,这里用上了。

实验二:让它念没见过的话

把 demo01 的预置句子改成你自己编的怪话(比如带生僻字的),重新烧录再点。念出来了?跳过了?念成别的音?把现象记下来。如果喇叭里预先藏了句子,它不可能"没见过"。

实验三:拔掉 WiFi(拆台实验)

板子有电、有喇叭、句子就在屏幕上——断掉 WiFi,点句子。

✏️ 可以直接在表格里填写
观察推测
屏幕出现什么?喇叭响了吗?
为什么不响?

做完把网连回去(不然 demo03 也做不了)。


6. 想自己看懂一点点代码:两个名字就够

打开 demo01_tts_player.ino(或问 AI 帮手),只看两个名字:

  • textToSpeech:寄字换声音的那一棒。誊写文字 → 连同三个旋钮寄给百度 → 收回声音数字交给仓库。
  • pcmBuffer:声音数字的家。上一课装出去换文字,这一课收回来喂喇叭——同一个仓库,一课出一课进。

中文伪代码(不用背):

点一下句子:
    数一数有几个字
    textToSpeech():
        文字誊写成安全字符(urlEncode)
        连同 per 发音人 / spd 语速 / pit 音调 寄给百度
        收到声音数字,存进 pcmBuffer
    playPcm():
        一勺一勺写进喇叭(每秒 16000 个)
        喂完多等一小会,让喇叭咽下最后一口
    屏幕报告:字数 声音B 合成ms 播放ms

7. 把两课连起来:会说话的便签(demo03)

烧录 demo03_talking_notes。点底部按钮说 1~3 秒,你的话变成文字便签(24 课);点任意一条便签,板子把它念出来(25 课)。

试一试:录一句"下课去打球",然后点它——你说的和它念的,走的是同一个云端、两个相反的方向。这就是第 28 课语音助手的雏形:听懂你 → 想一想 → 说出来。

💡 demo03 里便签还是存在内存里,断电就丢。想不丢?把文字写进 TF 卡(第 10/14 课学过),这就是挑战任务第三题。


8. 换个思路:把"念"搬进板子(demo04 本地 TTS)

前面几节都在讲"念在云端"。现在反着来:把大厨请进板子。

烧录 demo04_zh_local_tts——它不需要 WiFi、不需要密钥,根本不联网。触摸屏幕,板子开口了;再拔一次网线试试:照样说话。

观察demo01 云端(刚才)demo04 本地(现在)
需要联网吗必须不需要
需要密钥吗要不要
拔掉 WiFi 点句子不响照样念
声音更自然略机械但清楚

为什么它不用网? 因为"合成"这一步就发生在板子自己身上:文字 → 板子里的"小嗓门"(ESP-TTS 引擎 + 烧在 flash 里的音色模型)→ 现场做出声音 → 喂喇叭。没有寄出、没有寄回,接力少了两棒。

本地 TTS 和云端 TTS 的对比:同样的"合成",一个在云端、一个在板子

云端 vs 本地:一张表说清

云端 TTS(demo01)本地 TTS(demo04)
合成在哪百度云端板子本地
需要什么WiFi + 百度 Key什么都不需要
声音质量更自然、音色多(女/男声)略机械,内置小乐/小新等 4 个音色
升级换代云端升级,板子跟着变好板子出厂什么样就什么样
成本要密钥、要流量零成本、零依赖
一句话板子 = 快递员 + 喇叭板子自己就是大厨

⚠️ 但喇叭还是那个只认数字的婴儿:本地 TTS 同样要把声音数字一勺一勺喂给它。变的只是"声音从哪来"——一个在云端做、一个在板子做,做出来的都是同一串 PCM 数字。

实验四:串口说怪话

demo04 支持从电脑串口(115200)发一行中文,板子立刻念出来。试试:

  1. 让它念你的名字;
  2. 念一句"床前明月光"——和 demo02 云端念的比一比,哪个更像真人?
  3. 念一个生僻字——对比实验二的"云端大厨翻车",本地小嗓门也会翻车吗?

结论:云端 TTS 和本地 TTS 都会"做声音",只是大厨住址不同。选谁?要音质、要换音色 → 云端;要离线、要零成本、要隐私 → 本地。真实产品里两个常常搭配用。


9. 选读:为什么不要 MP3?

有人会问:手机里存的不都是 MP3 吗?为什么这课不用?

MP3 是压缩格式——把声音压小了省空间,但喇叭不认,必须先"解压"回原始数字才能播。解压要专门的解码库、要更多内存,对我们这块小板子是一笔大开支。

这课我们让云端直接寄回 PCM(喇叭认的原始数字),收来就能喂。代价是数据大:念 1 分钟的声音约 1.9MB。所以适合"念一句话",不适合"存一整首歌"。

一句话总结:MP3 省地方但要解压,PCM 占地方但开袋即食。 我们念的是短句,选开袋即食。


10. 自检小测(点开对答案)

1. 收回 59200 字节的声音,大约念多久?怎么算的?约 1.85 秒。喇叭每秒吃 16000 个数字 × 2 字节 = 每秒 32000 字节,59200 ÷ 32000 ≈ 1.85。
2. 文字变声音的三步里,哪步在云端?第 2 步"合成":云端把文字做成声音数字。第 1 步誊写寄出和第 3 步喂喇叭都在板子上。
3. 拔掉 WiFi 点句子,为什么不响?这说明了什么?字条寄不出去,云端没做成声音。说明"念"发生在云端,板子只是快递员+喇叭;字里面没有藏着声音,本地没得解压。
4. pcmBuffer 在 24 课和 25 课里各干什么?24 课:装出去的仓库——你的声音数字从这里寄出去换文字。25 课:收回来的仓库——云端寄回的声音数字住在这里,等着喂给喇叭。方向相反,同一个仓库。
5. textToSpeech 寄出去的是什么?捎带了哪三个旋钮?寄出去的是誊写过的文字;捎带 per(发音人:女声/男声)、spd(语速:慢/正常/快)、pit(音调:低/正常/高)。
6. 同一句话,为什么"快"档收回的字节数明显少?念得快 = 声音更短 = 数字更少。字节就是声音的长度。
7. 生僻字念不出来,是板子坏了吗?不是。云端大厨没学过这个字,做不出来。换常用字能正常念,就说明链路是好的。
8. demo04 本地 TTS 和 demo01 云端 TTS,最大的区别是什么?合成发生在哪。demo01 在百度云端做声音(要联网+密钥);demo04 在板子本地做声音(ESP-TTS 引擎 + flash 里的音色模型),不需要任何网络和密钥。
9. 拔掉网线,demo01 和 demo04 分别会怎样?为什么?demo01 哑了——字条寄不出去,云端做不了声音。demo04 照样念——合成在板子自己身上,跟网络没关系。这正是"本地 AI vs 云端 AI"的分水岭。
10. 本地 TTS 也是把声音一勺一勺喂给喇叭吗?是。喇叭永远只认 PCM 数字,不管声音是云端做的还是本地做的,都得一勺一勺喂。变的只是"声音从哪来"。

11. 挑战任务

  1. 字节预言家:在 demo01 里挑两句长度不同的句子,先在纸上算出它们各收回多少字节(提示:先估念的秒数 × 32000),再点开对照,看误差多大。
  2. 错误收藏家:故意找 3 句会让大厨"翻车"的话(生僻字 / 多音字 / 中英夹杂),把每句的翻车现象记下来,并归因。再拿同样的 3 句喂 demo04,比较"云端大厨"和"本地小嗓门"谁翻车翻得更有意思。
  3. 断电不丢的便签:给 demo03 想一个办法,让便签重启后还在(提示:第 10/14 课 TF 卡),把思路写给 AI 帮手看。
  4. 离线版语音助手(挑战):把 demo04 的"串口说话"接到第 23 课的本地大模型回答上——不联网,板子"听懂→想一想→说出来"全本地完成。这才是真·离线 AI。
第 25 课 · 点哪句念哪句

第 25 课 · 点哪句念哪句

屏幕上列着几句话,手指点哪一句,板子就把哪一句念出来。

25语音合成TTS云端
第 25 课 · 声音旋钮

第 25 课 · 声音旋钮

同一句话,改一改发音人、语速和音调,念出来的声音就不一样。

25语音合成发音人语速
第 25 课 · 会说话的便签

第 25 课 · 会说话的便签

先说话,云端把它听写成文字存进便签;再点便签,板子就把那句话念出来。

25语音合成语音识别便签
第 25 课 · 拔了网线也会说话

第 25 课 · 拔了网线也会说话

不联网、不连云端,板子自己把文字合成中文声音念出来。

25本地TTS离线中文语音