cmu_lex.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385
  1. /*************************************************************************/
  2. /* */
  3. /* Language Technologies Institute */
  4. /* Carnegie Mellon University */
  5. /* Copyright (c) 2001 */
  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. /* CARNEGIE MELLON UNIVERSITY 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 CARNEGIE MELLON UNIVERSITY 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 (awb@cs.cmu.edu) */
  34. /* Date: January 2001 */
  35. /*************************************************************************/
  36. /* */
  37. /* CMU Lexicon definition */
  38. /* */
  39. /*************************************************************************/
  40. #include "flite.h"
  41. #include "cmu_lex.h"
  42. extern const int cmu_lex_entry[];
  43. extern const unsigned char cmu_lex_data[];
  44. extern const int cmu_lex_num_entries;
  45. extern const int cmu_lex_num_bytes;
  46. extern const char * const cmu_lex_phone_table[54];
  47. extern const char * const cmu_lex_phones_huff_table[];
  48. extern const char * const cmu_lex_entries_huff_table[];
  49. static int cmu_is_vowel(const char *p);
  50. static int cmu_is_silence(const char *p);
  51. static int cmu_has_vowel_in_list(const cst_val *v);
  52. static int cmu_has_vowel_in_syl(const cst_item *i);
  53. static int cmu_sonority(const char *p);
  54. static const char * const addenda0[] = { "p,", NULL };
  55. static const char * const addenda1[] = { "p.", NULL };
  56. static const char * const addenda2[] = { "p(", NULL };
  57. static const char * const addenda3[] = { "p)", NULL };
  58. static const char * const addenda4[] = { "p[", NULL };
  59. static const char * const addenda5[] = { "p]", NULL };
  60. static const char * const addenda6[] = { "p{", NULL };
  61. static const char * const addenda7[] = { "p}", NULL };
  62. static const char * const addenda8[] = { "p:", NULL };
  63. static const char * const addenda9[] = { "p;", NULL };
  64. static const char * const addenda10[] = { "p?", NULL};
  65. static const char * const addenda11[] = { "p!", NULL };
  66. static const char * const addenda12[] = { "n@", "ae1", "t", NULL };
  67. static const char * const addenda13[] = { "n#", "hh", "ae1","sh", NULL };
  68. static const char * const addenda14[] = { "n$", "d", "aa1", "l", "er", NULL };
  69. static const char * const addenda15[] = { "n%", "p", "er", "s", "eh1", "n", "t", NULL };
  70. static const char * const addenda16[] = { "n^", "k", "eh1", "r", "eh1", "t", NULL };
  71. static const char * const addenda17[] = { "n&","ae1","m","p","er","s","ae1","n","d", NULL };
  72. static const char * const addenda18[] = { "n*","ae1","s","t","er","ih1","s","k",NULL };
  73. static const char * const addenda19[] = { "n|","b","aa1","r",NULL };
  74. static const char * const addenda20[] = { "n\\","b","ae1","k","s","l","ae1","sh",NULL };
  75. static const char * const addenda21[] = { "n=","iy1","k","w","ax","l","z",NULL};
  76. static const char * const addenda22[] = { "n+","p","l","ah1","s",NULL};
  77. static const char * const addenda23[] = { "n~","t","ih1","l","d","ax",NULL};
  78. static const char * const addenda24[] = { "p'",NULL};
  79. static const char * const addenda25[] = { "p`",NULL};
  80. static const char * const addenda26[] = { "p\"",NULL};
  81. static const char * const addenda27[] = { "p-",NULL};
  82. static const char * const addenda28[] = { "p<",NULL};
  83. static const char * const addenda29[] = { "p>",NULL};
  84. static const char * const addenda30[] = { "n_","ah1","n","d","er","s","k","ao1","r",NULL};
  85. static const char * const addenda31[] = { "s's","z",NULL};
  86. static const char * const addenda32[] = { "nim","ay1","m",NULL};
  87. static const char * const addenda33[] = { "vdoesnt","d","ah1","z","n","t",NULL};
  88. static const char * const addenda34[] = { "vyoull","y","uw1","l",NULL};
  89. static const char * const addenda35[] = { "n/","s","l","ae1","sh",NULL};
  90. static const char * const addenda36[] = { "nin","ih","n",NULL};
  91. static const char * const addenda37[] = { "nto","t","ax",NULL};
  92. static const char * const addenda38[] = { "0_a","ey",NULL};
  93. static const char * const addenda39[] = { "vhavent","hh","ae1","v","ax","n","t",NULL};
  94. static const char * const addenda40[] = { "nemail","iy1","m","ey1","l",NULL};
  95. static const char * const addenda41[] = { "nshit","sh","ih1","t",NULL};
  96. static const char * const * const addenda[] = {
  97. addenda0,
  98. addenda1,
  99. addenda2,
  100. addenda3,
  101. addenda4,
  102. addenda5,
  103. addenda6,
  104. addenda7,
  105. addenda8,
  106. addenda9,
  107. addenda10,
  108. addenda11,
  109. addenda12,
  110. addenda13,
  111. addenda14,
  112. addenda15,
  113. addenda16,
  114. addenda17,
  115. addenda18,
  116. addenda19,
  117. addenda20,
  118. addenda21,
  119. addenda22,
  120. addenda23,
  121. addenda24,
  122. addenda25,
  123. addenda26,
  124. addenda27,
  125. addenda28,
  126. addenda29,
  127. addenda30,
  128. addenda31,
  129. addenda32,
  130. addenda33,
  131. addenda34,
  132. addenda35,
  133. addenda36,
  134. addenda37,
  135. addenda38,
  136. addenda39,
  137. addenda40,
  138. addenda41,
  139. NULL };
  140. static int cmu_is_silence(const char *p)
  141. {
  142. if (cst_streq(p,"pau"))
  143. return TRUE;
  144. else
  145. return FALSE;
  146. }
  147. static int cmu_has_vowel_in_list(const cst_val *v)
  148. {
  149. const cst_val *t;
  150. for (t=v; t; t=val_cdr(t))
  151. if (cmu_is_vowel(val_string(val_car(t))))
  152. return TRUE;
  153. return FALSE;
  154. }
  155. static int cmu_has_vowel_in_syl(const cst_item *i)
  156. {
  157. const cst_item *n;
  158. for (n=i; n; n=item_prev(n))
  159. if (cmu_is_vowel(item_feat_string(n,"name")))
  160. return TRUE;
  161. return FALSE;
  162. }
  163. static int cmu_is_vowel(const char *p)
  164. {
  165. /* this happens to work for US English phoneset */
  166. if (strchr("aeiou",p[0]) == NULL)
  167. return FALSE;
  168. else
  169. return TRUE;
  170. }
  171. static int cmu_sonority(const char *p)
  172. {
  173. /* A bunch of hacks for US English phoneset */
  174. if (cmu_is_vowel(p) || (cmu_is_silence(p)))
  175. return 5;
  176. else if (strchr("wylr",p[0]) != NULL)
  177. return 4; /* glides/liquids */
  178. else if (strchr("nm",p[0]) != NULL)
  179. return 3; /* nasals */
  180. else if (strchr("bdgjlmnnnrvwyz",p[0]) != NULL)
  181. return 2; /* voiced obstruents */
  182. else
  183. return 1;
  184. }
  185. int cmu_syl_boundary(const cst_item *i,const cst_val *rest)
  186. {
  187. /* Returns TRUE if this should be a syllable boundary */
  188. /* This is of course phone set dependent */
  189. int p, n, nn;
  190. if (rest == NULL)
  191. return TRUE;
  192. else if (cmu_is_silence(val_string(val_car(rest))))
  193. return TRUE;
  194. else if (!cmu_has_vowel_in_list(rest)) /* no more vowels so rest *all* coda */
  195. return FALSE;
  196. else if (!cmu_has_vowel_in_syl(i)) /* need a vowel */
  197. return FALSE;
  198. else if (cmu_is_vowel(val_string(val_car(rest))))
  199. return TRUE;
  200. else if (val_cdr(rest) == NULL)
  201. return FALSE;
  202. else
  203. { /* so there is following vowel, and multiple phones left */
  204. p = cmu_sonority(item_feat_string(i,"name"));
  205. n = cmu_sonority(val_string(val_car(rest)));
  206. nn = cmu_sonority(val_string(val_car(val_cdr(rest))));
  207. if ((p <= n) && (n <= nn))
  208. return TRUE;
  209. else
  210. return FALSE;
  211. }
  212. }
  213. static int cmulex_dist_to_vowel(const cst_val *rest)
  214. {
  215. if (rest == 0)
  216. return 0; /* shouldn't get here */
  217. else if (cmu_is_vowel(val_string(val_car(rest))))
  218. return 0;
  219. else
  220. return 1+cmulex_dist_to_vowel(val_cdr(rest));
  221. }
  222. static const char * const cmulex_onset_trigrams[] = {
  223. "str", "spy", "spr", "spl", "sky", "skw", "skr", "skl", NULL
  224. };
  225. static const char * const cmulex_onset_bigrams[] = {
  226. "zw", "zl",
  227. "vy", "vr", "vl",
  228. "thw", "thr",
  229. "ty", "tw",
  230. "tr", /* "ts", */
  231. "shw", "shr", "shn", "shm", "shl",
  232. "sw", "sv", "st", "sr", "sp", "sn", "sm", "sl", "sk", "sf",
  233. "py", "pw", "pr", "pl",
  234. "ny",
  235. "my", "mr",
  236. "ly",
  237. "ky", "kw", "kr", "kl",
  238. "hhy", "hhw", "hhr", "hhl",
  239. "gy", "gw", "gr", "gl",
  240. "fy", "fr", "fl",
  241. "dy", "dw", "dr",
  242. "by", "bw", "br", "bl",
  243. NULL
  244. };
  245. static int cmulex_onset_bigram(const cst_val *rest)
  246. {
  247. char x[10];
  248. int i;
  249. cst_sprintf(x,"%s%s",val_string(val_car(rest)),
  250. val_string(val_car(val_cdr(rest))));
  251. for (i=0; cmulex_onset_bigrams[i]; i++)
  252. if (cst_streq(x,cmulex_onset_bigrams[i]))
  253. return TRUE;
  254. return FALSE;
  255. }
  256. static int cmulex_onset_trigram(const cst_val *rest)
  257. {
  258. char x[15];
  259. int i;
  260. cst_sprintf(x,"%s%s%s",val_string(val_car(rest)),
  261. val_string(val_car(val_cdr(rest))),
  262. val_string(val_car(val_cdr(val_cdr(rest)))));
  263. for (i=0; cmulex_onset_trigrams[i]; i++)
  264. if (cst_streq(x,cmulex_onset_trigrams[i]))
  265. return TRUE;
  266. return FALSE;
  267. }
  268. int cmu_syl_boundary_mo(const cst_item *i,const cst_val *rest)
  269. {
  270. /* syl boundary maximal onset */
  271. int d2v;
  272. if (rest == NULL)
  273. return TRUE;
  274. else if (cmu_is_silence(val_string(val_car(rest))))
  275. return TRUE;
  276. else if (!cmu_has_vowel_in_list(rest))
  277. /* no more vowels so rest *all* coda */
  278. return FALSE;
  279. else if (!cmu_has_vowel_in_syl(i)) /* need a vowel */
  280. /* no vowel yet in syl so keep copying */
  281. return FALSE;
  282. else if (cmu_is_vowel(val_string(val_car(rest))))
  283. /* next is a vowel, syl has vowel, so this is a break */
  284. return TRUE;
  285. else if (cst_streq("ng",val_string(val_car(rest))))
  286. /* next is "ng" which can't start a word internal syl */
  287. return FALSE;
  288. else
  289. {
  290. /* want to know if from rest to the next vowel is a valid onset */
  291. d2v = cmulex_dist_to_vowel(rest);
  292. if (d2v < 2)
  293. return TRUE;
  294. else if (d2v > 3)
  295. return FALSE;
  296. else if (d2v == 2)
  297. return cmulex_onset_bigram(rest);
  298. else /* if (d2v == 3) */
  299. return cmulex_onset_trigram(rest);
  300. return TRUE;
  301. }
  302. }
  303. cst_lexicon cmu_lex;
  304. cst_lts_rules cmu_lts_rules;
  305. extern const char * const cmu_lts_phone_table[];
  306. extern const char * const cmu_lts_letter_table[];
  307. extern const cst_lts_addr cmu_lts_letter_index[];
  308. extern const cst_lts_model cmu_lts_model[];
  309. cst_lexicon *cmulex_init()
  310. {
  311. /* We actually need the init function match the directory name */
  312. return cmu_lex_init();
  313. }
  314. cst_lexicon *cmu_lex_init()
  315. {
  316. /* I'd like to do this as a const but it needs everything in this */
  317. /* file and already the bits are too big for some compilers */
  318. if (cmu_lts_rules.name)
  319. return &cmu_lex; /* Already initialized */
  320. cmu_lts_rules.name = "cmu";
  321. cmu_lts_rules.letter_index = cmu_lts_letter_index;
  322. #ifdef CST_NO_STATIC_LTS_MODEL
  323. /* cmu_lts_rules.models will be set elsewhere */
  324. #else
  325. cmu_lts_rules.models = cmu_lts_model;
  326. #endif
  327. cmu_lts_rules.phone_table = cmu_lts_phone_table;
  328. cmu_lts_rules.context_window_size = 4;
  329. cmu_lts_rules.context_extra_feats = 1;
  330. cmu_lts_rules.letter_table = 0 /* cmu_lts_letter_table */;
  331. cmu_lex.name = "cmu";
  332. cmu_lex.num_entries = cmu_lex_num_entries;
  333. #ifdef CST_NO_STATIC_LEX
  334. /* cmu_lex.data will be set elsewhere */
  335. #else
  336. /* as the data is const, we cast it through void * */
  337. cmu_lex.data = (unsigned char *)(void *)cmu_lex_data;
  338. #endif
  339. cmu_lex.num_bytes = cmu_lex_num_bytes;
  340. cmu_lex.phone_table = (char **) cmu_lex_phone_table;
  341. cmu_lex.syl_boundary = cmu_syl_boundary_mo;
  342. cmu_lex.addenda = (char ***) addenda;
  343. cmu_lex.lts_rule_set = (cst_lts_rules *) &cmu_lts_rules;
  344. cmu_lex.phone_hufftable = cmu_lex_phones_huff_table;
  345. cmu_lex.entry_hufftable = cmu_lex_entries_huff_table;
  346. cmu_lex.postlex = cmu_postlex;
  347. return &cmu_lex;
  348. }