In this tutorial, we’ll look at how to give your Android device a voice using a Text to Speech (TTS) library. Whether you’re developing applications for the visually impaired, or just want to liven up your Android system, giving your project a voice can be an interesting feature. To do this, we’re going to integrate the react-native-tts library into an Android application developed with React Native.
Hardware
- Android device
- Computer for programming
- USB cable to connect Android device to PC
React Native project configuration
The react-native-tts text-to-speech library lets you use the voices, or text-to-speech models, available on your Android device to read text.
npm install react-native-tts --save
We use a drop-down list to select the desired voice.
npm install react-native-dropdown-select-list --save
Using the react-native-tts library
First, we import the TextToSpeech library and the
import Tts from 'react-native-tts'
import { SelectList } from 'react-native-dropdown-select-list'
In a functional component, we add the states we’re interested in:
- selected voice
- selected gear
- voting list
- gear list
There are other parameters that could be interesting to test
- defaultLanguage
- defaultPitch defines the pitch of the voice (high or low)
- defaultRate defines voice playback speed
In a useEffect hook, we initialise the voice and gear lists and then assign the voice and gear selected by default.
N.B.: We use the promise resulting from the initialization of the TextToSpeech engine to ensure that it will be available when the component is initialized (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]);
Finally, we return the rendering, which includes the order:
- the drop-down list of available voices
- the drop-down list of available gears
- a text zone for writing the text to be read
- a button to read the text
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> )
Results
Once your code has been compiled and installed on your device, you can select and test the available voices (uninstalled voices are grayed out). Enter a text and press the “Speak” button to make your application speak.
Full source code: 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, }, });
Applications
- Make your Android system talk, whether it’s a phone, a car or a robot!