7

I am trying to run a program using freetts. I am able to compile the program however I am not able to use kevin or mbrola voices I get the follwing output message at the end

System property "mbrola.base" is undefined. Will not use MBROLA voices.
LINE UNAVAILABLE: Format is pcm_signed 16000.0 Hz 16 bits 1 channel big endian

import javax.speech.*;
import javax.speech.synthesis.*;
import java.util.*;

class freetts {

    public static void main(String[] args) {
        try{ 
            Calendar calendar = new GregorianCalendar();
            String sayTime = "It is " + calendar.get(Calendar.HOUR) + " " + calendar.get(Calendar.MINUTE) + " " + (calendar.get(Calendar.AM_PM)==0 ? "AM":"PM");
            Synthesizer synth = Central.createSynthesizer(null);
            synth.allocate();
            synth.resume();
            synth.speakPlainText(sayTime, null);
            synth.waitEngineState(Synthesizer.QUEUE_EMPTY);
            synth.deallocate();
        }
        catch(Exception e){
            e.printStackTrace();
        }
    }
}
Manindar
  • 999
  • 2
  • 14
  • 30
manugupt1
  • 2,337
  • 6
  • 31
  • 39
  • I have not used this in a long time. But, did you put everything you need in your classpath? Also from what I remember there was something you had to put in your home directory (this was an older version), that could be another reason for a problem (if you still need to do this). Also, there may be other environment variables that you need to set, like did you have to set an MBROLA_HOME variable. Also Have you been able to run any of the sample programs that came with it? Im sorry to keep asking questions, but they help narrow down the problem. – John Kane Mar 21 '10 at 12:22
  • sorry a couple more, the line unavailable exception can be thrown when you are trying to play sounds at the same time, depending on what you did to play the files. Can you show some of the code you are using to play the voice. – John Kane Mar 21 '10 at 12:24
  • We need to copy speech.properties I already did that. However I am not able to bind the mbrola voice interfaces withmy program nor the default kevin speaker however I have included the kevin user in my program 's classpath – manugupt1 Mar 21 '10 at 12:30

4 Answers4

2

It seems that "To enable FreeTTS support for MBROLA, merely copy mbrola/mbrola.jar to lib/mbrola.jar. Then, whenever you run any FreeTTS application, specify the "mbrola.base" directory as a system property:

  java -Dmbrola.base=/home/jim/mbrola -jar bin/FreeTTSHelloWorld.jar mbrola_us1"

I found this at:

http://freetts.sourceforge.net/mbrola/README.html

John Kane
  • 4,383
  • 1
  • 24
  • 42
2

http://workorhobby.blogspot.com/2011/02/java-audio-freetts-line-unavailable.html

A big thanks to the author.


A program based on FreeTTS, the free text-to-speech engine for Java, was getting occasional errors

"LINE UNAVAILABLE: Format is ..."

Turns out there is no Java Exception or other mechanism to detect this error that occurs inside the FreeTTS library. All you get is the message on System.out, so there is no good way to react programatically.

Workaround: Configure the FreeTTS audio player to attempt accessing the audio device more than once until it succeeds. In this example, a short delay of 0.1 seconds is used to not miss an opportunity to grab the audio device; we keep trying for 30 seconds:

System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.openFailDelayMs", "100");
System.setProperty("com.sun.speech.freetts.audio.AudioPlayer.totalOpenFailDelayMs", "30000");

If the audio device is permanently used by another program, there is of course no way to get access. Under Linux, this command will display the ID of the process that is currently holding the audio device, so you can then try to get rid of the offending program:

/sbin/fuser /dev/dsp
Ondra Žižka
  • 43,948
  • 41
  • 217
  • 277
1

The second phrase has nothing to do with mbrola, but with a horrendous java linux sound bug that is still not fixed. Check the third post here: https://forums.oracle.com/forums/thread.jspa?threadID=2206163

That is happening because freetts "trusts" the sourcedataline, instead of doing the workaround on that post. The bug is in the jdk, but can be worked around by finding where in freetts that is happening and inserting the workaround & recompiling.

Here is a testcase

package util.speech;

import java.util.Iterator;
import java.util.Locale;
import javax.sound.sampled.AudioFormat;
import javax.sound.sampled.AudioSystem;
import javax.sound.sampled.DataLine;
import javax.sound.sampled.LineUnavailableException;
import javax.sound.sampled.Mixer;
import javax.sound.sampled.SourceDataLine;
import org.junit.After;
import org.junit.AfterClass;
import org.junit.Assume;
import org.junit.Before;
import org.junit.BeforeClass;
import org.junit.Test;
import static org.junit.Assert.*;

public class VoiceTest {



    public VoiceTest() {
    }

    @BeforeClass
    public static void setUpClass() throws Exception {
    }

    @AfterClass
    public static void tearDownClass() throws Exception {
    }

    @Before
    public void setUp() {

    }

    @After
    public void tearDown() {
    }

