2 * Portions Copyright 2001 Sun Microsystems, Inc.
3 * Portions Copyright 1999-2001 Language Technologies Institute,
4 * Carnegie Mellon University.
5 * All Rights Reserved. Use is subject to license terms.
7 * See the file "license.terms" for information on usage and
8 * redistribution of this file, and for a DISCLAIMER OF ALL
11 package com.sun.speech.freetts;
13 import java.io.PrintWriter;
14 import java.io.Serializable;
15 import java.util.Iterator;
16 import java.util.List;
18 import com.sun.speech.freetts.util.SegmentRelationUtils;
21 * Holds all the data for an utterance to be spoken.
22 * It is incrementally modified by various UtteranceProcessor
23 * implementations. An utterance contains a set of Features (essential
24 * a set of properties) and a set of Relations. A Relation is an
25 * ordered set of Item graphs. The utterance contains a set of
26 * features and implements FeatureSet so that applications can set/get
27 * features directly from the utterance. If a feature query is not
28 * found in the utterance feature set, the query is forwarded to the
29 * FeatureSet of the voice associated with the utterance.
31 public class Utterance implements FeatureSet, Serializable {
34 private FeatureSetImpl features;
35 private FeatureSetImpl relations;
36 private boolean first; // first in a connected series
37 private boolean last; // last in a connected series
38 private FreeTTSSpeakable speakable;
41 * Creates a new, empty utterance.
43 * @param voice the voice associated with the utterance
45 public Utterance(Voice voice) {
47 features = new FeatureSetImpl();
48 relations = new FeatureSetImpl();
52 * Creates an utterance with the given set of tokenized text.
54 * @param voice the voice associated with the utterance
55 * @param tokenList the list of tokens for this utterance
57 public Utterance(Voice voice, List tokenList) {
59 setTokenList(tokenList);
63 * Sets the speakable item for this utterance.
65 * @param speakable the speakable item for this utterance
67 public void setSpeakable(FreeTTSSpeakable speakable) {
68 this.speakable = speakable;
72 * Returns the queueitem associated with this utterance.
74 * @return the queue item
76 public FreeTTSSpeakable getSpeakable() {
81 * Creates a new relation with the given name and adds it to this
84 * @param name the name of the new relation
86 * @return the newly created relation
88 public Relation createRelation(String name) {
89 Relation relation = new Relation(name, this);
90 relations.setObject(name, relation);
96 * Retrieves a relation from this utterance.
98 * @param name the name of the Relation
100 * @return the relation or null if the relation is not found
102 public Relation getRelation(String name) {
103 return (Relation) relations.getObject(name);
107 * Determines if this utterance contains a relation with the given
110 * @param name the name of the relation of interest.
112 public boolean hasRelation(String name) {
113 return relations.isPresent(name);
117 * Retrieves the Voice associated with this Utterance.
119 * @return the voice associated with this utterance.
121 public Voice getVoice() {
126 * Dumps this utterance in textual form.
128 * @param output where to send the formatted output
129 * @param pad the initial padding
130 * @param title the title to print when dumping out the utterance
131 * @param justRelations if true don't print voice features
133 public void dump(PrintWriter output, int pad, String title,
134 boolean justRelations) {
135 output.println(" ============ " + title + " ========== ");
136 if (!justRelations) {
137 voice.dump(output, pad + 4, "Voice");
138 features.dump(output, pad + 4, "Features");
140 relations.dump(output, pad + 4, "Relations");
145 * Dumps this utterance in textual form.
147 * @param output where to send the formatted output
148 * @param pad the initial padding
149 * @param title the title to print when dumping out the utterance
151 public void dump(PrintWriter output, int pad, String title) {
152 dump(output, pad, title, false);
156 * Dumps this utterance in textual form.
158 * @param output where to send the formatted output
159 * @param title the title to print when dumping out the utterance
161 public void dump(PrintWriter output, String title) {
162 dump(output, 0, title, false);
166 * Dumps this utterance in textual form.
168 * @param title the title to print when dumping out the utterance
170 public void dump(String title) {
171 dump(new PrintWriter(System.out), 0, title, false);
175 * Dumps the utterance in textual form
176 * @param title the title to print when dumping out the utterance
178 public void dumpRelations(String title) {
179 dump(new PrintWriter(System.out), 0, title, true);
183 * Determines if the given feature is present. If the feature is
184 * not present in the utterance, the feature set of the voice is
187 * @param name the name of the feature of interest
188 * @return true if the named feature is present
190 public boolean isPresent(String name) {
191 if (!features.isPresent(name)) {
192 return getVoice().getFeatures().isPresent(name);
199 * Removes the named feature from this set of features.
201 * @param name the name of the feature of interest
203 public void remove(String name) {
204 features.remove(name);
208 * Convenience method that returns the named feature as a string.
209 * If the named feature is not present in the utterance, then this
210 * attempts to retrieve it from the voice.
212 * @param name the name of the feature
214 * @return the value associated with the name or null if the value
217 * @throws ClassCastException if the associated value is not a
220 public String getString(String name) {
221 if (!features.isPresent(name)) {
222 return getVoice().getFeatures().getString(name);
224 return features.getString(name);
229 * Convenience method that returns the named feature as a int.
230 * If the named feature is not present in the utterance, then this
231 * attempts to retrieve it from the voice.
233 * @param name the name of the feature
235 * @return the value associated with the name or null if the value
238 * @throws ClassCastException if the associated value is not an
241 public int getInt(String name) {
242 if (!features.isPresent(name)) {
243 return getVoice().getFeatures().getInt(name);
245 return features.getInt(name);
250 * Convenience method that returns the named feature as a float.
251 * If the named feature is not present in the utterance, then this
252 * attempts to retrieve it from the voice.
254 * @param name the name of the feature
256 * @return the value associated with the name or null if the value
259 * @throws ClassCastException if the associated value is not a
262 public float getFloat(String name) {
263 if (!features.isPresent(name)) {
264 return getVoice().getFeatures().getFloat(name);
266 return features.getFloat(name);
271 * Returns the named feature as an object.
272 * If the named feature is not present in the utterance, then this
273 * attempts to retrieve it from the voice.
275 * @param name the name of the feature
277 * @return the value associated with the name or null if the value
280 public Object getObject(String name) {
281 if (!features.isPresent(name)) {
282 return getVoice().getFeatures().getObject(name);
284 return features.getObject(name);
289 * Convenience method that sets the named feature as an int.
291 * @param name the name of the feature
292 * @param value the value of the feature
294 public void setInt(String name, int value) {
295 features.setInt(name, value);
299 * Convenience method that sets the named feature as a float.
301 * @param name the name of the feature
302 * @param value the value of the feature
304 public void setFloat(String name, float value) {
305 features.setFloat(name, value);
309 * Convenience method that sets the named feature as a String.
311 * @param name the name of the feature
312 * @param value the value of the feature
314 public void setString(String name, String value) {
315 features.setString(name, value);
319 * Sets the named feature.
321 * @param name the name of the feature
322 * @param value the value of the feature
324 public void setObject(String name, Object value) {
325 features.setObject(name, value);
329 * Returns the Item in the given Relation associated with the given time.
331 * @param relation the name of the relation
332 * @param time the time
334 * @throws IllegalStateException if the Segment durations
335 * have not been calculated in the Utterance or if the
336 * given relation is not present in the Utterance
338 public Item getItem(String relation, float time) {
340 Relation segmentRelation = null;
342 if ((segmentRelation = getRelation(Relation.SEGMENT)) == null) {
343 throw new IllegalStateException
344 ("Utterance has no Segment relation");
347 String pathName = null;
349 if (relation.equals(Relation.SEGMENT)) {
351 } else if (relation.equals(Relation.SYLLABLE)) {
352 pathName = "R:SylStructure.parent.R:Syllable";
353 } else if (relation.equals(Relation.SYLLABLE_STRUCTURE)) {
354 pathName = "R:SylStructure.parent.parent";
355 } else if (relation.equals(Relation.WORD)) {
356 pathName = "R:SylStructure.parent.parent.R:Word";
357 } else if (relation.equals(Relation.TOKEN)) {
358 pathName = "R:SylStructure.parent.parent.R:Token.parent";
359 } else if (relation.equals(Relation.PHRASE)) {
360 pathName = "R:SylStructure.parent.parent.R:Phrase.parent";
362 throw new IllegalArgumentException
363 ("Utterance.getItem(): relation cannot be " + relation);
366 PathExtractor path = new PathExtractorImpl(pathName, false);
368 // get the Item in the Segment Relation with the given time
369 Item segmentItem = SegmentRelationUtils.getItem
370 (segmentRelation, time);
372 if (relation.equals(Relation.SEGMENT)) {
374 } else if (segmentItem != null) {
375 return path.findItem(segmentItem);
382 * Returns the duration of this Utterance in seconds. It does this
383 * by looking at last Item in the following Relations, in this order:
384 * Segment, Target. If none of these Relations exist, or if these
385 * Relations contain no Items, an IllegalStateException will be thrown.
387 * @return the duration of this Utterance in seconds
389 public float getDuration() {
391 if ((duration = getLastFloat(Relation.SEGMENT, "end")) == -1) {
392 if ((duration = getLastFloat(Relation.TARGET, "pos")) == -1) {
393 throw new IllegalStateException
394 ("Utterance: Error finding duration");
401 * Returns the float feature of the last Item in the named
404 * @return the float feature of the last Item in the named Relation,
407 private float getLastFloat(String relationName, String feature) {
410 if ((relation = getRelation(relationName)) != null) {
411 Item lastItem = relation.getTail();
412 if (lastItem != null) {
413 duration = lastItem.getFeatures().getFloat(feature);
421 * Sets the input text for this utterance
423 * @param tokenList the set of tokens for this utterance
426 private void setInputText(List tokenList) {
427 StringBuffer sb = new StringBuffer();
428 for (Iterator i = tokenList.iterator(); i.hasNext(); ) {
429 sb.append(i.next().toString());
431 setString("input_text", sb.toString());
436 * Sets the token list for this utterance. Note that this could be
437 * optimized by turning the token list directly into the token
440 * @param tokenList the tokenList
443 private void setTokenList(List tokenList) {
444 setInputText(tokenList);
446 Relation relation = createRelation(Relation.TOKEN);
447 for (Iterator i = tokenList.iterator(); i.hasNext(); ) {
448 Token token = (Token) i.next();
449 String tokenWord = token.getWord();
451 if (tokenWord != null && tokenWord.length() > 0) {
452 Item item = relation.appendItem();
454 FeatureSet featureSet = item.getFeatures();
455 featureSet.setString("name", tokenWord);
456 featureSet.setString("whitespace", token.getWhitespace());
457 featureSet.setString("prepunctuation",
458 token.getPrepunctuation());
459 featureSet.setString("punc", token.getPostpunctuation());
460 featureSet.setString("file_pos",
461 String.valueOf(token.getPosition()));
462 featureSet.setString("line_number",
463 String.valueOf(token.getLineNumber()));
470 * Returns true if this utterance is the first is a series of
473 * @return true if this is the first utterance in a series of
474 * connected utterances.
476 public boolean isFirst() {
481 * Sets this utterance as the first in a series.
483 * @param first if true, the item is the first in a series
485 public void setFirst(boolean first) {
490 * Returns true if this utterance is the last is a series of
493 * @return true if this is the last utterance in a series of
494 * connected utterances.
496 public boolean isLast() {
501 * Sets this utterance as the last in a series.
503 * @param last if true, the item is the last in a series
505 public void setLast(boolean last) {