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.

speak.cpp 19KB

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