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;
012
013import com.sun.speech.freetts.UtteranceProcessor;
014import com.sun.speech.freetts.Voice;
015import com.sun.speech.freetts.Utterance;
016import com.sun.speech.freetts.Item;
017import com.sun.speech.freetts.Relation;
018import com.sun.speech.freetts.ProcessException;
019import com.sun.speech.freetts.PathExtractorImpl;
020import com.sun.speech.freetts.PathExtractor;
021
022
023/**
024 * Annotates the utterance with post lexical information.
025 */
026public class PostLexicalAnalyzer implements UtteranceProcessor {
027    private static final PathExtractor wordPath =
028        new PathExtractorImpl("R:SylStructure.parent.parent.name", true);
029    private static final PathExtractor P_PH_VC =
030        new PathExtractorImpl("p.ph_vc", true);
031    private static final PathExtractor N_PH_VC =
032        new PathExtractorImpl("n.ph_vc", true);
033
034    /**
035     * Constructs a PostLexicalAnalyzer
036     */
037     public PostLexicalAnalyzer () {
038     }
039
040    /**
041     * Performs the post lexical processing.
042     *
043     * @param  utterance  the utterance to process
044     *
045     * @throws ProcessException if an error occurs while
046     *         processing of the utterance
047     */
048    public void processUtterance(Utterance utterance) throws ProcessException {
049        fixApostrophe(utterance);
050        fixTheIy(utterance);
051    }
052
053    /**
054     * Fixes apostrophe s segments.
055     *
056     * @param utterance the utterance to fix
057     */
058    private void fixApostrophe(Utterance utterance) {
059        Voice voice = utterance.getVoice();
060        for (Item item = utterance.getRelation(Relation.SEGMENT).getHead();
061                item != null;
062                item = item.getNext()) {
063            String word = wordPath.findFeature(item).toString();
064
065            if (word.equals("'s")) {
066
067                String pname = item.getPrevious().toString();
068
069                if (("fa".indexOf(
070                            voice.getPhoneFeature(pname,"ctype")) != -1) &&
071                    ("dbg".indexOf(
072                            voice.getPhoneFeature(pname, "cplace")) == -1)) {
073                    prependSchwa(item);
074                } else  if (voice.getPhoneFeature(pname, "cvox").equals("-")) {
075                    item.getFeatures().setString("name", "s");
076                }
077            } else if (word.equals("'ve") ||
078                       word.equals("'ll") || word.equals("'d")) {
079                if ("-".equals(P_PH_VC.findFeature(item))) {
080                    prependSchwa(item);
081                }
082            }
083        }
084    }
085
086
087    /**
088     * Prepends a schwa to the given item
089     * 
090     * @param item the item to prepend the schwa to.
091     */
092    private static void prependSchwa(Item item) {
093        Item schwa = item.prependItem(null);
094        schwa.getFeatures().setString("name", "ax");
095        item.getItemAs(
096            Relation.SYLLABLE_STRUCTURE).prependItem(schwa);
097    }
098
099
100    /**
101     * Changes the pronunciation of "the" from 'd ax'  to 'd iy' if
102     * the following word starts with a vowel. "The every" is a good
103     * example.
104     *
105     * @param  utterance  the utterance to process
106     */
107    private void fixTheIy(Utterance utterance) {
108        Voice voice = utterance.getVoice();
109        for (Item item = utterance.getRelation(Relation.SEGMENT).getHead();
110                item != null; item = item.getNext()) {
111
112            if ("ax".equals(item.toString())) {
113                String word = wordPath.findFeature(item).toString();
114                if ("the".equals(word) &&
115                        ("+".equals(N_PH_VC.findFeature(item)))) {
116                    item.getFeatures().setString("name", "iy");
117                }
118            }
119        }
120    }
121
122    /**
123     * Returns the string representation of the object
124     *
125     * @return the string representation of the object
126     */
127    public String toString() {
128        return "PostLexicalAnalyzer";
129    }
130}
131