自从
Windows Phone 8 SDK 泄漏后,经过一些研究以及官方文档和示例,我的注意力放到了新的 SpeechSynthesizer
和 InstalledVoices.All 类上。
于是我做了一个示例来试用 WP8 的 TTS 文本朗读,先开始 XAML:
<phone:PhoneApplicationPage
x:Class="TextToSpeechDemo.MainPage"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:phone="clr-namespace:Microsoft.Phone.Controls;assembly=Microsoft.Phone"
xmlns:shell="clr-namespace:Microsoft.Phone.Shell;assembly=Microsoft.Phone"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
mc:Ignorable="d"
FontFamily="{StaticResource PhoneFontFamilyNormal}"
FontSize="{StaticResource PhoneFontSizeNormal}"
Foreground="{StaticResource PhoneForegroundBrush}"
SupportedOrientations="Portrait" Orientation="Portrait"
shell:SystemTray.IsVisible="True">
<!--LayoutRoot is the root grid where all page content is placed-->
<Grid x:Name="LayoutRoot" Background="Transparent">
<Grid.RowDefinitions>
<RowDefinition Height="Auto"/>
<RowDefinition Height="*"/>
</Grid.RowDefinitions>
<!--TitlePanel contains the name of the application and page title-->
<StackPanel x:Name="TitlePanel" Grid.Row="0" Margin="12,17,0,28">
<TextBlock Text="{Binding Path=LocalizedResources.ApplicationTitle, Source={StaticResource
LocalizedStrings}}" Style="{StaticResource PhoneTextNormalStyle}"/>
<TextBlock Text="{Binding Path=LocalizedResources.PageTitle, Source={StaticResource
LocalizedStrings}}" Margin="9,-7,0,0" Style="{StaticResource PhoneTextTitle1Style}"/>
</StackPanel>
<!--ContentPanel - place additional content here-->
<Grid x:Name="ContentPanel" Grid.Row="1" Margin="12,0,12,0">
<StackPanel>
<ScrollViewer Height="200">
<ComboBox HorizontalAlignment="Left" Width="456" Name="voicesComboBox" DisplayMemberPath="Name"/>
</ScrollViewer>
<StackPanel Orientation="Horizontal" HorizontalAlignment="Center">
<RadioButton Content="Male" IsChecked="true" Name="MaleRadioButton"/>
<RadioButton Content="Female"/>
</StackPanel>
<TextBox HorizontalAlignment="Left" Height="230" TextWrapping="Wrap" Width="456" Text="I may be
a sorry case, but I don't write jokes in base 13." Name="inputTextBox"/>
<Button Content="Speak to me" HorizontalAlignment="Left" Width="456" Click="SpeakToMe_Click"/>
</StackPanel>
</Grid>
</Grid>
</phone:PhoneApplicationPage> |
接下来是 MainPage.xaml 对应的代码,其内容基本上都来自于
WP8 SDK 文档,我增加了一些错误检查和小改进:
using System;
using System.Linq;
using System.Windows;
using Microsoft.Phone.Controls;
using Windows.Phone.Speech.Synthesis;
namespace TextToSpeechDemo
{
public partial class MainPage : PhoneApplicationPage
{
SpeechSynthesizer synth;
// Constructor
public MainPage()
{
InitializeComponent();
voicesComboBox.ItemsSource = new MyLocals().Items();
}
private async void SpeakToMe_Click(object sender, RoutedEventArgs e)
{
if (voicesComboBox.SelectedIndex == -1)
{
MessageBox.Show("Please select a language.");
}
else
{
if (string.IsNullOrEmpty(inputTextBox.Text))
{
MessageBox.Show("Please enter some text.");
}
else
{
try
{
// Initialize the SpeechSynthesizer object.
synth = new SpeechSynthesizer();
var myLocal = (MyLocale)voicesComboBox.SelectedItem;
// Query for a voice. Results rdered by Gender to ensure the order always goes Female
then Male.
var voices = (from voice in InstalledVoices.All
where voice.Language == myLocal.Lcid
select voice).OrderByDescending(v => v.Gender);
// gender: 0 = Female, 1 = Male. Corresponds to the index of the above results.
int gender = 0;
if (MaleRadioButton.IsChecked == true) gender = 1; else gender = 0;
// Set the voice as identified by the query.
synth.SetVoice(voices.ElementAt(gender));
// Speak
await synth.SpeakTextAsync(inputTextBox.Text);
}
catch (Exception ex)
{
MessageBox.Show(ex.Message);
}
}
}
}
}
} |
然后是一个帮忙填充 ComboBox 列表语言的类,检查 InstalledVoices.All
显示出 30 条数据。我不知道为什么我无法直接获取,好像是一个 COM 对象跟 LINQ 查询的关系吧。这里我能监测出
12 种语言,我没有深入研究去找另外 3 个。
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace TextToSpeechDemo
{
class MyLocale
{
public MyLocale(string name, string lcid)
{
_name = name;
_lcid = lcid;
}
private string _name;
public string Name
{
get { return _name; }
set { _name = value; }
}
private string _lcid;
public string Lcid
{
get { return _lcid; }
set { _lcid = value; }
}
}
class MyLocals
{
private IList<MyLocale> _myLocals;
public MyLocals()
{
_myLocals = new List<MyLocale>();
_myLocals.Add(new MyLocale("Chinese Simplified (PRC)", "zh-CN"));
_myLocals.Add(new MyLocale("Chinese Traditional (Taiwan)", "zh-TW"));
_myLocals.Add(new MyLocale("English (United States)", "en-US"));
_myLocals.Add(new MyLocale("English (United Kingdom)", "en-GB"));
_myLocals.Add(new MyLocale("French (France)", "fr-FR"));
_myLocals.Add(new MyLocale("German (Germany)", "de-DE"));
_myLocals.Add(new MyLocale("Italian (Italy)", "it-IT"));
_myLocals.Add(new MyLocale("Japanese (Japan)", "ja-JP"));
_myLocals.Add(new MyLocale("Polish (Poland)", "pl-PL"));
_myLocals.Add(new MyLocale("Portuguese (Brazil)", "pt-BR"));
_myLocals.Add(new MyLocale("Russian (Russia)", "ru-RU"));
_myLocals.Add(new MyLocale("Spanish (Spain)", "es-ES"));
}
public IEnumerable<MyLocale> Items()
{
return (IEnumerable<MyLocale>)_myLocals;
}
}
} |
接下来是设置 ID_CAP_SPEECH_RECOGNITION 功能,否则将会出异常:
下图是程序运行结果,选择其中一个语言并点击按钮将会开始阅读。
我注意到另外一件事:如果我选择一种非英语的语言让它朗读英语文本,朗读出来的效果是带口音的,例如我选择法语的1,2,3,4,然后用西班牙语来朗读,它发出的声音是西班牙语的法语4,很有趣。
|