在 Windows Store 应用中处理文本转语音并生成音频文件





5.00/5 (4投票s)
在本帖中,您将学习如何在 Windows 运行时中为 Windows 应用商店应用执行文本转语音操作,以及如何将语音流以波形文件格式保存在您的计算机上。
引言和背景
我正在为我现有的 Windows 应用商店应用程序“Speak It!”添加一些新功能,在此过程中,随着我深入研究流,这项任务变得更加复杂。请记住,Windows 运行时提供的流不像 .NET 中的流那样简单。因此,在本帖中,我将讨论您可能会遇到的一些难题。本帖包含两个部分,第一部分将讨论 Windows 应用商店(抱歉,是通用 Windows 平台)中的“文本转语音” API,第二部分将讨论将生成的语音流保存到音频文件。
我已经在我的另一篇文章中分享了大部分概念,其中涵盖了构建文本转语音应用程序所需的基本概念、先决条件和其他基础知识。不幸的是,那篇文章是面向 .NET 的,而本文涵盖的是 Windows 运行时 API 集中的文本转语音 API 的概念。这篇文章可以在“An app that reads out text for you”处阅读,因为我没有将其作为博客在此处发布,抱歉。
那篇文章非常相似,因为适用于 Windows 应用商店的 .NET 与我们现有的 .NET 非常相似!.NET 框架(在我看来!)与 Windows 运行时 API 集相比,非常简单、易用且直观。您可以为此处提供的代码使用相同的代码来启动文本转语音部分,但是有一些差异我必须警告您。那篇文章也讨论了音频文件生成,在本篇文章中,我将讨论 Windows 运行时的开发阶段。所以,请继续关注我,学习如何做到这一点!
1. 构建应用程序的文本转语音部分
第一部分将是构建应用程序的基础。我根本不打算讨论 UI 或 UX 指南,而是直接进入 C# 代码,分享如何实际构建应用程序的后端,使其能够执行一些实际工作,而不仅仅是显示其内容。 :)
我不知道为什么,但 Windows 开发团队喜欢将语音 API 添加到媒体技术中,因此他们提供了 `Windows.Media.SpeechSynthesis` 命名空间下的对象(类)。请理解这一点,Windows API 中的文本转语音是一项非常简单直观的任务,您甚至无需执行任何操作即可执行生成文本语音的功能。Windows 会自行管理一切。因此,我将向您展示简单的 C# 代码,它可以在应用程序中为输入的文本生成音频结果。
初始化合成器
合成器定义在上述命名空间中,您可以通过调用构造函数并传递语言(*或使用 Windows 操作系统提供的默认语言;由用户安装*)来使用它。在大多数情况下,您无需设置引擎,它们已经设置好了。但是,如果您想上下调整引擎,仍然可以操作您创建的对象。
// Namespace addition using Windows.Media.SpeechSynthesis; // Create the object here... var synthesizer = new SpeechSynthesizer(); // You can update the properties, such as voice engine being used.
下一步只是执行“Synthesize…”函数!此函数将根据您传递的内容返回流。您可以传递文本和 SSML;我不会涵盖 SSML,然后引擎将根据参数返回基于音频语音的流。
修改属性
在最后阶段之前,我想讨论您可能想要在引擎中更新的属性,以便为您的用户提供更好的体验并覆盖更广泛的受众。
声音和其他内容
首先,您应该考虑引擎始终需要系统上安装的声音。您想使用的每一种声音,在您的应用程序开始考虑在应用程序中使用它之前,必须已经安装在系统中!因此,我建议您首先考虑安装了哪种语言。我使用英语,我的家人也用,但我的朋友们不用。有些人喜欢法语,而有些人则安装了乌尔都语或印地语。因此,如果您在应用程序中硬编码任何内容,当应用程序无法使用指定语言构建引擎时,可能会导致运行时异常。在这种情况下,您可以遍历可用的语言(声音!)。
// Object created above var voices = synthesizer.AllVoices;
现在您可以遍历每种语言的声音,然后提供用户界面,让他们可以从机器上安装的每种声音中选择一种语言。此外,还允许用户安装更多语言,以便他们可以使用更多声音将文本渲染成音频流。声音还基于性别、地理位置、音高和年龄。因此,您也可以查找是否安装了特定语言。
然后,此数组中的每个项都将指向 `Voice` 对象。该对象是另一种类型,`VoiceInformation`,它保存有关用于渲染文本的声音的信息。声音(如前所述!)可以包含其所说的语言、基于年龄和性别的等信息。如果您想选择一种语言而不知道安装了哪种语言,或者不想在应用程序中硬编码语言名称,您也可以基于这些参数选择一种语言。
然后,您可以将合成器的声音更改为您想要使用的声音。例如,
// Assume you collected a voice information from the AllVoices list synthesizer.Voice = voiceFromList;
然后您可以继续到下一个阶段,即获取流!
获取和加载语音流
在 Windows 10 中,您无法从该 API 获取音频,而是获取数据流,即音频数据,然后您需要一个播放器来播放该流。Windows 10 有一个名为 `MediaElement` 的控件。您可以使用该播放器为您渲染流。我认为这是简单的方法!关键是,MediaElement 会为您处理大部分麻烦,您无需处理编解码器和其他字节管理概念,只需将其作为资源发送到 media element,它就会预览它。
即使是执行此操作的代码也非常简单直接,您只需要指定流和内容类型,以便 `MediaElement` 能够正确渲染媒体。看看下面的两行代码
// Generate the stream var stream = await synthesizer.SynthesizeTextToStreamAsync(message); // Set it as a source mediaElement.SetSource(stream, stream.ContentType);
MediaElement 将会渲染控件、进度条和其他它需要的组件。
图 1:应用程序显示文本转语音的控件和资源
在上图中,很明显 `MediaElement` 显示控件,渲染流,并允许用户暂停或播放内容,甚至可以对其音频流进行定位。这使其成为故事阅读器应用程序的更好选择。
好了,文本转流部分就到这里。其余的内容只是“额外的芝士点缀”,我不想讨论,我只想专注于生成可以保存到机器上的音频内容。所以,请转到下一节。
2. 为音频语音流生成音频文件
这一部分是比较困难的部分,我花了一个半小时才弄好!实际上,.NET 中的 Stream 对象和适用于 Windows 应用商店的 .NET 之间存在一些混淆。这给我带来了很多麻烦,但无论如何,我想与您分享我的成果,这样您就不必抓耳挠腮了。
选择文件
在 Windows 运行时(或 Windows 应用商店应用程序)中,您不能像在 .NET 环境中那样随意移动。您受到权限集的约束,因此最好允许用户选择并为您设置一个工作位置。这样,Windows 就不会干预,并会允许您的应用程序拥有权限,就像用户自己操作一样。
以下代码可以做到这一点,所使用的对象是 `FileSavePicker`,它允许用户选择您的应用程序将保存数据的文件的位置。您可以指定文件类型、扩展名以及(*可选*)文件名。
// Create the object var picker = new FileSavePicker(); // Set up a few settings picker.DefaultFileExtension = ".wav"; picker.CommitButtonText = "Save"; picker.FileTypeChoices.Add("Audio", new List<string>() { ".wav" }); // Let the user select a file now; and a location var file = await picker.PickSaveFileAsync();
然后您可以使用选定的文件并将数据加载到其中。之后是概念点。如果用户选择了文件,您现在需要
- 以读/写权限打开该文件的流。
- 为您的流创建一个字节数组。
- 为此,您需要使用 MemoryStream。
- 将这些字节数组值写入文件。
- 文件类型将是 .wav 文件,所以请确保是那种文件。
- 将更改提交到文件系统,您就完成了!
现在,实现上述逻辑也是非常相似的部分。看看下面的代码,Windows 运行时提供的 `FileIO` 对象是一个很好的对象,它允许我们处理文件输入/输出。因此,使用相同的对象,我将编写一个执行我想要的操作的块……
// If user selected a file if (file != null) { // Create a memory stream using (var mem = new MemoryStream()) { // Get the stream object; Stream of .NET var strm = stream.AsStream(); strm.Position = 0; // Change the location index to copy from await strm.CopyToAsync(mem); // Convert to array of bytes var array = mem.ToArray(); // Write the byte-array to the file. await FileIO.WriteBytesAsync(file, array); } }
只需要上面的代码!我们完成了。代码当我重构它时,令我惊讶,我非常震惊,为什么我一开始没有想到它。代码很简单,并且完成了它的预期功能,所以如果我将上面的语音流转换为音频文件,它就会是这样。
图 2:FileSavePicker 显示选择要保存数据的文件的界面。
图 3:Windows 文件管理器显示使用上述 Windows 10 应用程序创建的“MyAudio”文件!
所以,通过这种方式,我们可以将数据存储在音频文件中。
关注点
Windows 10 是新的,Windows 运行时也是新的……大多数 C# 程序员仍然喜欢 .NET 环境,尽管微软为他们提供了在 Windows 运行时中工作的工具,但 Windows 运行时 API 仍然不如 .NET 框架那样简单和美观。
本帖讨论并分享了构建自己的文本转语音应用程序所需的信息,而且不仅仅是这样,它还分享了如何将该音频流转换为可以稍后播放的音频文件。当然,在这篇文章中,我无法播放文件,但在实际中,它确实说了我写的内容。 :-)
这个月快结束了,我可能会更早地写一篇新帖子,但无论如何,祝大家新年快乐! :-)