【Unity】Androidのテキスト読み上げ(TextToSpeech)を使う 
2017/10/29 Sun [edit]
Unity で Android の音声認識を利用できたから、テキスト読み上げも利用できるだろうと安直に考えて作ったみたもの(笑)。やってみたら意外と面白かった。合成音声は棒読みでリアリティないけど、最近はよく動画(MAD等)などにも使われているし、英語の発音チェックアプリなんかもある(認識と読み上げで英単語を声を出して学習するアプリ)。アイデア次第で面白いものが作れるかもしれない。
内容的にはAndroidの基本機能を利用するプラグインのアップデート版。一部仕様変更した部分もあるが(詳細は更新履歴を参照)、基本的にはそのまま使えるので旧バージョンがある場合は上書きでも構わないと思う。プラグイン自体のセットアップは以前の記事を参照して欲しい。自分で作りたい場合は簡略化したものだが、今回も元の Java コードを書いておくので挑戦してみるのも良いだろう(※Java コードは解説用に一部抜粋・省略したものであって、そのままコピペでは使えないことに注意)。
|
テキスト読み上げ機能を使うには端末に読み上げエンジンと音声データのインストールが必要だ。最近の端末ならあらかじめメーカーのプレインストールが入っているとは思うが、格安スマホなどは入っていないかもしれない。またエンジン・音声データを替えると同じ文章でも感じが変わって面白かったりするので、一応インストール方法も載せておこう。既に知っているなら「■テキスト読み上げ機能を使う」まで飛ばしても構わないと思う。
(※) Unity 5.6.3p1 / AndroidStudio 2.3.3 / Windows10(x64) / Galaxy S7 Edge (Android 7.0) で確認
■テキスト読み上げ機能を端末にインストールする
端末の種類によってどこのメニューに入っているか違うらしいが、例えば Galaxy S7 Edge では「ユーザー補助」のメニューに入っていた。端末の「設定>ユーザー補助(※端末による)>テキスト読み上げ」を開いてみよう。Galaxy の場合ははじめから「Galaxy読み上げエンジン」が入っているのでそのまま使えるが、歯車アイコンを押して優先言語や音声(女性/男性)を選ぶこともできる。「サンプル視聴」で確認もできるので、気に入ったものを選んでおくのも良いかもしれない。

テキスト読み上げエンジンや音声データは Google Play などを検索すれば(※"TTS"で検索すれば色々出てくる)、有料/無料色々出てくるが、ここでは「Googleテキスト読み上げ」と「KDDI N2」を紹介しておこう。どちらも無料で使えるのでとりあえず試してみるのには良いかもしれない。
(Google Play)
・Googleテキスト読み上げ
・N2 TTS
インストールし終わったら、先ほどと同じように端末のメニューからテキスト読み上げ設定を開いてみよう。「Googleテキスト読み上げ」と「KDDILABS N2 TTS」がエンジンに追加されていれば成功だ。あとは各エンジンの歯車アイコンを押して音声データを追加インストール・選択すれば良い。なお、N2 の場合「KDDILABS N2 TTS設定>デフォルト音質」でインストールした音声を選択するようだ。

●KDDI N2

■テキスト読み上げ機能を使う(TextToSpeech)
※Android11 以降ではテキスト読み上げ(Text-to-speech)に専用パーミッションが必要になったようです。

