1 /*************************************************************************/
2 /*                                                                       */
3 /*                Centre for Speech Technology Research                  */
4 /*                     University of Edinburgh, UK                       */
5 /*                       Copyright (c) 1996,1997                         */
6 /*                        All Rights Reserved.                           */
7 /*                                                                       */
8 /*  Permission is hereby granted, free of charge, to use and distribute  */
9 /*  this software and its documentation without restriction, including   */
10 /*  without limitation the rights to use, copy, modify, merge, publish,  */
11 /*  distribute, sublicense, and/or sell copies of this work, and to      */
12 /*  permit persons to whom this work is furnished to do so, subject to   */
13 /*  the following conditions:                                            */
14 /*   1. The code must retain the above copyright notice, this list of    */
15 /*      conditions and the following disclaimer.                         */
16 /*   2. Any modifications must be clearly marked as such.                */
17 /*   3. Original authors' names are not deleted.                         */
18 /*   4. The authors' names are not used to endorse or promote products   */
19 /*      derived from this software without specific prior written        */
20 /*      permission.                                                      */
21 /*                                                                       */
22 /*  THE UNIVERSITY OF EDINBURGH AND THE CONTRIBUTORS TO THIS WORK        */
23 /*  DISCLAIM ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, INCLUDING      */
24 /*  ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS, IN NO EVENT   */
25 /*  SHALL THE UNIVERSITY OF EDINBURGH NOR THE CONTRIBUTORS BE LIABLE     */
26 /*  FOR ANY SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES    */
27 /*  WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN   */
28 /*  AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION,          */
29 /*  ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF       */
30 /*  THIS SOFTWARE.                                                       */
31 /*                                                                       */
32 /*************************************************************************/
33 /*                      Author :  Alan W Black                           */
34 /*                      Date   :  April 1996                             */
35 /*-----------------------------------------------------------------------*/
36 /*                                                                       */
37 /* From words to syllables and segments using the lexicon                */
38 /*                                                                       */
39 /*=======================================================================*/
40 
41 #include <cstdio>
42 #include "festival.h"
43 #include "lexicon.h"
44 #include "modules.h"
45 
46 static EST_Item *add_syllable(EST_Utterance *u, int stress);
47 static LISP specified_word_pronunciation(EST_Item *w, LISP lpos);
48 
FT_Classic_Word_Utt(LISP utt)49 LISP FT_Classic_Word_Utt(LISP utt)
50 {
51     // Look up words in lexicon and create syllable and segment streams
52     EST_Utterance *u = get_c_utt(utt);
53     EST_Item *w;
54     LISP entry,s,p,lpos;
55     EST_String pos;
56     EST_Item *syl,*seg;
57     EST_Relation *SylStructure;
58 
59     *cdebug << "Word module\n";
60 
61     u->create_relation("Syllable");
62     u->create_relation("Segment");
63     SylStructure = u->create_relation("SylStructure");
64 
65     for (w=u->relation("Word")->first(); w != 0; w = w->next())
66     {
67 	lpos = NIL;
68 	pos = (EST_String)ffeature(w,"hg_pos");
69                         // explicit homograph pos disambiguation
70 	if (pos == "0")
71 	    pos = (EST_String)ffeature(w,"pos");
72 	if (pos != "0")
73 	    lpos = rintern(pos);
74 
75 	//  Check if there is an explicitly given pronunciation before
76 	//  going to the lexicon
77 	if ((entry = specified_word_pronunciation(w,lpos)) == NIL)
78 	    entry = lex_lookup_word(w->name(),lpos);
79 	if (lpos == NIL)
80 	    w->set("pos",get_c_string(car(cdr(entry))));
81 	SylStructure->append(w);
82 	for (s=car(cdr(cdr(entry))); s != NIL; s=cdr(s))
83 	{
84 	    syl = add_syllable(u,get_c_int(car(cdr(car(s)))));
85 	    append_daughter(w,"SylStructure",syl);
86 	    for (p=car(car(s)); p != NIL; p=cdr(p))
87 	    {
88 		seg = add_segment(u,get_c_string(car(p)));
89 		append_daughter(syl,"SylStructure",seg);
90 	    }
91 	}
92     }
93 
94     return utt;
95 }
96 
FT_Unilex_Word_Utt(LISP utt)97 LISP FT_Unilex_Word_Utt(LISP utt)
98 {
99   // This tries to be a bit cleverer than Classic_Word in dealing with full and reduced forms of words.
100   // Look up words in lexicon and create syllable and segment streams
101     EST_Utterance *u = get_c_utt(utt);
102     EST_Item *w;
103     LISP entry,entry2,s,p,s2,p2,lpos,lexpos;
104     EST_String pos, vowel_form,sname,s2name;
105     EST_Item *syl,*seg;
106     EST_Relation *SylStructure;
107 
108     *cdebug << "Word module\n";
109 
110     u->create_relation("Syllable");
111     u->create_relation("Segment");
112     SylStructure = u->create_relation("SylStructure");
113 
114     for (w=u->relation("Word")->first(); w != 0; w = w->next())
115     {
116 	lpos = NIL;
117 	pos = EST_String(ffeature(w,"hg_pos"));
118                         // explicit homograph pos disambiguation
119 	if (pos == "0")
120 	    pos = EST_String(ffeature(w,"pos"));
121 	if (pos != "0")
122 	    lpos = rintern(pos);
123 
124 	//  Check if there is an explicitly given pronunciation before
125 	//  going to the lexicon
126 	if ((entry = specified_word_pronunciation(w,lpos)) == NIL)
127 	    entry = lex_lookup_word(w->name(),lpos);
128 	lexpos = car(cdr(entry));
129 	// deal with full/reduced specification in pos as a list.
130 	entry2 = NIL;
131 	if (! atomp(lexpos))
132 	  {
133 	    if ( (vowel_form = get_c_string(car(cdr(lexpos)))) == "full")
134 	      {
135 		entry2 = lex_lookup_word(w->name(),cons(rintern("reduced"),NIL));
136 		if (lpos == NIL)
137 		  w->set("pos",get_c_string(car(lexpos)));
138 	      }
139 	  }
140 	else if (lpos == NIL)
141 	  w->set("pos",get_c_string(lexpos));
142 	SylStructure->append(w);
143 	if (entry2) // compare full and reduced form entries
144 	  for (s=car(cdr(cdr(entry))),s2=car(cdr(cdr(entry2))) ; s != NIL; s=cdr(s))
145 	    {
146 	      syl = add_syllable(u,get_c_int(car(cdr(car(s)))));
147 	      append_daughter(w,"SylStructure",syl);
148 	      for (p=car(car(s)),p2=car(car(s2)); p != NIL; p=cdr(p))
149 		{
150 		  seg = add_segment(u,get_c_string(car(p)));
151 		  append_daughter(syl,"SylStructure",seg);
152 
153 		  if(p2 != NIL)
154 		    {
155 		      sname = get_c_string(car(p));
156 		      s2name = get_c_string(car(p2));
157 		      if (sname != s2name)
158 			{
159 			  seg->set("reducable",1);
160 			  seg->set("fullform",sname);
161 			  seg->set("reducedform",s2name);
162 			}
163 		      p2=cdr(p2);
164 		    }
165 		}
166 	      if(s2 != NIL)
167 		s2 = cdr(s2);
168 	  }
169 	else
170 	  for (s=car(cdr(cdr(entry))); s != NIL; s=cdr(s))
171 	    {
172 	      syl = add_syllable(u,get_c_int(car(cdr(car(s)))));
173 	      append_daughter(w,"SylStructure",syl);
174 	      for (p=car(car(s)); p != NIL; p=cdr(p))
175 		{
176 		  seg = add_segment(u,get_c_string(car(p)));
177 		  append_daughter(syl,"SylStructure",seg);
178 		}
179 	    }
180     }
181 
182     return utt;
183 }
184 
185 
specified_word_pronunciation(EST_Item * w,LISP lpos)186 static LISP specified_word_pronunciation(EST_Item *w, LISP lpos)
187 {
188     //  If there is a phoneme feature on w or the Token related to
189     //  w use that as the pronunciation.  Note the value will be a string
190     //  from which a list can be read.
191     EST_String p;
192 
193     if (((p = (EST_String)ffeature(w,"phonemes")) != "0") ||
194 	((p = (EST_String)ffeature(w,"R:Token.parent.phonemes")) != "0"))
195     {
196 	LISP phones = read_from_lstring(strintern(p));
197 
198 	return cons(strintern(w->name()),
199 		    cons(lpos,
200 			 cons(lex_syllabify(phones),NIL)));
201     }
202     else
203 	return NIL;
204 
205 }
206 
add_word(EST_Utterance * u,const EST_String & name)207 EST_Item *add_word(EST_Utterance *u, const EST_String &name)
208 {
209     EST_Item *item = u->relation("Word")->append();
210 
211     item->set_name(name);
212 
213     return item;
214 }
215 
add_word(EST_Utterance * u,LISP word)216 EST_Item *add_word(EST_Utterance *u, LISP word)
217 {
218     // Build a Word Ling_Item from the Lisp description, which may
219     // contain other features
220     LISP f;
221     EST_Item *si_word;
222     int has_name = FALSE;
223 
224     if (consp(word))
225     {
226 	// feature form
227 	si_word = add_word(u,"");
228 	for (f=word; f != NIL; f=cdr(f))
229 	{
230 	    if (streq("name",get_c_string(car(car(f)))))
231 	    {
232 		has_name = TRUE;
233 		si_word->set_name(get_c_string(car(cdr(car(f)))));
234 	    }
235 	    else
236 		si_word->set(get_c_string(car(car(f))),
237 			      get_c_string(car(cdr(car(f)))));
238 	}
239 	if (!has_name)
240 	{
241 	    cerr << "add_word: word has description but no name" << endl;
242 	    cerr << "  " << siod_sprint(word) << endl;
243 	    festival_error();
244 	}
245     }
246     else // just the name
247 	si_word = add_word(u,get_c_string(word));
248 
249     return si_word;
250 }
251 
add_syllable(EST_Utterance * u,int stress)252 static EST_Item *add_syllable(EST_Utterance *u, int stress)
253 {
254     EST_Item *item = u->relation("Syllable")->append();
255 
256     item->set_name("syl");
257     item->set("stress",stress);
258 
259     return item;
260 }
261 
add_segment(EST_Utterance * u,const EST_String & s)262 EST_Item *add_segment(EST_Utterance *u, const EST_String &s)
263 {
264     EST_Item *item = u->relation("Segment")->append();
265 
266     item->set_name(s);
267 
268     return item;
269 }
270 
271