2 * Copyright 2002 DFKI GmbH.
3 * All Rights Reserved. Use is subject to license terms.
5 * See the file "license.terms" for information on usage and
6 * redistribution of this file, and for a DISCLAIMER OF ALL
10 package de.dfki.lt.freetts.mbrola;
12 import java.io.BufferedInputStream;
13 import java.io.IOException;
14 import java.io.PrintWriter;
15 import java.util.List;
17 import com.sun.speech.freetts.Item;
18 import com.sun.speech.freetts.ProcessException;
19 import com.sun.speech.freetts.Relation;
20 import com.sun.speech.freetts.Utterance;
21 import com.sun.speech.freetts.UtteranceProcessor;
22 import com.sun.speech.freetts.util.Utilities;
25 * Calls external MBROLA binary to synthesise the utterance.
27 public class MbrolaCaller implements UtteranceProcessor {
30 private long closeDelay = 0l;
33 * Create an Mbrola caller which will call an external MBROLA binary
34 * using the command <code>cmd</code>. The command string is used
35 * as it is, which means that it must contain full path specifications
36 * and the correct file separators.
38 public MbrolaCaller(String[] cmd) {
40 closeDelay = Utilities.getLong
41 ("de.dfki.lt.freetts.mbrola.MbrolaCaller.closeDelay",
46 * Call external MBROLA binary to synthesize the utterance.
48 * @param utterance the utterance to process
50 * @throws ProcessException if an error occurs while
51 * processing of the utterance
53 public void processUtterance(Utterance utterance) throws ProcessException {
54 // Go through Segment relation and print values into Mbrola
55 Relation segmentRelation = utterance.getRelation(Relation.SEGMENT);
56 Item segment = segmentRelation.getHead();
58 if (segment == null) {
65 process = Runtime.getRuntime().exec(cmd);
66 } catch (Exception e) {
67 throw new ProcessException("Cannot start mbrola program: " + cmd);
69 PrintWriter toMbrola = new PrintWriter(process.getOutputStream());
70 BufferedInputStream fromMbrola =
71 new BufferedInputStream(process.getInputStream());
73 while (segment != null) {
74 String name = segment.getFeatures().getString("name");
75 // Individual duration of segment, in milliseconds:
76 int dur = segment.getFeatures().getInt("mbr_dur");
77 // List of time-f0 targets. In each target, the first value
78 // indicates where on the time axis the target is reached,
79 // expressed in percent of segment duration; the second value in
80 // each pair is f0, in Hz.
81 String targets = segment.getFeatures().getString("mbr_targets");
82 String output = (name + " " + dur + " " + targets);
83 // System.out.println(output);
84 toMbrola.println(output);
85 segment = segment.getNext();
91 // There is a bug that causes the final 'close' on a stream
92 // going to a sub-process to not be seen by the sub-process on
93 // occasion. This seems to occur mainly when the close occurs
94 // very soon after the creation and writing of data to the
95 // sub-process. This delay can help work around the problem
96 // If we delay before the close by
97 // a small amount (100ms), the hang is averted. This is a WORKAROUND
98 // only and should be removed once the bug in the 'exec' is
99 // fixed. We get the delay from the property:
101 // de.dfki.lt.freetts.mbrola.MbrolaCaller.closeDelay,
104 if (closeDelay > 0l) {
106 Thread.sleep(closeDelay);
107 } catch (InterruptedException ie) {
112 // reading the audio output
113 byte[] buffer = new byte[1024];
115 // In order to avoid resizing a large array, we save the audio data
116 // in the chunks in which we read it.
118 List audioData = new java.util.ArrayList();
120 int nrRead = -1; // -1 means end of file
123 while ((nrRead = fromMbrola.read(buffer)) != -1) {
124 if (nrRead < buffer.length) {
125 byte[] slice = new byte[nrRead];
126 System.arraycopy(buffer, 0, slice, 0, nrRead);
127 audioData.add(slice);
129 audioData.add(buffer);
130 buffer = new byte[buffer.length];
135 } catch (IOException e) {
136 throw new ProcessException("Cannot read from mbrola");
139 if (totalSize == 0) {
140 throw new ProcessException("No audio data read");
143 utterance.setObject("mbrolaAudio", audioData);
144 utterance.setInt("mbrolaAudioLength", totalSize);
147 public String toString() {
148 return "MbrolaCaller";