N.Yamazaki's blog

主に音声合成について思ったことを書いてみようと思います。
<< AquesTalkで漢字を含むテキストを読み上げる | main | ビルド時のリンクエラー AquesTalk2 iPhone >>
AquesTalk2 Android を使ってみる

音声合成エンジン AquesTalk2 をGoogleのOSプラットフォームであるAndroidに移植しました。
サンプルアプリを含むライブラリは、こちらから、ダウンロード出来ます。
非営利の個人利用に限り無償で使用できますので、お手元のAndroid端末に組み込んでみてはいかがでしょうか。

基本的な使い方は、先に書いたAquesTalkと同じですが、声種データを指定すれば異なる声種で合成ができるようになっています。

サンプルアプリ
ダウンロードしたパッケージには、ライブラリと一緒に、サンプルアプリが2つ(HelloAquesTalk2,AqTk2App)入っています。

    * HelloAquesTalk2:
      最も単純なサンプルで、起動時に規定のメッセージを合成出力するだけのものです。
    * AqTkApp2:
      GUIを持たせ、任意の音声記号列と話速 、声種を指定して音声合成するものです。


 

サンプルアプリの動かし方
AndroidSDK(+Eclipse)の開発環境が構築されていることが前提です。

   1. ダウンロードしたプロジェクトファイル一式を任意の場所に展開
   2. Eclipse を起動
   3. メニュー>ファイル>新規>Androidプロジェクト
   4. [外部ソースからプロジェクトを作成]を選択し、
   5. ロケーションに、プロジェクトファイルの(AndroidManifest.xmlがある)フォルダを指定
   6. あとは、実行するだけ。

AquesTalkライブラリのファイル
注意 「AquesTalk2 Android」の実体はネイティブコードで書いてあり、JNI経由で呼び出しています。そのため、AndroidOSであっても、ARM CPU以外では動作しません。

任意のアプリケーションで音声合成するときには、次の2つのファイルを使用します。

    * ¥lib¥libAquesTalk2.so : AquesTalk2 Androidの実体(ネイティブコード)
    * ¥lib¥AquesTalk2.java : libAquesTalk2.so を呼び出すためのJavaラッパークラス

この2つのファイルを、アプリケーションのプロジェクトに追加します。Eclipseであれば、プロジェクトディレクトリに、上のファイルを下記のようなディレクトリ構造上に(ディレクトリがなければ作成する)コピーすればOKだと思います。

/<app project>
    /src
       /<アプリのソース>
       /aquestalk2
           /AquesTalk2.java
    /libs
       /armeabi
           /libAquesTalk2.so
    /res
      .
      .

なお、呼び出しの関係は、次のようになります。

    * アプリ -> AquesTalk2.java -> libAquesTalk2.so



AquesTalkライブラリの 使用方法
任意のアプリにAquesTalk2を組み込む方法を、サンプルアプリのコード(samples¥AqTk2App¥src¥com¥a_quest¥aquestalk2¥AqTkApp2.java)を参照しながら以下に示します。

AquesTalk2 のクラスをインポートします。
 

import aquestalk2.AquesTalk2;


AquesTalk2.java の中を見ればわかりますが、静的メソッドと、通常のメソッドが用意されています。いまのところ、関数は1つだけなので、どちらを使っても違いはありません。
AqTkApp2.javaでは、アプリ起動時のonCreate()のなかで、インスタンスを生成しています。

 

 

aquestalk2 = new AquesTalk2();


そして、発声ボタンが押されたときに、音声記号列 と発話速度を取得して、次のように音声データをメモリ上に生成します。なお、音声記号列の文字コードはUTF-8で指定します(Androidのデフォルトのままでok)。最期の引数にはPhontデータを指定します。デフォルトのPhont(声種)を使用するときは、nullで構いません。Phontデータの指定方法は、後述します。

 

 

 

 

