001/**
002 * Portions Copyright 2001 Sun Microsystems, Inc.
003 * Portions Copyright 1999-2001 Language Technologies Institute, 
004 * Carnegie Mellon University.
005 * All Rights Reserved.  Use is subject to license terms.
006 * 
007 * See the file "license.terms" for information on usage and
008 * redistribution of this file, and for a DISCLAIMER OF ALL 
009 * WARRANTIES.
010 */
011package com.sun.speech.freetts.en.us;
012
013import com.sun.speech.freetts.diphone.DiphonePitchmarkGenerator;
014import com.sun.speech.freetts.diphone.DiphoneUnitSelector;
015import com.sun.speech.freetts.Item;
016import com.sun.speech.freetts.ProcessException;
017import com.sun.speech.freetts.Relation;
018import com.sun.speech.freetts.relp.UnitConcatenator;
019import com.sun.speech.freetts.Utterance;
020import com.sun.speech.freetts.UtteranceProcessor;
021import com.sun.speech.freetts.Voice;
022
023import com.sun.speech.freetts.Gender;
024import com.sun.speech.freetts.Age;
025
026import de.dfki.lt.freetts.ConcatenativeVoice;
027
028import java.util.Locale;
029
030import java.io.IOException;
031
032import java.net.URL;
033
034
035/**
036 * Defines an unlimited-domain diphone synthesis based voice 
037 */
038public class CMUDiphoneVoice extends CMUVoice implements ConcatenativeVoice {
039
040    protected URL database;
041
042    /**
043     * Creates a simple voice.  This is merely for backwards
044     * compatibility with versions of FreeTTS earlier than v1.2
045     * (i.e., before the voice manager was introduced).
046     */
047    public CMUDiphoneVoice() {
048        this(null, null, null, null, null, null, null, null, null);
049    }
050    
051    /**
052     * Creates a simple voice
053     *
054     * @param name the name of the voice
055     * @param gender the gender of the voice
056     * @param age the age of the voice
057     * @param description a human-readable string providing a
058     * description that can be displayed for the users.
059     * @param locale the locale of the voice
060     * @param domain the domain of this voice.  For example,
061     * @param organization the organization which created the voice
062     * "general", "time", or
063     * "weather".
064     * @param lexicon the lexicon to load
065     * @param database a url to the unit database file for this voice
066     */
067    public CMUDiphoneVoice(String name, Gender gender,
068            Age age, String description, Locale locale, String domain,
069            String organization, CMULexicon lexicon, URL database) {
070        super(name, gender, age, description, locale,
071                domain, organization, lexicon);
072        setRate(150f);
073        setPitch(100F);
074        setPitchRange(11F);
075        this.database = database;
076    }
077
078    /**
079     * Gets the url to the database that defines the unit data for this
080     * voice.
081     *
082     * @return a url to the database
083     */
084    public URL getDatabase() {
085        if (database == null) {
086            /* This is merely for backwards compatibility with
087             * versions of FreeTTS earlier than v1.2 (i.e.,
088             * before the voice manager was introduced).
089             */
090            String name = getFeatures().getString(Voice.DATABASE_NAME);
091            database = this.getClass().getResource(name);
092        }
093        return database;
094    }
095
096    /**
097     * Sets the FeatureSet for this Voice.
098     *
099     * @throws IOException if an I/O error occurs
100     */
101    protected void setupFeatureSet() throws IOException {
102        super.setupFeatureSet();
103    }
104
105    /**
106     * Returns the post lexical processor to be used by this voice.
107     * Derived voices typically override this to customize behaviors.
108     * 
109     * @return the Unit selector
110     * 
111     * @throws IOException if an IO error occurs while getting
112     *     processor
113     */
114    protected UtteranceProcessor getPostLexicalAnalyzer() throws IOException {
115        return new CMUDiphoneVoicePostLexicalAnalyzer();
116    }
117
118    /**
119     * Returns the pitch mark generator to be used by this voice.
120     * Derived voices typically override this to customize behaviors.
121     * This voice uses a DiphonePitchMark generator to generate
122     * pitchmarks.
123     * 
124     * @return the pitchmark processor
125     * 
126     * @throws IOException if an IO error occurs while getting
127     *     processor
128     */
129    public UtteranceProcessor getPitchmarkGenerator() throws IOException {
130        return new DiphonePitchmarkGenerator();
131    }
132
133    /**
134     * Returns the unit concatenator to be used by this voice.
135     * Derived voices typically override this to customize behaviors.
136     * This voice uses a relp.UnitConcatenator to concatenate units.
137     * 
138     * @return the unit concatenator processor
139     * 
140     * @throws IOException if an IO error occurs while getting
141     *     processor
142     */
143    public UtteranceProcessor getUnitConcatenator() throws IOException {
144        return new UnitConcatenator();
145    }
146
147
148    /**
149     * Returns the unit selector to be used by this voice.
150     * Derived voices typically override this to customize behaviors.
151     * This voice uses the DiphoneUnitSelector to select units. The
152     * unit selector requires the name of a diphone database. If no
153     * diphone database has been specified then an Error is thrown.
154     * 
155     * @return the unit selector processor
156     * 
157     * @throws IOException if an IO error occurs while getting
158     *     processor
159     */
160    public UtteranceProcessor getUnitSelector() throws IOException {
161        return new DiphoneUnitSelector(getDatabase());
162    }
163
164    
165    /**
166     * Converts this object to a string
167     * 
168     * @return a string representation of this object
169     */
170    public String toString() {
171        return "CMUDiphoneVoice";
172    }
173}
174
175
176/**
177 * Annotates the utterance with post lexical information. Converts AH
178 * phonemes to AA phoneme in addition to the standard english postlex
179 * processing.
180 */
181class CMUDiphoneVoicePostLexicalAnalyzer implements UtteranceProcessor {
182    UtteranceProcessor englishPostLex =
183        new com.sun.speech.freetts.en.PostLexicalAnalyzer();
184
185    /**
186     * performs the processing
187     * @param  utterance  the utterance to process/tokenize
188     * @throws ProcessException if an IOException is thrown during the
189     *         processing of the utterance
190     */
191    public void processUtterance(Utterance utterance) throws ProcessException {
192        fixPhoneme_AH(utterance);
193        englishPostLex.processUtterance(utterance);
194    }
195
196
197    /**
198     * Turns all AH phonemes into AA phonemes.
199     * This should really be done in the index itself
200     * @param utterance the utterance to fix
201     */
202    private void fixPhoneme_AH(Utterance utterance) {
203        for (Item item = utterance.getRelation(Relation.SEGMENT).getHead();
204                item != null;
205                item = item.getNext()) {
206            if (item.getFeatures().getString("name").equals("ah")) {
207                item.getFeatures().setString("name", "aa");
208            }
209        }
210    }
211
212    // inherited from Object
213    public String toString() {
214        return "PostLexicalAnalyzer";
215    }
216}