android TextToSpeech; switching between male and female voices

1.8k views Asked by At

I am trying to do an app which can switch between the Google's default en-UK male voice (en-gb-x-rjs-phone-hmm) and female voice (en-gb-x-fis-phone-hmm). I am using two Text-To-Speech objects and, after initializing the engine for each one, I assign the corresponding voice to each of them with setVoice(voice).

 mTTS1 = new TextToSpeech(this, onInitListener, packname);
 mTTS2 = new TextToSpeech(this, onInitListener, packname);

And in onInit() method, when both are initialized:

 mTTS1.setVoice(voice1);
 mTTS2.setVoice(voice2);

'voice1' and 'voice2' are obtained calling to getVoices(), and when I get the voice name, I obtain 'en-gb-x-rjs-phone-hmm' and 'en-gb-x-fis-phone-hmm' respectively, so this make me think voices are correctly stored.

When I display two buttons for making them speak, the female voice speaks in both cases. I think it's a fact of the default voice. That happens having the female voice as the default voice. When I set the male voice as the default one, it happens just the opposite.

Something I should know that I'm missing...?

Thank you all,

1

There are 1 answers

0
NickGlowsinDark On

Four-and-a-half years late to the game, but I just fought this myself. Turns out, just because the voice shows up in getVoices(), isn't flagged with isNetworkConnectionRequired, and the TTS isLanguageAvailable() method doesn't include LANG_MISSING_DATA or LANG_NOT_SUPPORTED, doesn't mean it's ready to be used. And if you try to set a voice that isn't ready, the TTS engine just falls back to the default.

What I had to do was check all of that, but then also make sure there weren't any missing features on that voice (in Kotlin, where tts is my TextToSpeech object after it's been successfully initialized):

var availableVoices = tts.voices
var availableLocales:List<Locale> = Locale.getAvailableLocales().toList()
for (v:Voice in availableVoices){
    if (v.locale.language == Locale.getDefault().language &&
        availableLocales.contains(v.locale) &&
        !v.isNetworkConnectionRequired &&
        tts.isLanguageAvailable(v.locale)!=TextToSpeech.LANG_MISSING_DATA &&
        tts.isLanguageAvailable(v.locale)!=TextToSpeech.LANG_NOT_SUPPORTED &&
        !(v.features.contains(TextToSpeech.Engine.KEY_FEATURE_NOT_INSTALLED))
    ){
        // voice is ready to use
    }
}

As long as you actually have a network connection, maybe you can get away with using non-local voices, but I didn't feel that trying to designate a fallback was worth the effort, so I just stripped them from my list of availables.