🔬

android.speech.ttsをJetpack Composeで使ってみた

2024/08/12に公開

🎤テキストを読み上げてくれるらしい

普段は、Fltterとたまに、SwiftUIでお仕事をしてます。Flutterで新しいアプリを作ろうとしてたんですけど、Kotlinのバージョン上げろとエラーが出て苦しみました😇

OSに依存したエラー出てくるの辛いな。Kotlinでもあるでしょうけど。オリジナルのAndroidには、ttsが標準機能であった!

https://developer.android.com/reference/android/speech/tts/package-summary

こちらの記事を使えば簡単に実装できた!

やること

  • プロジェクトを作る
  • サンプルコードを日本語対応にする
  • これだけ

example:

package com.junichi.ttsapplication

import android.os.Bundle
import android.speech.tts.TextToSpeech
import androidx.activity.ComponentActivity
import androidx.activity.compose.setContent
import androidx.compose.foundation.layout.Column
import androidx.compose.foundation.layout.fillMaxSize
import androidx.compose.foundation.layout.padding
import androidx.compose.material3.Button
import androidx.compose.material3.MaterialTheme
import androidx.compose.material3.Surface
import androidx.compose.material3.Text
import androidx.compose.runtime.Composable
import androidx.compose.runtime.DisposableEffect
import androidx.compose.runtime.MutableState
import androidx.compose.runtime.getValue
import androidx.compose.runtime.mutableStateOf
import androidx.compose.runtime.remember
import androidx.compose.runtime.setValue
import androidx.compose.ui.Modifier
import androidx.compose.ui.platform.LocalContext
import androidx.compose.ui.tooling.preview.Preview
import androidx.compose.ui.unit.dp
import com.junichi.ttsapplication.ui.theme.TtsApplicationTheme
import java.util.Locale

class MainActivity : ComponentActivity() {
    override fun onCreate(savedInstanceState: Bundle?) {
        super.onCreate(savedInstanceState)
        setContent {
            TtsApplicationTheme {
                // A surface container using the 'background' color from the theme
                Surface(
                    modifier = Modifier.fillMaxSize(),
                    color = MaterialTheme.colorScheme.background
                ) {
                    TextToSpeechScreen()
                }
            }
        }
    }
}

val sentences = listOf(
    "おはようございます。",
    "こんにちは。",
    "こんばんは。",
)

@Composable
fun TextToSpeechScreen() {
    var isSpeaking by remember { mutableStateOf(false) }
    val tts = rememberTextToSpeech()

    Column(modifier = Modifier.padding(24.dp)) {
        isSpeaking = false
        for (sentence in sentences) {
            Button(onClick = {
                if (tts.value?.isSpeaking == true) {
                    tts.value?.stop()
                    isSpeaking = false
                } else {
                    tts.value?.speak(
                        sentence, TextToSpeech.QUEUE_FLUSH, null, ""
                    )
                    isSpeaking = true
                }
            }) {
                Text(sentence)
            } // End Button
        } // End for

    }
}

@Composable
fun rememberTextToSpeech(): MutableState<TextToSpeech?> {
    val context = LocalContext.current
    val tts = remember { mutableStateOf<TextToSpeech?>(null) }
    DisposableEffect(context) {
        val textToSpeech = TextToSpeech(context) { status ->
            if (status == TextToSpeech.SUCCESS) {
                tts.value?.language = Locale.JAPAN
            }
        }
        tts.value = textToSpeech

        onDispose {
            textToSpeech.stop()
            textToSpeech.shutdown()
        }
    }
    return tts
}

@Preview(showBackground = true)
@Composable
fun DefaultPreview() {
    TtsApplicationTheme {
        TextToSpeechScreen()
    }
}

日本語対応にする

tts.value?.language = Locale.JAPAN

サンプルだと、tts.value?.language = Locale.USになっています。JAPANに修正すると日本語で、音声を読み上げてくれます。
for文で、ダミーのデータをループして渡して、3個ボタンを作ってくれます。ボタンを押すと、日本語の挨拶を読み上げてくれます。

@Composable
fun rememberTextToSpeech(): MutableState<TextToSpeech?> {
    val context = LocalContext.current
    val tts = remember { mutableStateOf<TextToSpeech?>(null) }
    DisposableEffect(context) {
        val textToSpeech = TextToSpeech(context) { status ->
            if (status == TextToSpeech.SUCCESS) {
                tts.value?.language = Locale.JAPAN
            }
        }
        tts.value = textToSpeech

        onDispose {
            textToSpeech.stop()
            textToSpeech.shutdown()
        }
    }
    return tts
}

感想

標準機能で、ttsが使えるのがありがたかったですね。Swiftでも標準機能で使えるみたいです。

Discussion