eSpeak NG is an open source speech synthesizer that supports more than hundred languages and accents.

speak.cpp 20KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883
  1. /***************************************************************************
  2. * Copyright (C) 2005 to 2007 by Jonathan Duddington *
  3. * email: jonsd@users.sourceforge.net *
  4. * *
  5. * This program is free software; you can redistribute it and/or modify *
  6. * it under the terms of the GNU General Public License as published by *
  7. * the Free Software Foundation; either version 3 of the License, or *
  8. * (at your option) any later version. *
  9. * *
  10. * This program is distributed in the hope that it will be useful, *
  11. * but WITHOUT ANY WARRANTY; without even the implied warranty of *
  12. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
  13. * GNU General Public License for more details. *
  14. * *
  15. * You should have received a copy of the GNU General Public License *
  16. * along with this program; if not, write see: *
  17. * <http://www.gnu.org/licenses/>. *
  18. ***************************************************************************/
  19. #include "StdAfx.h"
  20. #include "speech.h"
  21. #include <stdio.h>
  22. #include <stdlib.h>
  23. #include <string.h>
  24. #ifndef PLATFORM_DOS
  25. #ifdef PLATFORM_WINDOWS
  26. #include <windows.h>
  27. #include <winreg.h>
  28. #else
  29. #include <unistd.h>
  30. #endif
  31. #endif
  32. #ifndef NEED_GETOPT
  33. #include <getopt.h>
  34. #endif
  35. #include <time.h>
  36. #include <signal.h>
  37. #include <locale.h>
  38. #include <sys/stat.h>
  39. #include "speak_lib.h"
  40. #include "phoneme.h"
  41. #include "synthesize.h"
  42. #include "voice.h"
  43. #include "translate.h"
  44. extern void Write4Bytes(FILE *f, int value);
  45. char path_home[N_PATH_HOME]; // this is the espeak-data directory
  46. char filetype[5];
  47. char wavefile[200];
  48. int (* uri_callback)(int, const char *, const char *) = NULL;
  49. int (* phoneme_callback)(const char *) = NULL;
  50. FILE *f_wave = NULL;
  51. int quiet = 0;
  52. unsigned int samples_total = 0;
  53. unsigned int samples_split = 0;
  54. unsigned int wavefile_count = 0;
  55. int end_of_sentence = 0;
  56. static const char *help_text =
  57. "\nspeak [options] [\"<words>\"]\n\n"
  58. "-f <text file> Text file to speak\n"
  59. "--stdin Read text input from stdin instead of a file\n\n"
  60. "If neither -f nor --stdin, <words> are spoken, or if none then text is\n"
  61. "spoken from stdin, each line separately.\n\n"
  62. "-a <integer>\n"
  63. "\t Amplitude, 0 to 200, default is 100\n"
  64. "-g <integer>\n"
  65. "\t Word gap. Pause between words, units of 10mS at the default speed\n"
  66. "-l <integer>\n"
  67. "\t Line length. If not zero (which is the default), consider\n"
  68. "\t lines less than this length as end-of-clause\n"
  69. "-p <integer>\n"
  70. "\t Pitch adjustment, 0 to 99, default is 50\n"
  71. "-s <integer>\n"
  72. "\t Speed in words per minute 80 to 390, default is 170\n"
  73. "-v <voice name>\n"
  74. "\t Use voice file of this name from espeak-data/voices\n"
  75. "-w <wave file name>\n"
  76. "\t Write output to this WAV file, rather than speaking it directly\n"
  77. "-b\t Input text is 8-bit encoding\n"
  78. "-m\t Interpret SSML markup, and ignore other < > tags\n"
  79. "-q\t Quiet, don't produce any speech (may be useful with -x)\n"
  80. "-x\t Write phoneme mnemonics to stdout\n"
  81. "-X\t Write phonemes mnemonics and translation trace to stdout\n"
  82. "-z\t No final sentence pause at the end of the text\n"
  83. "--stdout Write speech output to stdout\n"
  84. "--compile=<voice name>\n"
  85. "\t Compile the pronunciation rules and dictionary in the current\n"
  86. "\t directory. =<voice name> is optional and specifies which language\n"
  87. "--path=\"<path>\"\n"
  88. "\t Specifies the directory containing the espeak-data directory\n"
  89. "--phonout=\"<filename>\"\n"
  90. "\t Write output from -x -X commands and mbrola phoneme data to this file\n"
  91. "--punct=\"<characters>\"\n"
  92. "\t Speak the names of punctuation characters during speaking. If\n"
  93. "\t =<characters> is omitted, all punctuation is spoken.\n"
  94. "--split=\"<minutes>\"\n"
  95. "\t Starts a new WAV file every <minutes>. Used with -w\n"
  96. "--voices=<language>\n"
  97. "\t List the available voices for the specified language.\n"
  98. "\t If <language> is omitted, then list all voices.\n"
  99. "-k <integer>\n"
  100. "\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
  101. "\t higher values = a pitch increase (try -k20).\n";
  102. void DisplayVoices(FILE *f_out, char *language);
  103. USHORT voice_pcnt[N_PEAKS+1][3];
  104. int GetFileLength(const char *filename)
  105. {//====================================
  106. struct stat statbuf;
  107. if(stat(filename,&statbuf) != 0)
  108. return(0);
  109. if((statbuf.st_mode & S_IFMT) == S_IFDIR)
  110. // if(S_ISDIR(statbuf.st_mode))
  111. return(-2); // a directory
  112. return(statbuf.st_size);
  113. } // end of GetFileLength
  114. char *Alloc(int size)
  115. {//==================
  116. char *p;
  117. if((p = (char *)malloc(size)) == NULL)
  118. fprintf(stderr,"Can't allocate memory\n");
  119. return(p);
  120. }
  121. void Free(void *ptr)
  122. {//=================
  123. if(ptr != NULL)
  124. free(ptr);
  125. }
  126. void DisplayVoices(FILE *f_out, char *language)
  127. {//============================================
  128. int ix;
  129. const char *p;
  130. int len;
  131. int count;
  132. int scores = 0;
  133. const espeak_VOICE *v;
  134. const char *lang_name;
  135. char age_buf[12];
  136. const espeak_VOICE **voices;
  137. espeak_VOICE voice_select;
  138. static char genders[4] = {' ','M','F',' '};
  139. if((language != NULL) && (language[0] != 0))
  140. {
  141. // display only voices for the specified language, in order of priority
  142. voice_select.languages = language;
  143. voice_select.age = 0;
  144. voice_select.gender = 0;
  145. voice_select.name = NULL;
  146. voices = espeak_ListVoices(&voice_select);
  147. scores = 1;
  148. }
  149. else
  150. {
  151. voices = espeak_ListVoices(NULL);
  152. }
  153. fprintf(f_out,"Pty Language Age/Gender VoiceName File Other Langs\n");
  154. for(ix=0; (v = voices[ix]) != NULL; ix++)
  155. {
  156. count = 0;
  157. p = v->languages;
  158. while(*p != 0)
  159. {
  160. len = strlen(p+1);
  161. lang_name = p+1;
  162. if(v->age == 0)
  163. strcpy(age_buf," ");
  164. else
  165. sprintf(age_buf,"%3d",v->age);
  166. if(count==0)
  167. {
  168. fprintf(f_out,"%2d %-12s%s%c %-17s %-11s ",
  169. p[0],lang_name,age_buf,genders[v->gender],v->name,v->identifier);
  170. }
  171. else
  172. {
  173. fprintf(f_out,"(%s %d)",lang_name,p[0]);
  174. }
  175. count++;
  176. p += len+2;
  177. }
  178. // if(scores)
  179. // fprintf(f_out,"%3d ",v->score);
  180. fputc('\n',f_out);
  181. }
  182. } // end of DisplayVoices
  183. static int OpenWaveFile(const char *path, int rate)
  184. //=================================================
  185. {
  186. // Set the length of 0x7ffff000 for --stdout
  187. // This will be changed to the correct length for -w (write to file)
  188. static unsigned char wave_hdr[44] = {
  189. 'R','I','F','F',0x24,0xf0,0xff,0x7f,'W','A','V','E','f','m','t',' ',
  190. 0x10,0,0,0,1,0,1,0, 9,0x3d,0,0,0x12,0x7a,0,0,
  191. 2,0,0x10,0,'d','a','t','a', 0x00,0xf0,0xff,0x7f};
  192. if(path == NULL)
  193. return(2);
  194. if(strcmp(path,"stdout")==0)
  195. f_wave = stdout;
  196. else
  197. f_wave = fopen(path,"wb");
  198. if(f_wave != NULL)
  199. {
  200. fwrite(wave_hdr,1,24,f_wave);
  201. Write4Bytes(f_wave,rate);
  202. Write4Bytes(f_wave,rate * 2);
  203. fwrite(&wave_hdr[32],1,12,f_wave);
  204. return(0);
  205. }
  206. return(1);
  207. } // end of OpenWaveFile
  208. static void CloseWaveFile()
  209. //=========================
  210. {
  211. unsigned int pos;
  212. if((f_wave == NULL) || (f_wave == stdout))
  213. return;
  214. fflush(f_wave);
  215. pos = ftell(f_wave);
  216. fseek(f_wave,4,SEEK_SET);
  217. Write4Bytes(f_wave,pos - 8);
  218. fseek(f_wave,40,SEEK_SET);
  219. Write4Bytes(f_wave,pos - 44);
  220. fclose(f_wave);
  221. f_wave = NULL;
  222. } // end of CloseWaveFile
  223. void MarkerEvent(int type, unsigned int char_position, int value, unsigned char *out_ptr)
  224. {//======================================================================================
  225. // Do nothing in the command-line version.
  226. if(type == 2)
  227. end_of_sentence = 1;
  228. } // end of MarkerEvent
  229. static int WavegenFile(void)
  230. {//=========================
  231. int finished;
  232. unsigned char wav_outbuf[512];
  233. char fname[210];
  234. out_ptr = out_start = wav_outbuf;
  235. out_end = wav_outbuf + sizeof(wav_outbuf);
  236. finished = WavegenFill(0);
  237. if(quiet)
  238. return(finished);
  239. if(f_wave == NULL)
  240. {
  241. sprintf(fname,"%s_%.2d%s",wavefile,++wavefile_count,filetype);
  242. if(OpenWaveFile(fname, samplerate) != 0)
  243. return(1);
  244. }
  245. if(end_of_sentence)
  246. {
  247. end_of_sentence = 0;
  248. if((samples_split > 0 ) && (samples_total > samples_split))
  249. {
  250. CloseWaveFile();
  251. samples_total = 0;
  252. }
  253. }
  254. if(f_wave != NULL)
  255. {
  256. samples_total += (out_ptr - wav_outbuf)/2;
  257. fwrite(wav_outbuf, 1, out_ptr - wav_outbuf, f_wave);
  258. }
  259. return(finished);
  260. } // end of WavegenFile
  261. static void init_path(char *argv0, char *path_specified)
  262. {//=====================================================
  263. if(path_specified)
  264. {
  265. sprintf(path_home,"%s/espeak-data",path_specified);
  266. return;
  267. }
  268. #ifdef PLATFORM_WINDOWS
  269. HKEY RegKey;
  270. unsigned long size;
  271. unsigned long var_type;
  272. char *p;
  273. char *env;
  274. unsigned char buf[sizeof(path_home)-12];
  275. if(((env = getenv("ESPEAK_DATA_PATH")) != NULL) && ((strlen(env)+12) < sizeof(path_home)))
  276. {
  277. sprintf(path_home,"%s\\espeak-data",env);
  278. if(GetFileLength(path_home) == -2)
  279. return; // an espeak-data directory exists in the directory specified by environment variable
  280. }
  281. strcpy(path_home,argv0);
  282. if((p = strrchr(path_home,'\\')) != NULL)
  283. {
  284. strcpy(&p[1],"espeak-data");
  285. if(GetFileLength(path_home) == -2)
  286. return; // an espeak-data directory exists in the same directory as the espeak program
  287. }
  288. // otherwise, look in the Windows Registry
  289. buf[0] = 0;
  290. RegOpenKeyEx(HKEY_LOCAL_MACHINE, "Software\\Microsoft\\Speech\\Voices\\Tokens\\eSpeak", 0, KEY_READ, &RegKey);
  291. size = sizeof(buf);
  292. var_type = REG_SZ;
  293. RegQueryValueEx(RegKey, "path", 0, &var_type, buf, &size);
  294. sprintf(path_home,"%s\\espeak-data",buf);
  295. #else
  296. #ifdef PLATFORM_DOS
  297. strcpy(path_home,PATH_ESPEAK_DATA);
  298. #else
  299. char *env;
  300. if((env = getenv("ESPEAK_DATA_PATH")) != NULL)
  301. {
  302. snprintf(path_home,sizeof(path_home),"%s/espeak-data",env);
  303. if(GetFileLength(path_home) == -2)
  304. return; // an espeak-data directory exists
  305. }
  306. snprintf(path_home,sizeof(path_home),"%s/espeak-data",getenv("HOME"));
  307. if(access(path_home,R_OK) != 0)
  308. {
  309. strcpy(path_home,PATH_ESPEAK_DATA);
  310. }
  311. #endif
  312. #endif
  313. }
  314. static int initialise(void)
  315. {//========================
  316. int param;
  317. int result;
  318. // It seems that the wctype functions don't work until the locale has been set
  319. // to something other than the default "C". Then, not only Latin1 but also the
  320. // other characters give the correct results with iswalpha() etc.
  321. #ifdef PLATFORM_RISCOS
  322. setlocale(LC_CTYPE,"ISO8859-1");
  323. #else
  324. if(setlocale(LC_CTYPE,"en_US.UTF-8") == NULL)
  325. {
  326. if(setlocale(LC_CTYPE,"UTF-8") == NULL)
  327. setlocale(LC_CTYPE,"");
  328. }
  329. #endif
  330. WavegenInit(22050,0); // 22050
  331. if((result = LoadPhData()) != 1)
  332. {
  333. if(result == -1)
  334. {
  335. fprintf(stderr,"Failed to load espeak-data\n");
  336. exit(1);
  337. }
  338. else
  339. fprintf(stderr,"Wrong version of espeak-data 0x%x (expects 0x%x) at %s\n",result,version_phdata,path_home);
  340. }
  341. LoadConfig();
  342. SetVoiceStack(NULL);
  343. SynthesizeInit();
  344. for(param=0; param<N_SPEECH_PARAM; param++)
  345. param_stack[0].parameter[param] = param_defaults[param];
  346. return(0);
  347. }
  348. static void StopSpeak(int unused)
  349. {//==============================
  350. signal(SIGINT,SIG_IGN);
  351. // DEBUG
  352. // printf("\n*** Interrupting speech output (use Ctrl-D to actually quit).\n");
  353. fflush(stdout);
  354. SpeakNextClause(NULL,NULL,5);
  355. signal(SIGINT,StopSpeak);
  356. } // end of StopSpeak()
  357. #ifdef NEED_GETOPT
  358. struct option {
  359. char *name;
  360. int has_arg;
  361. int *flag;
  362. int val;
  363. };
  364. int optind;
  365. static int optional_argument;
  366. static const char *arg_opts = "afklpsvw"; // which options have arguments
  367. static char *opt_string="";
  368. #define no_argument 0
  369. #define required_argument 1
  370. #define optional_argument 2
  371. #endif
  372. int main (int argc, char **argv)
  373. //==============================
  374. {
  375. static struct option long_options[] =
  376. {
  377. /* These options set a flag. */
  378. // {"verbose", no_argument, &verbose_flag, 1},
  379. // {"brief", no_argument, &verbose_flag, 0},
  380. /* These options don't set a flag.
  381. We distinguish them by their indices. */
  382. {"help", no_argument, 0, 'h'},
  383. {"stdin", no_argument, 0, 0x100},
  384. {"compile-debug", optional_argument, 0, 0x101},
  385. {"compile", optional_argument, 0, 0x102},
  386. {"punct", optional_argument, 0, 0x103},
  387. {"voices", optional_argument, 0, 0x104},
  388. {"stdout", no_argument, 0, 0x105},
  389. {"split", optional_argument, 0, 0x106},
  390. {"path", required_argument, 0, 0x107},
  391. {"phonout", required_argument, 0, 0x108},
  392. {0, 0, 0, 0}
  393. };
  394. static const char *err_load = "Failed to read ";
  395. FILE *f_text=NULL;
  396. const char *p_text=NULL;
  397. char *data_path = NULL; // use default path for espeak-data
  398. int option_index = 0;
  399. int c;
  400. int value;
  401. int speed=170;
  402. int ix;
  403. char *optarg2;
  404. int amp = 100; // default
  405. int wordgap = 0;
  406. int speaking = 0;
  407. int flag_stdin = 0;
  408. int flag_compile = 0;
  409. int pitch_adjustment = 50;
  410. espeak_VOICE voice_select;
  411. char filename[200];
  412. char voicename[40];
  413. char dictname[40];
  414. voicename[0] = 0;
  415. mbrola_name[0] = 0;
  416. dictname[0] = 0;
  417. wavefile[0] = 0;
  418. filename[0] = 0;
  419. option_linelength = 0;
  420. option_phonemes = 0;
  421. option_waveout = 0;
  422. option_wordgap = 0;
  423. option_endpause = 1;
  424. option_phoneme_input = 1;
  425. option_multibyte = espeakCHARS_AUTO; // auto
  426. f_trans = stdout;
  427. #ifdef NEED_GETOPT
  428. optind = 1;
  429. opt_string = "";
  430. while(optind < argc)
  431. {
  432. int len;
  433. char *p;
  434. if((c = *opt_string) == 0)
  435. {
  436. opt_string = argv[optind];
  437. if(opt_string[0] != '-')
  438. break;
  439. optind++;
  440. opt_string++;
  441. c = *opt_string;
  442. }
  443. opt_string++;
  444. p = optarg2 = opt_string;
  445. if(c == '-')
  446. {
  447. opt_string="";
  448. for(ix=0; ;ix++)
  449. {
  450. if(long_options[ix].name == 0)
  451. break;
  452. len = strlen(long_options[ix].name);
  453. if(memcmp(long_options[ix].name,p,len)==0)
  454. {
  455. c = long_options[ix].val;
  456. optarg2 = NULL;
  457. if((long_options[ix].has_arg != 0) && (p[len]=='='))
  458. {
  459. optarg2 = &p[len+1];
  460. }
  461. break;
  462. }
  463. }
  464. }
  465. else
  466. if(strchr(arg_opts,c) != NULL)
  467. {
  468. opt_string="";
  469. if(optarg2[0]==0)
  470. {
  471. // the option's value is in the next argument
  472. optarg2 = argv[optind++];
  473. }
  474. }
  475. #else
  476. while(true)
  477. {
  478. c = getopt_long (argc, argv, "a:bf:g:hk:l:p:qs:v:w:xXmz",
  479. long_options, &option_index);
  480. /* Detect the end of the options. */
  481. if (c == -1)
  482. break;
  483. optarg2 = optarg;
  484. #endif
  485. switch (c)
  486. {
  487. case 'b':
  488. option_multibyte = espeakCHARS_8BIT;
  489. break;
  490. case 'h':
  491. printf("\nspeak text-to-speech: %s\n%s",version_string,help_text);
  492. exit(0);
  493. break;
  494. case 'k':
  495. option_capitals = atoi(optarg2);
  496. break;
  497. case 'x':
  498. option_phonemes = 1;
  499. break;
  500. case 'X':
  501. option_phonemes = 2;
  502. break;
  503. case 'm':
  504. option_ssml = 1;
  505. break;
  506. case 'p':
  507. pitch_adjustment = atoi(optarg2);
  508. if(pitch_adjustment > 99) pitch_adjustment = 99;
  509. break;
  510. case 'q':
  511. quiet = 1;
  512. break;
  513. case 'f':
  514. strncpy0(filename,optarg2,sizeof(filename));
  515. break;
  516. case 'l':
  517. value = 0;
  518. value = atoi(optarg2);
  519. option_linelength = value;
  520. break;
  521. case 'a':
  522. amp = atoi(optarg2);
  523. break;
  524. case 's':
  525. speed = atoi(optarg2);
  526. break;
  527. case 'g':
  528. wordgap = atoi(optarg2);
  529. break;
  530. case 'v':
  531. strncpy0(voicename,optarg2,sizeof(voicename));
  532. break;
  533. case 'w':
  534. option_waveout = 1;
  535. strncpy0(wavefile,optarg2,sizeof(wavefile));
  536. break;
  537. case 'z':
  538. option_endpause = 0;
  539. break;
  540. case 0x100: // --stdin
  541. flag_stdin = 1;
  542. break;
  543. case 0x105: // --stdout
  544. option_waveout = 1;
  545. strcpy(wavefile,"stdout");
  546. break;
  547. case 0x101: // --compile-debug
  548. case 0x102: // --compile
  549. if(optarg2 != NULL)
  550. strncpy0(voicename,optarg2,sizeof(voicename));
  551. flag_compile = c;
  552. break;
  553. case 0x103: // --punct
  554. option_punctuation = 1;
  555. if(optarg2 != NULL)
  556. {
  557. ix = 0;
  558. while((ix < N_PUNCTLIST) && ((option_punctlist[ix] = optarg2[ix]) != 0)) ix++;
  559. option_punctlist[N_PUNCTLIST-1] = 0;
  560. option_punctuation = 2;
  561. }
  562. break;
  563. case 0x104: // --voices
  564. DisplayVoices(stdout,optarg2);
  565. exit(0);
  566. case 0x106: // -- split
  567. if(optarg2 == NULL)
  568. samples_split = 30; // default 30 minutes
  569. else
  570. samples_split = atoi(optarg2);
  571. break;
  572. case 0x107: // --path
  573. data_path = optarg2;
  574. break;
  575. case 0x108: // --phonout
  576. if((f_trans = fopen(optarg2,"w")) == NULL)
  577. {
  578. fprintf(stderr,"Can't write to: %s\n",optarg2);
  579. f_trans = stderr;
  580. }
  581. break;
  582. default:
  583. exit(0);
  584. }
  585. }
  586. init_path(argv[0],data_path);
  587. initialise();
  588. if(flag_compile)
  589. {
  590. LoadVoice(voicename,5);
  591. #ifdef PLATFORM_DOS
  592. char path_dsource[sizeof(path_home)+20];
  593. strcpy(path_dsource,path_home);
  594. path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
  595. strcat(path_dsource,"dictsource\\");
  596. CompileDictionary(path_dsource,dictionary_name,NULL,NULL, flag_compile & 0x1);
  597. #else
  598. #ifdef PLATFORM_WINDOWS
  599. char path_dsource[sizeof(path_home)+20];
  600. strcpy(path_dsource,path_home);
  601. path_dsource[strlen(path_home)-11] = 0; // remove "espeak-data" from the end
  602. strcat(path_dsource,"dictsource\\");
  603. CompileDictionary(path_dsource,dictionary_name,NULL,NULL, flag_compile & 0x1);
  604. #else
  605. CompileDictionary(NULL,dictionary_name,NULL,NULL, flag_compile & 0x1);
  606. #endif
  607. #endif
  608. exit(0);
  609. }
  610. if(voicename[0] == 0)
  611. strcpy(voicename,"default");
  612. if(SetVoiceByName(voicename) != EE_OK)
  613. {
  614. memset(&voice_select,0,sizeof(voice_select));
  615. voice_select.languages = voicename;
  616. if(SetVoiceByProperties(&voice_select) != EE_OK)
  617. {
  618. fprintf(stderr,"%svoice '%s'\n",err_load,voicename);
  619. exit(2);
  620. }
  621. }
  622. SetParameter(espeakRATE,speed,0);
  623. SetParameter(espeakVOLUME,amp,0);
  624. SetParameter(espeakCAPITALS,option_capitals,0);
  625. SetParameter(espeakPUNCTUATION,option_punctuation,0);
  626. SetParameter(espeakWORDGAP,wordgap,0);
  627. if(pitch_adjustment != 50)
  628. {
  629. SetParameter(espeakPITCH,pitch_adjustment,0);
  630. }
  631. DoVoiceChange(voice);
  632. if(filename[0]==0)
  633. {
  634. if((optind < argc) && (flag_stdin == 0))
  635. {
  636. // there's a non-option parameter, and no -f or --stdin
  637. // use it as text
  638. p_text = argv[optind];
  639. }
  640. else
  641. {
  642. f_text = stdin;
  643. if(flag_stdin == 0)
  644. option_linelength = -1; // single input lines on stdin
  645. }
  646. }
  647. else
  648. {
  649. f_text = fopen(filename,"r");
  650. }
  651. if((f_text == NULL) && (p_text == NULL))
  652. {
  653. fprintf(stderr,"%sfile '%s'\n",err_load,filename);
  654. exit(1);
  655. }
  656. if(option_waveout || quiet)
  657. {
  658. if(quiet)
  659. {
  660. // no sound output
  661. OpenWaveFile(NULL,samplerate);
  662. option_waveout = 1;
  663. }
  664. else
  665. {
  666. // write sound output to a WAV file
  667. samples_split = (samplerate * samples_split) * 60;
  668. if(samples_split)
  669. {
  670. // don't open the wav file until we start generating speech
  671. char *extn;
  672. extn = strrchr(wavefile,'.');
  673. if((extn != NULL) && ((wavefile + strlen(wavefile) - extn) <= 4))
  674. {
  675. strcpy(filetype,extn);
  676. *extn = 0;
  677. }
  678. }
  679. else
  680. if(OpenWaveFile(wavefile,samplerate) != 0)
  681. {
  682. fprintf(stderr,"Can't write to output file '%s'\n'",wavefile);
  683. exit(3);
  684. }
  685. }
  686. InitText(0);
  687. SpeakNextClause(f_text,p_text,0);
  688. ix = 1;
  689. for(;;)
  690. {
  691. if(WavegenFile() != 0)
  692. {
  693. if(ix == 0)
  694. break; // finished, wavegen command queue is empty
  695. }
  696. if(Generate(phoneme_list,&n_phoneme_list,1)==0)
  697. {
  698. ix = SpeakNextClause(NULL,NULL,1);
  699. }
  700. }
  701. CloseWaveFile();
  702. }
  703. else
  704. {
  705. // Silence on ^C or SIGINT
  706. // signal(SIGINT,StopSpeak);
  707. // output sound using portaudio
  708. WavegenInitSound();
  709. InitText(0);
  710. SpeakNextClause(f_text,p_text,0);
  711. if(option_quiet)
  712. {
  713. while(SpeakNextClause(NULL,NULL,1) != 0);
  714. return(0);
  715. }
  716. #ifdef USE_PORTAUDIO
  717. speaking = 1;
  718. while(speaking)
  719. {
  720. // NOTE: if nanosleep() isn't recognised on your system, try replacing
  721. // this by sleep(1);
  722. #ifdef PLATFORM_WINDOWS
  723. Sleep(300); // 0.3s
  724. #else
  725. #ifdef USE_NANOSLEEP
  726. struct timespec period;
  727. struct timespec remaining;
  728. period.tv_sec = 0;
  729. period.tv_nsec = 300000000; // 0.3 sec
  730. nanosleep(&period,&remaining);
  731. #else
  732. sleep(1);
  733. #endif
  734. #endif
  735. if(SynthOnTimer() != 0)
  736. speaking = 0;
  737. }
  738. #else
  739. fprintf(stderr,"-w option must be used because the program was built without a sound interface\n");
  740. #endif // USE_PORTAUDIO
  741. }
  742. return(0);
  743. }