はじめに
こんにちは。最近ようやくKotlinに手を付け始めたnomuraです。
つい先日、テキスト読み上げのTextToSpeechを実装するにあたり、Kotlinではどのように書くのかを調べたところ、あまり日本語記事が見当たらなかったので、サンプルを書いてみようと思います。
環境
- macOS High Sierra 10.13.4
- Android Studio 3.0.1
MainActivity.kt
日本語もしくは英語のテキストを入力し、読み上げる機能を実装してみます。
TextToSpeechを初期化する際、
OnInitListener
インターフェース実装が必須となります。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 | class MainActivity : AppCompatActivity(), View.OnClickListener, TextToSpeech.OnInitListener{ private var tts : TextToSpeech? = null override fun onCreate(savedInstanceState: Bundle?) { super.onCreate(savedInstanceState) setContentView(R.layout.activity_main) // TextToSpeech初期化 tts = TextToSpeech(this, this) speech_ja.setOnClickListener(this) speech_en.setOnClickListener(this) } override fun onClick(v: View) { var input = "" var langLocale : Locale? = null when (v.id) { R.id.speech_ja -> { // 日本語を指定する input = input_ja.text.toString() langLocale = Locale.JAPANESE } R.id.speech_en -> { // 英語を指定する input = input_en.text.toString() langLocale = Locale.ENGLISH } } if (langLocale != null && input.isNotBlank()) { // 指定された言語でテキストを読み上げる speakText(langLocale, input) } } private fun speakText(langLocale: Locale, text: String) { tts!!.setLanguage(langLocale) tts!!.speak(text, TextToSpeech.QUEUE_FLUSH, null, "speech1") } override fun onInit(status: Int) { if (status == TextToSpeech.SUCCESS) { Log.d("TTS", "TextToSpeechが初期化されました。") // 音声再生のイベントリスナを登録 val listener : SpeechListener? = SpeechListener() tts!!.setOnUtteranceProgressListener(listener) } else { Log.e("TTS", "TextToSpeechの初期化に失敗しました。") } } } |
SpeechListener.kt
抽象クラス
UtteranceProgressListener
を継承して読み上げのイベントリスナークラスを実装します。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 | class SpeechListener : UtteranceProgressListener() { var tag : String = "TTS" override fun onDone(utteranceId: String?) { Log.d(tag,"音声再生が完了しました。") } override fun onError(utteranceId: String?) { Log.d(tag,"音声再生中にエラーが発生しました。") } override fun onError(utteranceId: String?, errorCode: Int) { Log.d(tag,"音声再生中にエラーが発生しました。") } override fun onStart(utteranceId: String?) { Log.d(tag,"音声再生を開始します。") } override fun onStop(utteranceId: String?, interrupted: Boolean) { Log.d(tag,"音声再生を中止します。") } override fun onBeginSynthesis(utteranceId: String?, sampleRateInHz: Int, audioFormat: Int, channelCount: Int) { Log.d(tag,"音声の合成を開始します。") } override fun onAudioAvailable(utteranceId: String?, audio: ByteArray?) { Log.d(tag,"音声が利用可能になりました。") } } |
activity_main.xml
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 | <?xml version="1.0" encoding="utf-8"?> <android.support.constraint.ConstraintLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:app="http://schemas.android.com/apk/res-auto" xmlns:tools="http://schemas.android.com/tools" android:id="@+id/container" android:layout_width="match_parent" android:layout_height="match_parent" tools:context=".MainActivity"> <EditText android:id="@+id/input_ja" android:hint="@string/hint_ja" android:inputType="text" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" /> <Button android:id="@+id/speech_ja" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="@string/button_ja" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/input_ja" /> <EditText android:id="@+id/input_en" android:hint="@string/hint_en" android:inputType="text" android:layout_margin="20dp" android:layout_width="match_parent" android:layout_height="wrap_content" android:text="@string/text_en" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@id/speech_ja" /> <Button android:id="@+id/speech_en" android:layout_width="match_parent" android:layout_height="wrap_content" android:layout_margin="20dp" android:layout_marginEnd="8dp" android:layout_marginStart="8dp" android:layout_marginTop="8dp" android:text="@string/button_en" app:layout_constraintEnd_toEndOf="parent" app:layout_constraintStart_toStartOf="parent" app:layout_constraintTop_toBottomOf="@+id/input_en" /> </android.support.constraint.ConstraintLayout> |
さいごに
実際にアプリを実装していくとなると、バックグラウンドで音声再生を行うために、foreground serviceと絡めた実装になっていくと思いますが、ひとまず最低限、テキストの読み上げと言語の切り替え、イベントを拾うところまでのコードになります。