1

I am working on a project where I needed Text to speech conversion. I Downloaded this FreeTTS 1.2 and to get familiar with the working I started making a simple spell bee program where the words will be spoken by the application and you have to spell it correctly. But I'm facing problems with functions like the voice is same irrespective of the changes I make. Like the initially the code I found had following parameters in the Voice() constructor

Voice kevin = new Voice("kevin", 
    Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null);

but then I changed it to

Voice kevin = new Voice("Different1", 
        Voice.GENDER_FEMALE, Voice.AGE_MIDDLE_ADULT, null);

and still the voice is same. There is a speech.properties file which came with FreeTTS and to run the code I have to paste that file in my home folder. I have searched a lot of links to solve this even checked the Javadocs for JSAPI and FreeTTS. The only thing I got in common was something called MBrola. I don't what this is but when I run the code, the console also gives a message related to it.

System property "mbrola.base" is undefined.  Will not use MBROLA voices.

Here's is the whole code:

package game;

    import java.beans.PropertyChangeEvent;
import java.beans.PropertyChangeListener;
import java.io.File;
import java.util.Locale;

import javax.speech.Central;
import javax.speech.synthesis.SpeakableAdapter;
import javax.speech.synthesis.SpeakableEvent;
import javax.speech.synthesis.Synthesizer;
import javax.speech.synthesis.SynthesizerModeDesc;
import javax.speech.synthesis.Voice;

public class MixedVoices {

    private final static void usage() {
    System.out.println("MixedVoices [-showEvents] [-showPropertyChanges]");
    }

    /**
    * Returns a "no synthesizer" message, and asks 
    * the user to check if the "speech.properties" file is
    * at <code>user.home</code> or <code>java.home/lib</code>.
    *
    * @return a no synthesizer message
    */
    static private String noSynthesizerMessage(String synthesizer)
    {
        String message =
            "Cannot find " + synthesizer + ".\n" +
            "This may be the result of any number of problems.  It's\n" +
            "typically due to a missing \"speech.properties\" file that\n" +
            "should be at either of these locations: \n\n";
        message += "user.home    : " + System.getProperty("user.home") + "\n";
        message += "java.home/lib: " + System.getProperty("java.home") +
        File.separator + "lib\n\n" +
            "Another cause of this problem might be corrupt or missing\n" +
            "voice jar files in the freetts lib directory.  This problem\n" +
            "also sometimes arises when the freetts.jar file is corrupt\n" +
            "or missing.  Sorry about that.  Please check for these\n" +
            "various conditions and then try again.\n";
        return message;
    }

