]>
git.bts.cx Git - benzene.git/blob - third_party/soloud_speech/tts.cpp
8 static const char *ASCII
[] =
18 "space", "exclamation mark", "double quote", "hash",
19 "dollar", "percent", "ampersand", "quote",
20 "open parenthesis", "close parenthesis", "asterisk", "plus",
21 "comma", "minus", "full stop", "slash",
22 "zero", "one", "two", "three",
23 "four", "five", "six", "seven",
24 "eight", "nine", "colon", "semi colon",
25 "less than", "equals", "greater than", "question mark",
27 "at", "ay", "bee", "see",
28 "dee", "e", "eff", "gee",
29 "aych", "i", "jay", "kay",
30 "ell", "em", "en", "ohe",
31 "pee", "kju", "are", "es",
32 "tee", "you", "vee", "double you",
33 "eks", "why", "zed", "open bracket",
34 #else /* ALPHA_IN_DICT */
41 "X", "Y", "Z", "open bracket",
42 #endif /* ALPHA_IN_DICT */
43 "back slash", "close bracket", "circumflex", "underscore",
45 "back quote", "ay", "bee", "see",
46 "dee", "e", "eff", "gee",
47 "aych", "i", "jay", "kay",
48 "ell", "em", "en", "ohe",
49 "pee", "kju", "are", "es",
50 "tee", "you", "vee", "double you",
51 "eks", "why", "zed", "open brace",
52 #else /* ALPHA_IN_DICT */
53 "back quote", "A", "B", "C",
59 "X", "Y", "Z", "open brace",
60 #endif /* ALPHA_IN_DICT */
61 "vertical bar", "close brace", "tilde", "delete",
65 /* Context definitions */
66 static const char Anything
[] = "";
67 /* No context requirement */
69 static const char Nothing
[] = " ";
70 /* Context is beginning or end of word */
72 static const char Silent
[] = "";
81 typedef const char *Rule
[4];
82 /* Rule is an array of 4 character pointers */
87 ** LEFT_PART MATCH_PART RIGHT_PART OUT_PART
91 static Rule punct_rules
[] =
93 {Anything
, " ", Anything
, " "},
94 {Anything
, "-", Anything
, ""},
95 {".", "'S", Anything
, "z"},
96 {"#:.E", "'S", Anything
, "z"},
97 {"#", "'S", Anything
, "z"},
98 {Anything
, "'", Anything
, ""},
99 {Anything
, ",", Anything
, " "},
100 {Anything
, ".", Anything
, " "},
101 {Anything
, "?", Anything
, " "},
102 {Anything
, "!", Anything
, " "},
103 {Anything
, 0, Anything
, Silent
},
106 static Rule A_rules
[] =
108 {Anything
, "A", Nothing
, "@"},
109 {Nothing
, "ARE", Nothing
, "0r"},
110 {Nothing
, "AR", "O", "@r"},
111 {Anything
, "AR", "#", "er"},
112 {"^", "AS", "#", "eIs"},
113 {Anything
, "A", "WA", "@"},
114 {Anything
, "AW", Anything
, "O"},
115 {" :", "ANY", Anything
, "eni"},
116 {Anything
, "A", "^+#", "eI"},
117 {"#:", "ALLY", Anything
, "@li"},
118 {Nothing
, "AL", "#", "@l"},
119 {Anything
, "AGAIN", Anything
, "@gen"},
120 {"#:", "AG", "E", "IdZ"},
121 {Anything
, "A", "^+:#", "&"},
122 {" :", "A", "^+ ", "eI"},
123 {Anything
, "A", "^%", "eI"},
124 {Nothing
, "ARR", Anything
, "@r"},
125 {Anything
, "ARR", Anything
, "&r"},
126 {" :", "AR", Nothing
, "0r"},
127 {Anything
, "AR", Nothing
, "3"},
128 {Anything
, "AR", Anything
, "0r"},
129 {Anything
, "AIR", Anything
, "er"},
130 {Anything
, "AI", Anything
, "eI"},
131 {Anything
, "AY", Anything
, "eI"},
132 {Anything
, "AU", Anything
, "O"},
133 {"#:", "AL", Nothing
, "@l"},
134 {"#:", "ALS", Nothing
, "@lz"},
135 {Anything
, "ALK", Anything
, "Ok"},
136 {Anything
, "AL", "^", "Ol"},
137 {" :", "ABLE", Anything
, "eIb@l"},
138 {Anything
, "ABLE", Anything
, "@b@l"},
139 {Anything
, "ANG", "+", "eIndZ"},
140 {"^", "A", "^#", "eI"},
141 {Anything
, "A", Anything
, "&"},
142 {Anything
, 0, Anything
, Silent
},
145 static Rule B_rules
[] =
147 {Nothing
, "BE", "^#", "bI"},
148 {Anything
, "BEING", Anything
, "biIN"},
149 {Nothing
, "BOTH", Nothing
, "b@UT"},
150 {Nothing
, "BUS", "#", "bIz"},
151 {Anything
, "BUIL", Anything
, "bIl"},
152 {Anything
, "B", Anything
, "b"},
153 {Anything
, 0, Anything
, Silent
},
156 static Rule C_rules
[] =
158 {Nothing
, "CH", "^", "k"},
159 {"^E", "CH", Anything
, "k"},
160 {Anything
, "CH", Anything
, "tS"},
161 {" S", "CI", "#", "saI"},
162 {Anything
, "CI", "A", "S"},
163 {Anything
, "CI", "O", "S"},
164 {Anything
, "CI", "EN", "S"},
165 {Anything
, "C", "+", "s"},
166 {Anything
, "CK", Anything
, "k"},
167 {Anything
, "COM", "%", "kVm"},
168 {Anything
, "C", Anything
, "k"},
169 {Anything
, 0, Anything
, Silent
},
172 static Rule D_rules
[] =
174 {"#:", "DED", Nothing
, "dId"},
175 {".E", "D", Nothing
, "d"},
176 {"#:^E", "D", Nothing
, "t"},
177 {Nothing
, "DE", "^#", "dI"},
178 {Nothing
, "DO", Nothing
, "mDU"},
179 {Nothing
, "DOES", Anything
, "dVz"},
180 {Nothing
, "DOING", Anything
, "duIN"},
181 {Nothing
, "DOW", Anything
, "daU"},
182 {Anything
, "DU", "A", "dZu"},
183 {Anything
, "D", Anything
, "d"},
184 {Anything
, 0, Anything
, Silent
},
187 static Rule E_rules
[] =
189 {"#:", "E", Nothing
, ""},
190 {"':^", "E", Nothing
, ""},
191 {" :", "E", Nothing
, "i"},
192 {"#", "ED", Nothing
, "d"},
193 {"#:", "E", "D ", ""},
194 {Anything
, "EV", "ER", "ev"},
195 {Anything
, "E", "^%", "i"},
196 {Anything
, "ERI", "#", "iri"},
197 {Anything
, "ERI", Anything
, "erI"},
198 {"#:", "ER", "#", "3"},
199 {Anything
, "ER", "#", "er"},
200 {Anything
, "ER", Anything
, "3"},
201 {Nothing
, "EVEN", Anything
, "iven"},
202 {"#:", "E", "W", ""},
203 {"T", "EW", Anything
, "u"},
204 {"S", "EW", Anything
, "u"},
205 {"R", "EW", Anything
, "u"},
206 {"D", "EW", Anything
, "u"},
207 {"L", "EW", Anything
, "u"},
208 {"Z", "EW", Anything
, "u"},
209 {"N", "EW", Anything
, "u"},
210 {"J", "EW", Anything
, "u"},
211 {"TH", "EW", Anything
, "u"},
212 {"CH", "EW", Anything
, "u"},
213 {"SH", "EW", Anything
, "u"},
214 {Anything
, "EW", Anything
, "ju"},
215 {Anything
, "E", "O", "i"},
216 {"#:S", "ES", Nothing
, "Iz"},
217 {"#:C", "ES", Nothing
, "Iz"},
218 {"#:G", "ES", Nothing
, "Iz"},
219 {"#:Z", "ES", Nothing
, "Iz"},
220 {"#:X", "ES", Nothing
, "Iz"},
221 {"#:J", "ES", Nothing
, "Iz"},
222 {"#:CH", "ES", Nothing
, "Iz"},
223 {"#:SH", "ES", Nothing
, "Iz"},
224 {"#:", "E", "S ", ""},
225 {"#:", "ELY", Nothing
, "li"},
226 {"#:", "EMENT", Anything
, "ment"},
227 {Anything
, "EFUL", Anything
, "fUl"},
228 {Anything
, "EE", Anything
, "i"},
229 {Anything
, "EARN", Anything
, "3n"},
230 {Nothing
, "EAR", "^", "3"},
231 {Anything
, "EAD", Anything
, "ed"},
232 {"#:", "EA", Nothing
, "i@"},
233 {Anything
, "EA", "SU", "e"},
234 {Anything
, "EA", Anything
, "i"},
235 {Anything
, "EIGH", Anything
, "eI"},
236 {Anything
, "EI", Anything
, "i"},
237 {Nothing
, "EYE", Anything
, "aI"},
238 {Anything
, "EY", Anything
, "i"},
239 {Anything
, "EU", Anything
, "ju"},
240 {Anything
, "E", Anything
, "e"},
241 {Anything
, 0, Anything
, Silent
},
244 static Rule F_rules
[] =
246 {Anything
, "FUL", Anything
, "fUl"},
247 {Anything
, "F", Anything
, "f"},
248 {Anything
, 0, Anything
, Silent
},
251 static Rule G_rules
[] =
253 {Anything
, "GIV", Anything
, "gIv"},
254 {Nothing
, "G", "I^", "g"},
255 {Anything
, "GE", "T", "ge"},
256 {"SU", "GGES", Anything
, "gdZes"},
257 {Anything
, "GG", Anything
, "g"},
258 {" B#", "G", Anything
, "g"},
259 {Anything
, "G", "+", "dZ"},
260 {Anything
, "GREAT", Anything
, "greIt"},
261 {"#", "GH", Anything
, ""},
262 {Anything
, "G", Anything
, "g"},
263 {Anything
, 0, Anything
, Silent
},
266 static Rule H_rules
[] =
268 {Nothing
, "HAV", Anything
, "h&v"},
269 {Nothing
, "HERE", Anything
, "hir"},
270 {Nothing
, "HOUR", Anything
, "aU3"},
271 {Anything
, "HOW", Anything
, "haU"},
272 {Anything
, "H", "#", "h"},
273 {Anything
, "H", Anything
, ""},
274 {Anything
, 0, Anything
, Silent
},
277 static Rule I_rules
[] =
279 {Nothing
, "IAIN", Nothing
, "I@n"},
280 {Nothing
, "ING", Nothing
, "IN"},
281 {Nothing
, "IN", Anything
, "In"},
282 {Nothing
, "I", Nothing
, "aI"},
283 {Anything
, "IN", "D", "aIn"},
284 {Anything
, "IER", Anything
, "i3"},
285 {"#:R", "IED", Anything
, "id"},
286 {Anything
, "IED", Nothing
, "aId"},
287 {Anything
, "IEN", Anything
, "ien"},
288 {Anything
, "IE", "T", "aIe"},
289 {" :", "I", "%", "aI"},
290 {Anything
, "I", "%", "i"},
291 {Anything
, "IE", Anything
, "i"},
292 {Anything
, "I", "^+:#", "I"},
293 {Anything
, "IR", "#", "aIr"},
294 {Anything
, "IZ", "%", "aIz"},
295 {Anything
, "IS", "%", "aIz"},
296 {Anything
, "I", "D%", "aI"},
297 {"+^", "I", "^+", "I"},
298 {Anything
, "I", "T%", "aI"},
299 {"#:^", "I", "^+", "I"},
300 {Anything
, "I", "^+", "aI"},
301 {Anything
, "IR", Anything
, "3"},
302 {Anything
, "IGH", Anything
, "aI"},
303 {Anything
, "ILD", Anything
, "aIld"},
304 {Anything
, "IGN", Nothing
, "aIn"},
305 {Anything
, "IGN", "^", "aIn"},
306 {Anything
, "IGN", "%", "aIn"},
307 {Anything
, "IQUE", Anything
, "ik"},
308 {"^", "I", "^#", "aI"},
309 {Anything
, "I", Anything
, "I"},
310 {Anything
, 0, Anything
, Silent
},
313 static Rule J_rules
[] =
315 {Anything
, "J", Anything
, "dZ"},
316 {Anything
, 0, Anything
, Silent
},
319 static Rule K_rules
[] =
321 {Nothing
, "K", "N", ""},
322 {Anything
, "K", Anything
, "k"},
323 {Anything
, 0, Anything
, Silent
},
326 static Rule L_rules
[] =
328 {Anything
, "LO", "C#", "l@U"},
329 {"L", "L", Anything
, ""},
330 {"#:^", "L", "%", "@l"},
331 {Anything
, "LEAD", Anything
, "lid"},
332 {Anything
, "L", Anything
, "l"},
333 {Anything
, 0, Anything
, Silent
},
336 static Rule M_rules
[] =
338 {Anything
, "MOV", Anything
, "muv"},
339 {"#", "MM", "#", "m"},
340 {Anything
, "M", Anything
, "m"},
341 {Anything
, 0, Anything
, Silent
},
344 static Rule N_rules
[] =
346 {"E", "NG", "+", "ndZ"},
347 {Anything
, "NG", "R", "Ng"},
348 {Anything
, "NG", "#", "Ng"},
349 {Anything
, "NGL", "%", "Ng@l"},
350 {Anything
, "NG", Anything
, "N"},
351 {Anything
, "NK", Anything
, "Nk"},
352 {Nothing
, "NOW", Nothing
, "naU"},
353 {"#", "NG", Nothing
, "Ng"},
354 {Anything
, "N", Anything
, "n"},
355 {Anything
, 0, Anything
, Silent
},
358 static Rule O_rules
[] =
360 {Anything
, "OF", Nothing
, "@v"},
361 {Anything
, "OROUGH", Anything
, "3@U"},
362 {"#:", "OR", Nothing
, "3"},
363 {"#:", "ORS", Nothing
, "3z"},
364 {Anything
, "OR", Anything
, "Or"},
365 {Nothing
, "ONE", Anything
, "wVn"},
366 {Anything
, "OW", Anything
, "@U"},
367 {Nothing
, "OVER", Anything
, "@Uv3"},
368 {Anything
, "OV", Anything
, "Vv"},
369 {Anything
, "O", "^%", "@U"},
370 {Anything
, "O", "^EN", "@U"},
371 {Anything
, "O", "^I#", "@U"},
372 {Anything
, "OL", "D", "@Ul"},
373 {Anything
, "OUGHT", Anything
, "Ot"},
374 {Anything
, "OUGH", Anything
, "Vf"},
375 {Nothing
, "OU", Anything
, "aU"},
376 {"H", "OU", "S#", "aU"},
377 {Anything
, "OUS", Anything
, "@s"},
378 {Anything
, "OUR", Anything
, "Or"},
379 {Anything
, "OULD", Anything
, "Ud"},
380 {"^", "OU", "^L", "V"},
381 {Anything
, "OUP", Anything
, "up"},
382 {Anything
, "OU", Anything
, "aU"},
383 {Anything
, "OY", Anything
, "oI"},
384 {Anything
, "OING", Anything
, "@UIN"},
385 {Anything
, "OI", Anything
, "oI"},
386 {Anything
, "OOR", Anything
, "Or"},
387 {Anything
, "OOK", Anything
, "Uk"},
388 {Anything
, "OOD", Anything
, "Ud"},
389 {Anything
, "OO", Anything
, "u"},
390 {Anything
, "O", "E", "@U"},
391 {Anything
, "O", Nothing
, "@U"},
392 {Anything
, "OA", Anything
, "@U"},
393 {Nothing
, "ONLY", Anything
, "@Unli"},
394 {Nothing
, "ONCE", Anything
, "wVns"},
395 {Anything
, "ON'T", Anything
, "@Unt"},
396 {"C", "O", "N", "0"},
397 {Anything
, "O", "NG", "O"},
398 {" :^", "O", "N", "V"},
399 {"I", "ON", Anything
, "@n"},
400 {"#:", "ON", Nothing
, "@n"},
401 {"#^", "ON", Anything
, "@n"},
402 {Anything
, "O", "ST ", "@U"},
403 {Anything
, "OF", "^", "Of"},
404 {Anything
, "OTHER", Anything
, "VD3"},
405 {Anything
, "OSS", Nothing
, "Os"},
406 {"#:^", "OM", Anything
, "Vm"},
407 {Anything
, "O", Anything
, "0"},
408 {Anything
, 0, Anything
, Silent
},
411 static Rule P_rules
[] =
413 {Anything
, "PH", Anything
, "f"},
414 {Anything
, "PEOP", Anything
, "pip"},
415 {Anything
, "POW", Anything
, "paU"},
416 {Anything
, "PUT", Nothing
, "pUt"},
417 {Anything
, "P", Anything
, "p"},
418 {Anything
, 0, Anything
, Silent
},
421 static Rule Q_rules
[] =
423 {Anything
, "QUAR", Anything
, "kwOr"},
424 {Anything
, "QU", Anything
, "kw"},
425 {Anything
, "Q", Anything
, "k"},
426 {Anything
, 0, Anything
, Silent
},
429 static Rule R_rules
[] =
431 {Nothing
, "RE", "^#", "ri"},
432 {Anything
, "R", Anything
, "r"},
433 {Anything
, 0, Anything
, Silent
},
436 static Rule S_rules
[] =
438 {Anything
, "SH", Anything
, "S"},
439 {"#", "SION", Anything
, "Z@n"},
440 {Anything
, "SOME", Anything
, "sVm"},
441 {"#", "SUR", "#", "Z3"},
442 {Anything
, "SUR", "#", "S3"},
443 {"#", "SU", "#", "Zu"},
444 {"#", "SSU", "#", "Su"},
445 {"#", "SED", Nothing
, "zd"},
446 {"#", "S", "#", "z"},
447 {Anything
, "SAID", Anything
, "sed"},
448 {"^", "SION", Anything
, "S@n"},
449 {Anything
, "S", "S", ""},
450 {".", "S", Nothing
, "z"},
451 {"#:.E", "S", Nothing
, "z"},
452 {"#:^##", "S", Nothing
, "z"},
453 {"#:^#", "S", Nothing
, "s"},
454 {"U", "S", Nothing
, "s"},
455 {" :#", "S", Nothing
, "z"},
456 {Nothing
, "SCH", Anything
, "sk"},
457 {Anything
, "S", "C+", ""},
458 {"#", "SM", Anything
, "zm"},
459 {"#", "SN", "'", "z@n"},
460 {Anything
, "S", Anything
, "s"},
461 {Anything
, 0, Anything
, Silent
},
464 static Rule T_rules
[] =
466 {Nothing
, "THE", Nothing
, "D@"},
467 {Anything
, "TO", Nothing
, "tu"},
468 {Anything
, "THAT", Nothing
, "D&t"},
469 {Nothing
, "THIS", Nothing
, "DIs"},
470 {Nothing
, "THEY", Anything
, "DeI"},
471 {Nothing
, "THERE", Anything
, "Der"},
472 {Anything
, "THER", Anything
, "D3"},
473 {Anything
, "THEIR", Anything
, "Der"},
474 {Nothing
, "THAN", Nothing
, "D&n"},
475 {Nothing
, "THEM", Nothing
, "Dem"},
476 {Anything
, "THESE", Nothing
, "Diz"},
477 {Nothing
, "THEN", Anything
, "Den"},
478 {Anything
, "THROUGH", Anything
, "Tru"},
479 {Anything
, "THOSE", Anything
, "D@Uz"},
480 {Anything
, "THOUGH", Nothing
, "D@U"},
481 {Nothing
, "THUS", Anything
, "DVs"},
482 {Anything
, "TH", Anything
, "T"},
483 {"#:", "TED", Nothing
, "tId"},
484 {"S", "TI", "#N", "tS"},
485 {Anything
, "TI", "O", "S"},
486 {Anything
, "TI", "A", "S"},
487 {Anything
, "TIEN", Anything
, "S@n"},
488 {Anything
, "TUR", "#", "tS3"},
489 {Anything
, "TU", "A", "tSu"},
490 {Nothing
, "TWO", Anything
, "tu"},
491 {Anything
, "T", Anything
, "t"},
492 {Anything
, 0, Anything
, Silent
},
495 static Rule U_rules
[] =
497 {Nothing
, "UN", "I", "jun"},
498 {Nothing
, "UN", Anything
, "Vn"},
499 {Nothing
, "UPON", Anything
, "@pOn"},
500 {"T", "UR", "#", "Ur"},
501 {"S", "UR", "#", "Ur"},
502 {"R", "UR", "#", "Ur"},
503 {"D", "UR", "#", "Ur"},
504 {"L", "UR", "#", "Ur"},
505 {"Z", "UR", "#", "Ur"},
506 {"N", "UR", "#", "Ur"},
507 {"J", "UR", "#", "Ur"},
508 {"TH", "UR", "#", "Ur"},
509 {"CH", "UR", "#", "Ur"},
510 {"SH", "UR", "#", "Ur"},
511 {Anything
, "UR", "#", "jUr"},
512 {Anything
, "UR", Anything
, "3"},
513 {Anything
, "U", "^ ", "V"},
514 {Anything
, "U", "^^", "V"},
515 {Anything
, "UY", Anything
, "aI"},
516 {" G", "U", "#", ""},
518 {"G", "U", "#", "w"},
519 {"#N", "U", Anything
, "ju"},
520 {"T", "U", Anything
, "u"},
521 {"S", "U", Anything
, "u"},
522 {"R", "U", Anything
, "u"},
523 {"D", "U", Anything
, "u"},
524 {"L", "U", Anything
, "u"},
525 {"Z", "U", Anything
, "u"},
526 {"N", "U", Anything
, "u"},
527 {"J", "U", Anything
, "u"},
528 {"TH", "U", Anything
, "u"},
529 {"CH", "U", Anything
, "u"},
530 {"SH", "U", Anything
, "u"},
531 {Anything
, "U", Anything
, "ju"},
532 {Anything
, 0, Anything
, Silent
},
535 static Rule V_rules
[] =
537 {Anything
, "VIEW", Anything
, "vju"},
538 {Anything
, "V", Anything
, "v"},
539 {Anything
, 0, Anything
, Silent
},
542 static Rule W_rules
[] =
544 {Nothing
, "WERE", Anything
, "w3"},
545 {Anything
, "WA", "S", "w0"},
546 {Anything
, "WA", "T", "w0"},
547 {Anything
, "WHERE", Anything
, "hwer"},
548 {Anything
, "WHAT", Anything
, "hw0t"},
549 {Anything
, "WHOL", Anything
, "h@Ul"},
550 {Anything
, "WHO", Anything
, "hu"},
551 {Anything
, "WH", Anything
, "hw"},
552 {Anything
, "WAR", Anything
, "wOr"},
553 {Anything
, "WOR", "^", "w3"},
554 {Anything
, "WR", Anything
, "r"},
555 {Anything
, "W", Anything
, "w"},
556 {Anything
, 0, Anything
, Silent
},
559 static Rule X_rules
[] =
561 {Anything
, "X", Anything
, "ks"},
562 {Anything
, 0, Anything
, Silent
},
565 static Rule Y_rules
[] =
567 {Anything
, "YOUNG", Anything
, "jVN"},
568 {Nothing
, "YOU", Anything
, "ju"},
569 {Nothing
, "YES", Anything
, "jes"},
570 {Nothing
, "Y", Anything
, "j"},
571 {"#:^", "Y", Nothing
, "i"},
572 {"#:^", "Y", "I", "i"},
573 {" :", "Y", Nothing
, "aI"},
574 {" :", "Y", "#", "aI"},
575 {" :", "Y", "^+:#", "I"},
576 {" :", "Y", "^#", "aI"},
577 {Anything
, "Y", Anything
, "I"},
578 {Anything
, 0, Anything
, Silent
},
581 static Rule Z_rules
[] =
583 {Anything
, "Z", Anything
, "z"},
584 {Anything
, 0, Anything
, Silent
},
587 static Rule
*Rules
[] =
590 A_rules
, B_rules
, C_rules
, D_rules
, E_rules
, F_rules
, G_rules
,
591 H_rules
, I_rules
, J_rules
, K_rules
, L_rules
, M_rules
, N_rules
,
592 O_rules
, P_rules
, Q_rules
, R_rules
, S_rules
, T_rules
, U_rules
,
593 V_rules
, W_rules
, X_rules
, Y_rules
, Z_rules
597 static const char *Cardinals
[] =
599 "zero", "one", "two", "three", "four",
600 "five", "six", "seven", "eight", "nine",
601 "ten", "eleven", "twelve", "thirteen", "fourteen",
602 "fifteen", "sixteen", "seventeen", "eighteen", "nineteen"
606 static const char *Twenties
[] =
608 "twenty", "thirty", "forty", "fifty",
609 "sixty", "seventy", "eighty", "ninety"
613 static const char *Ordinals
[] =
615 "zeroth", "first", "second", "third", "fourth",
616 "fifth", "sixth", "seventh","eighth", "ninth",
617 "tenth", "eleventh", "twelfth", "thirteenth", "fourteenth",
618 "fifteenth", "sixteenth", "seventeenth", "eighteenth", "nineteenth"
622 static const char *Ord_twenties
[] =
624 "twentieth", "thirtieth", "fortieth", "fiftieth",
625 "sixtieth", "seventieth", "eightieth", "ninetieth"
630 ** Translate a number to phonemes. This version is for CARDINAL numbers.
631 ** Note: this is recursive.
633 static int xlate_cardinal(int value
, darray
*phone
)
639 nph
+= xlate_string("minus", phone
);
642 if (value
< 0) /* Overflow! -32768 */
644 nph
+= xlate_string("a lot", phone
);
649 if (value
>= 1000000000L)
652 nph
+= xlate_cardinal(value
/ 1000000000L, phone
);
653 nph
+= xlate_string("billion", phone
);
654 value
= value
% 1000000000;
657 return nph
; /* Even billion */
660 nph
+= xlate_string("and", phone
);
662 /* as in THREE BILLION AND FIVE */
665 if (value
>= 1000000L)
668 nph
+= xlate_cardinal(value
/ 1000000L, phone
);
669 nph
+= xlate_string("million", phone
);
670 value
= value
% 1000000L;
673 return nph
; /* Even million */
676 nph
+= xlate_string("and", phone
);
678 /* as in THREE MILLION AND FIVE */
681 /* Thousands 1000..1099 2000..99999 */
682 /* 1100 to 1999 is eleven-hunderd to ninteen-hunderd */
684 if ((value
>= 1000L && value
<= 1099L) || value
>= 2000L)
686 nph
+= xlate_cardinal(value
/ 1000L, phone
);
687 nph
+= xlate_string("thousand", phone
);
688 value
= value
% 1000L;
691 return nph
; /* Even thousand */
694 nph
+= xlate_string("and", phone
);
696 /* as in THREE THOUSAND AND FIVE */
701 nph
+= xlate_string(Cardinals
[value
/ 100], phone
);
702 nph
+= xlate_string("hundred", phone
);
706 return nph
; /* Even hundred */
711 nph
+= xlate_string(Twenties
[(value
- 20) / 10], phone
);
715 return nph
; /* Even ten */
718 nph
+= xlate_string(Cardinals
[value
], phone
);
725 ** Translate a number to phonemes. This version is for ORDINAL numbers.
726 ** Note: this is recursive.
728 static int xlate_ordinal(int value
, darray
*phone
)
734 nph
+= xlate_string("minus", phone
);
737 if (value
< 0) /* Overflow! -32768 */
739 nph
+= xlate_string("a lot", phone
);
744 if (value
>= 1000000000L)
747 nph
+= xlate_cardinal(value
/ 1000000000L, phone
);
748 value
= value
% 1000000000;
752 nph
+= xlate_string("billionth", phone
);
753 return nph
; /* Even billion */
756 nph
+= xlate_string("billion", phone
);
759 nph
+= xlate_string("and", phone
);
761 /* as in THREE BILLION AND FIVE */
764 if (value
>= 1000000L)
767 nph
+= xlate_cardinal(value
/ 1000000L, phone
);
768 value
= value
% 1000000L;
772 nph
+= xlate_string("millionth", phone
);
773 return nph
; /* Even million */
776 nph
+= xlate_string("million", phone
);
779 nph
+= xlate_string("and", phone
);
781 /* as in THREE MILLION AND FIVE */
784 /* Thousands 1000..1099 2000..99999 */
785 /* 1100 to 1999 is eleven-hunderd to ninteen-hunderd */
787 if ((value
>= 1000L && value
<= 1099L) || value
>= 2000L)
789 nph
+= xlate_cardinal(value
/ 1000L, phone
);
790 value
= value
% 1000L;
794 nph
+= xlate_string("thousandth", phone
);
795 return nph
; /* Even thousand */
798 nph
+= xlate_string("thousand", phone
);
801 nph
+= xlate_string("and", phone
);
803 /* as in THREE THOUSAND AND FIVE */
808 nph
+= xlate_string(Cardinals
[value
/ 100], phone
);
813 nph
+= xlate_string("hundredth", phone
);
814 return nph
; /* Even hundred */
817 nph
+= xlate_string("hundred", phone
);
822 if ((value
% 10) == 0)
824 nph
+= xlate_string(Ord_twenties
[(value
- 20) / 10], phone
);
825 return nph
; /* Even ten */
828 nph
+= xlate_string(Twenties
[(value
- 20) / 10], phone
);
833 nph
+= xlate_string(Ordinals
[value
], phone
);
839 static int isvowel(int chr
)
841 return (chr
== 'A' || chr
== 'E' || chr
== 'I' ||
842 chr
== 'O' || chr
== 'U');
845 static int isconsonant(int chr
)
847 return (isupper(chr
) && !isvowel(chr
));
850 static int leftmatch(
851 const char *pattern
, /* first char of pattern to match in text */
852 const char *context
) /* last char of text to be matched */
859 if (*pattern
== '\0')
860 /* null string matches any context */
865 /* point to last character in pattern string */
866 count
= (int)strlen(pattern
);
868 pat
= pattern
+ (count
- 1);
872 for (; count
> 0; pat
--, count
--)
874 /* First check for simple text or space */
875 if (isalpha(*pat
) || *pat
== '\'' || *pat
== ' ')
891 case '#': /* One or more vowels */
898 while (isvowel(*text
))
903 case ':': /* Zero or more consonants */
904 while (isconsonant(*text
))
909 case '^': /* One consonant */
910 if (!isconsonant(*text
))
917 case '.': /* B, D, V, G, J, L, M, N, R, W, Z */
918 if (*text
!= 'B' && *text
!= 'D' && *text
!= 'V'
919 && *text
!= 'G' && *text
!= 'J' && *text
!= 'L'
920 && *text
!= 'M' && *text
!= 'N' && *text
!= 'R'
921 && *text
!= 'W' && *text
!= 'Z')
928 case '+': /* E, I or Y (front vowel) */
929 if (*text
!= 'E' && *text
!= 'I' && *text
!= 'Y')
939 fprintf(stderr
, "Bad char in left rule: '%c'\n", *pat
);
948 static int rightmatch(
949 const char *pattern
, /* first char of pattern to match in text */
950 const char *context
) /* last char of text to be matched */
955 if (*pattern
== '\0')
956 /* null string matches any context */
963 for (pat
= pattern
; *pat
!= '\0'; pat
++)
965 /* First check for simple text or space */
966 if (isalpha(*pat
) || *pat
== '\'' || *pat
== ' ')
982 case '#': /* One or more vowels */
989 while (isvowel(*text
))
994 case ':': /* Zero or more consonants */
995 while (isconsonant(*text
))
1000 case '^': /* One consonant */
1001 if (!isconsonant(*text
))
1008 case '.': /* B, D, V, G, J, L, M, N, R, W, Z */
1009 if (*text
!= 'B' && *text
!= 'D' && *text
!= 'V'
1010 && *text
!= 'G' && *text
!= 'J' && *text
!= 'L'
1011 && *text
!= 'M' && *text
!= 'N' && *text
!= 'R'
1012 && *text
!= 'W' && *text
!= 'Z')
1019 case '+': /* E, I or Y (front vowel) */
1020 if (*text
!= 'E' && *text
!= 'I' && *text
!= 'Y')
1027 case '%': /* ER, E, ES, ED, ING, ELY (a suffix) */
1044 text
--; /* Don't gobble L */
1050 if (*text
== 'R' || *text
== 'S' || *text
== 'D')
1079 fprintf(stderr
, "Bad char in right rule:'%c'\n", *pat
);
1088 static void phone_cat(darray
*arg
, const char *s
)
1097 static int find_rule(darray
*arg
, char *word
, int index
, Rule
*rules
)
1099 for (;;) /* Search for the rule */
1113 fprintf(stderr
, "Error: Can't find rule for: '%c' in \"%s\"\n",
1115 return index
+ 1; /* Skip it! */
1118 for (remainder
= index
; *match
!= '\0'; match
++, remainder
++)
1120 if (*match
!= word
[remainder
])
1125 continue; /* found missmatch */
1131 if (!leftmatch(left
, &word
[index
- 1]))
1134 if (!rightmatch(right
, &word
[remainder
]))
1137 output
= (*rule
)[3];
1139 phone_cat(arg
, output
);
1145 static void guess_word(darray
*arg
, char *word
)
1147 int index
; /* Current position in word */
1148 int type
; /* First letter of match part */
1149 index
= 1; /* Skip the initial blank */
1153 if (isupper(word
[index
]))
1154 type
= word
[index
] - 'A' + 1;
1158 index
= find_rule(arg
, word
, index
, Rules
[type
]);
1161 while (word
[index
] != '\0');
1165 static int NRL(const char *s
, int n
, darray
*phone
)
1167 int old
= phone
->getSize();
1168 char *word
= (char *) malloc(n
+ 3); // TODO: may return null
1177 ch
= (char)toupper(ch
);
1182 *d
++ = ' '; // kinda unnecessary
1185 guess_word(phone
, word
);
1187 return phone
->getSize() - old
;
1191 static int spell_out(const char *word
, int n
, darray
*phone
)
1197 nph
+= xlate_string(ASCII
[*word
++ & 0x7F], phone
);
1203 static int suspect_word(const char *s
, int n
)
1211 for (i
= 0; i
< n
; i
++)
1215 if (i
&& last
!= '-' && isupper(ch
))
1221 ch
= (char)toupper(ch
);
1224 if (ch
== 'A' || ch
== 'E' || ch
== 'I' || ch
== 'O' || ch
== 'U' || ch
== 'Y')
1230 return !seen_vowel
|| (seen_upper
&& seen_lower
) || !seen_lower
;
1233 static int xlate_word(const char *word
, int n
, darray
*phone
)
1239 if (suspect_word(word
, n
))
1240 return spell_out(word
, n
, phone
);
1243 nph
+= NRL(word
, n
, phone
);
1249 if ((++word
)[(--n
) - 1] == ']')
1254 phone
->put(*word
++);
1265 int xlate_string(const char *string
, darray
*phone
)
1268 const char *s
= string
;
1271 while (isspace(ch
= *s
))
1277 const char *word
= s
;
1281 while (isalpha(ch
= *s
) || ((ch
== '\'' || ch
== '-' || ch
== '.') && isalpha(s
[1])))
1286 if (!ch
|| isspace(ch
) || ispunct(ch
) || (isdigit(ch
) && !suspect_word(word
, (int)(s
- word
))))
1288 nph
+= xlate_word(word
, (int)(s
- word
), phone
);
1292 while (*s
&& !isspace(*s
) && !ispunct(*s
))
1298 nph
+= spell_out(word
, (int)(s
- word
), phone
);
1303 if (isdigit(ch
) || (ch
== '-' && isdigit(s
[1])))
1305 int sign
= (ch
== '-') ? -1 : 1;
1313 while (isdigit(ch
= *s
))
1315 value
= value
* 10 + ch
- '0';
1319 if (ch
== '.' && isdigit(s
[1]))
1322 nph
+= xlate_cardinal(value
* sign
, phone
);
1323 nph
+= xlate_string("point", phone
);
1325 while (isdigit(ch
= *s
))
1330 nph
+= spell_out(word
, (int)(s
- word
), phone
);
1334 /* check for ordinals, date, time etc. can go in here */
1335 nph
+= xlate_cardinal(value
* sign
, phone
);
1340 if (ch
== '[' && strchr(s
, ']'))
1342 const char *thisword
= s
;
1344 while (*s
&& *s
++ != ']')
1348 nph
+= xlate_word(thisword
, (int)(s
- thisword
), phone
);
1363 phone
->put('.');// (' ');
1366 case '"': /* change pitch ? */
1385 const char *e
= strchr(s
, ']');
1401 nph
+= spell_out(word
, 1, phone
);
1408 while (*s
&& !isspace(*s
))
1414 nph
+= spell_out(word
, (int)(s
- word
), phone
);
1419 while (isspace(ch
= *s
))