    @Test
    public void testDataLineAvailableAndBuggyInJDK() throws LineUnavailableException {
        boolean failedSimpleGetLine = false;
        AudioFormat format = new AudioFormat(44100, 16, 2, true, false);
        SourceDataLine line = null;
        DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
        try {
            line = (SourceDataLine) AudioSystem.getLine(info);
        } catch (LineUnavailableException e) {
            //ok, at least it says so
            throw e;
        }
        try {
            //if this fails the jdk is very buggy, since it just told us
            //the line was available
            line.open(format);
        } catch (LineUnavailableException e) {
            failedSimpleGetLine = true;
        } finally {
            if (line.isOpen()) {
                line.close();
            }
        }



        //now if this is true, test if it's possible to get a valid sourcedataline
        //or the only bug is adquiring a sourcedataline doesn't throw a lineunavailable
        //exception before open
        Assume.assumeTrue(failedSimpleGetLine);
        line = getSourceDataLine(format);
        if (line == null) {
            return;
        }

        try {
            line.open(format);
        } catch (LineUnavailableException e) {
            //ok then it is consistent, and there is only one bug
            fail("Line Unavailable after being adquired");
        } finally {
            if (line.isOpen()) {
                line.close();
            }
        }
        fail("line available after first test not managing to adquire it");
    }


    private SourceDataLine getSourceDataLine(AudioFormat format) {
        try {
            DataLine.Info info = new DataLine.Info(SourceDataLine.class, format);
            for (Mixer.Info mi : AudioSystem.getMixerInfo()) {
                SourceDataLine dataline = null;
                try {
                    Mixer mixer = AudioSystem.getMixer(mi);
                    dataline = (SourceDataLine) mixer.getLine(info);
                    dataline.open(format);
                    dataline.start();
                    return dataline;
                } catch (Exception e) {
                }
                if (dataline != null) {
                    try {
                        dataline.close();
                    } catch (Exception e) {
                    }
                }
            }
        } catch (Exception e) {
        }
        return null;
    }
}
gnat
  • 6,213
  • 108
  • 53
  • 73
i30817
  • 1,356
  • 2
  • 13
  • 26
  • 2
    Oracle screwed that forum link, does someone know where it is now? – Ondra Žižka Feb 17 '11 at 22:00
  • IIRC the workaround was to open the dataline (with try catch finally close). This is needed because some datalines report that they support a format, but when you actually try to open them they blow up. This sucks of course. – i30817 Mar 07 '11 at 06:17
  • screwed forum link was most likely moved to https://forums.oracle.com/forums/thread.jspa?threadID=2206163 – gnat Oct 25 '11 at 22:00
1

I know i am posting it little late, but this may help someone. I tried with both kevin and mbrola, and it worked for me. Please find the code below.

    package com.mani.texttospeech;

import java.beans.PropertyVetoException;
import java.util.Locale;

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;

/**
 *
 * @author Manindar
 */
public class SpeechUtils {

    SynthesizerModeDesc desc;
    Synthesizer synthesizer;
    Voice voice;

    public void init(String voiceName) throws EngineException, AudioException, EngineStateError, PropertyVetoException {
        if (desc == null) {
            System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory");
            desc = new SynthesizerModeDesc(Locale.US);
            Central.registerEngineCentral("com.sun.speech.freetts.jsapi.FreeTTSEngineCentral");
            synthesizer = Central.createSynthesizer(desc);
            synthesizer.allocate();
            synthesizer.resume();
            SynthesizerModeDesc smd = (SynthesizerModeDesc) synthesizer.getEngineModeDesc();
            Voice[] voices = smd.getVoices();
            for (Voice voice1 : voices) {
                if (voice1.getName().equals(voiceName)) {
                    voice = voice1;
                    break;
                }
            }
            synthesizer.getSynthesizerProperties().setVoice(voice);
        }
    }

    public void terminate() throws EngineException, EngineStateError {
        synthesizer.deallocate();
    }

    public void doSpeak(String speakText) throws EngineException, AudioException, IllegalArgumentException, InterruptedException {
        synthesizer.speakPlainText(speakText, null);
        synthesizer.waitEngineState(Synthesizer.QUEUE_EMPTY);
    }

    public static void main(String[] args) throws Exception {
        SpeechUtils su = new SpeechUtils();
        su.init("kevin16");
//        su.init("kevin");
//        su.init("mbrola_us1");
//        su.init("mbrola_us2");
//        su.init("mbrola_us3");
        // high quality
        su.doSpeak("Hi this is Manindar. Welcome to audio world.");
        su.terminate();
    }
}

And add the below dependencies to your pom.xml file.

<dependencies>
        <dependency>
            <groupId>net.sf.sociaal</groupId>
            <artifactId>freetts</artifactId>
            <version>1.2.2</version>
        </dependency>
    </dependencies>

Hope this will be helpful.

Manindar
  • 999
  • 2
  • 14
  • 30
  • Adding line System.setProperty("freetts.voices", "com.sun.speech.freetts.en.us.cmu_us_kal.KevinVoiceDirectory"); And then my code works well, thank so much. – VanThaoNguyen Aug 23 '17 at 20:11