语音

警告

注意!这只是字母编码(ALPHA CODE)。 随着开发的不断进行,我们保留更改此API的权利。 语音的质量不够好,只能说“差强人意”。 鉴于设备的限制,播放过程中可能会遇到内存错误和(或)意外的杂音。 现在是开发初期,我们一直在改进语音合成器的代码。欢迎大家提交错误报告和代码合并请求(pull requests)。

只要将扬声器连接到你的主板上,这个模块便能使microbit谈话、唱歌,并发出类似声音一样的其他语音,如下所示:

_images/speech.png

注解

这项工作源于Sebastian Macke令人惊叹的逆向工程的努力,于1982年最初为Commodore 64创建,基于旧文本到语音(TTS)转换程序的语音合成软件。最终移植成了C,并为micro:bit所采用。 你可以从它的 主页 中找到更多。本文档中的大部分信息是从可以获取的原始 用户手册 中收集而来。

语音合成器可以从最多255个字符的文本输入中产生大约2.5秒的声音。

要访问此模块需要:

import speech

假设你已经完成了以下示例。

函数

speech.translate(words)

给定字符串 words 中的英文单词,返回一个包含最佳猜测的字符串以适当的音素发音。 输出 由此产生 文本到音素转换表.

这个函数应用来生成音素的第一个近似值,可以进一步手动编辑,以提高准确性、调整音调以及重音。

speech.pronounce(phonemes, *, pitch=64, speed=72, mouth=128, throat=128)

在字符串 phonemes 中发音。 详阅下文了解如何使用音素来精确控制语音合成器的输出。 覆盖可选的音调、音速、嘴巴和喉咙开度来改变声音的音色(音质)。

speech.say(words, *, pitch=64, speed=72, mouth=128, throat=128)

在字符串 words 中说英文单词。 结果为半精确的英语。 覆盖可选的音调、音速、嘴巴和喉咙开度来改变声音的音色(音质)。 可简写为:speech.pronounce(speech.translate(words))

speech.sing(phonemes, *, pitch=64, speed=72, mouth=128, throat=128)

唱出包含在字符串 phonemes 中的音素。文中会描述音符的音调和持续时间的改变。 覆盖可选的音调、音速、嘴巴和喉咙开度来改变声音的音色(音质)。

标点

标点符号用于改变语音的传送。合成器了解四个标点符号:连字符、逗号、句号和问号。

连字符(-)通过在语音中插入短暂停顿来标记子句边界。

逗号()标记短语边界,插入的停顿大约为连字符的两倍。

句号(.)和问号()标记句子的结束。

句号插入中止,音调下降。

问号也会插入中止,但音调升高。 在表达是/否的问题时更为形象,例如“我们到家了吗? 而不是更复杂 诸如“我们为什么要回家?”等问题。 在后一种情况下,使用句号。

音色

声音的音色就是声音的质量。 例如可以据此区别DALEK的声音和人的声音。要控制 音色只需改变 pitchspeedmouththroat 参数数值设置即可。

音调(声音听起来的高低)和音速(语速传输的有多快)的设置是相当明显的,通常可以归为以下几类 类别:

Pitch: 音调

  • 0-20 不切实际的
  • 20-30 非常高的
  • 30-40 高的
  • 40-50 一般高的
  • 50-70 正常
  • 70-80 低于正常值
  • 80-90 低的
  • 90-255 非常低的

(默认值是64)

Speed:音速

  • 0-20 不切实际的
  • 20-40 非常快的
  • 40-60 快的
  • 60-70 相对快的
  • 70-75 正常的
  • 75-90 一般正常的
  • 90-100 慢的
  • 100-225 非常慢的

(默认值是72)

嘴和喉咙的开度值有些难以解释,以下描述是基于我们对随着每个设置值的改变而变化的语言的听觉印象。

对于嘴巴,数字越低,说话者听起来就越像没有动嘴巴说话。 相反,数字越高(最多255), 听起来就越像特别夸张的嘴巴动作发出的声音。

对于喉咙,数字越低,说话者听起来就越放松。 相反,数字越高,语调变得越紧张。

重要的是试验和调整设置,直到你得到想要的效果为止。

可以从下面例子开始:

speech.say("I am a little robot",  speed=92, pitch=60, throat=190, mouth=190)
speech.say("I am an elf", speed=72, pitch=64, throat=110, mouth=160)
speech.say("I am a news presenter", speed=82, pitch=72, throat=110, mouth=105)
speech.say("I am an old lady", speed=82, pitch=32, throat=145, mouth=145)
speech.say("I am E.T.", speed=100, pitch=64, throat=150, mouth=200)
speech.say("I am a DALEK - EXTERMINATE", speed=120, pitch=100, throat=100, mouth=200)

音素

say 函数可以很容易地产生语音 - 但通常不会准确。 要想确保语音合成器发出 *完全*你想要的音,必须使用音素:最小的感知不同声音的单位可以用来区分不同的声音 。 从本质上讲,它们是语音的构建块。

pronounce 函数需要一个包含简单可读的字符串 国际音标字母 和可选标注以指示变调和重音。

使用音素的优点是你不必知道如何拼写它!你只需要知道如何说出单词并用音素拼写它的发音。

下表列出了合成器所理解的音素。

注解

该表包含音素作为字符,以及一个示例词。该示例词具有音素的声音(括号内),但不 必是相同的字母。

往往容易忽略的是:”H” 音的符号是 /H。 声门停止是声音的强制停止。

SIMPLE VOWELS                          VOICED CONSONANTS
IY           f(ee)t                    R        (r)ed
IH           p(i)n                     L        a(ll)ow
EH           b(e)g                     W        a(w)ay
AE           S(a)m                     W        (wh)ale
AA           p(o)t                     Y        (y)ou
AH           b(u)dget                  M        (S)am
AO           t(al)k                    N        ma(n)
OH           c(o)ne                    NX       so(ng)
UH           b(oo)k                    B        (b)ad
UX           l(oo)t                    D        (d)og
ER           b(ir)d                    G        a(g)ain
AX           gall(o)n                  J        (j)u(dg)e
IX           dig(i)t                   Z        (z)oo
                                       ZH       plea(s)ure
DIPHTHONGS                             V        se(v)en
EY           m(a)de                    DH       (th)en
AY           h(igh)
OY           b(oy)
AW           h(ow)                     UNVOICED CONSONANTS
OW           sl(ow)                    S         (S)am
UW           cr(ew)                    SH        fi(sh)
                                       F         (f)ish
                                       TH        (th)in
SPECIAL PHONEMES                       P         (p)oke
UL           sett(le) (=AXL)           T         (t)alk
UM           astron(om)y (=AXM)        K         (c)ake
UN           functi(on) (=AXN)         CH        spee(ch)
Q            kitt-en (glottal stop)    /H        a(h)ead

下面的非标准标志对使用者同样适用:

YX           diphthong ending (weaker version of Y)
WX           diphthong ending (weaker version of W)
RX           R after a vowel (smooth version of R)
LX           L after a vowel (smooth version of L)
/X           H before a non-front vowel or consonant - as in (wh)o
DX           T as in pi(t)y (weaker version of T)

这里有几个很少使用的音素组合(和建议的选择):

PHONEME        YOU PROBABLY WANT:     UNLESS IT SPLITS SYLLABLES LIKE:
COMBINATION
GS             GZ e.g. ba(gs)         bu(gs)pray
BS             BZ e.g. slo(bz)        o(bsc)ene
DS             DZ e.g. su(ds)         Hu(ds)son
PZ             PS e.g. sla(ps)        -----
TZ             TS e.g. cur(ts)y       -----
KZ             KS e.g. fi(x)          -----
NG             NXG e.g. singing       i(ng)rate
NK             NXK e.g. bank          Su(nk)ist

如果你使用除上述音素以外的任何内容, ValueError 异常将会出现。以字符串传递音素如下:

speech.pronounce("/HEHLOW")  # "Hello"

音素分为两大组:元音和辅音。

元音被进一步细分为简单的元音和双元音。 简单的元音在说出时不会被改变声音,而双元音从一个 声音开始并以另一个结束。例如,当你说“oil”这个词时,“oi”元音以“oh”开始,但以“ee”声结束。

辅音也分为两组:浊音和清音。浊辅音要求说话者使用他们的声带发出声音。例如,辅音如“L”,“N”和“Z”是浊音。 清辅音是通过送气产生声音,如 “P”,“T”和“SH”。

一旦你习惯了它,音素系统其实很容易。 先从一些拼写可能看起来很棘手的开始(例如,“adventure”中有一个“CH”),但是 规则是写出你所说的话,而不是你拼写的内容。实验是解决问题单词的最好方式。

语音听起来自然且易于理解也很重要。为了提高口语输出的质量,通常使用内置重音系统来增加变调或重音。

数字 1 - 8 表示8个重音标记。只需在要加重音的元音后插入所需要的数值即可。例如, 轻音表达“/ HEHLOW”会在拼出“/ HEH3LOW”后有很大的改进(并且更友好)。

也可以通过改变重音方式来改变单词的含义。例如一句“我为什么要走到商店?,它可以 以几种不同的方式发音:

# You need a reason to do it.
speech.pronounce("WAY2 SHUH7D AY WAO5K TUX DHAH STOH5R.")
# You are reluctant to go.
speech.pronounce("WAY7 SHUH2D AY WAO7K TUX DHAH STOH5R.")
# You want someone else to do it.
speech.pronounce("WAY5 SHUH7D AY2 WAO7K TUX DHAH STOHR.")
# You'd rather drive.
speech.pronounce("WAY5 SHUHD AY7 WAO2K TUX7 DHAH STOHR.")
# You want to walk somewhere else.
speech.pronounce("WAY5 SHUHD AY WAO5K TUX DHAH STOH2OH7R.")

简而言之,语音中不同的重音会创造出更具表现力的语调。

根据所给出的数值,他们会提高或降低音调,并延长相关元音的声音来发音:

  1. 非常情绪化的重音
  2. 非常强调的重音
  3. 相当强调的重音
  4. 普通的重音
  5. 紧张的重音
  6. 中性 (没有音调变化) 的重音
  7. 音调降低的重音
  8. 音调极度降低的重音

数字越小,重音越强。但是,这样的重音标记将有助于正确发音。例如,如果 一个音节没有足够的发音,放入一个中性重音标记。

也可以用重音标记延长单词:

speech.pronounce("/HEH5EH4EH3EH2EH2EH3EH4EH5EHLP.”)

演唱

可以让MicroPython唱出音素。

这是通过在音素上注释与音调有关的数字来完成的。数字越低,音调越高。数字大致可以转译为音符, 如下图所示:

_images/speech-pitch.png

注释是在音素的前面预先加入一个散列( # )符号和音高数字。音调将保持不变直到给出新的注释, 例如,让MicroPython唱这样的音阶:

solfa = [
    "#115DOWWWWWW",   # Doh
    "#103REYYYYYY",   # Re
    "#94MIYYYYYY",    # Mi
    "#88FAOAOAOAOR",  # Fa
    "#78SOHWWWWW",    # Soh
    "#70LAOAOAOAOR",  # La
    "#62TIYYYYYY",    # Ti
    "#58DOWWWWWW",    # Doh
]
song = ''.join(solfa)
speech.sing(song, speed=100)

通过重复元音或浊辅音音素,以便在一定时间内唱出一个音符来(如上例所示)。注意双元音: 要扩展它们,你需要打破它们到其组成部分。例如,“OY”可以由“OHOHIYIYIY”扩展而来。

想要测算出需要重复一个音素多少次才能使音符持续想要的时间,只有反复试验,仔细倾听和不断调整,这才是唯一可行的方式。

工作原理

最初的手册对此作出了很好地解释:

首先,不是记录实际的语音波形,而是只存储实际的语音波形频谱。通过这样做,我们可以节省内存并选择其他优点。其次,我们存储一些关于计时的数据。这些是在不同情况下与每个音素持续时间不同的数字,还有一些关于过渡时间的数据,由此我们可以知道如何将音素混合到其邻近音素中。第三,我们设计了一套规则体系来处理所有这些数据,令我们惊讶的是,我们的电脑立刻喋喋不休。

—S.A.M. owner’s manual.

输出通过 audio 模块提供的功能进行传送, hey presto,我们有一个会说话的micro:bit。

示例

import speech
from microbit import sleep

# The say method attempts to convert English into phonemes.
speech.say("I can sing!")
sleep(1000)
speech.say("Listen to me!")
sleep(1000)

# Clearing the throat requires the use of phonemes. Changing
# the pitch and speed also helps create the right effect.
speech.pronounce("AEAE/HAEMM", pitch=200, speed=100)  # Ahem
sleep(1000)

# Singing requires a phoneme with an annotated pitch for each syllable.
solfa = [
    "#115DOWWWWWW",   # Doh
    "#103REYYYYYY",   # Re
    "#94MIYYYYYY",    # Mi
    "#88FAOAOAOAOR",  # Fa
    "#78SOHWWWWW",    # Soh
    "#70LAOAOAOAOR",  # La
    "#62TIYYYYYY",    # Ti
    "#58DOWWWWWW",    # Doh
]

# Sing the scale ascending in pitch.
song = ''.join(solfa)
speech.sing(song, speed=100)
# Reverse the list of syllables.
solfa.reverse()
song = ''.join(solfa)
# Sing the scale descending in pitch.
speech.sing(song, speed=100)