flowm_flite.c 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418
  1. /*************************************************************************/
  2. /* */
  3. /* Language Technologies Institute */
  4. /* Carnegie Mellon University */
  5. /* Copyright (c) 2009 */
  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 2009 */
  35. /*************************************************************************/
  36. /* */
  37. /* flowm functions for flite access */
  38. /* */
  39. /*************************************************************************/
  40. #include <windows.h>
  41. #include <commctrl.h>
  42. #include <aygshell.h>
  43. #include "cst_wchar.h"
  44. #include "flite.h"
  45. #include "flowm.h"
  46. /* For debugging its sometimes good to switch off the actual synthesis */
  47. #define DOTTS 1
  48. static cst_audiodev *fl_ad = 0;
  49. #ifdef DOTTS
  50. cst_voice *register_cmu_us_kal(const char *voxdir);
  51. void unregister_cmu_us_kal(cst_voice *v);
  52. cst_voice *register_cmu_us_awb(const char *voxdir);
  53. void unregister_cmu_us_awb(cst_voice *v);
  54. cst_voice *register_cmu_us_rms(const char *voxdir);
  55. void unregister_cmu_us_rms(cst_voice *v);
  56. cst_voice *register_cmu_us_slt(const char *voxdir);
  57. void unregister_cmu_us_slt(cst_voice *v);
  58. #endif
  59. cst_wave *previous_wave = NULL;
  60. typedef struct VoxDef_struct
  61. {
  62. TCHAR *name;
  63. cst_voice *(*rv)(const char *voxdir); /* register_voice */
  64. void (*urv)(cst_voice *v); /* unregister_voice */
  65. int min_buffsize; /* for audio streaming */
  66. cst_voice *v;
  67. } VoxDef;
  68. VoxDef VoxDefs[] = {
  69. #ifdef cmu_us_kal
  70. { L"kal", register_cmu_us_kal, unregister_cmu_us_kal, 256, NULL },
  71. #endif
  72. #ifdef cmu_us_awb
  73. { L"awb", register_cmu_us_awb, unregister_cmu_us_awb, 2000, NULL },
  74. #endif
  75. #ifdef cmu_us_rms
  76. { L"rms", register_cmu_us_rms, unregister_cmu_us_rms, 2000, NULL },
  77. #endif
  78. #ifdef cmu_us_slt
  79. { L"slt", register_cmu_us_slt, unregister_cmu_us_slt, 2000, NULL },
  80. #endif
  81. { NULL, NULL }
  82. };
  83. cst_utterance *flowm_print_relation_callback(cst_utterance *u);
  84. cst_utterance *flowm_utt_callback(cst_utterance *u);
  85. int flowm_audio_stream_chunk(const cst_wave *w, int start, int size,
  86. int last, cst_audio_streaming_info *asi);
  87. float flowm_find_file_percentage()
  88. {
  89. if (flowm_file_size <= 0)
  90. return 0.0;
  91. else
  92. return (flowm_file_pos*100.0)/flowm_file_size;
  93. }
  94. TCHAR *flowm_voice_name(int i)
  95. {
  96. /* In order not to have flite things in flowm_main, we provide an */
  97. /* interface to the voice list */
  98. return VoxDefs[i].name;
  99. }
  100. void flowm_init()
  101. {
  102. #ifdef DOTTS
  103. int i;
  104. cst_audio_streaming_info *asi;
  105. flite_init(); /* Initialize flite interface */
  106. for (i=0; VoxDefs[i].name; i++)
  107. {
  108. VoxDefs[i].v = (VoxDefs[i].rv)(NULL); /* register voice */
  109. /* Set up call back function for low level audio streaming */
  110. /* This way it plays the waveform as it synthesizes it */
  111. /* This is necessary for the slower (CG) voices */
  112. asi = new_audio_streaming_info();
  113. asi->asc = flowm_audio_stream_chunk;
  114. asi->min_buffsize = VoxDefs[i].min_buffsize;
  115. feat_set(VoxDefs[i].v->features,
  116. "streaming_info",
  117. audio_streaming_info_val(asi));
  118. /* Set up call back function for sending what tokens are being */
  119. /* synthesized and for keeping track of the current position in */
  120. /* the file */
  121. feat_set(VoxDefs[i].v->features,
  122. "utt_user_callback",
  123. uttfunc_val(flowm_utt_callback));
  124. /* For outputing results of a relation (only used in play) */
  125. feat_set(VoxDefs[i].v->features,
  126. "post_synth_hook_func",
  127. uttfunc_val(flowm_print_relation_callback));
  128. }
  129. #endif
  130. return;
  131. }
  132. void flowm_terminate()
  133. {
  134. #ifdef DOTTS
  135. int i;
  136. for (i=0; VoxDefs[i].name; i++)
  137. {
  138. (VoxDefs[i].urv)(VoxDefs[i].v); /* unregister voice */
  139. }
  140. #endif
  141. if (previous_wave)
  142. {
  143. delete_wave(previous_wave);
  144. previous_wave = NULL;
  145. }
  146. return;
  147. }
  148. int flowm_save_wave(TCHAR *filename)
  149. {
  150. /* Save the Last synthesized waveform file to filename */
  151. char *sfilename;
  152. int rc;
  153. if (!previous_wave)
  154. return -1;
  155. sfilename = cst_wstr2cstr(filename);
  156. rc = cst_wave_save_riff(previous_wave,sfilename);
  157. cst_free(sfilename);
  158. return rc;
  159. }
  160. #ifdef DOTTS
  161. int flowm_say_text(TCHAR *text)
  162. {
  163. char *s;
  164. int ns;
  165. cst_voice *v;
  166. if (previous_wave)
  167. {
  168. delete_wave(previous_wave);
  169. previous_wave = NULL;
  170. }
  171. s = cst_wstr2cstr(text); /* text to synthesize */
  172. v = VoxDefs[flowm_selected_voice].v; /* voice to synthesize with */
  173. feat_remove(v->features,"print_info_relation");
  174. if (flowm_selected_relation == 1)
  175. feat_set_string(v->features, "print_info_relation", "Word");
  176. if (flowm_selected_relation == 2)
  177. feat_set_string(v->features, "print_info_relation", "Segment");
  178. /* Do the synthesis */
  179. previous_wave = flite_text_to_wave(s,v);
  180. ns = cst_wave_num_samples(previous_wave);
  181. cst_free(s);
  182. audio_flush(fl_ad);
  183. audio_close(fl_ad);
  184. fl_ad = NULL;
  185. return ns;
  186. }
  187. #else
  188. int flowm_say_text(TCHAR *text)
  189. {
  190. MessageBoxW(0,text,L"SayText",0);
  191. return 0;
  192. }
  193. #endif
  194. cst_utterance *flowm_print_relation_callback(cst_utterance *u)
  195. {
  196. /* Say the details of a named relation for display */
  197. char rst[FL_MAX_MSG_CHARS];
  198. const char *name;
  199. const char *relname;
  200. cst_item *item;
  201. char *space;
  202. space = "";
  203. relname = get_param_string(u->features,"print_info_relation", NULL);
  204. cst_sprintf(rst,"%s: ",relname);
  205. if (!relname)
  206. {
  207. mbstowcs(fl_tts_msg,"",FL_MAX_MSG_CHARS);
  208. return u;
  209. }
  210. for (item=relation_head(utt_relation(u,relname));
  211. item; item=item_next(item))
  212. {
  213. name = item_feat_string(item,"name");
  214. if (cst_strlen(name)+1+4 < FL_MAX_MSG_CHARS)
  215. cst_sprintf(rst,"%s%s%s",rst,space,name);
  216. else if (cst_strlen(rst)+4 < FL_MAX_MSG_CHARS)
  217. cst_sprintf(rst,"%s ...",rst);
  218. else
  219. break;
  220. space = " ";
  221. }
  222. mbstowcs(fl_tts_msg,rst,FL_MAX_MSG_CHARS);
  223. return u;
  224. }
  225. cst_utterance *flowm_utt_callback(cst_utterance *u)
  226. {
  227. char rst[FL_MAX_MSG_CHARS];
  228. const char *tok;
  229. cst_item *item;
  230. char *space;
  231. int extend_length;
  232. /* In order to stop the synthesizer if the STOP button is pressed */
  233. /* This stops the synthesis of the next utterance */
  234. if ((flowm_play_status == FLOWM_PLAY) ||
  235. (flowm_play_status == FLOWM_SKIP))
  236. {
  237. if (TTSWindow)
  238. {
  239. rst[0] = '\0';
  240. space = "";
  241. for (item=relation_head(utt_relation(u,"Token"));
  242. item; item=item_next(item))
  243. {
  244. tok = item_feat_string(item,"name");
  245. if (cst_streq("",space))
  246. /* Only do this on the first token/word */
  247. flowm_file_pos = item_feat_int(item,"file_pos");
  248. extend_length = cst_strlen(rst) + 1 +
  249. cst_strlen(item_feat_string(item,"prepunctuation"))+
  250. cst_strlen(item_feat_string(item,"punc"));
  251. if (cst_strlen(tok)+extend_length+4 < FL_MAX_MSG_CHARS)
  252. cst_sprintf(rst,"%s%s%s%s%s",rst,space,
  253. item_feat_string(item,"prepunctuation"),
  254. tok,
  255. item_feat_string(item,"punc"));
  256. else
  257. {
  258. if (cst_strlen(rst)+4 < FL_MAX_MSG_CHARS)
  259. cst_sprintf(rst,"%s ...",rst);
  260. break;
  261. }
  262. space = " ";
  263. }
  264. if (flowm_file_pos > flowm_prev_utt_pos[flowm_utt_pos_pos])
  265. {
  266. if ((flowm_utt_pos_pos+1) >= FLOWM_NUM_UTT_POS)
  267. {
  268. /* Filled it up, so move it down */
  269. memmove(flowm_prev_utt_pos,&flowm_prev_utt_pos[1],
  270. sizeof(int)*(FLOWM_NUM_UTT_POS-10));
  271. flowm_utt_pos_pos = (FLOWM_NUM_UTT_POS-10);
  272. }
  273. flowm_utt_pos_pos++;
  274. flowm_prev_utt_pos[flowm_utt_pos_pos] = flowm_file_pos;
  275. }
  276. /* Send text to TTSWindow */
  277. mbstowcs(fl_tts_msg,rst,FL_MAX_MSG_CHARS);
  278. SetDlgItemText(TTSWindow, FL_SYNTHTEXT, fl_tts_msg);
  279. /* Update file pos percentage in FilePos window */
  280. cst_sprintf(rst,"%2.3f",flowm_find_file_percentage());
  281. mbstowcs(fl_fp_msg,rst,FL_MAX_MSG_CHARS);
  282. SetDlgItemText(TTSWindow, FL_FILEPOS, fl_fp_msg);
  283. SystemIdleTimerReset(); /* keep alive while synthesizing */
  284. if (flowm_play_status == FLOWM_SKIP)
  285. flowm_play_status = FLOWM_PLAY;
  286. }
  287. return u;
  288. }
  289. else
  290. {
  291. delete_utterance(u);
  292. return 0;
  293. }
  294. }
  295. int flowm_audio_stream_chunk(const cst_wave *w, int start, int size,
  296. int last, cst_audio_streaming_info *asi)
  297. {
  298. if (fl_ad == NULL)
  299. {
  300. fl_ad = audio_open(w->sample_rate,w->num_channels,CST_AUDIO_LINEAR16);
  301. }
  302. if (flowm_play_status == FLOWM_PLAY)
  303. {
  304. audio_write(fl_ad,&w->samples[start],size*sizeof(short));
  305. return CST_AUDIO_STREAM_CONT;
  306. }
  307. else if (flowm_play_status == FLOWM_BENCH)
  308. { /* Do TTS but don't actually play it */
  309. /* How much have we played */
  310. flowm_duration += (size*1.0)/w->sample_rate;
  311. return CST_AUDIO_STREAM_CONT;
  312. }
  313. else
  314. { /* for STOP, and the SKIPS (if they get here) */
  315. return CST_AUDIO_STREAM_STOP;
  316. }
  317. }
  318. #ifdef DOTTS
  319. int flowm_say_file(TCHAR *tfilename)
  320. {
  321. int rc = 0;
  322. char *filename;
  323. cst_voice *v;
  324. if (previous_wave)
  325. { /* This is really tidy up from Play -- but might say space */
  326. delete_wave(previous_wave);
  327. previous_wave = NULL;
  328. }
  329. if (fl_ad)
  330. {
  331. MessageBoxW(0,L"audio fd still open",L"SayFile",0);
  332. audio_close(fl_ad);
  333. fl_ad = NULL;
  334. }
  335. v = VoxDefs[flowm_selected_voice].v;
  336. /* Where we want to start from */
  337. feat_set_int(v->features, "file_start_position", flowm_file_pos);
  338. /* Only do print_info in play mode */
  339. feat_remove(v->features,"print_info_relation");
  340. filename = cst_wstr2cstr(tfilename);
  341. rc = flite_file_to_speech(filename, v, "stream");
  342. cst_free(filename);
  343. audio_flush(fl_ad);
  344. audio_close(fl_ad);
  345. fl_ad = NULL;
  346. return rc;
  347. }
  348. #else
  349. int flowm_say_file(TCHAR *text)
  350. {
  351. MessageBoxW(0,text,L"SayFile",0);
  352. return 0;
  353. }
  354. #endif