onPlayBtn():
    byte[] wav = aquestalk2.syntheWav(koe, speed, null);


ここで得られる音声データはwavフォーマット(8KHz,Mono,Straight PCM)です。
音声記号列が不正な場合など生成エラーの時は、byte[]のサイズが1になり、配列の先頭にエラーコードが返されます。エラーコードは、samples¥AqTk2App¥src¥aquestalk2¥AquesTalk2.javaの後ろに記述してあります。

現時点では、「AquesTalk Android」に直接音声を出力するメソッドは用意されていませんので、音声再生はアプリ側で記述する必要があります。AudioTrack クラスを用いて音声出力するコードの例がAqTkApp.javaにありますので、参考にしてください。
注意すべき点は、AquesTalk2の出力はwavフォーマットであるのに対し、AudioTrackで再生するデータは、ヘッダを含まない生のデータ列を指定する必要があります。そこで、生成した音声データの先頭にあるWAVヘッダ(44バイト)を除いて、それ以降をAudioTrackに渡します。また、データの長さ(サンプル数)は、1つのサンプルが2バイトですので、次のようになります。

 

 

 

 

サンプル数=(wav.length-44)/2


Phontの指定方法

aquestalk2.syntheWav()の最後の引数にPhontデータを指定することが出来ます。これにより異なる声種で合成が可能になります。

各種のPhontファイル(拡張子が.phont)が、AquesTalk2ライブラリのパッケージ中(/phontフォルダ内)に含まれています。なお、Phontファイルは、Windows版その他のプラットフォーム間で互換がありますので、今後公開されるPhontファイルをダウンロードして利用することもできます。

AndroidアプリプログラムでPhontを指定する方法ですが、PhontファイルをAndroid規定の場所に配置してアプリからファイルを読み込んでも良いのですが、ここではアプリのリソースにPhontデータをつっこんで、それを実行時に読み出す方法を示します。

まず、Phontファイルをリソースに含まれるようにします。
エクスプローラなどでアプリパッケージのフォルダを見ると、resフォルダがあるはずです。その下にrawフォルダを作成し、さらにその下に使用する各Phontファイルをコピーします。Eclipse上のパッケージ・エクスプローラでF5でリフレッシュして確認すると、次のようになります。これでビルド後にアプリパッケージの中に自動的にPhontデータが含まれるようになります。




次に示すコードは、Phont名(ファイル名の拡張子を除いたもの)を指定して、Phontデータをリソースからbyte配列に読み込むプログラムです。
当該PhontのリソースIDは、android.content.res.ResourcesクラスのgetIdentifier()で、リソース名から取得しています。その後、InputStream を使って、Phontデータをbyte[]に読み込んでいます。
この関数の戻り値を、aquestalk2.syntheWav()の最後の引数に指定すれば、その声種で音声合成ができるようになります。


AqTk2App.java:

 

 

 

// 指定のPhont名に等しいPhontデータをリソースからLoad
private byte[] LoadPhont(String phont) {
    try {
        String packageName = getResources().getResourcePackageName(R.raw.aq_robo);
        String typeName = getResources().getResourceTypeName(R.raw.aq_robo);
     int resID = getResources().getIdentifier(phont,typeName, packageName);
     if(resID==0) return null;
     InputStream    in = getResources().openRawResource(resID);
     int size = in.available();    // リソースのデータサイズ
     byte[] phontDat = new byte[size];
     in.read(phontDat);
     return phontDat;
    }catch (IOException e) {
        return null;
    }
}


以上、駆け足でAndroid上でAquesTalk2を使用する方法を示しましたが、Javaに不慣れなこともあり、メモリ管理等で怪しいところがあるかもしれません。ご指摘の点があればコメントをお寄せ頂ければ幸いです。

 

 

 

 

 

| AquesTalk | 12:44 | - | - |
PROFILE
Follow
CATEGORIES
LATEST ENTRIES
SEARCH THIS SITE