1. 文档中心
  2. 比卜创造 Micro:bit
  3. Python
  4. 语音

语音

会说话的电脑和机器人,总让人觉得更「像人」。

我们往往通过图形界面(GUI)了解电脑在做什么。对 micro:bit 来说,GUI 就是 5×5 LED 矩阵——信息容量有限。

让 micro:bit 开口说话,是一种有趣、高效又有用的表达方式。为此,我们集成了基于 20 世纪 80 年代一款语音合成器逆向工程的简易合成器。音色很「萌」,带着一点「人类必须灭亡」的科幻味。

DALEK 诗会

DALEK
DALEK

有个冷知识:DALEK 酷爱诗歌,尤其是五行打油诗(limerick)。它们对严格 AABBA 格式的抑扬格简直疯狂。(其实下文会讲,是博士让 DALEK 迷上打油诗的,Davros 对此很恼火。)

总之,我们要做一个按需朗诵的 DALEK 诗会。

说点什么

micro:bit 自带扬声器,可以直接出声;也可以像下面这样外接蜂鸣器或耳机到 P0 和 GND:

蜂鸣器接 P0 与 GND
蜂鸣器接 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)