I'm currently writing a Java application (chat app) which requires text-to-speech. After looking online for a bit I found out that FreeTTS is a good option, I managed to get it work, and it currently prevents the main UI thread from being blocked as I'm running it in a thread.
The only issue is that FreeTTS only lets one voice speak at once (even though they are in multiple threads as multiple instances). Is there a way I can circumvent this and have multiple users' speak at once? This is my code I have so far.
import lombok.extern.slf4j.Slf4j;
import java.beans.PropertyVetoException;
import java.util.Locale;
import java.util.Random;
import java.util.logging.Level;
import java.util.logging.Logger;
import javax.speech.AudioException;
import javax.speech.Central;
import javax.speech.EngineException;
import javax.speech.EngineStateError;
import javax.speech.synthesis.Synthesizer;
import javax.speech.synthesis.SynthesizerModeDesc;
import javax.speech.synthesis.Voice;
@Slf4j
public enum Speech implements SpeechAgent {
Instance;
private static Random pool = new Random();
private static Synthesizer createSynthesizer() {
try {
System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
SynthesizerModeDesc desc = new SynthesizerModeDesc(Locale.US);
Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
Synthesizer synthesizer = Central.createSynthesizer(desc);
synthesizer.allocate();
synthesizer.resume();
Voice[] voices = null;
while (voices == null) {
voices = ((SynthesizerModeDesc) synthesizer.getEngineModeDesc()).getVoices();
}
synthesizer.getSynthesizerProperties().setVoice(voices[pool.nextInt(voices.length)]);
return synthesizer;
} catch (Exception e) {
log.error(String.format("Failed to load synthesizer: %s", e.toString()));
}
return null;
}
public void speak(String input) {
new Thread(new Runnable() {
public void run() {
Synthesizer synthesizer = createSynthesizer();
if (synthesizer == null) {
return;
}
synthesizer.speakPlainText(input.replaceAll("[^a-zA-Z ]+", ""), null);
}
}).start();
}
}
Errors thrown in thread:
Trouble while processing utterance java.lang.IllegalStateException: Syllable relation has already been set
java.lang.IllegalStateException: Syllable relation has already been set
at com.sun.speech.freetts.Segmenter.processUtterance(Segmenter.java:56)
at com.sun.speech.freetts.Voice.runProcessor(Voice.java:595)
at com.sun.speech.freetts.Voice.processUtterance(Voice.java:414)
at com.sun.speech.freetts.Voice.speak(Voice.java:289)
at com.sun.speech.freetts.jsapi.FreeTTSSynthesizer$OutputHandler.outputItem(FreeTTSSynthesizer.java:695)
at com.sun.speech.freetts.jsapi.FreeTTSSynthesizer$OutputHandler.run(FreeTTSSynthesizer.java:622)