    public static void main(String[] argv) 
    {
        boolean showEvents = false;
        boolean showPropertyChanges = false;

        for (int i = 0; i < argv.length; i++) 
        {
            if (argv[i].equals("-showEvents")) {
                showEvents = true;
        } else if (argv[i].equals("-showPropertyChanges")) {
        showPropertyChanges = true;
        } else {
        usage();
        System.exit(0);
        }
    }

    System.out.println(" ** Mixed Voices - JSAPI Demonstration program **");
        /* kevin in an 8khz general domain diphone voice
        */
    Voice kevin = new Voice("kevin", 
        Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null);

        /* kevin16 in a 16khz general domain diphone voice
        */
    Voice kevinHQ = new Voice("kevin16", 
        Voice.GENDER_DONT_CARE, Voice.AGE_DONT_CARE, null);

    try {
        /* Find a synthesizer that has the general domain voice
            * we are looking for.  NOTE:  this uses the Central class
            * of JSAPI to find a Synthesizer.  The Central class
            * expects to find a speech.properties file in user.home
            * or java.home/lib.
            *
            * If your situation doesn't allow you to set up a
            * speech.properties file, you can circumvent the Central
            * class and do a very non-JSAPI thing by talking to
            * FreeTTSEngineCentral directly.  See the WebStartClock
            * demo for an example of how to do this.
            */
        SynthesizerModeDesc generalDesc = new SynthesizerModeDesc(
        null,          // engine name
                "general",     // mode name
                Locale.US,     // locale
                null,          // running
                null);         // voice

        final Synthesizer synthesizer1 =
                Central.createSynthesizer(generalDesc);

        if (synthesizer1 == null) {
        System.err.println(
                    noSynthesizerMessage("general domain synthesizer"));
        System.exit(1);
        }

        /* Find a synthesizer that has the time domain voice.
        */
        SynthesizerModeDesc limitedDesc = new SynthesizerModeDesc(
                null,          // engine name
                "time",        // mode name
                Locale.US,     // locale
                null,          // running
                null);         // voice

        final Synthesizer synthesizer2 =
                Central.createSynthesizer(limitedDesc);

        if (synthesizer2 == null) {
        System.err.println(
                    noSynthesizerMessage("time domain synthesizer"));
        System.exit(1);
        }

        System.out.print("  Allocating synthesizers...");
        synthesizer1.allocate();
        synthesizer2.allocate();

        /* get general domain synthesizer ready to speak
            */
        System.out.print("Loading voices...");
        synthesizer1.getSynthesizerProperties().setVoice(kevinHQ);
        synthesizer1.getSynthesizerProperties().setVoice(kevin);

        if (showPropertyChanges) {
        synthesizer1.getSynthesizerProperties().addPropertyChangeListener(
                    new PropertyChangeListener() {
                        public void propertyChange(
                            PropertyChangeEvent pce) {
                            if (pce.getNewValue() instanceof Voice) {
                                String newVoice = 
                                    ((Voice) pce.getNewValue()).getName();
                                    System.out.println(
                                        "  PCE Voice changed to " + newVoice);
                            }
                            else {
                                System.out.println(
                                    "  PCE " + pce.getPropertyName()
                                    + " changed from " 
                                    + pce.getOldValue() + " to " +
                                    pce.getNewValue() + ".");
                            }
            }
            });
        }

        if (showEvents) {
        synthesizer1.addSpeakableListener(
            new SpeakableAdapter() {
            public void markerReached(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void speakableCancelled(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void speakableEnded(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void speakablePaused(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void speakableResumed(SpeakableEvent e) {
            dumpEvent(e);
            }
            public void speakableStarted(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void topOfQueue(SpeakableEvent e) {
                dumpEvent(e);
            }
            public void wordStarted(SpeakableEvent e) {
                dumpEvent(e);
            }
            private void dumpEvent(SpeakableEvent e) {
            System.out.println(" EVT: " + e.paramString() 
                                            + " source: " + e.getSource());
        }   
            });
        }

        System.out.println("And here we go!");
        synthesizer1.resume();
        synthesizer2.resume();

        // speak the "Hello world" string
        synthesizer1.speakPlainText("Hello! My name is Kevin.", null);
        synthesizer1.speakPlainText("I am a die phone synthesizer", null);
        synthesizer1.speakPlainText("I have a friend named Alan.", null);
        synthesizer1.speakPlainText("Listen to him count!", null);

        // get synth2 ready to speak
    synthesizer2.waitEngineState(Synthesizer.ALLOCATED);
        synthesizer2.resume();

        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);
        synthesizer2.speakPlainText("1 2 3 4 5 6 7 8 9 ten", null);

        synthesizer2.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText("Now listen to me count!", null);
        synthesizer1.speakPlainText("1 2 3 4 5 6 7 8 9 10.", null);

        synthesizer1.speakPlainText(
            "Now, let's try that a little bit faster.", null);
    synthesi    zer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

    synthesizer1.getSynthesizerProperties().setSpeakingRate(240.0f);
        synthesizer1.speakPlainText("1 2 3 4 5 6 7 8 9 10.", null);
        synthesizer1.speakPlainText("That's pretty fast.", null);
        synthesizer1.speakPlainText("Now lets go very slow.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.getSynthesizerProperties().setSpeakingRate(80.0f);
        synthesizer1.speakPlainText("1 2 3 4 5 6 7 8 9 10.", null);
        synthesizer1.speakPlainText("That is pretty slow.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

    synthesizer1.getSynthesizerProperties().setSpeakingRate(150.0f);
        synthesizer1.speakPlainText("Now back to normal", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.getSynthesizerProperties().setPitch(200);
        synthesizer1.speakPlainText("I can talk very high.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.getSynthesizerProperties().setPitch(50);
        synthesizer1.speakPlainText("and I can talk very low.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.getSynthesizerProperties().setPitch(100);
    synthesizer1.getSynthesizerProperties().setVolume(.8f);
        synthesizer1.speakPlainText("and I can talk very softly.", null);
    synt    hesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.getSynthesizerProperties().setVolume(1.0f);
        synthesizer1.speakPlainText(
        "I can talk with a higher quality voice", null);
        synthesizer1.speakPlainText(
            "Here is a low quality tongue twister. "
            + "She sells seashells by the seashore.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

    synthesizer1.getSynthesizerProperties().setVoice(kevinHQ);
        synthesizer1.speakPlainText("And this is high quality. "
            + "She sells seashells by the seashore.", null);
        synthesizer1.speakPlainText(
            "The funny thing is, I do not have a tongue.", null);
        synthesizer1.speakPlainText(
        "Hey Alan, what time is it where you are right now?", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer2.speakPlainText(
            "the time is now twenty past six.", null);
        synthesizer2.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText("Is that the exact time?", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer2.speakPlainText("Almost", null);
    synthesizer2.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText(
        "Is it twenty past six In the morning or the evening?", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer2.speakPlainText("in the morning.", null);
        synthesizer2.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText(
        "Alan and I can talk at the same time", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText("1 2 3 4 5 6 7 8 9 11 12", null);
        synthesizer2.speakPlainText("1 2 3 4 5 6 7 8 9", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);
        synthesizer2.waitEngineState(Synthesizer.QUEUE_EMPTY);

        synthesizer1.speakPlainText( "That is a bit confusing.", null);
        synthesizer1.speakPlainText( "Well, thanks. This was fun.", null);
        synthesizer1.speakPlainText("Goodbye everyone.", null);
        synthesizer1.waitEngineState(Synthesizer.QUEUE_EMPTY);

        // clean up
        synthesizer1.deallocate();
        synthesizer2.deallocate();
    }
    catch (Exception e) {
        e.printStackTrace();
    }

    System.exit(0);
    }
}
halfer
  • 19,824
  • 17
  • 99
  • 186

1 Answers1

1

The voices that you have access to is controlled by the VoiceManager class. It will search for voice packages installed in your system via a couple of different methods. By default you will have 3 voices installed: "alan", "kevin", and "kevin16". You need to install other voice packages (e.g. CMUArctic or MBROLA) before you can use voices other than the 3 default voices.

However, once you've installed a new voice (look at the corresponding websites for install instructions), you will also need to add that Voice Directory to the correct place, and add its name to a text file that lists all installed voices. Take a look at the Programmer's Guide under Installing Voice Packages. For reference, I ended up adding my new voice package paths to the voices.txt file next to the freetts.jar that I was using (which was a bit ttricky- I forgot I had added it to my Library/Java/Extensions folder on my Mac, so you may have to add the voices.txt file there).

You can check which voice are available with the following code:

VoiceManager voiceManager = VoiceManager.getInstance();
Voice[] voices = voiceManager.getVoices();
for (int i = 0; i < voices.length; i++){
    System.out.print( "voice name is: " + voices[i].getName() +"\n");
}

Once you've successfully added the Voice Directories for the voices you've installed, you should see them listed when you run that code.