2016/06/21
テキスト読み上げ機能
開発中のアプリに英単語の発音機能を実装したくて、EasyTTS(有料Asset 5ドル)を使って見た話。
これさえいれておけばAndroidでもiOSでもテキストを読み上げてくれる。ツール系のアプリにも使えそう。
要求スペック
iOS7 以上
Adroid 1.6以上
AndroidではTTS Engineがインストールされている必要あり。
実装方法
需要が少ないのか、情報が少なかった。
公式が参考になるかな。
使い方はとても簡単。
①EasyTTSのパッケージをインポート
②使用するメソッドは以下
EasyTTSUtil.SpeechAdd (a string that converts into speech)
EasyTTSUtil.Initialize()
EasyTTSUtil.Stop()
DemoEasyTTS.cs
public class DemoEasyTTS : MonoBehaviour { private string stringToEdit = "Test"; void OnGUI () { stringToEdit = GUI.TextField (new Rect (Screen.width/2-100, Screen.height/2-100, 200, 50), stringToEdit,200); if (GUI.Button (new Rect (Screen.width/2-50, Screen.height/2-20, 100, 40), "Speak")) { EasyTTSUtil.SpeechAdd(stringToEdit); } } void Start(){ EasyTTSUtil.Initialize (EasyTTSUtil.UnitedStates); } void OnApplicationQuit() { EasyTTSUtil.Stop (); } }
Start時にEasyTTSUtil.Initialize(EasyTTSUtil.UnitedStates)で使用する言語を指定して初期化。
EasyTTSUtil.Speech (a string that converts into speech) で読み上げたいTextを引数に渡す。
読むのを止めたいときは
EasyTTSUtil.Stop()を呼ぶ。
※Android, iOSの違いを意識する必要はない。
簡単!と思いきや。。
iOS実機でデバッグすると、EasyTTS.Speech(string)を呼んだときに1フレーム内で処理しきれず、かくついてしまう。。
これじゃ使い物にならないよ。。。。ということで。
EasyTTSのコード内部を調査
EasyTTS.mm
static EasyTTSUtil *tts = nil; void EasyTTSUtilSpeech(char* text,char* _local) { if(tts == nil) { tts = [EasyTTSUtil alloc]; } NSString *sName = (text != nil) ? [NSString stringWithUTF8String: text] : [NSString stringWithUTF8String: ""]; NSString *slocal = (text != nil) ? [NSString stringWithUTF8String: _local] : [NSString stringWithUTF8String: ""]; [tts convertTextToSpeech:sName local:slocal]; }
出たよ。。objective-c。。。nilって気持ち悪い。。
よくわからないけど、解読すると、EasyTTSUtil.Speechを最初に呼び出したときにttsがnil(null?)のとき、memory allocしてるっぽい。メモリの確保は結構重い処理だろうから、ここがボトルネックかな?ということで下の関数を切り出し。
void EasyTTSUtilAlloc() { if(tts == nil) { tts = [EasyTTSUtil alloc]; } }
EasyTTSUtil.cs
public class EasyTTSUtil { #if UNITY_IPHONE && !UNITY_EDITOR [DllImport("__Internal")] private static extern void EasyTTSUtilSpeech(string text,string local); [DllImport("__Internal")] private static extern void EasyTTSUtilStop(); [DllImport("__Internal") // →追記 private static extern void EasyTTSUtilAlloc(); //→追記 //以下省略... }
EasyTTSUtilAlloc()はobjective-cコードのため、c#コードでよびだせるよう、2行分追記。
EasyTTSUtil.cs/Initialize
public static void Initialize(string local = UnitedStates,string enginePkg = null) { #if UNITY_ANDROID && !UNITY_EDITOR //省略 } #elif UNITY_IPHONE && !UNITY_EDITOR localSetting = local; EasyTTSUtilAlloc(); //追記 #endif }
EasyTTSUtil.csのScriptで初期化時にメモリ確保するように変更。
EasyTTSUtil.cs内コードInitializeメソッド内にEasyTTSUtilAlloc()を追記。
EasyTTS.Initialize()を呼んだときに、メモリを確保しておく。
あとは通常の使い方の通り、使う前にInitializeを呼んで、EasyTTSUtil.Speech(string)を実行するだけ。
ちゃんと評価できてないけど、Unity Profilerで確認したら、スパイクが小さくなったし、フレーム遅延もなくなってそうだから、良しとしよう。
※iOS版は改善されたけど、Android版は確認できてない。。
いろいろと試行錯誤したけど、英単語ひとつひとつの音声ファイル用意するよりは簡単かな。
Twitterでご教示いただいた方々ありがとうございました。