]> git.gag.com Git - debian/freetts/blob - de/dfki/lt/freetts/mbrola/MbrolaCaller.java
upstream version 1.2.2
[debian/freetts] / de / dfki / lt / freetts / mbrola / MbrolaCaller.java
1 /**
2  * Copyright 2002 DFKI GmbH.
3  * All Rights Reserved.  Use is subject to license terms.
4  *
5  * See the file "license.terms" for information on usage and
6  * redistribution of this file, and for a DISCLAIMER OF ALL
7  * WARRANTIES.
8  */
9
10 package de.dfki.lt.freetts.mbrola;
11
12 import java.io.BufferedInputStream;
13 import java.io.IOException;
14 import java.io.PrintWriter;
15 import java.util.List;
16
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;
23
24 /**
25  * Calls external MBROLA binary to synthesise the utterance.
26  */
27 public class MbrolaCaller implements UtteranceProcessor {
28
29     private String[] cmd;
30     private long closeDelay = 0l;
31
32     /**
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.
37      */
38     public MbrolaCaller(String[] cmd) {
39         this.cmd = cmd;
40         closeDelay = Utilities.getLong
41                 ("de.dfki.lt.freetts.mbrola.MbrolaCaller.closeDelay",
42                         100L).longValue();
43     }
44
45     /**
46      * Call external MBROLA binary to synthesize the utterance.
47      *
48      * @param  utterance  the utterance to process
49      *
50      * @throws ProcessException if an error occurs while
51      *         processing of the utterance
52      */
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();
57
58         if (segment == null) {
59             return;
60         }
61
62         // Open Mbrola
63         Process process;
64         try {
65             process = Runtime.getRuntime().exec(cmd);
66         } catch (Exception e) {
67             throw new ProcessException("Cannot start mbrola program: " + cmd);
68         }
69         PrintWriter toMbrola = new PrintWriter(process.getOutputStream());
70         BufferedInputStream fromMbrola =
71             new BufferedInputStream(process.getInputStream());
72
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();
86         }
87
88         toMbrola.flush();
89
90         // BUG:
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:
100         //
101         // de.dfki.lt.freetts.mbrola.MbrolaCaller.closeDelay,
102         //
103
104         if (closeDelay > 0l) {
105             try {
106                 Thread.sleep(closeDelay);
107             } catch (InterruptedException ie) {
108             }
109         }
110         toMbrola.close();
111       
112         // reading the audio output
113         byte[] buffer = new byte[1024];
114         
115         // In order to avoid resizing a large array, we save the audio data
116         // in the chunks in which we read it.
117
118         List audioData = new java.util.ArrayList();
119         int totalSize = 0;
120         int nrRead = -1; // -1 means end of file
121
122         try {
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);
128                 } else {
129                     audioData.add(buffer);
130                     buffer = new byte[buffer.length];
131                 }
132                 totalSize += nrRead;
133             }
134             fromMbrola.close();
135         } catch (IOException e) {
136             throw new ProcessException("Cannot read from mbrola");
137         }
138
139         if (totalSize == 0) {
140             throw new ProcessException("No audio data read");
141         }
142
143         utterance.setObject("mbrolaAudio", audioData);
144         utterance.setInt("mbrolaAudioLength", totalSize);
145     }
146
147     public String toString() {
148         return "MbrolaCaller";
149     }
150 }