1 /***************************************************************************
2 * Copyright (C) 2005 to 2013 by Jonathan Duddington *
3 * email: jonsd@users.sourceforge.net *
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. *
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. *
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 ***************************************************************************/
29 #ifdef PLATFORM_WINDOWS
32 #ifdef PLATFORM_RISCOS
39 #include "speak_lib.h"
41 #include "synthesize.h"
43 #include "translate.h"
46 MNEM_TAB genders [] = {
53 int tone_points[12] = {600,170, 1200,135, 2000,110, 3000,110, -1,0};
54 //int tone_points[12] = {250,200, 400,170, 600,170, 1200,135, 2000,110, -1,0};
56 // limit the rate of change for each formant number
57 //static int formant_rate_22050[9] = {50, 104, 165, 230, 220, 220, 220, 220, 220}; // values for 22kHz sample rate
58 //static int formant_rate_22050[9] = {240, 180, 180, 180, 180, 180, 180, 180, 180}; // values for 22kHz sample rate
59 static int formant_rate_22050[9] = {240, 170, 170, 170, 170, 170, 170, 170, 170}; // values for 22kHz sample rate
60 int formant_rate[9]; // values adjusted for actual sample rate
64 #define DEFAULT_LANGUAGE_PRIORITY 5
65 #define N_VOICES_LIST 250
66 static int n_voices_list = 0;
67 static espeak_VOICE *voices_list[N_VOICES_LIST];
68 static int len_path_voices;
70 espeak_VOICE current_voice_selected;
81 // these affect voice quality, are independent of language
93 // these override defaults set by the translator
114 // these need a phoneme table to have been specified
121 static MNEM_TAB options_tab[] = {
122 {"reduce_t", LOPT_REDUCE_T},
123 {"bracket", LOPT_BRACKET_PAUSE},
127 static MNEM_TAB keyword_tab[] = {
129 {"language", V_LANGUAGE},
130 {"gender", V_GENDER},
132 {"formant", V_FORMANT},
134 {"phonemes", V_PHONEMES},
135 {"translator", V_TRANSLATOR},
136 {"dictionary", V_DICTIONARY},
137 {"stressLength", V_STRESSLENGTH},
138 {"stressAmp", V_STRESSAMP},
139 {"stressAdd", V_STRESSADD},
140 {"intonation", V_INTONATION},
142 {"dictrules", V_DICTRULES},
143 {"stressrule", V_STRESSRULE},
144 {"stressopt", V_STRESSOPT},
145 {"charset", V_CHARSET},
146 {"replace", V_REPLACE},
147 {"words", V_WORDGAP},
149 {"flutter", V_FLUTTER},
150 {"roughness", V_ROUGHNESS},
151 {"clarity", V_CLARITY},
153 {"voicing", V_VOICING},
154 {"breath", V_BREATH},
155 {"breathw", V_BREATHW},
156 {"numbers", V_NUMBERS},
157 {"option", V_OPTION},
158 {"mbrola", V_MBROLA},
159 {"consonants", V_CONSONANTS},
161 {"fast_test2", V_FAST},
163 {"dict_min", V_DICTMIN},
164 {"alphabet2", V_ALPHABET2},
166 // these just set a value in langopts.param[]
167 {"l_dieresis", 0x100+LOPT_DIERESES},
168 // {"l_lengthen", 0x100+LOPT_IT_LENGTHEN},
169 {"l_prefix", 0x100+LOPT_PREFIXES},
170 {"l_regressive_v", 0x100+LOPT_REGRESSIVE_VOICING},
171 {"l_unpronouncable", 0x100+LOPT_UNPRONOUNCABLE},
172 {"l_sonorant_min", 0x100+LOPT_SONORANT_MIN},
173 {"l_length_mods", 0x100+LOPT_LENGTH_MODS},
174 {"apostrophe", 0x100+LOPT_APOSTROPHE},
178 #define N_VOICE_VARIANTS 12
179 const char variants_either[N_VOICE_VARIANTS] = {1,2,12,3,13,4,14,5,11,0};
180 const char variants_male[N_VOICE_VARIANTS] = {1,2,3,4,5,0};
181 const char variants_female[N_VOICE_VARIANTS] = {11,12,13,14,0};
182 const char *variant_lists[3] = {variants_either, variants_male, variants_female};
184 static voice_t voicedata;
185 voice_t *voice = &voicedata;
188 static char *fgets_strip(char *buf, int size, FILE *f_in)
189 {//======================================================
190 // strip trailing spaces, and truncate lines at // comment
194 if(fgets(buf,size,f_in) == NULL)
204 while((--len > 0) && isspace(buf[len]))
207 if((p = strstr(buf,"//")) != NULL)
214 static int LookupTune(const char *name)
215 {//====================================
218 for(ix=0; ix<n_tunes; ix++)
220 if(strcmp(name, tunes[ix].name) == 0)
224 } // end of LookupTune
228 static void SetToneAdjust(voice_t *voice, int *tone_pts)
229 {//=====================================================
235 int height1 = tone_pts[1];
239 for(pt=0; pt<12; pt+=2)
241 if(tone_pts[pt] == -1)
243 tone_pts[pt] = N_TONE_ADJUST*8;
245 tone_pts[pt+1] = tone_pts[pt-1];
247 freq2 = tone_pts[pt] / 8; // 8Hz steps
248 height2 = tone_pts[pt+1];
249 if((freq2 - freq1) > 0)
251 rate = double(height2-height1)/(freq2-freq1);
253 for(ix=freq1; ix<freq2; ix++)
255 y = height1 + int(rate * (ix-freq1));
258 voice->tone_adjust[ix] = y;
267 void ReadTonePoints(char *string, int *tone_pts)
268 {//=============================================
269 // tone_pts[] is int[12]
272 for(ix=0; ix<12; ix++)
275 sscanf(string,"%d %d %d %d %d %d %d %d %d %d",
276 &tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3],
277 &tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7],
278 &tone_pts[8],&tone_pts[9]);
284 static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*leafname)
285 {//===================================================================================
286 // Read a Voice file, allocate a VOICE_DATA and set data from the
287 // file's language, gender, name lines
293 char languages[300]; // allow space for several alternate language names and priorities
300 espeak_VOICE *voice_data;
303 int n_variants = 3; // default, number of variants of this voice before using another voice
306 #ifdef PLATFORM_WINDOWS
307 char fname_buf[sizeof(path_home)+15];
308 if(memcmp(leafname,"mb-",3) == 0)
310 // check whether the mbrola speech data is present for this voice
311 memcpy(vname,&leafname[3],3);
313 sprintf(fname_buf,"%s/mbrola/%s",path_home,vname);
315 if(GetFileLength(fname_buf) <= 0)
324 while(fgets_strip(linebuf,sizeof(linebuf),f_in) != NULL)
326 if(memcmp(linebuf,"name",4)==0)
329 while(isspace(*p)) p++;
330 strncpy0(vname,p,sizeof(vname));
332 else if(memcmp(linebuf,"language",8)==0)
334 priority = DEFAULT_LANGUAGE_PRIORITY;
337 sscanf(&linebuf[8],"%s %d",vlanguage,&priority);
338 len = strlen(vlanguage) + 2;
339 // check for space in languages[]
340 if(len < (sizeof(languages)-langix-1))
342 languages[langix] = priority;
344 strcpy(&languages[langix+1],vlanguage);
349 else if(memcmp(linebuf,"gender",6)==0)
351 sscanf(&linebuf[6],"%s %d",vgender,&age);
353 else if(memcmp(linebuf,"variants",8)==0)
355 sscanf(&linebuf[8],"%d",&n_variants);
358 languages[langix++] = 0;
360 gender = LookupMnem(genders,vgender);
364 return(NULL); // no language lines in the voice file
367 p = (char *)calloc(sizeof(espeak_VOICE) + langix + strlen(fname) + strlen(vname) + 3, 1);
368 voice_data = (espeak_VOICE *)p;
369 p = &p[sizeof(espeak_VOICE)];
371 memcpy(p,languages,langix);
372 voice_data->languages = p;
374 strcpy(&p[langix],fname);
375 voice_data->identifier = &p[langix];
376 voice_data->name = &p[langix];
380 langix += strlen(fname)+1;
381 strcpy(&p[langix],vname);
382 voice_data->name = &p[langix];
385 voice_data->age = age;
386 voice_data->gender = gender;
387 voice_data->variant = 0;
388 voice_data->xx1 = n_variants;
390 } // end of ReadVoiceFile
395 void VoiceReset(int tone_only)
396 {//===========================
397 // Set voice to the default values
400 static unsigned char default_heights[N_PEAKS] = {130,128,120,116,100,100,128,128,128}; // changed for v.1.47
401 static unsigned char default_widths[N_PEAKS] = {140,128,128,160,171,171,128,128,128};
402 // static unsigned char default_heights[N_PEAKS] = {128,128,120,120,110,110,128,128,128}; // previous version
403 // static unsigned char default_widths[N_PEAKS] = {128,128,128,160,171,171,128,128,128};
405 static int breath_widths[N_PEAKS] = {0,200,200,400,400,400,600,600,600};
407 // default is: pitch 80,118
408 voice->pitch_base = 0x47000;
409 voice->pitch_range = 4104;
411 // default is: pitch 80,117
412 // voice->pitch_base = 0x47000;
413 // voice->pitch_range = 3996;
415 voice->formant_factor = 256;
417 voice->speed_percent = 100;
418 voice->echo_delay = 0;
421 voice->n_harmonic_peaks = 5;
422 voice->peak_shape = 0;
424 voice->consonant_amp = 90; // change from 100 to 90 for v.1.47
425 voice->consonant_ampv = 100;
426 voice->samplerate = samplerate_native;
427 memset(voice->klattv,0,sizeof(voice->klattv));
429 speed.fast_settings[0] = 450;
430 speed.fast_settings[1] = 800;
431 speed.fast_settings[2] = 175;
433 #ifdef PLATFORM_RISCOS
434 voice->roughness = 1;
436 voice->roughness = 2;
440 for(pk=0; pk<N_PEAKS; pk++)
442 voice->freq[pk] = 256;
443 voice->height[pk] = default_heights[pk]*2;
444 voice->width[pk] = default_widths[pk]*2;
445 voice->breath[pk] = 0;
446 voice->breathw[pk] = breath_widths[pk]; // default breath formant woidths
447 voice->freqadd[pk] = 0;
449 // adjust formant smoothing depending on sample rate
450 formant_rate[pk] = (formant_rate_22050[pk] * 22050)/samplerate;
453 // This table provides the opportunity for tone control.
454 // Adjustment of harmonic amplitudes, steps of 8Hz
455 // value of 128 means no change
456 // memset(voice->tone_adjust,128,sizeof(voice->tone_adjust));
457 SetToneAdjust(voice,tone_points);
459 // default values of speed factors
460 voice->speedf1 = 256;
461 voice->speedf2 = 238;
462 voice->speedf3 = 232;
466 n_replace_phonemes = 0;
468 LoadMbrolaTable(NULL,NULL,0);
470 } // end of VoiceReset
473 static void VoiceFormant(char *p)
474 {//==============================
475 // Set parameters for a formant
483 ix = sscanf(p,"%d %d %d %d %d",&formant,&freq,&height,&width,&freqadd);
487 if((formant < 0) || (formant > 8))
491 voice->freq[formant] = int(freq * 2.56001);
493 voice->height[formant] = int(height * 2.56001);
495 voice->width[formant] = int(width * 2.56001);
496 voice->freqadd[formant] = freqadd;
503 static void PhonemeReplacement(int type, char *p)
504 {//==============================================
508 char phon_string1[12];
509 char phon_string2[12];
511 strcpy(phon_string2,"NULL");
512 n = sscanf(p,"%d %s %s",&flags,phon_string1,phon_string2);
513 if((n < 2) || (n_replace_phonemes >= N_REPLACE_PHONEMES))
516 if((phon = LookupPhonemeString(phon_string1)) == 0)
517 return; // not recognised
519 replace_phonemes[n_replace_phonemes].old_ph = phon;
520 replace_phonemes[n_replace_phonemes].new_ph = LookupPhonemeString(phon_string2);
521 replace_phonemes[n_replace_phonemes++].type = flags;
522 } // end of PhonemeReplacement
526 static int Read8Numbers(char *data_in,int *data)
527 {//=============================================
528 // Read 8 integer numbers
529 memset(data, 0, 8+sizeof(int));
530 return(sscanf(data_in,"%d %d %d %d %d %d %d %d",
531 &data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7]));
535 static unsigned int StringToWord2(const char *string)
536 {//======================================================
537 // Convert a language name string to a word such as L('e','n')
540 unsigned int value = 0;
542 for(ix=0; (ix<4) && ((c = string[ix]) != 0); ix++)
544 value = (value << 8) | (c & 0xff);
550 voice_t *LoadVoice(const char *vname, int control)
551 {//===============================================
552 // control, bit 0 1= no_default
553 // bit 1 1 = change tone only, not language
554 // bit 2 1 = don't report error on LoadDictionary
555 // bit 4 1 = vname = full path
557 FILE *f_voice = NULL;
565 int tone_only = control & 2;
566 int language_set = 0;
567 int phonemes_set = 0;
568 int stress_amps_set = 0;
569 int stress_lengths_set = 0;
570 int stress_add_set = 0;
571 int conditional_rules = 0;
572 LANGUAGE_OPTIONS *langopts = NULL;
574 Translator *new_translator = NULL;
577 char language_name[40];
578 char translator_name[40];
579 char new_dictionary[40];
580 char phonemes_name[40];
581 char option_name[40];
582 const char *language_type;
583 char buf[sizeof(path_home)+30];
584 char path_voices[sizeof(path_home)+12];
588 int stress_lengths[8];
593 const char *voice_dir;
598 static char voice_identifier[40]; // file name for current_voice_selected
599 static char voice_name[40]; // voice name for current_voice_selected
600 static char voice_languages[100]; // list of languages and priorities for current_voice_selected
602 // which directory to look for a named voice. List of voice names, must end in a space.
603 static const char *voices_asia =
604 "bn fa fa-pin hi hy hy-west id ka kn ku ml ms ne pa ta te tr vi vi-hue zh zh-yue ";
605 static const char *voices_europe =
606 "an bg bs ca cs cy da de el en en-us es et fi fr fr-be ga hr hu is it lt lv mk nl no pl pt-pt ro ru sk sq sr sv ";
609 strncpy0(voicename, vname, sizeof(voicename));
613 if(GetFileLength(buf) <= 0)
619 strcpy(voicename,"default");
621 sprintf(path_voices,"%s%cvoices%c",path_home,PATHSEP,PATHSEP);
622 sprintf(buf,"%s%s",path_voices,voicename); // first, look in the main voices directory
624 if(GetFileLength(buf) <= 0)
626 // then look in the appropriate subdirectory
627 if((voicename[0]=='m') && (voicename[1]=='b'))
629 voice_dir = "mb"; // mbrola voices
633 sprintf(name2, "%s ", voicename);
634 if(strstr(voices_europe, voicename) != NULL)
635 voice_dir = "europe";
636 else if(strstr(voices_asia, voicename) != NULL)
641 sprintf(buf,"%s%s%c%s", path_voices,voice_dir,PATHSEP,voicename);
643 if(GetFileLength(buf) <= 0)
645 // if not found, look in "test" sub-directory
646 sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename);
652 f_voice = fopen(buf,"r");
654 language_type = "en"; // default
658 return(NULL); // can't open file
660 if(SelectPhonemeTableName(voicename) >= 0)
661 language_type = voicename;
664 if(!tone_only && (translator != NULL))
666 DeleteTranslator(translator);
670 strcpy(translator_name,language_type);
671 strcpy(new_dictionary,language_type);
672 strcpy(phonemes_name,language_type);
678 strncpy0(voice_identifier,vname,sizeof(voice_identifier));
680 voice_languages[0] = 0;
682 current_voice_selected.identifier = voice_identifier;
683 current_voice_selected.name = voice_name;
684 current_voice_selected.languages = voice_languages;
688 // append the variant file name to the voice identifier
689 if((p = strchr(voice_identifier,'+')) != NULL)
690 *p = 0; // remove previous variant name
691 sprintf(buf,"+%s",&vname[3]); // omit !v/ from the variant filename
692 strcat(voice_identifier,buf);
693 langopts = &translator->langopts;
695 VoiceReset(tone_only);
698 SelectPhonemeTableName(phonemes_name); // set up phoneme_tab
701 while((f_voice != NULL) && (fgets_strip(buf,sizeof(buf),f_voice) != NULL))
703 // isolate the attribute name
704 for(p=buf; (*p != 0) && !isspace(*p); p++);
707 if(buf[0] == 0) continue;
709 key = LookupMnem(keyword_tab, buf);
721 priority = DEFAULT_LANGUAGE_PRIORITY;
722 language_name[0] = 0;
724 sscanf(p,"%s %d",language_name,&priority);
725 if(strcmp(language_name,"variant") == 0)
728 len = strlen(language_name) + 2;
729 // check for space in languages[]
730 if(len < (sizeof(voice_languages)-langix-1))
732 voice_languages[langix] = priority;
734 strcpy(&voice_languages[langix+1],language_name);
738 // only act on the first language line
739 if(language_set == 0)
741 language_type = strtok(language_name,"-");
743 strcpy(translator_name,language_type);
744 strcpy(new_dictionary,language_type);
745 strcpy(phonemes_name,language_type);
746 SelectPhonemeTableName(phonemes_name);
748 if(new_translator != NULL)
749 DeleteTranslator(new_translator);
751 new_translator = SelectTranslator(translator_name);
752 langopts = &new_translator->langopts;
753 strncpy0(voice->language_name, language_name, sizeof(voice->language_name));
761 while(isspace(*p)) p++;
762 strncpy0(voice_name,p,sizeof(voice_name));
770 sscanf(p,"%s %d",vgender,&age);
771 current_voice_selected.gender = LookupMnem(genders,vgender);
772 current_voice_selected.age = age;
779 sscanf(p,"%s",translator_name);
781 if(new_translator != NULL)
782 DeleteTranslator(new_translator);
784 new_translator = SelectTranslator(translator_name);
785 langopts = &new_translator->langopts;
788 case V_DICTIONARY: // dictionary
789 sscanf(p,"%s",new_dictionary);
792 case V_PHONEMES: // phoneme table
793 sscanf(p,"%s",phonemes_name);
803 // default is pitch 82 118
804 n = sscanf(p,"%d %d",&pitch1,&pitch2);
805 voice->pitch_base = (pitch1 - 9) << 12;
806 voice->pitch_range = (pitch2 - pitch1) * 108;
807 factor = double(pitch1 - 82)/82;
808 voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch
812 case V_STRESSLENGTH: // stressLength
813 stress_lengths_set = Read8Numbers(p,stress_lengths);
816 case V_STRESSAMP: // stressAmp
817 stress_amps_set = Read8Numbers(p,stress_amps);
820 case V_STRESSADD: // stressAdd
821 stress_add_set = Read8Numbers(p,stress_add);
824 case V_INTONATION: // intonation
825 sscanf(p,"%d %d",&option_tone_flags,&option_tone2);
826 if((option_tone_flags & 0xff) != 0)
827 langopts->intonation_group = option_tone_flags & 0xff;
831 n = sscanf(p,"%s %s %s %s %s %s",names[0],names[1],names[2],names[3],names[4],names[5]);
832 langopts->intonation_group = 0;
833 for(ix=0; ix<n; ix++)
835 if(strcmp(names[ix],"NULL")==0)
838 if((value = LookupTune(names[ix])) < 0)
839 fprintf(stderr,"Unknown tune '%s'\n",names[ix]);
841 langopts->tunes[ix] = value;
845 case V_DICTRULES: // conditional dictionary rules and list entries
848 // expect a list of numbers
851 while(isspace(*p)) p++;
853 if((n = atoi(p)) > 0)
859 conditional_rules |= (1 << n);
860 else if(key==V_NUMBERS)
861 langopts->numbers |= (1 << n);
862 else if(key==V_STRESSOPT)
863 langopts->stress_flags |= (1 << n);
867 if((key==V_NUMBERS) && (n < 64))
868 langopts->numbers |= (1 << (n-32));
870 fprintf(stderr,"Bad option number %d\n", n);
873 while(isalnum(*p)) p++;
878 if(phonemes_set == 0)
880 // must set up a phoneme table before we can lookup phoneme mnemonics
881 SelectPhonemeTableName(phonemes_name);
884 PhonemeReplacement(key,p);
887 case V_WORDGAP: // words
888 sscanf(p,"%d %d",&langopts->word_gap, &langopts->vowel_pause);
892 sscanf(p,"%d %d %d %d",&langopts->stress_rule,
893 &langopts->stress_flags,
894 &langopts->unstressed_wd1,
895 &langopts->unstressed_wd2);
899 if((sscanf(p,"%d",&value)==1) && (value < N_CHARSETS))
900 new_translator->charset_a0 = charsets[value];
905 if((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0))
907 langopts->param[ix] = value;
908 langopts->param2[ix] = value2;
912 fprintf(stderr,"Bad voice option: %s %s\n",buf,p);
917 // echo. suggest: 135mS 11%
920 sscanf(p,"%d %d",&voice->echo_delay,&voice->echo_amp);
923 case V_FLUTTER: // flutter
924 if(sscanf(p,"%d",&value)==1)
925 voice->flutter = value * 32;
928 case V_ROUGHNESS: // roughness
929 if(sscanf(p,"%d",&value)==1)
930 voice->roughness = value;
933 case V_CLARITY: // formantshape
934 if(sscanf(p,"%d",&value)==1)
938 voice->peak_shape = 1; // squarer formant peaks
941 voice->n_harmonic_peaks = 1+value;
948 ReadTonePoints(p,tone_data);
949 SetToneAdjust(voice,tone_data);
954 if(sscanf(p,"%d",&value)==1)
955 voice->voicing = (value * 64)/100;
959 voice->breath[0] = Read8Numbers(p,&voice->breath[1]);
960 for(ix=1; ix<8; ix++)
963 voice->breath[ix] = -voice->breath[ix];
968 voice->breathw[0] = Read8Numbers(p,&voice->breathw[1]);
972 value = sscanf(p,"%d %d",&voice->consonant_amp, &voice->consonant_ampv);
976 sscanf(p,"%d",&voice->speed_percent);
984 sscanf(p,"%s %s %d",name1,name2,&srate);
985 if(LoadMbrolaTable(name1,name2,srate) != EE_OK)
987 fprintf(stderr,"mbrola voice not found\n");
989 voice->samplerate = srate;
994 voice->klattv[0] = 1; // default source: IMPULSIVE
995 Read8Numbers(p,voice->klattv);
996 voice->klattv[KLATT_Kopen] -= 40;
1000 Read8Numbers(p,speed.fast_settings);
1005 sscanf(p,"%d",&dict_min);
1011 name1[0] = name2[0] = 0;
1012 sscanf(p, "%s %s", name1, name2);
1014 if(strcmp(name1, "latin") == 0)
1016 strncpy0(langopts->ascii_language,name2,sizeof(langopts->ascii_language));
1018 else if((alphabet = AlphabetFromName(name1)) != 0)
1020 langopts->alt_alphabet = alphabet->offset;
1021 langopts->alt_alphabet_lang = StringToWord2(name2);
1025 fprintf(stderr,"alphabet name '%s' not found\n", name1);
1031 if((key & 0xff00) == 0x100)
1033 sscanf(p,"%d",&langopts->param[key &0xff]);
1037 fprintf(stderr,"Bad voice attribute: %s\n",buf);
1045 if((new_translator == NULL) && (!tone_only))
1047 // not set by language attribute
1048 new_translator = SelectTranslator(translator_name);
1051 SetSpeed(3); // for speed_percent
1053 for(ix=0; ix<N_PEAKS; ix++)
1055 voice->freq2[ix] = voice->freq[ix];
1056 voice->height2[ix] = voice->height[ix];
1057 voice->width2[ix] = voice->width[ix];
1062 new_translator = translator;
1066 if((ix = SelectPhonemeTableName(phonemes_name)) < 0)
1068 fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name);
1070 voice->phoneme_tab_ix = ix;
1071 new_translator->phoneme_tab_ix = ix;
1072 new_translator->dict_min_size = dict_min;
1073 LoadDictionary(new_translator, new_dictionary, control & 4);
1074 if(dictionary_name[0]==0)
1075 return(NULL); // no dictionary loaded
1077 new_translator->dict_condition = conditional_rules;
1079 voice_languages[langix] = 0;
1082 langopts = &new_translator->langopts;
1085 if((value = langopts->param[LOPT_LENGTH_MODS]) != 0)
1087 SetLengthMods(new_translator,value);
1090 voice->width[0] = (voice->width[0] * 105)/100;
1094 translator = new_translator;
1098 // relative lengths of different stress syllables
1099 for(ix=0; ix<stress_lengths_set; ix++)
1101 translator->stress_lengths[ix] = stress_lengths[ix];
1103 for(ix=0; ix<stress_add_set; ix++)
1105 translator->stress_lengths[ix] += stress_add[ix];
1107 for(ix=0; ix<stress_amps_set; ix++)
1109 translator->stress_amps[ix] = stress_amps[ix];
1110 translator->stress_amps_r[ix] = stress_amps[ix] -1;
1114 } // end of LoadVoice
1117 static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir)
1118 {//===========================================================================
1119 // Remove any voice variant suffix (name or number) from a voice name
1120 // Returns the voice variant name
1123 static char variant_name[40];
1124 char variant_prefix[5];
1126 variant_name[0] = 0;
1127 sprintf(variant_prefix,"!v%c",PATHSEP);
1129 variant_prefix[0] = 0;
1133 if((p = strchr(vname,'+')) != NULL)
1135 // The voice name has a +variant suffix
1137 *p++ = 0; // delete the suffix from the voice name
1140 variant_num = atoi(p); // variant number
1144 // voice variant name, not number
1145 sprintf(variant_name, "%s%s", variant_prefix, p);
1152 if(variant_num < 10)
1153 sprintf(variant_name,"%sm%d",variant_prefix, variant_num); // male
1155 sprintf(variant_name,"%sf%d",variant_prefix, variant_num-10); // female
1158 return(variant_name);
1159 } // end of ExtractVoiceVariantName
1163 voice_t *LoadVoiceVariant(const char *vname, int variant_num)
1164 {//==========================================================
1165 // Load a voice file.
1166 // Also apply a voice variant if specified by "variant", or by "+number" or "+name" in the "vname"
1172 strncpy0(buf,vname,sizeof(buf));
1173 variant_name = ExtractVoiceVariantName(buf,variant_num, 1);
1175 if((v = LoadVoice(buf,0)) == NULL)
1178 if(variant_name[0] != 0)
1180 v = LoadVoice(variant_name,2);
1187 static int __cdecl VoiceNameSorter(const void *p1, const void *p2)
1188 {//=======================================================
1190 espeak_VOICE *v1 = *(espeak_VOICE **)p1;
1191 espeak_VOICE *v2 = *(espeak_VOICE **)p2;
1194 if((ix = strcmp(&v1->languages[1],&v2->languages[1])) != 0) // primary language name
1196 if((ix = v1->languages[0] - v2->languages[0]) != 0) // priority number
1198 return(strcmp(v1->name,v2->name));
1202 static int __cdecl VoiceScoreSorter(const void *p1, const void *p2)
1203 {//========================================================
1205 espeak_VOICE *v1 = *(espeak_VOICE **)p1;
1206 espeak_VOICE *v2 = *(espeak_VOICE **)p2;
1208 if((ix = v2->score - v1->score) != 0)
1210 return(strcmp(v1->name,v2->name));
1214 static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int spec_n_parts, int spec_lang_len, espeak_VOICE *voice)
1215 {//=========================================================================================================================
1219 int language_priority;
1229 p = voice->languages; // list of languages+dialects for which this voice is suitable
1231 if(spec_n_parts < 0)
1233 // match on the subdirectory
1234 if(memcmp(voice->identifier, spec_language, spec_lang_len) == 0)
1239 if(spec_n_parts == 0)
1245 if((*p == 0) && (strcmp(spec_language,"variants")==0))
1247 // match on a voice with no languages if the required language is "variants"
1251 // compare the required language with each of the languages of this voice
1254 language_priority = *p++;
1262 if((ix >= spec_lang_len) || ((c1 = spec_language[ix]) == '-'))
1264 if((c2 = p[ix]) == '-')
1282 matching_parts += matching; // number of parts which match
1284 if(matching_parts == 0)
1285 continue; // no matching parts for this language
1288 // reduce the score if not all parts of the required language match
1289 if((diff = (spec_n_parts - matching_parts)) > 0)
1292 // reduce score if the language is more specific than required
1293 if((diff = (n_parts - matching_parts)) > 0)
1296 x = x*100 - (language_priority * 2);
1305 if(voice_spec->name != NULL)
1307 if(strcmp(voice_spec->name,voice->name)==0)
1309 // match on voice name
1312 else if(strcmp(voice_spec->name,voice->identifier)==0)
1318 if(((voice_spec->gender == 1) || (voice_spec->gender == 2)) &&
1319 ((voice->gender == 1) || (voice->gender == 2)))
1321 if(voice_spec->gender == voice->gender)
1327 if((voice_spec->age <= 12) && (voice->gender == 2) && (voice->age > 12))
1329 score += 5; // give some preference for non-child female voice if a child is requested
1334 if(voice_spec->age == 0)
1337 required_age = voice_spec->age;
1339 ratio = (required_age*100)/voice->age;
1341 ratio = 10000/ratio;
1342 ratio = (ratio - 100)/10; // 0=exact match, 10=out by factor of 2
1348 if(voice_spec->age > 0)
1349 score += 10; // required age specified, favour voices with a specified age (near it)
1354 } // end of ScoreVoice
1357 static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int control)
1358 {//======================================================================================
1359 // control: bit0=1 include mbrola voices
1362 int nv; // number of candidates
1367 char buf[sizeof(path_home)+80];
1369 // count number of parts in the specified language
1370 if((voice_select->languages != NULL) && (voice_select->languages[0] != 0))
1373 lang_len = strlen(voice_select->languages);
1374 for(ix=0; (ix<=lang_len) && ((unsigned)ix < sizeof(language)); ix++)
1376 if((language[ix] = tolower(voice_select->languages[ix])) == '-')
1381 if((n_parts == 1) && (control & 1))
1383 if(strcmp(language, "mbrola") == 0)
1385 language[2] = 0; // truncate to "mb"
1389 sprintf(buf, "%s/voices/%s", path_home, language);
1390 if(GetFileLength(buf) == -2)
1392 // A subdirectory name has been specified. List all the voices in that subdirectory
1393 language[lang_len++] = PATHSEP;
1394 language[lang_len] = 0;
1400 // select those voices which match the specified language
1402 for(ix=0; ix<n_voices_list; ix++)
1404 vp = voices_list[ix];
1406 if(((control & 1) == 0) && (memcmp(vp->identifier,"mb/",3) == 0))
1409 if((score = ScoreVoice(voice_select, language, n_parts, lang_len, voices_list[ix])) > 0)
1415 voices[nv] = NULL; // list terminator
1420 // sort the selected voices by their score
1421 qsort(voices,nv,sizeof(espeak_VOICE *),(int (__cdecl *)(const void *,const void *))VoiceScoreSorter);
1424 } // end of SetVoiceScores
1429 espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)
1430 {//======================================================================
1432 int match_fname = -1;
1433 int match_fname2 = -1;
1434 int match_name = -1;
1435 const char *id; // this is the filename within espeak-data/voices
1443 if(n_voices_list == 0)
1444 espeak_ListVoices(NULL); // create the voices list
1445 voices = voices_list;
1448 strncpy0(name, name2, sizeof(name));
1449 if((variant_name = strchr(name, '+')) != NULL)
1455 sprintf(last_part,"%c%s",PATHSEP,name);
1456 last_part_len = strlen(last_part);
1458 for(ix=0; voices[ix] != NULL; ix++)
1460 if(strcmp(name,voices[ix]->name)==0)
1462 match_name = ix; // found matching voice name
1467 id = voices[ix]->identifier;
1468 if(strcmp(name, id)==0)
1470 match_fname = ix; // matching identifier, use this if no matching name
1472 else if(strcmp(last_part,&id[strlen(id)-last_part_len])==0)
1481 match_name = match_fname; // no matching name, try matching filename
1483 match_name = match_fname2; // try matching just the last part of the filename
1489 return(voices[match_name]);
1490 } // end of SelectVoiceByName
1495 char const *SelectVoice(espeak_VOICE *voice_select, int *found)
1496 {//============================================================
1497 // Returns a path within espeak-voices, with a possible +variant suffix
1498 // variant is an output-only parameter
1499 int nv; // number of candidates
1508 const char *p, *p_start;
1509 espeak_VOICE *vp = NULL;
1511 espeak_VOICE voice_select2;
1512 espeak_VOICE *voices[N_VOICES_LIST]; // list of candidates
1513 espeak_VOICE *voices2[N_VOICES_LIST+N_VOICE_VARIANTS];
1514 static espeak_VOICE voice_variants[N_VOICE_VARIANTS];
1515 static char voice_id[50];
1518 memcpy(&voice_select2,voice_select,sizeof(voice_select2));
1520 if(n_voices_list == 0)
1521 espeak_ListVoices(NULL); // create the voices list
1523 if((voice_select2.languages == NULL) || (voice_select2.languages[0] == 0))
1525 // no language is specified. Get language from the named voice
1526 static char buf[60];
1528 if(voice_select2.name == NULL)
1530 if((voice_select2.name = voice_select2.identifier) == NULL)
1531 voice_select2.name = "default";
1534 strncpy0(buf,voice_select2.name,sizeof(buf));
1535 variant_name = ExtractVoiceVariantName(buf,0,0);
1537 vp = SelectVoiceByName(voices_list,buf);
1540 voice_select2.languages = &(vp->languages[1]);
1542 if((voice_select2.gender==0) && (voice_select2.age==0) && (voice_select2.variant==0))
1544 if(variant_name[0] != 0)
1546 sprintf(voice_id,"%s+%s", vp->identifier, variant_name);
1550 return(vp->identifier);
1555 // select and sort voices for the required language
1556 nv = SetVoiceScores(&voice_select2,voices,0);
1560 // no matching voice, choose the default
1562 if((voices[0] = SelectVoiceByName(voices_list,"default")) != NULL)
1567 if((voice_select2.gender == 2) || ((voice_select2.age > 0) && (voice_select2.age < 13)))
1569 else if(voice_select2.gender == 1)
1573 if(voice_select2.age < AGE_OLD)
1576 p = p_start = variant_lists[gender];
1578 p++; // the first voice in the variants list is older
1580 // add variants for the top voices
1582 for(ix=0, ix2=0; ix<nv; ix++)
1585 // is the main voice the required gender?
1587 if((gender != 0) && (vp->gender != gender))
1591 if((ix2==0) && aged && (vp->age < AGE_OLD))
1597 voices2[ix2++] = vp;
1600 for(j=0; (j < vp->xx1) && (n_variants < N_VOICE_VARIANTS);)
1602 if((variant_number = *p) == 0)
1608 vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
1609 memcpy(vp2,vp,sizeof(espeak_VOICE)); // copy from the original voice
1610 vp2->variant = variant_number;
1611 voices2[ix2++] = vp2;
1616 // add any more variants to the end of the list
1617 while((vp != NULL) && ((variant_number = *p++) != 0) && (n_variants < N_VOICE_VARIANTS))
1619 vp2 = &voice_variants[n_variants++]; // allocate space for voice variant
1620 memcpy(vp2,vp,sizeof(espeak_VOICE)); // copy from the original voice
1621 vp2->variant = variant_number;
1622 voices2[ix2++] = vp2;
1625 // index the sorted list by the required variant number
1628 vp = voices2[voice_select2.variant % ix2];
1630 if(vp->variant != 0)
1632 variant_name = ExtractVoiceVariantName(NULL, vp->variant, 0);
1633 sprintf(voice_id,"%s+%s", vp->identifier, variant_name);
1637 return(vp->identifier);
1638 } // end of SelectVoice
1642 static void GetVoices(const char *path)
1643 {//====================================
1645 espeak_VOICE *voice_data;
1647 char fname[sizeof(path_home)+100];
1649 #ifdef PLATFORM_RISCOS
1653 _kernel_swi_regs regs;
1654 _kernel_oserror *error;
1656 char directory2[sizeof(path_home)+100];
1659 regs.r[1] = (int)path;
1660 regs.r[2] = (int)buf;
1663 regs.r[5] = sizeof(buf);
1666 while(regs.r[3] > 0)
1668 error = _kernel_swi(0x0c+0x20000,®s,®s); /* OS_GBPB 10, read directory entries */
1669 if((error != NULL) || (regs.r[3] == 0))
1673 type = (int *)(&buf[16]);
1674 len = strlen(&buf[20]);
1675 sprintf(fname,"%s.%s",path,&buf[20]);
1684 // a regular line, add it to the voices list
1685 if((f_voice = fopen(fname,"r")) == NULL)
1688 // pass voice file name within the voices directory
1689 voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, &buf[20]);
1692 if(voice_data != NULL)
1694 voices_list[n_voices_list++] = voice_data;
1699 #ifdef PLATFORM_WINDOWS
1700 WIN32_FIND_DATAA FindFileData;
1701 HANDLE hFind = INVALID_HANDLE_VALUE;
1703 #undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string
1704 sprintf(fname,"%s\\*",path);
1705 hFind = FindFirstFileA(fname, &FindFileData);
1706 if(hFind == INVALID_HANDLE_VALUE)
1710 if(n_voices_list >= (N_VOICES_LIST-2))
1711 break; // voices list is full
1713 if(FindFileData.cFileName[0] != '.')
1715 sprintf(fname,"%s%c%s",path,PATHSEP,FindFileData.cFileName);
1716 ftype = GetFileLength(fname);
1725 // a regular line, add it to the voices list
1726 if((f_voice = fopen(fname,"r")) == NULL)
1729 // pass voice file name within the voices directory
1730 voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, FindFileData.cFileName);
1733 if(voice_data != NULL)
1735 voices_list[n_voices_list++] = voice_data;
1739 } while(FindNextFileA(hFind, &FindFileData) != 0);
1746 if((dir = opendir((char *)path)) == NULL) // note: (char *) is needed for WINCE
1749 while((ent = readdir(dir)) != NULL)
1751 if(n_voices_list >= (N_VOICES_LIST-2))
1752 break; // voices list is full
1754 if(ent->d_name[0] == '.')
1757 sprintf(fname,"%s%c%s",path,PATHSEP,ent->d_name);
1759 ftype = GetFileLength(fname);
1768 // a regular line, add it to the voices list
1769 if((f_voice = fopen(fname,"r")) == NULL)
1772 // pass voice file name within the voices directory
1773 voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, ent->d_name);
1776 if(voice_data != NULL)
1778 voices_list[n_voices_list++] = voice_data;
1785 } // end of GetVoices
1789 espeak_ERROR SetVoiceByName(const char *name)
1790 {//=========================================
1793 espeak_VOICE voice_selector;
1795 static char buf[60];
1797 strncpy0(buf,name,sizeof(buf));
1799 variant_name = ExtractVoiceVariantName(buf, 0, 1);
1803 // convert voice name to lower case (ascii)
1804 if((buf[ix] = tolower(buf[ix])) == 0)
1808 memset(&voice_selector,0,sizeof(voice_selector));
1809 voice_selector.name = (char *)name; // include variant name in voice stack ??
1811 // first check for a voice with this filename
1812 // This may avoid the need to call espeak_ListVoices().
1814 if(LoadVoice(buf,1) != NULL)
1816 if(variant_name[0] != 0)
1818 LoadVoice(variant_name,2);
1821 DoVoiceChange(voice);
1822 voice_selector.languages = voice->language_name;
1823 SetVoiceStack(&voice_selector, variant_name);
1827 if(n_voices_list == 0)
1828 espeak_ListVoices(NULL); // create the voices list
1830 if((v = SelectVoiceByName(voices_list,buf)) != NULL)
1832 if(LoadVoice(v->identifier,0) != NULL)
1834 if(variant_name[0] != 0)
1836 LoadVoice(variant_name,2);
1838 DoVoiceChange(voice);
1839 voice_selector.languages = voice->language_name;
1840 SetVoiceStack(&voice_selector, variant_name);
1844 return(EE_INTERNAL_ERROR); // voice name not found
1845 } // end of SetVoiceByName
1849 espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector)
1850 {//============================================================
1851 const char *voice_id;
1854 voice_id = SelectVoice(voice_selector, &voice_found);
1856 if(voice_found == 0)
1857 return(EE_NOT_FOUND);
1859 LoadVoiceVariant(voice_id,0);
1860 DoVoiceChange(voice);
1861 SetVoiceStack(voice_selector, "");
1864 } // end of SetVoiceByProperties
1867 void FreeVoiceList()
1868 {//=================
1869 for(int ix=0; ix<n_voices_list; ix++)
1871 if(voices_list[ix] != NULL)
1873 free(voices_list[ix]);
1874 voices_list[ix] = NULL;
1881 //=======================================================================
1882 // Library Interface Functions
1883 //=======================================================================
1884 #pragma GCC visibility push(default)
1887 ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
1888 {//========================================================================
1889 char path_voices[sizeof(path_home)+12];
1892 #ifdef PLATFORM_RISCOS
1893 if(n_voices_list == 0)
1895 sprintf(path_voices,"%s%cvoices",path_home,PATHSEP);
1896 len_path_voices = strlen(path_voices)+1;
1897 GetVoices(path_voices);
1898 voices_list[n_voices_list] = NULL; // voices list terminator
1900 return((const espeak_VOICE **)voices_list);
1906 static espeak_VOICE **voices = NULL;
1908 // free previous voice list data
1911 sprintf(path_voices,"%s%cvoices",path_home,PATHSEP);
1912 len_path_voices = strlen(path_voices)+1;
1914 GetVoices(path_voices);
1915 voices_list[n_voices_list] = NULL; // voices list terminator
1916 voices = (espeak_VOICE **)realloc(voices, sizeof(espeak_VOICE *)*(n_voices_list+1));
1918 // sort the voices list
1919 qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *),
1920 (int (__cdecl *)(const void *,const void *))VoiceNameSorter);
1925 // select the voices which match the voice_spec, and sort them by preference
1926 SetVoiceScores(voice_spec,voices,1);
1930 // list all: omit variant voices and mbrola voices and test voices
1932 for(ix=0; (v = voices_list[ix]) != NULL; ix++)
1934 if((v->languages[0] != 0) && (strcmp(&v->languages[1],"variant") != 0)
1935 && (memcmp(v->identifier,"mb/",3) != 0) && (memcmp(v->identifier,"test/",5) != 0))
1942 return((const espeak_VOICE **)voices);
1944 } // end of espeak_ListVoices
1948 ESPEAK_API espeak_VOICE *espeak_GetCurrentVoice(void)
1949 {//==================================================
1950 return(¤t_voice_selected);
1953 #pragma GCC visibility pop