2012年7月2日月曜日

[C# .NET] System.Speech.Synthesisを使って音声合成を試してみた

.NETにSystem.Speech.Synthesisという名前空間があり、これを利用するとテキストを音声で出力することができます。OSによって異なるかもしれませんが、SAPI5を使用しているようです。そのため、SAPI5に対応した合成エンジンをインストールしないと、音声合成を利用することができないということになります。

現在のところ、MSからはMicrosoft Speech Platformのエンジンが提供されているのですが、このままだとSAPIには対応していないようです。ただ、レジストリを書けばSAPIで利用できるようになるようですが、ここではその方法は紹介しません。

エンジンが使えるかどうかチェック

まず、音声合成エンジンが使えるかどうかということですが、
SpeechSynthesizer.GetInstalledVoices(CultureInfo);を使って、インストールされている声を取得します。指定するCultureInfoは、基本的にはアプリケーションの現在のカルチャでいいと思います。その場合、Formアプリケーションであれば、System.Windows.Forms.Application.CurrentCulture プロパティを使います。このプロパティはstaticなので、どこからでも参照できます。また、カルチャを決め打ちしたいのであれば、CultureInfoのコンストラクタで適切な値を渡して、オブジェクトを作成すればよいと思います。

そうすると、ReadOnlyCollection<InstalledVoice>が得られるので、このコレクションを見て中に何もなければ、指定したカルチャでは音声合成が使えないということになります。

音声合成を出力する

通常、文章を音声に変えてサウンドデバイスから出力できればよいと思うので、その方法を説明します。以下がC#のコードです(名前空間への参照をusingを使って指定しておいてください)。

SpeechSynthesizer speechSynthesizer = new SpeechSynthesizer();
CultureInfo cultureInfo = Application.CurrentCulture;
ReadOnlyCollection<InstalledVoice> voices = speechSynthesizer.GetInstalledVoices(cultureInfo);
//ここでvoices.Countが0なら使える声がない。
InstalledVoice voice = voices[0];
speechSynthesizer.SelectVoice(voice.VoiceInfo.Name);
string text; //音声合成させたい文章
speechSynthesizer.Speak(text);
というのが、簡単な方法だと思います。あと、非同期のSpeechSynthesizer.SpeakAsyncというメソッドがあるので、必要であればこちらを使ったほうがいいと思います。

SSMLを使って出力する

SpeechSynthesizer.SpeechSynthesizer.SpeakSsmlまたは、SpeechSynthesizer.SpeakSsmlAsyncというメソッドが用意されており、これを使うと音声を制御しながら、出力することができます。SSMLについては、W3Cで勧告されているので、詳細はそちらを参照していただきたいのですが、基本的にはspeak要素の中に、出力したい文章をいれておけば大丈夫です。ただし、言語の指定もSSMLの中で指定しないとダメなようです。

C#のコードについては、上記のコードのspeechSynthesizer.Speak(text)speechSynthesizer.SpeakSsml(text)に置き換えればいいのですが、SelectVoiceメソッドの呼び出しは意味がないようです。

以下が単純なSSMLです。

<?xml version="1.0" encoding="utf-8" ?>
<speak version="1.0" xmlns="http://www.w3.org/2001/10/synthesis"
         xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"
         xsi:schemaLocation="http://www.w3.org/2001/10/synthesis
                   http://www.w3.org/TR/speech-synthesis/synthesis.xsd"
         xml:lang="en-US">
  <voice xml:lang="ja">
  <!-- ここに文章を書く -->
  </voice>
</speak>
文章は、HTMLのようにp要素でくくっておいたほうが、それらしいと思います。ただ、なくても出力はされます。

あと、ピッチ(声の高さ)レート(話速)ですが、SSMLを使う場合には、prosody要素を使って指定すればよいです。あと、読みをがうまくいかなくて、発音を明示的に指定する場合には、phoneme要素で設定することがきます。このとき、ph属性で発音を指定するのですが、いわゆるローマ字表記で指定できます。発音記号でもできるようですが、試してはいません。