Este tutorial enseñará a través de ejemplos sencillos Text To Speech y Speech To Text. Cómo se puede convertir un texto escrito en palabras habladas o palabras habladas en texto escrito mediante programación.
Hay dos ejemplos hasta ahora:
- Ejemplo 1 Kotlin Speech to Text y Text to Speech
- Ejemplo 2- Kotlin Speech to Text y Text to Speech
Empecemos.
Ejemplo 1: Kotlin Android Text to Speech y Text to Speech
Veamos nuestro ejemplo. Este ejemplo cubre tanto el texto a voz como el texto a voz. Hay un texto de edición donde se escribe el texto a convertir.
Aquí está una demostración de lo que vamos a crear:
Paso 1: Crear el proyecto
Comienza creando un proyecto vacío de Android Studio
.
Paso 2: Dependencias
No se necesita ninguna librería de terceros.
Paso 3: Diseñar el layout
Tenemos un diseño: el diseño para nuestra MainActivity:
activity_main.xml
Añadiremos TextInputEditText, un FloatingActionButton y un ExtendedFloatingAction como nuestros componentes UI:
<?xml version="1.0" encoding="utf-8"?>
<androidx.constraintlayout.widget.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:layout_width="match_parent"
android:layout_height="match_parent"
tools:context=".MainActivity">
<com.google.android.material.textfield.TextInputLayout
android:id="@+id/textInputLayout"
style="@style/Widget.MaterialComponents.TextInputLayout.OutlinedBox"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:layout_marginStart="16dp"
android:layout_marginTop="16dp"
android:layout_marginEnd="16dp"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toTopOf="parent">
<com.google.android.material.textfield.TextInputEditText
android:id="@+id/edtText"
android:layout_width="match_parent"
android:layout_height="wrap_content"
android:hint="Text" />
</com.google.android.material.textfield.TextInputLayout>
<com.google.android.material.floatingactionbutton.ExtendedFloatingActionButton
android:id="@+id/fabPlay"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginTop="16dp"
android:text="Play"
android:textAlignment="center"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:layout_constraintTop_toBottomOf="@+id/textInputLayout" />
<com.google.android.material.floatingactionbutton.FloatingActionButton
android:id="@+id/fabVoice"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:layout_marginBottom="16dp"
android:clickable="true"
app:layout_constraintBottom_toBottomOf="parent"
app:layout_constraintEnd_toEndOf="parent"
app:layout_constraintStart_toStartOf="parent"
app:srcCompat="@drawable/ic_keyboard_voice" />
</androidx.constraintlayout.widget.ConstraintLayout>
Paso 4: Crear un ViewModel
Tendremos una clase llamada BaseViewModel
que extenderá el androidx.lifecycle.ViewModel
y será nuestra clase ViewModel. Aquí tendremos al menos dos funciones:
Una función para lanzar nuestro reconocedor de voz vía Intent:
fun displaySpeechRecognizer() {
startForResult.launch(Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale("in_ID"))
putExtra(RecognizerIntent.EXTRA_PROMPT, Locale("Bicara sekarang"))
})
}
Y una función para convertir nuestro Texto en Voz a través del textToSpeechEngine
:
fun speak(text: String) = viewModelScope.launch{
textToSpeechEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null, "")
}
Aquí está el código completo:
BaseViewModel.kt
import android.content.Intent
import android.speech.RecognizerIntent
import android.speech.tts.TextToSpeech
import androidx.activity.result.ActivityResultLauncher
import androidx.lifecycle.ViewModel
import androidx.lifecycle.viewModelScope
import kotlinx.coroutines.launch
import java.util.*
class BaseViewModel : ViewModel() {
private lateinit var textToSpeechEngine: TextToSpeech
private lateinit var startForResult: ActivityResultLauncher<Intent>
fun initial(
engine: TextToSpeech, launcher: ActivityResultLauncher<Intent>
) = viewModelScope.launch {
textToSpeechEngine = engine
startForResult = launcher
}
fun displaySpeechRecognizer() {
startForResult.launch(Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH).apply {
putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale("in_ID"))
putExtra(RecognizerIntent.EXTRA_PROMPT, Locale("Bicara sekarang"))
})
}
fun speak(text: String) = viewModelScope.launch{
textToSpeechEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null, "")
}
}
Paso 5: Crear nuestra MainActivity
Finalmente tendremos nuestra MainActivity:
MainActivity.kt
import android.os.Bundle
import android.speech.RecognizerIntent
import android.speech.tts.TextToSpeech
import androidx.activity.result.contract.ActivityResultContracts
import androidx.activity.viewModels
import androidx.appcompat.app.AppCompatActivity
import id.derysudrajat.stttts.databinding.ActivityMainBinding
import java.util.*
class MainActivity : AppCompatActivity() {
private lateinit var binding: ActivityMainBinding
private val model: BaseViewModel by viewModels()
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
binding = ActivityMainBinding.inflate(layoutInflater)
setContentView(binding.root)
model.initial(textToSpeechEngine, startForResult)
with(binding) {
fabVoice.setOnClickListener { model.displaySpeechRecognizer() }
fabPlay.setOnClickListener {
val text = edtText.text?.trim().toString()
model.speak(if (text.isNotEmpty()) text else "Text tidak boleh kosong")
}
}
}
private val startForResult = registerForActivityResult(
ActivityResultContracts.StartActivityForResult()
) { result ->
if (result.resultCode == RESULT_OK) {
val spokenText: String? =
result.data?.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
.let { text -> text?.get(0) }
binding.edtText.setText(spokenText)
}
}
private val textToSpeechEngine: TextToSpeech by lazy {
TextToSpeech(this) {
if (it == TextToSpeech.SUCCESS) textToSpeechEngine.language = Locale("in_ID")
}
}
}
Ejecutar
Copiar el código o descargarlo en el siguiente enlace, construir y ejecutar.
Referencia
Aquí están los enlaces de referencia:
Descargar Ejemplo
Ejemplo 2: Ejemplo simple de texto a voz y de voz a texto
Este es un ejemplo simple de Text To Speech y Speech To Text en Kotlin Android.
Paso 1: Crear el proyecto
Comienza creando un proyecto vacío de Android Studio
.
Paso 2: Dependencias
No se necesita ninguna librería de terceros.
Paso 3: Diseñar el layout
Añade dos botones: uno para TTS y otro STT, así como un texto de edición para introducir o mostrar el texto.
actividad_main.xml
<?xml version="1.0" encoding="utf-8"?>
<LinearLayout xmlns:android="http://schemas.android.com/apk/res/android"
xmlns:tools="http://schemas.android.com/tools"
android:layout_width="match_parent"
android:layout_height="match_parent"
android:gravity="center"
android:orientation="vertical"
android:padding="24dp"
tools:context=".MainActivity">
<Button
android:id="@+id/btn_stt"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Speak" />
<EditText
android:id="@+id/et_text_input"
android:layout_width="match_parent"
android:layout_height="0dp"
android:layout_marginTop="24dp"
android:layout_marginBottom="24dp"
android:layout_weight="1"
android:gravity="center"
android:hint="Text from STT or for TTS goes here." />
<Button
android:id="@+id/btn_tts"
android:layout_width="wrap_content"
android:layout_height="wrap_content"
android:text="Listen" />
</LinearLayout>
Paso 4: Escribir el código
Aquí está el código completo:
MainActivity.kt
import android.app.Activity
import android.content.ActivityNotFoundException
import android.content.Intent
import android.os.Build
import android.os.Bundle
import android.speech.RecognizerIntent
import android.speech.tts.TextToSpeech
import android.widget.Toast
import androidx.appcompat.app.AppCompatActivity
import kotlinx.android.synthetic.main.activity_main.*
import java.util.*
class MainActivity : AppCompatActivity() {
companion object {
private const val REQUEST_CODE_STT = 1
}
private val textToSpeechEngine: TextToSpeech by lazy {
TextToSpeech(this,
TextToSpeech.OnInitListener { status ->
if (status == TextToSpeech.SUCCESS) {
textToSpeechEngine.language = Locale.UK
}
})
}
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
setContentView(R.layout.activity_main)
btn_stt.setOnClickListener {
val sttIntent = Intent(RecognizerIntent.ACTION_RECOGNIZE_SPEECH)
sttIntent.putExtra(
RecognizerIntent.EXTRA_LANGUAGE_MODEL,
RecognizerIntent.LANGUAGE_MODEL_FREE_FORM
)
sttIntent.putExtra(RecognizerIntent.EXTRA_LANGUAGE, Locale.getDefault())
sttIntent.putExtra(RecognizerIntent.EXTRA_PROMPT, "Speak now!")
try {
startActivityForResult(sttIntent, REQUEST_CODE_STT)
} catch (e: ActivityNotFoundException) {
e.printStackTrace()
Toast.makeText(this, "Your device does not support STT.", Toast.LENGTH_LONG).show()
}
}
btn_tts.setOnClickListener {
val text = et_text_input.text.toString().trim()
if (text.isNotEmpty()) {
if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.LOLLIPOP) {
textToSpeechEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null, "tts1")
} else {
textToSpeechEngine.speak(text, TextToSpeech.QUEUE_FLUSH, null)
}
} else {
Toast.makeText(this, "Text cannot be empty", Toast.LENGTH_LONG).show()
}
}
}
override fun onActivityResult(requestCode: Int, resultCode: Int, data: Intent?) {
super.onActivityResult(requestCode, resultCode, data)
when (requestCode) {
REQUEST_CODE_STT -> {
if (resultCode == Activity.RESULT_OK && data != null) {
val result = data.getStringArrayListExtra(RecognizerIntent.EXTRA_RESULTS)
result?.let {
val recognizedText = it[0]
et_text_input.setText(recognizedText)
}
}
}
}
}
override fun onPause() {
textToSpeechEngine.stop()
super.onPause()
}
override fun onDestroy() {
textToSpeechEngine.shutdown()
super.onDestroy()
}
}
Ejecutar
Copia el código o descárgalo en el siguiente enlace, construye y ejecuta.
Referencia
Aquí están los enlaces de referencia:
Descargar Ejemplo