本文基于 WinFX 的预发布版本。文中包含的所有信息均有可能变更。
本文讨论:
| 本文使用下列技术: |
![*](http://img.microsoft.com/library/gallery/templates/MNP2.Common/images/3squares.gif)
本页内容
![]() | 语音的元素 |
![]() | 与 Windows Vista 交流 |
![]() | Windows Vista 语音API |
![]() | System.Speech.Synthesis |
![]() | System.Speech.Recognition |
![]() | 电话应用程序 |
![]() | 小结 |
Microsoft 研究和开发语音技术已经十年有余了。1993 年,它雇佣了 Xuedong (XD) Huang、Fil Alleva 和 Mei-Yuh Hwang — 他们是负责 Carnegie Mellon University Sphinx-II 语音识别系统的四个人中的三个,该系统因其空前的准确性于 1992 年即受到语音界的广泛赞誉。正是从那时开始,随着 Speech API (SAPI) 1.0 小组在 1994 年成立,Microsoft 志在创建一种允许开发人员通过强大的 API 访问的准确的语音技术。该小组在不断成长,在过去的这些年中,他们已经发布了一系列功能日益强大的语音平台。
近些年来,Microsoft 越来越注重将语音技术投入于主流使用,从而促生了一些产品,例如,Speech Server(用于实现启用语音的电话系统)和 Voice Command(使用户能够使用语音命令控制 Windows Mobile® 设备)。因此可想而知,Microsoft 的语音小组在 Windows Vista® 的开发中一定是始终忙个不停。将强大的语音技术与强大的 API 联合起来,这一策略始终是正确的,直到 Windows Vista 都是如此。
Windows Vista 包含一个内置的语音识别用户界面,专门针对需要控制 Windows® 并在不使用键盘或鼠标的情况下输入文本的用户而设计。其中还有一个先进的通用语音识别引擎。该引擎不仅极其准确,而且还可以在很多语言中使用。Windows Vista 也包括 Microsoft 的首批新一代语音合成器,它们已经被完全重写以便利用最新的技术。
对于开发人员而言,Windows Vista 包含了一个新的 WinFX® 命名空间 — System.Speech。这使开发人员能够轻松地为 Windows 窗体应用程序和基于 Windows Presentation Framework 的应用程序启用语音功能。此外,它还包含一个最新的 COM Speech API (SAPI 5.3),以便提供对平台增强语音功能的本机代码访问。有关更多信息,请参阅提要栏“SAPI 5.3 的新功能”。
语音的元素
语音技术的概念实际包括两个技术:合成器和识别器(参见图 1)。语音合成器将文本作为输入,并产生音频流作为输出。语音合成也称为“文本到语音”(text-to-speech,TTS)。另一方面,语音识别器的行为刚好相反。它将音频流作为输入,并将其转换为文本副本。
对于合成器而言,将一串字符转换为听起来符合规范的音频流需要做大量工作。想象其工作方式的最简单的方法是分析一个两部分系统的前端和后端。
前端负责使用自然的语言规则分析文本。它分析一串字符以分辨有哪些单词(对于英语而言很容易,但对于汉语和日语而言则没那么容易)。前端也可以分辨诸如语音功能和组成部分的详细信息 — 例如,哪些单词是正确的名词、数字等;哪里是语句的开头和结尾;一个短语是疑问句还是陈述句;陈述句是过去时、现在时,还是将来时。
所有这些元素对于选择单词、短语和语句的适当发音和语调而言是很关键的。例如在英语中,疑问句通常以声调结尾,对于单词“read”而言,它的发音会因其时态的不同而差异很大。很明显,了解单词或短语的使用环境对于将文本转换为声音相当重要。具体而言,这些规则对于每种语言而言也稍有不同。因此可想而知,前端必须进行一些非常复杂的分析。
而后端有完全不同的任务。它通过自身的一些重要分析,获取前端的分析,从而生成输入文本的适当声音。旧式合成器(以及当今具有最少足迹的合成器)以算法方式生成单独的声音,从而产生一个非常机器人化的声音。现代的合成器(例如,Windows Vista 中的合成器)使用一个声音片段数据库,这些片段来自于大量的录音。后端的有效性依赖于它针对给定的输入选择适当的声音片段并将它们流畅地结合在一起的能力。
这听起来是不是很复杂?没错,就是这样。具有内置于操作系统中的这些文本到语音功能是非常有利的,因为它允许应用程序使用该技术。您无需创建自己的语音引擎。正如您稍后将在本文中看到的一样,您可以使用单个函数调用来调用整个处理过程。您很幸运!
语音识别甚至比语音合成更复杂。然而,也可以认为其具有一个前端和一个后端。前端处理音频流,从而分隔可能发声的声音片段,并将它们转换成一系列能够在信号中表示元音的数值。后端是一个专用的搜索引擎,它获取前端产生的输出并跨以下三个数据库进行搜索:一个发音模型、一个词典和一个语言模型。发音模型表示一种语言的发音声音,可通过训练来识别某个特定用户的语音模式和发音环境的特征。词典列出该语言的大量单词,以及关于每个单词如何发音的信息。语言模型表示一种语言的单词如何合并。
这两种模型都很重要。准确指定什么语音听起来相似是不可能的。而且,人类的语音很少遵循可以轻松定义的严格且正规的语法规则。生成好模型的一个必要因素是获得大量可表示的数据。另一个同等重要的因素是用于分析该数据以生成实际模型的技术的复杂性。
当然,同一个单词不会存在两次发音完全相同的情况,因此识别器也无法找到一个准确的匹配。而且对于给定的声音片段,说话者的言语中可能包含了很多潜在含意。因此,识别器的质量取决于它提炼搜索、排除不适当匹配以及选择更类似匹配的能力。识别器的准确性依赖于它是否具有优秀的语言和发音模型,以及用于处理声音和跨模型搜索的算法。模型和算法越好,错误就越少,而且找到结果也越快。无庸置疑,这是一项非常困难的技术。
虽然识别器的内置语言模型旨在表示一个广泛的语言域(例如,英文日常用语),但是任何给定的应用程序通常有非常具体的语言模型要求。特定的应用程序通常只需要某些对它而言具有特定语义的说话方式。因此,除了使用通用语言模型外,应用程序还应该使用一种语法来限制识别器只收听应用程序关注的语音。这有很多好处:增加了识别的准确性,确保了所有识别结果对应用程序有意义,而且使识别引擎能够指定在识别文本中固有的语义值。图 2 显示关于这些优势如何实际投入使用的一个示例。
![](https://i-blog.csdnimg.cn/blog_migrate/92d7a914ec0eb19bf2bfb8a5114540dc.png)
图 2 使用针对应用程序输入的语音识别
与 Windows Vista 交流
准确性只是一部分因素。使用 Windows Vista 语音识别技术,Microsoft 旨在提供一个端到端的语音体验,从而提供用户在内置桌面语音识别体验中需要的关键功能。其中包括一个交互式指南,它解释如何使用语音识别技术,并帮助用户训练系统以理解用户的语音。
该系统包括用于控制 Windows 的内置命令 — 允许您使用诸如“Start Notepad”和“Switch to Calculator”这样的命令启动、切换和关闭应用程序。用户可以通过开口说出诸如“File”和“Open”的命令来控制屏幕上的界面元素(例如,菜单和按钮)。该系统也通过提供诸如“Press shift control left arrow 3 times”这样的命令,支持模拟鼠标和键盘。
Windows Vista 语音技术包括内置听写功能(用于将用户的声音转换成文本)和编辑控制(用于在文档中插入、更正和操作文本)。您可以通过重述、选择替代文字或拼写来更正未正确识别的单词。例如,“将 Robot 更正为 Robert”。或者“拼写 rabbit 中的 R、O、B、E、R,telephone 中的 T。”。您也可以说出命令来选择文本、在文档中导航并进行编辑 — 例如,“Select 'My name is'”、“Go after Robert”或“Capitalize Brown”。
该用户界面的设计并不显眼,然而仍然能使用户随时控制语音系统(请参见图 3)。您可以轻松地访问麦克风状态,它包含一个休眠模式。文本反馈通知用户该系统正在做什么,并为用户提供指令。也有一个用于阐明用户说话内容的用户界面 — 当用户说出一个能够以多种方式解释的命令时,系统使用该界面澄清真正的含义。同时,持续的使用允许基础模型采用不断提升的准确性。
![](https://i-blog.csdnimg.cn/blog_migrate/951c89111b580f3d5579da7fdc06f87c.png)
图 3 Windows Vista 中的语音 UI
要启用内置语音功能,从 Start Menu 中选择 All Programs | Accessories | Accessibility,并单击 Speech Recognition。当您第一次进行此操作时,系统会带您浏览该指南,其中有对一些基本命令的介绍。您也可以选择启用后台语言模型适配,这样,系统将在后台通读文档的电子邮件,以便采用与您的表达方式最匹配的语言模型。默认设置可以启用很多功能。建议您询问系统“what can I say”,然后浏览主题。
但您是开发人员,那么您为什么如此关注所有这些用户体验内容呢?它之所以与开发人员相关,原因在于它是操作系统提供的默认功能。它是应用程序自动获取的功能。该语音技术使用 Windows 可访问性界面显示每个应用程序的功能;然后它为每个应用程序提供一个能说话的 UI。如果用户说出一个可访问元素的名称,则该系统将调用该元素的默认函数。因此,如果您已经生成了一个可访问的应用程序,则默认情况下,您已经生成了一个可以启用语音的应用程序。
Windows Vista 语音API
Windows Vista 可以为任何可访问的应用程序启用语音。如果您希望用户通过简单的语音命令控制您的应用程序,这显然是不可能的。但您可能希望提供一个这样启用语音的用户界面,它比 Windows Vista 自动提供的启用语音的 UI 更复杂、更适用。
有很多示例说明为什么需要进行这样的操作。例如,如果用户的工作需要她始终动手操作。每次她使用鼠标或敲击键盘时都必须把手从工作中移开 — 这可能降低了安全性或者降低了工作效率。对于那些需要用眼睛盯着某物而非计算机屏幕的用户而言,情况也是如此。或者,比如说您的应用程序有大量在工具栏菜单中没有列出来的功能。语音命令可以展开深层菜单结构,从而提供对大量命令的快速访问。如果您的用户说过“说的确比做容易”,那他们可能说对了。
在 Windows Vista 中,有两个语音 API:
• | 用于本机应用程序的 SAPI 5.3 |
• | WinFX 中的 System.Speech.Recognition 和 System.Speech.Synthesis 命名空间 |
图 4 阐释每个 API 如何与应用程序以及基础的识别和合成引擎相关。
![](https://i-blog.csdnimg.cn/blog_migrate/dfa3d8a1ce7912a15b177d060ddaa52b.png)
图 4 Windows Vista 中的语音 API
该语音识别引擎可以通过 SAPI 访问。System.Speech.Recognition 命名空间中的类甚至包装 SAPI 公开的功能。(这是一个在将来版本中可能更改的 Windows Vista 的实现细节,但是它值得关注。)另一方面,语音合成引擎可以通过 System.Speech.Synthesis 中的类直接访问,在非托管应用程序中也可以通过 SAPI 访问。
这两种类型都实现 SAPI 设备驱动程序接口 (DDI),它是一个使引擎对于其上的层可互换的 API,非常类似于设备驱动程序 API 使硬件设备对于使用它们的软件而言可互换的方式。这意味着,使用 SAPI 或 System.Speech 的开发人员仍然可以自由地使用实现 SAPI DDI 的其他引擎(很多人确实是这样做的)。
请注意,在图 4 中,合成引擎始终用与应用程序一样的进程实例化,但是该识别引擎也可以用另一个称为 SAPISVR.EXE 的进程实例化。这提供了一个可由多个应用程序同时使用的共享识别引擎。该设计有很多好处。首先,识别器通常需要比合成器多得多的运行时资源,而且共享识别器是一个减少开销的最有效的方式。其次,共享识别器也可以由 Windows Vista 的内置语音功能使用。因此,使用共享识别器的应用程序也可以从系统的麦克风和反馈 UI 中获益。用户无需编写其他代码,也无需学习新 UI。
System.Speech.Synthesis
让我们看一下关于如何从托管应用程序使用语音合成的示例。作为最典型的一个 UI 输出示例,我将从只说出“Hello, world”的应用程序开始,如图 5 所示。该示例是一个明显的控制台应用程序,是最近使用 Visual C#® 创建的,其中添加了三行代码。所添加的第一行只引入 System.Speech.Synthesis 命名空间。第二行声明并实例化 SpeechSynthesizer 的实例,它准确表示了其名称的含意:语音合成器。所添加的第三行是对 SpeakText 的调用。这是调用合成器所需的全部。
默认情况下,SpeechSynthesizer 类使用 Speech 控件面板中默认推荐的合成器。但是它可以使用任何与 SAPI DDI 兼容的合成器。
下一个示例(请参见图 6)显示如何进行此操作,该操作使用 Windows 2000 和 Windows XP 的旧式 Sam 语音,以及新 Anna 和 Windows Vista 的 Microsoft® Lili 语音。(请注意,该示例以及其他所有 System.Speech.Synthesis 示例都使用和第一个示例相同的代码框架,并替换 Main 的主体。)该示例显示了使用所需合成器名称的 SelectVoice 方法的三个实例。它还演示了 Windows Vista Chinese 合成器(即 Lili)的用法。另外,Lili 也可以很好地说英语。
在这两个示例中,我使用合成 API 的方式非常类似于我使用控制台 API 的方式:应用程序只发送字符,然后这些字符立即串联呈现。但是对于更复杂的输出,更容易将合成看作文档呈现的等价物,其中合成器的输入是一个文档,该文档不仅包含要呈现的内容,还包括要在该内容的特定点应用的不同效果和设置。
SpeechSynthesizer 类可以使用名为语音合成标记语言(Speech Synthesis Markup Language,SSML)的 XML 文档格式,这非常类似于描述要应用到 Web 页特定内容片段中的呈现风格和结构的 XHTML 文档。W3C SSML 推荐 (www.w3.org/TR/speech-synthesis) 非常具有可读性,因此在本文中,我不打算深入描述SSML。可以肯定地说,应用程序可以简单地将 SSML 文档直接加载到合成器并使之呈现出来。以下是一个加载并呈现 SSML 文件的示例:
SpeechSynthesizer synth = new SpeechSynthesizer(); PromptBuilder savedPrompt = new PromptBuilder(); savedPrompt.AppendSsml("c://prompt.ssml"); synth.Speak(SavedPrompt);
编写 SSML 文件的另一个简便方法是在 System.Speech.Synthesis 中使用 PromptBuilder 类。PromptBuilder 几乎可以表示 SSML 文档可以表示的任何内容,而且更容易使用(请参见图 7)。用于创建复杂合成的通用模型首先使用 PromptBuilder 以您希望的方式生成提示符,然后使用合成器的 Speak 或 SpeakAsync 方法呈现它。
图 7 阐释 PromptBuilder 的大量强大功能。需要指出的首要一点是,它生成一个带有分层结构的文档。该示例使用的说话风格嵌套在另一个中。在该文档的开头,我使用了将在整个文档中使用的风格。然后在文档进行到一半的时候,我使用了另一种风格以示重点。当我结束这种风格时,文档又自动转换为以前的风格。
该示例也显示了其他很多方便的功能。AppendAudio 功能使 WAV 文件与输出结合,如果未找到 WAV 文件,可以使用一个等效文本文件。AppendTextWithPronunciation 功能允许您指定单词的正确发音。通过联合使用用于推导出未知单词发音的词典和算法,语音合成引擎已经知道如何对一种语言中的多数常用单词进行发音。但这并不对所有单词都奏效,例如,某些专用术语或商标名称。例如,“WinFX”将可能发音为“winfeks”。相反,我使用 International Phonetic Alphabet 将“WinFX”描述为“w?n?f?ks”,其中字母“?”是 Unicode 字符 0x026A(“i”的发音同“fish”中的“i”,不同于“five”中的“i”),而字母“?”是 Unicode character 0x025B(通用美语中“e”的发音同“bed”中的“e”)。
通常,合成引擎可以区分缩写和大写单词。但偶尔有些时候,您会发现一个缩写词由引擎的试探法错误地演绎为一个单词。因此,您可以使用 AppendTextWithHint 功能为缩写词作标记。对于 PromptBuilder 而言有很多细微差别。我的示例虽然不太全面,但非常具有说明性。
将内容规范从运行时呈现中分离出来的另一个好处是,之后您可以随意将应用程序从它呈现的特定内容分离出来。您可以利用 PromptBuilder 使其提示符作为 SSML 由该应用程序的另一部分或一个完全不同的应用程序加载。以下代码使用 PromptBuilder 写入一个 SSML 文件:
using(StreamWriter promptWriter = new StreamWriter("c://prompt.ssml")) { promptWriter.Write(myPrompt.ToXml()); }
分离内容片段的另一个方法是将整个提示符呈现给一个音频文件以用于稍后重播:
SpeechSynthesizer synth = new SpeechSynthesizer(); synth.SetOutputToWaveFile("c://message.wav"); synth.Speak(myPrompt); synth.SetOutputToNull();
使用 SSML 标记还是使用 PromptBuilder 类,可能取决于您偏好的风格。您应该使用自己觉得更舒服的那个。
对于 SSML 和 PromptBuilder,需要注意的最后一点是,每个合成器的功能将稍有不同。因此,对于使用这两种机制中的任一种请求的特定行为,如果该引擎有能力采取该行为,则应该将这些行为认为是该引擎将采用的建议性请求。
System.Speech.Recognition
虽然您可以在应用程序中使用通用听写语言模型,但是很快您将遇到大量应用程序开发困难,它们是关于如何处理识别结果的。例如,以比萨饼定购系统为例。用户可能说“I'd like a pepperoni pizza”,结果将包含该字符串。但是它也可能包含“I'd like pepper on a plaza”,或者很多发音类似的语句,这取决于用户的发音差别或背景噪音情况。同样,用户可能说“Mary had a little lamb”,而结果将包含它,即使它对于比萨饼定购系统毫无意义。所有这些错误的结果对于应用程序而言毫无用处。因此,应用程序应该始终提供专门描述应用程序所要听到内容的语法。
在图 8 中,我使用了一个普通的 Windows 窗体应用程序,并添加了若干行代码以实现基本的语音识别。首先,我引入 System.Speech.Recognition 命名空间,然后实例化一个 SpeechRecognizer 对象。然后,我在 Form1_Load 中执行三个操作:生成一个语法,将一个事件处理程序附加到该语法,以便从该语法接收 SpeechRecognized 事件,然后将该语法加载到识别器。此时,识别器将开始听取符合该语法定义的模式的语音。当它识别出符合该语法的内容时,将调用该语法的 SpeechRecognized 事件处理程序。该事件处理程序本身访问 Result 对象并使用识别的文本。
System.Speech.Recognition API 支持 W3C 语音识别语法规范 (SRGS) — 位于 www.w3.org/TR/speech-grammar。该 API 甚至提供一组用于创建和使用 SRGS XML 文档的类。但多数情况下,使用 SRGS 有些过了,因此 API 也提供了 GrammarBuilder 类,它能够很好地满足比萨饼定购系统的需要。
GrammarBuilder 允许您从一组短语和选项中组成语法。在图 8中,我已经排除了不关注的问题(“Mary had a little lamb”),并对引擎进行了限制,以便它可以在模糊的声音之间进行更好的选择。当用户将“pizza”错误发音为“plaza”时,它甚至不会考虑单词“plaza”。因此通过这几行代码,我已经极大地增强了该系统的准确性。但是,该语法仍然存在一些问题。
详尽列出用户可能说的话语的方法很单调、易于出错且难于维护,而且实际上只能对很少的语法实现这一点。比较可取的做法是定义一个能够定义单词组合方式的语法。此外,如果应用程序关注比萨饼的尺寸、陷料和类型,开发人员还需大量的工作来分析结果字符串中的这些值。如果该识别系统可以在结果中识别这些语义属性,就会方便得多。使用 System.Speech.Recognition 和 Windows Vista 识别引擎会使该操作非常容易。
图 9 显示在用户从备选列表中说出一些内容时,如何使用 Choices 类组成语法。在该代码中,每个 Choices 实例的内容在构造函数中作为一个字符串参数序列指定。但是您有其他很多用于填充 Choices 的选项:您可以迭代添加新短语,从一个数组构造 Choices,将 Choices 添加到 Choices 以生成用户能够理解的复杂组合规则,或者将 GrammarBuilder 实例添加到 Choices 以生成更为灵活的语法(如本示例的 Permutations 部分中演示的那样)。
图 9还显示如何使用语义值标记结果。当使用 GrammarBuilder 时,您可以将 Choices 附加到该语法,并将一个语义值附加到该选项,如以下语句示例所示:
AppendChoices(toppings, "topping");
有时一个特定的话语将具有从未公开的隐含语义值。例如,如果用户不指定比萨饼的尺寸,该语法可以将尺寸指定为“常规”,如以下语句所示:
AppendResultKeyValue("size", "regular");
从结果中获取语义值是通过访问 RecognitionEventArgs.Result.Semantics[] 来完成的。
电话应用程序
本文只介绍了 Windows Vista 中包含的新语音技术的功能。有关更多内容,请参阅以下资源:
• | |
• | |
• | |
• | Microsoft 语音新闻组:microsoft.public.speech_tech 和microsoft.public.speech_tech.sdk |
Microsoft 语音小组的以下成员撰写了很多有用的网络日记:
• | |
• | |
• | |
• | |
• | |
• |
语音应用程序的最大增长区域之一是启用语音的电话系统。这些原则中有很多和桌面语音相同:识别和合成仍然是关键技术,而且优秀的语法和提示设计也是关键的。
对于这些应用程序的开发而言,还有很多其他必要因素。电话应用程序需要完全不同的声音模型。它需要与电话系统交互,而且由于没有 GUI,因此它需要管理用户的对话。电话应用程序也需要具有可伸缩性,以便可以服务于尽可能多的并发呼叫而不会影响性能。
设计、调整、部署和宿主启用语音的电话应用程序并不是一个小项目,为此已经开发了 Microsoft Speech Server 平台和 SDK。有关 Microsoft Speech Server 的更多信息,请访问 Speech Server Web 站点。
小结
Windows Vista 包含一个新的、更加强大的桌面语音平台,它内置在 OS 中。直观的 UI 和功能强大的 API 使最终用户和开发人员可以更轻松地使用该技术。如果您有最新的 Beta 版 Windows Vista,您就可以立即尝试这些新功能。
Windows Vista 语音识别 Web站点在您阅读本文时应该是可访问的。有关 Microsoft 语音技术其他信息资源的链接,请参见提要栏中的“资源”。
Robert Brown 是 Microsoft Speech & Natural Language 小组的一位高级程序经理。Robert 在 1995 年加入 Microsoft,他已经研究了 VOIP 和消息处理技术、Speech Server 和 Windows Vista 中的语音平台。特别鸣谢 Robert Stumberger、Rob Chambers 和 Microsoft 语音小组的其他成员对本文做出的贡献。