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