カテゴリー: Android

[Android] KotlinでTextToSpeech

はじめに

こんにちは。最近ようやくKotlinに手を付け始めたnomuraです。
つい先日、テキスト読み上げのTextToSpeechを実装するにあたり、Kotlinではどのように書くのかを調べたところ、あまり日本語記事が見当たらなかったので、サンプルを書いてみようと思います。

環境

  • macOS High Sierra 10.13.4
  • Android Studio 3.0.1

MainActivity.kt

日本語もしくは英語のテキストを入力し、読み上げる機能を実装してみます。
TextToSpeechを初期化する際、OnInitListenerインターフェース実装が必須となります。

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を継承して読み上げのイベントリスナークラスを実装します。

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

<?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と絡めた実装になっていくと思いますが、ひとまず最低限、テキストの読み上げと言語の切り替え、イベントを拾うところまでのコードになります。

nomura

シェア
執筆者:
nomura

最近の投稿

フロントエンドで動画デコレーション&レンダリング

はじめに 今回は、以下のように…

2週間 前

Goのクエリビルダー goqu を使ってみる

はじめに 最近携わっているとあ…

3週間 前

【Xcode15】プライバシーマニフェスト対応に備えて

はじめに こんにちは、suzu…

2か月 前

FSMを使った状態管理をGoで実装する

はじめに 一般的なアプリケーシ…

3か月 前