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.util.ArrayList;
14 import java.util.List;
16 import com.sun.speech.freetts.lexicon.Lexicon;
19 * Annotates an utterance with <code>Relation.SYLLABLE</code>,
20 * <code>Relation.SYLLABLE_STRUCTURE</code>, and
21 * <code>Relation.SEGMENT</code>.
22 * To determine stress, the <code>isStressed</code> method relies upon
23 * a phone ending in the number "1". Subclasses should override
24 * <code>isStressed</code> and <code>deStress</code> if stresses are
25 * determined in other ways.
27 * @see Relation#SEGMENT
28 * @see Relation#SYLLABLE
29 * @see Relation#SYLLABLE_STRUCTURE
31 public class Segmenter implements UtteranceProcessor {
32 private final static String STRESS = "1";
33 private final static String NO_STRESS = "0";
36 * Annotates an utterance with <code>Relation.SYLLABLE</code>,
37 * <code>Relation.SYLLABLE_STRUCTURE</code>, and
38 * <code>Relation.SEGMENT</code>.
40 * @param utterance the utterance to process/tokenize
42 * @see Relation#SEGMENT
43 * @see Relation#SYLLABLE
44 * @see Relation#SYLLABLE_STRUCTURE
46 * @throws ProcessException if an IOException is thrown during the
47 * processing of the utterance
49 public void processUtterance(Utterance utterance) throws ProcessException {
52 if (utterance.getRelation(Relation.WORD) == null) {
53 throw new IllegalStateException(
54 "Word relation has not been set");
55 } else if (utterance.getRelation(Relation.SYLLABLE) != null) {
56 throw new IllegalStateException(
57 "Syllable relation has already been set");
58 } else if (utterance.getRelation(Relation.SYLLABLE_STRUCTURE)
60 throw new IllegalStateException(
61 "SylStructure relation has already been set");
62 } else if (utterance.getRelation(Relation.SEGMENT) != null) {
63 throw new IllegalStateException(
64 "Segment relation has already been set");
67 String stress = NO_STRESS;
68 Relation syl = utterance.createRelation(Relation.SYLLABLE);
69 Relation sylstructure =
70 utterance.createRelation(Relation.SYLLABLE_STRUCTURE);
71 Relation seg = utterance.createRelation(Relation.SEGMENT);
72 Lexicon lex = utterance.getVoice().getLexicon();
73 List syllableList = null;
75 for (Item word = utterance.getRelation(Relation.WORD).getHead();
76 word != null; word = word.getNext()) {
77 Item ssword = sylstructure.appendItem(word);
78 Item sylItem = null; // item denoting syllable boundaries
79 Item segItem = null; // item denoting phonelist (segments)
80 Item sssyl = null; // item denoting syl in word
82 String[] phones = null;
84 Item token = word.getItemAs("Token");
85 FeatureSet featureSet = null;
88 Item parent = token.getParent();
89 featureSet = parent.getFeatures();
92 if (featureSet != null && featureSet.isPresent("phones")) {
93 phones = (String[]) featureSet.getObject("phones");
95 phones = lex.getPhones(word.toString(), null);
98 for (int j = 0; j < phones.length; j++) {
99 if (sylItem == null) {
100 sylItem = syl.appendItem();
101 sssyl = ssword.addDaughter(sylItem);
103 syllableList = new ArrayList();
105 segItem = seg.appendItem();
106 if (isStressed(phones[j])) {
108 phones[j] = deStress(phones[j]);
110 segItem.getFeatures().setString("name", phones[j]);
111 sssyl.addDaughter(segItem);
112 syllableList.add(phones[j]);
113 if (lex.isSyllableBoundary(syllableList, phones, j + 1)) {
116 sssyl.getFeatures().setString("stress", stress);
124 * Determines if the given phonemene is stressed.
125 * To determine stress, this method relies upon
126 * a phone ending in the number "1". Subclasses should override this
127 * method if stresses are determined in other ways.
129 * @param phone the phone to check
131 * @return true if the phone is stressed, otherwise false
133 protected boolean isStressed(String phone) {
134 return phone.endsWith("1");
138 * Converts stressed phoneme to regular phoneme. This method
139 * merely removes the last character of the phone. Subclasses
140 * should override this if another method is to be used.
142 * @param phone the phone to convert
144 * @return de-stressed phone
146 protected String deStress(String phone) {
147 String retPhone = phone;
148 if (isStressed(phone)) {
149 retPhone = phone.substring(0, phone.length() - 1);
155 * Returns the simple name of this class.
157 * @return the simple name of this class
159 public String toString() {