En este tutorial veremos cómo dar voz a tu dispositivo Android utilizando una librería de Texto a Voz (TTS). Tanto si estás desarrollando aplicaciones para discapacitados visuales como si buscas darle vida a tu sistema Android, dotar de voz a tu proyecto puede ser una función interesante. Para ello, vamos a integrar la librería react-native-tts en una aplicación Android desarrollada con React Native.
Hardware
- Dispositivo Android
- Ordenador para programar
- Un cable USB para conectar el dispositivo Android al PC
Configuración del proyecto React Native
La biblioteca de texto a voz react-native-tts te permite utilizar las voces, o modelos de texto a voz, disponibles en tu dispositivo Android para leer texto.
npm install react-native-tts --save
Utilizamos una lista desplegable para seleccionar la voz que desee.
npm install react-native-dropdown-select-list --save
Uso de la biblioteca react-native-tts
En primer lugar, importamos la biblioteca TextToSpeech en el código, junto con la lista desplegable
import Tts from 'react-native-tts'
import { SelectList } from 'react-native-dropdown-select-list'
En un componente funcional, añadimos los estados que nos interesan:
- voz seleccionada
- marcha seleccionada
- lista de votación
- lista de equipos
Hay otros parámetros que podría valer la pena probar
- defaultLanguage
- defaultPitch define el tono de la voz (alto o bajo)
- defaultRate establece la velocidad de reproducción de la voz
En un hook useEffect, inicializamos las listas de voces y marchas y luego asignamos la voz y la marcha seleccionadas por defecto.
N.B.: Utilizamos la promesa resultante de la inicialización del motor TextToSpeech para asegurarnos de que está disponible cuando se inicializa el componente (Tts.getInitStatus().then(() => {)
useEffect(() => { //console.log("init availableVoice",availableVoice) if(availableVoice.length === 0){ console.log("No data found") Tts.getInitStatus().then(() => { Tts.voices().then(voices => { voicesList = voices.map((voice,index) => { //console.log(voice); return {key: index, value: voice.name+"("+voice.language+")", disabled: voice.notInstalled==true ? true:false} }) ; langList = voices.map((voice,index) => { return {key: index, value: voice.language, disabled: voice.notInstalled==true ? true:false} }) ; //console.log("voicesList", voicesList) setAvailableVoice(voicesList); }, (err) => {console.log("no voice loaded")}); //see all supported voices Tts.engines().then(engines => { engList = engines.map((engine,index) => { return {key: index, value: engine.name} }); //console.log("engList", engList) setAvailableEng(engList); }); //see all supported voices }, (err) => { console.log("TTS not loaded"); if (err.code === 'no_engine') { Tts.requestInstallEngine(); } }); } if(voice !== ""){ Tts.setDefaultVoice(voice); } if(lang !== ""){ Tts.setDefaultLanguage(lang); } }, [availableVoice,availableEng, voice,lang, eng]);
Por último, devolvemos el renderizado, que se incluye en el pedido:
- la lista desplegable de voces disponibles
- la lista desplegable de marchas disponibles
- un cuadro de texto para escribir el texto que se va a leer
- un botón para leer el texto
return ( <View style={{ flexGrow: 1, flex: 1 }}> <Text style={styles.mainTitle}>AC Text to Speech</Text> <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setVoice(val)} data={availableVoice} save="value" /> </View> {/*} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setLang(val)} data={availableLang} save="value" /> </View>*/} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setEng(val)} data={availableEng} save="value" /> </View> <View style={styles.inputBar}> <TextInput style={styles.textInput} placeholder="Enter a message" value={msgText} onChangeText={(text) => setMsgText(text) } /> <TouchableOpacity onPress={() => Tts.speak(msgText, { androidParams: { KEY_PARAM_PAN: -1, KEY_PARAM_VOLUME: 0.5, KEY_PARAM_STREAM: 'STREAM_MUSIC', }, }) } style={[styles.sendButton]}> <Text style={styles.buttonText}> Speak </Text> </TouchableOpacity> </View> {/*<Text>{currentDate}</Text>*/} <View style={{flex: 1 }}> </View> </View> )
Resultados
Una vez que tu código haya sido compilado e instalado en tu dispositivo, puedes seleccionar y probar las voces disponibles (las voces no instaladas aparecen atenuadas). Introduce un texto y pulsa el botón «Hablar» para que tu aplicación hable.
Código fuente completo: Text To Speech
/** * npm install react-native-tts --save * https://www.netguru.com/blog/react-native-text-to-speech * https://www.npmjs.com/package/react-native-tts * * npm install react-native-dropdown-select-list --save */ import React, { useEffect, useState } from 'react' import { Text, View, StyleSheet, TextInput, TouchableOpacity } from 'react-native' import Tts from 'react-native-tts' import { SelectList } from 'react-native-dropdown-select-list' //Tts.setDefaultLanguage('en-GB') Tts.setDefaultLanguage('fr-FR') //Tts.setDefaultVoice('com.apple.ttsbundle.Daniel-compact') //Tts.setDefaultRate(0.6); //Tts.setDefaultPitch(1.5); //Tts.setDefaultEngine('engineName'); //request install. app need reinstall after let voicesList: { key: number; value: string; disabled: boolean }[] | ((prevState: never[]) => never[])= [] let langList = [] let engList: { key: number; value: string }[] | ((prevState: never[]) => never[]) = [] const App = () => { const [msgText, setMsgText] = useState(""); const [voice, setVoice] = useState("") const [lang, setLang] = useState("") const [eng, setEng] = useState("") const [availableVoice, setAvailableVoice] = useState([]) const [availableLang, setAvailableLang] = useState([]) const [availableEng, setAvailableEng] = useState([]) useEffect(() => { //console.log("init availableVoice",availableVoice) if(availableVoice.length === 0){ console.log("No data found") Tts.getInitStatus().then(() => { Tts.voices().then(voices => { voicesList = voices.map((voice,index) => { //console.log(voice); return {key: index, value: voice.name+"("+voice.language+")", disabled: voice.notInstalled==true ? true:false} }) ; langList = voices.map((voice,index) => { return {key: index, value: voice.language, disabled: voice.notInstalled==true ? true:false} }) ; //console.log("voicesList", voicesList) setAvailableVoice(voicesList); }, (err) => {console.log("no voice loaded")}); //see all supported voices Tts.engines().then(engines => { engList = engines.map((engine,index) => { return {key: index, value: engine.name} }); //console.log("engList", engList) setAvailableEng(engList); }); //see all supported voices }, (err) => { console.log("TTS not loaded"); if (err.code === 'no_engine') { Tts.requestInstallEngine(); } }); } if(voice !== ""){ Tts.setDefaultVoice(voice); } if(lang !== ""){ Tts.setDefaultLanguage(lang); } }, [availableVoice,availableEng, voice,lang, eng]); return ( <View style={{ flexGrow: 1, flex: 1 }}> <Text style={styles.mainTitle}>AC Text to Speech</Text> <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setVoice(val)} data={availableVoice} save="value" /> </View> {/*} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setLang(val)} data={availableLang} save="value" /> </View>*/} <View style={styles.inputBar}> <SelectList setSelected={(val: React.SetStateAction<string>) => setEng(val)} data={availableEng} save="value" /> </View> <View style={styles.inputBar}> <TextInput style={styles.textInput} placeholder="Enter a message" value={msgText} onChangeText={(text) => setMsgText(text) } /> <TouchableOpacity onPress={() => Tts.speak(msgText, { androidParams: { KEY_PARAM_PAN: -1, KEY_PARAM_VOLUME: 0.5, KEY_PARAM_STREAM: 'STREAM_MUSIC', }, }) } style={[styles.sendButton]}> <Text style={styles.buttonText}> Speak </Text> </TouchableOpacity> </View> {/*<Text>{currentDate}</Text>*/} <View style={{flex: 1 }}> </View> </View> ) } export default App; let BACKGROUND_COLOR = "#161616"; //191A19 let BUTTON_COLOR = "#346751"; //1E5128 let ERROR_COLOR = "#C84B31"; //4E9F3D let TEXT_COLOR = "#ECDBBA"; //D8E9A8 var styles = StyleSheet.create({ mainTitle:{ color: TEXT_COLOR, fontSize: 30, textAlign: 'center', borderBottomWidth: 2, borderBottomColor: ERROR_COLOR, }, backgroundVideo: { borderWidth: 2, borderColor: 'red', position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, webVideo: { borderWidth: 2, borderColor: 'green', position: 'absolute', top: 0, left: 0, bottom: 0, right: 0, }, buttonText: { color: TEXT_COLOR, fontWeight: 'bold', fontSize: 12, textAlign: 'center', textAlignVertical: 'center', }, sendButton: { backgroundColor: BUTTON_COLOR, padding: 15, borderRadius: 15, margin: 2, paddingHorizontal: 20, }, inputBar:{ flexDirection: 'row', justifyContent: 'space-between', margin: 5, }, textInput:{ backgroundColor: '#888888', margin: 2, borderRadius: 15, flex:3, }, });
Aplicaciones
- Haz que tu sistema Android hable, ¡ya sea un teléfono, un coche o un robot!