Site icon AranaCorp

Give your Android device a voice with React Native TTS

0
(0)

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

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:

There are other parameters that could be interesting to test

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:

  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

Sources

How useful was this post?

Click on a star to rate it!

Average rating 0 / 5. Vote count: 0

No votes so far! Be the first to rate this post.

Exit mobile version