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