●Unity から Android の TextToSpeech を使う C# コード
using FantomLib;
#if UNITY_ANDROID && !UNITY_EDITOR
//起動ステータスを取得
AndroidPlugin.InitSpeechRecognizer(callbackGameObject, statusCallbackMethod);
//テキスト読み上げを開始
AndroidPlugin.StartTextToSpeech(message, callbackGameObject, statusCallbackMethod, startCallbackMethod,
doneCallbackMethod, stopCallbackMethod);
#endif
●プラグイン内の対応する Java コード
import android.content.Context;
import android.speech.tts.TextToSpeech;
import android.speech.tts.UtteranceProgressListener;
import java.util.Locale;
import com.unity3d.player.UnityPlayerActivity;
import static com.unity3d.player.UnityPlayer.UnitySendMessage;
TextToSpeech tts = new TextToSpeech(context, new TextToSpeech.OnInitListener(){
@Override
public void onInit(int status) {
if (status == TextToSpeech.SUCCESS) {
Locale locale = Locale.getDefault();
if (tts.isLanguageAvailable(locale) >= TextToSpeech.LANG_AVAILABLE) {
tts.setLanguage(locale);
tts.setSpeechRate(speed);
tts.setPitch(pitch);
tts.speak(message, TextToSpeech.QUEUE_FLUSH, null, utteranceId);//API 21
UnitySendMessage(callbackGameObject, statusCallbackMethod, "SUCCESS_INIT");
} else {
UnitySendMessage(callbackGameObject, statusCallbackMethod, "ERROR_LOCALE_NOT_AVAILABLE");
}
} else {
UnitySendMessage(callbackGameObject, statusCallbackMethod, "ERROR_INIT");
}
}
});
int listenerResult = tts.setOnUtteranceProgressListener(new UtteranceProgressListener() {
@Override
public void onStart(String utteranceId) { //API15
UnitySendMessage(callbackGameObject, startCallbackMethod, "onStart");
}
@Override
public void onDone(String utteranceId) { //API15
UnitySendMessage(callbackGameObject, doneCallbackMethod, "onDone");
}
@Override
public void onError(String utteranceId) { //API15
UnitySendMessage(callbackGameObject, statusCallbackMethod, "ERROR_UTTERANCEPROGRESS_LISTENER");
}
public void onError(String utteranceId, int errorCode) { //API21(Android5.0)
UnitySendMessage(callbackGameObject, statusCallbackMethod, String.valueOf(errorCode));
}
public void onStop(String utteranceId, boolean interrupted) { //API 23(Android 6.0)
UnitySendMessage(callbackGameObject, stopCallbackMethod, interrupted ? "INTERRUPTED" : "onStop");
}
});
if (listenerResult != TextToSpeech.SUCCESS) {
UnitySendMessage(callbackGameObject, statusCallbackMethod, "ERROR_UTTERANCEPROGRESS_LISTENER_REGISTER");
}
実際の Java コードはAPI Level で定義が違っていたりするので、条件分岐などでかなり複雑になっているので、ここではあくまで簡略化されたのものであると思って欲しい(API 21/23以降を抜粋)。
Unity 用の C# コードでは起動ステータス(テキスト読み上げが使用できるか等)を取得する「InitSpeechRecognizer()」メソッドを使っているが、実際にはテキスト読み上げ開始の「StartTextToSpeech()」メソッドをいきなり使ってもステータスは返ってくる(初回のみ)。実行中のエラーなども引数に与えたステータス用メソッド名(statusCallbackMethod)に返ってくるが、主に起動成功時には "SUCCESS_INIT" が、言語設定の不備(言語ごと読み上げのエンジン・音声データがない)は "ERROR_LOCALE_NOT_AVAILABLE" が返ってくると考えて良い。
実行中のイベントは、読み上げ開始イベント(onStart()→startCallbackMethod)、終了イベント(onDone()→doneCallbackMethod)、中断イベント(onStop()→stopCallbackMethod)[※API23(Android6.0)以降]、エラーなどのステータス(onError()→statusCallbackMethod) がヒエラルキーにある GameObject 名(callbackGameObject)の各メソッドに文字列で返ってくる。また、エラーと起動ステータスは同じメソッドから返ってきてるが、エラーの場合の文字列は必ず "ERROR_~" のようになっているのでわかる。
サンプルコードは「Assets/_Test/Scripts/TextToSpeechTest.cs」にまとまっているので、全体的に見て必要なものをコピペなどすれば簡単に扱えるだろう。
※この記事のUnityアセットはプラグインとして配布されています。
(関連記事)
【Unity】Androidのハードウェア音量操作・ハードウェアキーの無効化をする
【Unity】Androidのトーストやダイアログ、通知、音声認識、ハード音量操作など基本的な機能を使えるプラグインを作ってみた
【Unity】Androidでカスタマイズしたダイアログを動的生成できるプラグインを作ってみた
【Unity】Androidでチェックボックス付きのアラートダイアログ(AlertDialog)を使う
【Unity】Androidで日付・時刻選択ダイアログ(DatePicker, TimePicker)を使う
【Unity】Androidで数値・半角英数・パスワード入力ダイアログを使う
【Unity】Androidでテキスト入力ダイアログを使う
【Unity】Androidの選択ダイアログを使う
【Android】【Java】音声入力(音声認識)で文字列を取得する
【Android】【Java】AlertDialog を使ってみる
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/275-5b548e0f
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |