flite_main.c 14 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423
  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. /* Simple top level program */
  38. /* */
  39. /*************************************************************************/
  40. #include <stdio.h>
  41. #include <string.h>
  42. #include <sys/time.h>
  43. #include <unistd.h>
  44. #include "flite.h"
  45. #include "flite_version.h"
  46. cst_val *flite_set_voice_list(const char *voxdir);
  47. void *flite_set_lang_list(void);
  48. void cst_alloc_debug_summary();
  49. /* Its not very appropriate that these are declared here */
  50. void usenglish_init(cst_voice *v);
  51. cst_lexicon *cmu_lex_init(void);
  52. static void flite_version()
  53. {
  54. printf(" Carnegie Mellon University, Copyright (c) 1999-2011, all rights reserved\n");
  55. printf(" version: %s-%s-%s %s (http://cmuflite.org)\n",
  56. FLITE_PROJECT_PREFIX,
  57. FLITE_PROJECT_VERSION,
  58. FLITE_PROJECT_STATE,
  59. FLITE_PROJECT_DATE);
  60. }
  61. static void flite_usage()
  62. {
  63. printf("flite: a small simple speech synthesizer\n");
  64. flite_version();
  65. printf("usage: flite TEXT/FILE [WAVEFILE]\n"
  66. " Converts text in TEXTFILE to a waveform in WAVEFILE\n"
  67. " If text contains a space the it is treated as a literal\n"
  68. " textstring and spoken, and not as a file name\n"
  69. " if WAVEFILE is unspecified or \"play\" the result is\n"
  70. " played on the current systems audio device. If WAVEFILE\n"
  71. " is \"none\" the waveform is discarded (good for benchmarking)\n"
  72. " Other options must appear before these options\n"
  73. " --version Output flite version number\n"
  74. " --help Output usage string\n"
  75. " -o WAVEFILE Explicitly set output filename\n"
  76. " -f TEXTFILE Explicitly set input filename\n"
  77. " -t TEXT Explicitly set input textstring\n"
  78. " -p PHONES Explicitly set input textstring and synthesize as phones\n"
  79. " --set F=V Set feature (guesses type)\n"
  80. " -s F=V Set feature (guesses type)\n"
  81. " --seti F=V Set int feature\n"
  82. " --setf F=V Set float feature\n"
  83. " --sets F=V Set string feature\n"
  84. " -ssml Read input text/file in ssml mode\n"
  85. " -b Benchmark mode\n"
  86. " -l Loop endlessly\n"
  87. " -voice NAME Use voice NAME (NAME can be filename or url too)\n"
  88. " -voicedir NAME Directory contain voice data\n"
  89. " -lv List voices available\n"
  90. " -add_lex FILENAME add lex addenda from FILENAME\n"
  91. " -pw Print words\n"
  92. " -ps Print segments\n"
  93. " -psdur Print segments and their durations (end-time)\n"
  94. " -pr RelName Print relation RelName\n"
  95. " -voicedump FILENAME Dump selected (cg) voice to FILENAME\n"
  96. " -v Verbose mode\n");
  97. exit(0);
  98. }
  99. static void flite_voice_list_print(void)
  100. {
  101. cst_voice *voice;
  102. const cst_val *v;
  103. printf("Voices available: ");
  104. for (v=flite_voice_list; v; v=val_cdr(v))
  105. {
  106. voice = val_voice(val_car(v));
  107. printf("%s ",voice->name);
  108. }
  109. printf("\n");
  110. return;
  111. }
  112. static cst_utterance *print_info(cst_utterance *u)
  113. {
  114. cst_item *item;
  115. const char *relname;
  116. int printEndTime = 0;
  117. relname = utt_feat_string(u,"print_info_relation");
  118. if (!strcmp(relname, "SegmentEndTime"))
  119. {
  120. relname = "Segment";
  121. printEndTime = 1;
  122. }
  123. for (item=relation_head(utt_relation(u,relname));
  124. item;
  125. item=item_next(item))
  126. {
  127. if (!printEndTime)
  128. printf("%s ",item_feat_string(item,"name"));
  129. else
  130. printf("%s:%1.3f ",item_feat_string(item,"name"), item_feat_float(item,"end"));
  131. #if 0
  132. if (cst_streq("+",ffeature_string(item,"ph_vc")))
  133. printf("%s",ffeature_string(item,"R:SylStructure.parent.stress"));
  134. printf(" ");
  135. #endif
  136. }
  137. printf("\n");
  138. return u;
  139. }
  140. static void ef_set(cst_features *f,const char *fv,const char *type)
  141. {
  142. /* set feature from fv (F=V), guesses type if not explicit type given */
  143. const char *val;
  144. char *feat;
  145. const char *fname;
  146. if ((val = strchr(fv,'=')) == 0)
  147. {
  148. fprintf(stderr,
  149. "flite: can't find '=' in featval \"%s\", ignoring it\n",
  150. fv);
  151. }
  152. else
  153. {
  154. feat = cst_strdup(fv);
  155. feat[cst_strlen(fv)-cst_strlen(val)] = '\0';
  156. fname=feat_own_string(f,feat);
  157. val = val+1;
  158. if ((type && cst_streq("int",type)) ||
  159. ((type == 0) && (cst_regex_match(cst_rx_int,val))))
  160. feat_set_int(f,fname,atoi(val));
  161. else if ((type && cst_streq("float",type)) ||
  162. ((type == 0) && (cst_regex_match(cst_rx_double,val))))
  163. feat_set_float(f,fname,atof(val));
  164. else
  165. feat_set_string(f,fname,val);
  166. cst_free(feat);
  167. }
  168. }
  169. int main(int argc, char **argv)
  170. {
  171. struct timeval tv;
  172. cst_voice *v;
  173. const char *filename;
  174. const char *outtype;
  175. cst_voice *desired_voice = 0;
  176. const char *voicedir = NULL;
  177. int i;
  178. float durs;
  179. double time_start, time_end;
  180. int flite_verbose, flite_loop, flite_bench;
  181. int explicit_filename, explicit_text, explicit_phones, ssml_mode;
  182. #define ITER_MAX 3
  183. int bench_iter = 0;
  184. cst_features *extra_feats;
  185. const char *lex_addenda_file = NULL;
  186. const char *voicedumpfile = NULL;
  187. cst_audio_streaming_info *asi;
  188. filename = 0;
  189. outtype = "play"; /* default is to play */
  190. flite_verbose = FALSE;
  191. flite_loop = FALSE;
  192. flite_bench = FALSE;
  193. explicit_text = explicit_filename = explicit_phones = FALSE;
  194. ssml_mode = FALSE;
  195. extra_feats = new_features();
  196. flite_init();
  197. flite_set_lang_list(); /* defined at compilation time */
  198. for (i=1; i<argc; i++)
  199. {
  200. if (cst_streq(argv[i],"--version"))
  201. {
  202. flite_version();
  203. return 1;
  204. }
  205. else if (cst_streq(argv[i],"-h") ||
  206. cst_streq(argv[i],"--help") ||
  207. cst_streq(argv[i],"-?"))
  208. flite_usage();
  209. else if (cst_streq(argv[i],"-v"))
  210. flite_verbose = TRUE;
  211. else if (cst_streq(argv[i],"-lv"))
  212. {
  213. if (flite_voice_list == NULL)
  214. flite_set_voice_list(voicedir);
  215. flite_voice_list_print();
  216. exit(0);
  217. }
  218. else if (cst_streq(argv[i],"-l"))
  219. flite_loop = TRUE;
  220. else if (cst_streq(argv[i],"-b"))
  221. {
  222. flite_bench = TRUE;
  223. break; /* ignore other arguments */
  224. }
  225. else if ((cst_streq(argv[i],"-o")) && (i+1 < argc))
  226. {
  227. outtype = argv[i+1];
  228. i++;
  229. }
  230. else if ((cst_streq(argv[i],"-voice")) && (i+1 < argc))
  231. {
  232. if (flite_voice_list == NULL)
  233. flite_set_voice_list(voicedir);
  234. desired_voice = flite_voice_select(argv[i+1]);
  235. i++;
  236. }
  237. else if ((cst_streq(argv[i],"-voicedir")) && (i+1 < argc))
  238. {
  239. voicedir = argv[i+1];
  240. if (flite_voice_list == NULL)
  241. flite_set_voice_list(voicedir);
  242. i++;
  243. }
  244. else if ((cst_streq(argv[i],"-add_lex")) && (i+1 < argc))
  245. {
  246. lex_addenda_file = argv[i+1];
  247. i++;
  248. }
  249. else if (cst_streq(argv[i],"-f") && (i+1 < argc))
  250. {
  251. filename = argv[i+1];
  252. explicit_filename = TRUE;
  253. i++;
  254. }
  255. else if (cst_streq(argv[i],"-pw"))
  256. {
  257. feat_set_string(extra_feats,"print_info_relation","Word");
  258. feat_set(extra_feats,"post_synth_hook_func",
  259. uttfunc_val(&print_info));
  260. }
  261. else if (cst_streq(argv[i],"-ps"))
  262. {
  263. feat_set_string(extra_feats,"print_info_relation","Segment");
  264. feat_set(extra_feats,"post_synth_hook_func",
  265. uttfunc_val(&print_info));
  266. }
  267. else if (cst_streq(argv[i],"-psdur"))
  268. {
  269. // Added by AUP Mar 2013 for extracting durations (end-time) of segments
  270. // (useful in talking heads, etc.)
  271. feat_set_string(extra_feats,"print_info_relation","SegmentEndTime");
  272. feat_set(extra_feats,"post_synth_hook_func",
  273. uttfunc_val(&print_info));
  274. }
  275. else if (cst_streq(argv[i],"-ssml"))
  276. {
  277. ssml_mode = TRUE;
  278. }
  279. else if (cst_streq(argv[i],"-pr") && (i+1 < argc))
  280. {
  281. feat_set_string(extra_feats,"print_info_relation",argv[i+1]);
  282. feat_set(extra_feats,"post_synth_hook_func",
  283. uttfunc_val(&print_info));
  284. i++;
  285. }
  286. else if (cst_streq(argv[i],"-voicedump") && (i+1 < argc))
  287. {
  288. voicedumpfile = argv[i+1];
  289. i++;
  290. }
  291. else if ((cst_streq(argv[i],"-set") || cst_streq(argv[i],"-s"))
  292. && (i+1 < argc))
  293. {
  294. ef_set(extra_feats,argv[i+1],0);
  295. i++;
  296. }
  297. else if (cst_streq(argv[i],"--seti") && (i+1 < argc))
  298. {
  299. ef_set(extra_feats,argv[i+1],"int");
  300. i++;
  301. }
  302. else if (cst_streq(argv[i],"--setf") && (i+1 < argc))
  303. {
  304. ef_set(extra_feats,argv[i+1],"float");
  305. i++;
  306. }
  307. else if (cst_streq(argv[i],"--sets") && (i+1 < argc))
  308. {
  309. ef_set(extra_feats,argv[i+1],"string");
  310. i++;
  311. }
  312. else if (cst_streq(argv[i],"-p") && (i+1 < argc))
  313. {
  314. filename = argv[i+1];
  315. explicit_phones = TRUE;
  316. i++;
  317. }
  318. else if (cst_streq(argv[i],"-t") && (i+1 < argc))
  319. {
  320. filename = argv[i+1];
  321. explicit_text = TRUE;
  322. i++;
  323. }
  324. else if (filename)
  325. outtype = argv[i];
  326. else
  327. filename = argv[i];
  328. }
  329. if (filename == NULL) filename = "-"; /* stdin */
  330. if (flite_voice_list == NULL)
  331. flite_set_voice_list(voicedir);
  332. if (desired_voice == 0)
  333. desired_voice = flite_voice_select(NULL);
  334. v = desired_voice;
  335. feat_copy_into(extra_feats,v->features);
  336. durs = 0.0;
  337. if (voicedumpfile != NULL)
  338. {
  339. flite_voice_dump(v,voicedumpfile);
  340. exit(0);
  341. }
  342. if (lex_addenda_file)
  343. flite_voice_add_lex_addenda(v,lex_addenda_file);
  344. if (cst_streq("stream",outtype))
  345. {
  346. asi = new_audio_streaming_info();
  347. asi->asc = audio_stream_chunk;
  348. feat_set(v->features,"streaming_info",audio_streaming_info_val(asi));
  349. }
  350. if (flite_bench)
  351. {
  352. outtype = "none";
  353. filename = "A whole joy was reaping, but they've gone south, you should fetch azure mike.";
  354. explicit_text = TRUE;
  355. }
  356. loop:
  357. gettimeofday(&tv,NULL);
  358. time_start = (double)(tv.tv_sec)+(((double)tv.tv_usec)/1000000.0);
  359. if (explicit_phones)
  360. durs = flite_phones_to_speech(filename,v,outtype);
  361. else if ((strchr(filename,' ') && !explicit_filename) || explicit_text)
  362. {
  363. if (ssml_mode)
  364. durs = flite_ssml_text_to_speech(filename,v,outtype);
  365. else
  366. durs = flite_text_to_speech(filename,v,outtype);
  367. }
  368. else
  369. {
  370. if (ssml_mode)
  371. durs = flite_ssml_file_to_speech(filename,v,outtype);
  372. else
  373. durs = flite_file_to_speech(filename,v,outtype);
  374. }
  375. gettimeofday(&tv,NULL);
  376. time_end = ((double)(tv.tv_sec))+((double)tv.tv_usec/1000000.0);
  377. if (flite_verbose || (flite_bench && bench_iter == ITER_MAX))
  378. printf("times faster than real-time: %f\n(%f seconds of speech synthesized in %f)\n",
  379. durs/(float)(time_end-time_start),
  380. durs,
  381. (float)(time_end-time_start));
  382. if (flite_loop || (flite_bench && bench_iter++ < ITER_MAX))
  383. goto loop;
  384. delete_features(extra_feats);
  385. delete_val(flite_voice_list); flite_voice_list=0;
  386. /* cst_alloc_debug_summary(); */
  387. return 0;
  388. }