语音
会说话的电脑和机器人,总让人觉得更「像人」。
我们往往通过图形界面(GUI)了解电脑在做什么。对 micro:bit 来说,GUI 就是 5×5 LED 矩阵——信息容量有限。
让 micro:bit 开口说话,是一种有趣、高效又有用的表达方式。为此,我们集成了基于 20 世纪 80 年代一款语音合成器逆向工程的简易合成器。音色很「萌」,带着一点「人类必须灭亡」的科幻味。
DALEK 诗会

有个冷知识:DALEK 酷爱诗歌,尤其是五行打油诗(limerick)。它们对严格 AABBA 格式的抑扬格简直疯狂。(其实下文会讲,是博士让 DALEK 迷上打油诗的,Davros 对此很恼火。)
总之,我们要做一个按需朗诵的 DALEK 诗会。
说点什么
micro:bit 自带扬声器,可以直接出声;也可以像下面这样外接蜂鸣器或耳机到 P0 和 GND:

最简单的用法是导入 speech 模块,调用 say:
import speech
speech.say("Hello, World")
虽然可爱,但还不够 DALEK——需要调整合成器的参数。我们的合成器可以改四个量:
pitch— 音调高低(0 = 高,255 = 低)speed— 语速(0 = 快,255 = 慢)mouth— 嘴型松紧(0 = 闭,255 = 张大)throat— 声带松紧(0 = 紧,255 = 松)
合起来控制音色。要得到想要的效果,最好多试、多听、微调。
把参数作为 say 的参数传入即可。更多细节见 speech 模块 API 参考。
试下来,下面这组听起来挺像 DALEK:
speech.say("I am a DALEK - EXTERMINATE", speed=120, pitch=100, throat=100, mouth=200)
按需作诗
身为半机械生物,DALEK 用机器人能力写诗——算法用 Python 写,像这样:
# DALEK 诗歌生成器,作者:博士
import speech
import random
from bibo import sleep
# 从列表里随机选片段,填进模板
location = random.choice(["brent", "trent", "kent", "tashkent"])
action = random.choice(["wrapped up", "covered", "sang to", "played games with"])
obj = random.choice(["head", "hand", "dog", "foot"])
prop = random.choice(["in a tent", "with cement", "with some scent",
"that was bent"])
result = random.choice(["it ran off", "it glowed", "it blew up",
"it turned blue"])
attitude = random.choice(["in the park", "like a shark", "for a lark",
"with a bark"])
conclusion = random.choice(["where it went", "its intent", "why it went",
"what it meant"])
# 诗模板,{} 由上面片段填入
poem = [
"there was a young man from {}".format(location),
"who {} his {} {}".format(action, obj, prop),
"one night after dark",
"{} {}".format(result, attitude),
"and he never worked out {}".format(conclusion),
"EXTERMINATE",
]
# 逐行朗诵
for line in poem:
speech.say(line, speed=120, pitch=100, throat=100, mouth=200)
sleep(500)
设计很简单:
- 命名片段(
location、prop、attitude等)从预定义列表里用random.choice随机选一个。 - 诗模板是若干行,用
{}留「洞」,再用format填入片段。 - 循环每行,用 DALEK 音色的
speech.say朗诵;行间sleep(500)毫秒,连 DALEK 也要喘口气。
据说最初的诗程是 Davros 用 FORTRAN 写的(DALEK 语言嘛,全大写)。博士穿越到 Davros 单元测试刚通过、部署流水线还没启动的那一瞬间,把 BiBoPython 解释器塞进了 DALEK 操作系统——上面这段代码就像 Time Lord 留下的彩蛋。
音素
有时 say 不能把英文词准确转成发音。要精细控制,用音素——语言的积木音。
用音素的好处:不必会拼写,只要会读,就能用音标式写法拼出来。
合成器支持的音素列表见 speech API 参考。也可以把英文词传给 translate,它会返回近似音素串,再手工改重音、语调。
音素输出用 pronounce:
speech.pronounce("/HEH5EH4EH3EH2EH2EH3EH4EH5EHLP.")
你能改进博士的代码,让它用音素吗?
唱一首 micro:bit 之歌
改 pitch 并调用 sing,还能让设备「唱歌」(别指望拿欧洲电视网大奖)。
音高数字与音符的对应关系见下图:

sing 必须传入音素和音高:
speech.sing("#115DOWWWW")
音高用 # 加在音素前面;后续音素保持该音高,直到标注新音高。
下面示例演示 say、pronounce、sing 三种用法:
"""
speech.py
~~~~~~~~
让 micro:bit 说话、念音素、唱歌的简单示例。
可使用板载扬声器,或将蜂鸣器/耳机接到 P0 与 GND。
"""
import speech
from bibo import sleep
# say 尝试把英文转成音素
speech.say("I can sing!")
sleep(1000)
speech.say("Listen to me!")
sleep(1000)
# 清嗓子要用音素;改 pitch 和 speed 也有帮助
speech.pronounce("AEAE/HAEMM", pitch=200, speed=100) # 咳咳
sleep(1000)
# 唱歌:每个音节用带 # 音高的音素
solfa = [
"#115DOWWWWWW", # Do
"#103REYYYYYY", # Re
"#94MIYYYYYY", # Mi
"#88FAOAOAOAOR", # Fa
"#78SOHWWWWW", # So
"#70LAOAOAOAOR", # La
"#62TIYYYYYY", # Ti
"#58DOWWWWWW", # Do
]
# 上行音阶
song = ''.join(solfa)
speech.sing(song, speed=100)
# 反转,下行
solfa.reverse()
song = ''.join(solfa)
speech.sing(song, speed=100)