Java Speech APIとは

Java Speech API(以下、JSAPI)はJavaアプリケーションに音声認識や音声合成の機能を組み込むためのAPIである。Java Speech API自身はJCPがスタートする前に発表されたのでJSRは存在せず、Sun Microsystemsのサイト上でその仕様が公開されている。

JSAPIを使用することで、Javaプログラムで音声の認識や合成を行うことができるようになる。たとえば、合成音声によってテキストを読み上げるというような処理の実装が容易に行える。

JSAPIの代表的な実装としてはオープンソースで開発されているFreeTTSがある。もっとも新しいバージョンは1.2.1で、商用の音声認識/合成ツールのような高度な機能は有していないが、JSAPIを試すには十分な機能を提供してくれる。今回はまずこのFreeTTSを用いて、JSAPIの音声合成機能を利用したプログラムを作ってみる。

FreeTTSを試す

FreeTTSはこのページより入手することができる。配布ファイルにはライブラリのほかにドキュメントやデモプログラムなどが含まれている。

ライブラリはlibディレクトリに格納されている。FreeTTSの実装は「freetts.jar」だ。また、JSAPIの実装はWindows環境ならば「jsapi.exe」を、UNIX(シェル)環境ならば「jsapi.sh」を実行するとライセンス文書が表示され、同意すれば「jsapi.jar」というファイルが生成される。これらをクラスパスに追加して利用する。

リスト1に、FreeTTSを利用してテキストを読み上げるプログラムの例を示す。このプログラムは、実行時にコマンドライン引数で指定した英文テキストを合成音声で読み上げる。

リスト1 SpeechSample.java

package sample.speech;

import java.beans.PropertyVetoException;
import java.util.Locale;
import javax.speech.AudioException;
import javax.speech.Central;
import javax.speech.EngineException;
import javax.speech.EngineStateError;
import javax.speech.synthesis.Synthesizer;
import javax.speech.synthesis.SynthesizerModeDesc;
import javax.speech.synthesis.Voice;

public class SpeechSample {
    private Synthesizer synthesizer = null;

    public SpeechSample() {
        // シンセザイザのモードを指定
        SynthesizerModeDesc desc = new SynthesizerModeDesc
            (null, "general", Locale.US, Boolean.FALSE, null);
        try {
            // シンセザイザを作成
            synthesizer = Central.createSynthesizer(desc);
            if (synthesizer == null) {
                System.err.println("ERROR! シンセザイザが見つかりません。");
                System.exit(1);
           }

            // ボイスを作成
            String voiceName = "kevin16";
            Voice voice = new Voice(voiceName, Voice.GENDER_DONT_CARE,
                            Voice.AGE_DONT_CARE, null);
            if (voice == null) {
                System.err.println(
                    "ERROR! シンセザイザがボイス "
                    + voiceName + " をサポートしていません。");
                System.exit(1);
            }

            // リソースの割り当て
            synthesizer.allocate();
            synthesizer.resume();
            // ボイスの設定
            synthesizer.getSynthesizerProperties().setVoice(voice);
        } 
        catch (EngineException ex) {
            ex.printStackTrace();
        } catch (PropertyVetoException ex) {
            ex.printStackTrace();
        } catch (AudioException ex) {
            ex.printStackTrace();
        }
    }

    public void speak(String message) {
       try {
            // テキストの読み上げ
            synthesizer.speakPlainText(message, null);
            synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY);
        } catch (InterruptedException ex) {
            ex.printStackTrace();
        }
    }

    public void deallocateSynthesizer() {
        try {
            // リソースの開放
            synthesizer.deallocate();
        } catch (EngineException ex) {
            ex.printStackTrace();
        }

    }

    public static void main(String[] args) {
        String message = (args.length > 0) ? args[0] : "Hello World.";

        SpeechSample sample = new SpeechSample();
        sample.speak(message);
        sample.deallocateSynthesizer();
    } 
}

SpeechSampleクラスは、コンストラクタが呼び出されるとまずSynthesizerModeDescを使用してシンセザイザのモードを指定し、続いてSynthesizerオブジェクトを生成する。Synthesizerの生成は、CentralクラスのcreateSynthesizer()メソッドを用いて行う。

続いて、使用する音声を表すVoiceオブジェクトを生成する。そしてallocate()メソッドでSynthesizerにリソースを割り当て、SynthesizerPropertiesのsetVoice()メソッドを用いてボイスを設定する。

speak()メソッドでは引数に渡されたテキストの読み上げを行う。読み上げはSynthesizerオブジェクトに対してspeakPlainText()メソッドを呼び出せばよい。deallocateSynthesizer()メソッドではリソースの開放を行っている。

最後に、シンセザイザを有効にするため、リスト2のようなプロパティファイルを作成してユーザディレクトリに配置する。ここではシンセザイザを生成するためのCentralの実装としてcom.sun.speech.freetts.jsapi.FreeTTSEngineCentralを利用することを指定している。

リスト2 speech.properties

# Sample ResourceBundle properties file
FreeTTSSynthEngineCentral=com.sun.speech.freetts.jsapi.FreeTTSEngineCentral

これで、適当なテキストを引数に指定してSpeechSampleクラスを実行すれば、そのテキス]トが合成音声によって読み上げられるはずだ。

JSR 113: Java Speech API 2.0(JSAPI 2.0)

さて、JCPにはJava Speech APIの後継バージョンとして「JSR 113: Java Speech API 2.0」が登録されている。ちょうど6月11日にProposed Final Draft 2が公開され、今年第3四半期での正式リリースを目指して最終仕様の検討が進められている。

JSAPI 2.0では1.0との互換性を可能な限り確保するとしながらも、多くの点で変更が加えられている。その主たるものとしては、ターゲットがJava MEプラットフォーム(CLDC 1.0以上およびMIDP 1.0以上が対象)になっていることが挙げられる。クラス構成も大きく変更されており、たとえばJSAPI 1.0ではSynthesizerを生成するのにCentralクラスとSynthesizerModeDescクラスを利用していたのに対し、2.0ではEngineManagerクラスを用いてリスト3のように行う。

JSAPI 2.0でのSynthesizerの生成

Synthesizer synth = (Synthesizer)
        EngineManager.createEngine(SynthesizerMode.DEFAULT);

その他、2.0における主な変更点を以下に挙げる。

  • すべての浮動小数点の使用を廃止
  • AWTに依存しない
  • イベントキューをSpeechEventExecutorで統合
  • URLクラスの使用をStringクラスに置き換え
  • StringReaderの必要性を排除
  • Dictation機能の削除(ただし将来的には復活する可能性もある)
  • W3C SRGSのサポート
  • W3C SSMLのサポート
  • フィルタイベントにイベントマスクを追加
  • JSR 135(Mobile Media API)互換のAudioManagerの導入

JSR 113の参照実装の開発はExpert Groupにも名を連ねるConversayによって行われている。また、開発者向けのポータルサイトがConversations Developer Networkに開設されており、フォーラムでの議論Early Releaseの情報公開などが行われてる。