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