eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

phoneme.c 7.4KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320
  1. /*
  2. * Copyright (C) 2017 Reece H. Dunn
  3. *
  4. * This program is free software; you can redistribute it and/or modify
  5. * it under the terms of the GNU General Public License as published by
  6. * the Free Software Foundation; either version 3 of the License, or
  7. * (at your option) any later version.
  8. *
  9. * This program is distributed in the hope that it will be useful,
  10. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  11. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  12. * GNU General Public License for more details.
  13. *
  14. * You should have received a copy of the GNU General Public License
  15. * along with this program; if not, see: <http://www.gnu.org/licenses/>.
  16. */
  17. #include "config.h"
  18. #include <errno.h>
  19. #include <stdint.h>
  20. #include <string.h>
  21. #include <espeak-ng/espeak_ng.h>
  22. #include <espeak-ng/speak_lib.h>
  23. #include "phoneme.h"
  24. #include "error.h"
  25. #define FEATURE(a, b, c) ((a << 16) | (b << 8) | (c))
  26. // See docs/phonemes.md for the list of supported features.
  27. enum feature_t {
  28. // invalid phoneme feature name
  29. inv, // Not in docs/phonemes.md. This is used to signal an unknown feature name.
  30. // manner of articulation
  31. nas = FEATURE('n', 'a', 's'),
  32. stp = FEATURE('s', 't', 'p'),
  33. afr = FEATURE('a', 'f', 'r'),
  34. frc = FEATURE('f', 'r', 'c'),
  35. flp = FEATURE('f', 'l', 'p'),
  36. trl = FEATURE('t', 'r', 'l'),
  37. apr = FEATURE('a', 'p', 'r'),
  38. clk = FEATURE('c', 'l', 'k'),
  39. ejc = FEATURE('e', 'j', 'c'),
  40. imp = FEATURE('i', 'm', 'p'),
  41. vwl = FEATURE('v', 'w', 'l'),
  42. lat = FEATURE('l', 'a', 't'),
  43. sib = FEATURE('s', 'i', 'b'),
  44. // place of articulation
  45. blb = FEATURE('b', 'l', 'b'),
  46. lbd = FEATURE('l', 'b', 'd'),
  47. bld = FEATURE('b', 'l', 'd'),
  48. dnt = FEATURE('d', 'n', 't'),
  49. alv = FEATURE('a', 'l', 'v'),
  50. pla = FEATURE('p', 'l', 'a'),
  51. rfx = FEATURE('r', 'f', 'x'),
  52. alp = FEATURE('a', 'l', 'p'),
  53. pal = FEATURE('p', 'a', 'l'),
  54. vel = FEATURE('v', 'e', 'l'),
  55. lbv = FEATURE('l', 'b', 'v'),
  56. uvl = FEATURE('u', 'v', 'l'),
  57. phr = FEATURE('p', 'h', 'r'),
  58. glt = FEATURE('g', 'l', 't'),
  59. // voice
  60. vcd = FEATURE('v', 'c', 'd'),
  61. vls = FEATURE('v', 'l', 's'),
  62. // vowel height
  63. hgh = FEATURE('h', 'g', 'h'),
  64. smh = FEATURE('s', 'm', 'h'),
  65. umd = FEATURE('u', 'm', 'd'),
  66. mid = FEATURE('m', 'i', 'd'),
  67. lmd = FEATURE('l', 'm', 'd'),
  68. sml = FEATURE('s', 'm', 'l'),
  69. low = FEATURE('l', 'o', 'w'),
  70. // vowel backness
  71. fnt = FEATURE('f', 'n', 't'),
  72. cnt = FEATURE('c', 'n', 't'),
  73. bck = FEATURE('b', 'c', 'k'),
  74. // rounding
  75. unr = FEATURE('u', 'n', 'r'),
  76. rnd = FEATURE('r', 'n', 'd'),
  77. // articulation
  78. lgl = FEATURE('l', 'g', 'l'),
  79. idt = FEATURE('i', 'd', 't'),
  80. apc = FEATURE('a', 'p', 'c'),
  81. lmn = FEATURE('l', 'm', 'n'),
  82. // air flow
  83. egs = FEATURE('e', 'g', 's'),
  84. igs = FEATURE('i', 'g', 's'),
  85. // phonation
  86. brv = FEATURE('b', 'r', 'v'),
  87. slv = FEATURE('s', 'l', 'v'),
  88. stv = FEATURE('s', 't', 'v'),
  89. crv = FEATURE('c', 'r', 'v'),
  90. glc = FEATURE('g', 'l', 'c'),
  91. // rounding and labialization
  92. ptr = FEATURE('p', 't', 'r'),
  93. cmp = FEATURE('c', 'm', 'p'),
  94. mrd = FEATURE('m', 'r', 'd'),
  95. lrd = FEATURE('l', 'r', 'd'),
  96. // syllabicity
  97. syl = FEATURE('s', 'y', 'l'),
  98. nsy = FEATURE('n', 's', 'y'),
  99. // consonant release
  100. asp = FEATURE('a', 's', 'p'),
  101. nrs = FEATURE('n', 'r', 's'),
  102. lrs = FEATURE('l', 'r', 's'),
  103. unx = FEATURE('u', 'n', 'x'),
  104. // coarticulation
  105. pzd = FEATURE('p', 'z', 'd'),
  106. vzd = FEATURE('v', 'z', 'd'),
  107. fzd = FEATURE('f', 'z', 'd'),
  108. nzd = FEATURE('n', 'z', 'd'),
  109. rzd = FEATURE('r', 'z', 'd'),
  110. // tongue root
  111. atr = FEATURE('a', 't', 'r'),
  112. rtr = FEATURE('r', 't', 'r'),
  113. // fortis and lenis
  114. fts = FEATURE('f', 't', 's'),
  115. lns = FEATURE('l', 'n', 's'),
  116. };
  117. uint32_t lookup_feature(const char *feature) {
  118. if (strlen(feature) != 3)
  119. return inv;
  120. return FEATURE(feature[0], feature[1], feature[2]);
  121. }
  122. espeak_ng_STATUS
  123. phoneme_add_feature(PHONEME_TAB *phoneme,
  124. const char *feature,
  125. espeak_ng_ERROR_CONTEXT *context)
  126. {
  127. if (!phoneme || !feature) return EINVAL;
  128. switch (lookup_feature(feature))
  129. {
  130. // manner of articulation
  131. case nas:
  132. phoneme->type = phNASAL;
  133. break;
  134. case stp:
  135. case afr: // FIXME: eSpeak treats 'afr' as 'stp'.
  136. phoneme->type = phSTOP;
  137. break;
  138. case frc:
  139. case apr: // FIXME: eSpeak is using this for [h], with 'liquid' used for [l] and [r].
  140. phoneme->type = phFRICATIVE;
  141. break;
  142. case flp: // FIXME: Why is eSpeak using a vstop (vcd + stp) for this?
  143. phoneme->type = phVSTOP;
  144. break;
  145. case trl: // FIXME: 'trill' should be the type; 'liquid' should be a flag (phoneme files specify both).
  146. phoneme->phflags |= phTRILL;
  147. break;
  148. case clk:
  149. case ejc:
  150. case imp:
  151. case lat:
  152. // Not supported by eSpeak.
  153. break;
  154. case vwl:
  155. phoneme->type = phVOWEL;
  156. break;
  157. case sib:
  158. phoneme->phflags |= phSIBILANT;
  159. break;
  160. // place of articulation
  161. case blb:
  162. phoneme->phflags &= ~phARTICULATION;
  163. phoneme->phflags |= 1 << 16;
  164. break;
  165. case lbd:
  166. phoneme->phflags &= ~phARTICULATION;
  167. phoneme->phflags |= 2 << 16;
  168. break;
  169. case dnt:
  170. phoneme->phflags &= ~phARTICULATION;
  171. phoneme->phflags |= 3 << 16;
  172. break;
  173. case alv:
  174. phoneme->phflags &= ~phARTICULATION;
  175. phoneme->phflags |= 4 << 16;
  176. break;
  177. case rfx:
  178. phoneme->phflags &= ~phARTICULATION;
  179. phoneme->phflags |= 5 << 16;
  180. break;
  181. case pla:
  182. phoneme->phflags &= ~phARTICULATION;
  183. phoneme->phflags |= 6 << 16;
  184. break;
  185. case pal:
  186. phoneme->phflags &= ~phARTICULATION;
  187. phoneme->phflags |= 7 << 16;
  188. break;
  189. case vel:
  190. phoneme->phflags &= ~phARTICULATION;
  191. phoneme->phflags |= 8 << 16;
  192. break;
  193. case lbv:
  194. phoneme->phflags &= ~phARTICULATION;
  195. phoneme->phflags |= 9 << 16;
  196. break;
  197. case uvl:
  198. phoneme->phflags &= ~phARTICULATION;
  199. phoneme->phflags |= 10 << 16;
  200. break;
  201. case phr:
  202. phoneme->phflags &= ~phARTICULATION;
  203. phoneme->phflags |= 11 << 16;
  204. break;
  205. case glt:
  206. phoneme->phflags &= ~phARTICULATION;
  207. phoneme->phflags |= 12 << 16;
  208. break;
  209. case bld:
  210. // FIXME: Not supported by eSpeak. Used in German p͡f.
  211. break;
  212. case alp:
  213. // FIXME: Not supported by eSpeak. Used in Chinese/Japanese ɕ and ʑ.
  214. break;
  215. // voice
  216. case vcd:
  217. phoneme->phflags |= phVOICED;
  218. break;
  219. case vls:
  220. phoneme->phflags |= phVOICELESS;
  221. break;
  222. // vowel height
  223. case hgh:
  224. case smh:
  225. case umd:
  226. case mid:
  227. case lmd:
  228. case sml:
  229. case low:
  230. // Not supported by eSpeak.
  231. break;
  232. // vowel backness
  233. case fnt:
  234. case cnt:
  235. case bck:
  236. // Not supported by eSpeak.
  237. break;
  238. // rounding
  239. case unr:
  240. case rnd:
  241. // Not supported by eSpeak.
  242. break;
  243. // articulation
  244. case lgl:
  245. case idt:
  246. case apc:
  247. case lmn:
  248. // Not supported by eSpeak.
  249. break;
  250. // air flow
  251. case egs:
  252. case igs:
  253. // Not supported by eSpeak.
  254. break;
  255. // phonation
  256. case brv:
  257. case slv:
  258. case stv:
  259. case crv:
  260. case glc:
  261. // Not supported by eSpeak.
  262. break;
  263. // rounding and labialization
  264. case ptr:
  265. case cmp:
  266. case mrd:
  267. case lrd:
  268. // Not supported by eSpeak.
  269. break;
  270. // syllabicity
  271. case syl:
  272. // Not supported by eSpeak.
  273. break;
  274. case nsy:
  275. phoneme->phflags |= phNONSYLLABIC;
  276. break;
  277. // consonant release
  278. case asp:
  279. case nrs:
  280. case lrs:
  281. case unx:
  282. // Not supported by eSpeak.
  283. break;
  284. // coarticulation
  285. case pzd:
  286. phoneme->phflags |= phPALATAL;
  287. break;
  288. case vzd:
  289. case fzd:
  290. case nzd:
  291. // Not supported by eSpeak.
  292. break;
  293. case rzd:
  294. phoneme->phflags |= phRHOTIC;
  295. break;
  296. // tongue root
  297. case atr:
  298. case rtr:
  299. // Not supported by eSpeak.
  300. break;
  301. // fortis and lenis
  302. case fts:
  303. case lns:
  304. // Not supported by eSpeak.
  305. break;
  306. // invalid phoneme feature
  307. default:
  308. return create_name_error_context(context, ENS_UNKNOWN_PHONEME_FEATURE, feature);
  309. }
  310. return ENS_OK;
  311. }