diff options
Diffstat (limited to 'navit/support/espeak/voices.c')
| -rw-r--r--[-rwxr-xr-x] | navit/support/espeak/voices.c | 744 |
1 files changed, 492 insertions, 252 deletions
diff --git a/navit/support/espeak/voices.c b/navit/support/espeak/voices.c index a7bd3f5a0..c0279af9f 100755..100644 --- a/navit/support/espeak/voices.c +++ b/navit/support/espeak/voices.c @@ -1,5 +1,5 @@ /*************************************************************************** - * Copyright (C) 2005 to 2007 by Jonathan Duddington * + * Copyright (C) 2005 to 2014 by Jonathan Duddington * * email: jonsd@users.sourceforge.net * * * * This program is free software; you can redistribute it and/or modify * @@ -42,15 +42,14 @@ #include "voice.h" #include "translate.h" -#define int(x) ((int)(x)) -#define double(x) ((double)(x)) -#define __cdecl +#include "voices.h" MNEM_TAB genders [] = { {"unknown", 0}, {"male", 1}, {"female", 2}, - {NULL, 0 }}; + {NULL, 0 } +}; int tone_points[12] = {600,170, 1200,135, 2000,110, 3000,110, -1,0}; //int tone_points[12] = {250,200, 400,170, 600,170, 1200,135, 2000,110, -1,0}; @@ -64,12 +63,12 @@ int formant_rate[9]; // values adjusted for actual sample rate #define DEFAULT_LANGUAGE_PRIORITY 5 -#define N_VOICES_LIST 150 +#define N_VOICES_LIST 250 static int n_voices_list = 0; static espeak_VOICE *voices_list[N_VOICES_LIST]; static int len_path_voices; -espeak_VOICE voice_selected; +espeak_VOICE current_voice_selected; enum { @@ -95,11 +94,13 @@ enum { // these override defaults set by the translator V_WORDGAP, V_INTONATION, + V_TUNES, V_STRESSLENGTH, V_STRESSAMP, V_STRESSADD, V_DICTRULES, V_STRESSRULE, + V_STRESSOPT, V_CHARSET, V_NUMBERS, V_OPTION, @@ -107,6 +108,10 @@ enum { V_MBROLA, V_KLATT, V_FAST, + V_SPEED, + V_DICTMIN, + V_ALPHABET2, + V_DICTDIALECT, // these need a phoneme table to have been specified V_REPLACE, @@ -115,12 +120,13 @@ enum { -typedef struct { - const char *mnem; - int data; -} keywtab_t; +static MNEM_TAB options_tab[] = { + {"reduce_t", LOPT_REDUCE_T}, + {"bracket", LOPT_BRACKET_PAUSE}, + {NULL, -1} +}; -static keywtab_t keyword_tab[] = { +static MNEM_TAB keyword_tab[] = { {"name", V_NAME}, {"language", V_LANGUAGE}, {"gender", V_GENDER}, @@ -128,14 +134,16 @@ static keywtab_t keyword_tab[] = { {"formant", V_FORMANT}, {"pitch", V_PITCH}, {"phonemes", V_PHONEMES}, - {"translator", V_TRANSLATOR}, + {"translator", V_TRANSLATOR}, {"dictionary", V_DICTIONARY}, {"stressLength", V_STRESSLENGTH}, {"stressAmp", V_STRESSAMP}, {"stressAdd", V_STRESSADD}, {"intonation", V_INTONATION}, + {"tunes", V_TUNES}, {"dictrules", V_DICTRULES}, {"stressrule", V_STRESSRULE}, + {"stressopt", V_STRESSOPT}, {"charset", V_CHARSET}, {"replace", V_REPLACE}, {"words", V_WORDGAP}, @@ -152,7 +160,11 @@ static keywtab_t keyword_tab[] = { {"mbrola", V_MBROLA}, {"consonants", V_CONSONANTS}, {"klatt", V_KLATT}, - {"fast_test", V_FAST}, + {"fast_test2", V_FAST}, + {"speed", V_SPEED}, + {"dict_min", V_DICTMIN}, + {"alphabet2", V_ALPHABET2}, + {"dictdialect", V_DICTDIALECT}, // these just set a value in langopts.param[] {"l_dieresis", 0x100+LOPT_DIERESES}, @@ -162,11 +174,20 @@ static keywtab_t keyword_tab[] = { {"l_unpronouncable", 0x100+LOPT_UNPRONOUNCABLE}, {"l_sonorant_min", 0x100+LOPT_SONORANT_MIN}, {"l_length_mods", 0x100+LOPT_LENGTH_MODS}, - {NULL, 0} }; + {"apostrophe", 0x100+LOPT_APOSTROPHE}, + {NULL, 0} +}; + +static MNEM_TAB dict_dialects[] = { + {"en-us", DICTDIALECT_EN_US}, + {"es-la", DICTDIALECT_ES_LA}, + {NULL, 0} +}; + #define N_VOICE_VARIANTS 12 const char variants_either[N_VOICE_VARIANTS] = {1,2,12,3,13,4,14,5,11,0}; -const char variants_male[N_VOICE_VARIANTS] = {1,2,3,4,5,0}; +const char variants_male[N_VOICE_VARIANTS] = {1,2,3,4,5,6,0}; const char variants_female[N_VOICE_VARIANTS] = {11,12,13,14,0}; const char *variant_lists[3] = {variants_either, variants_male, variants_female}; @@ -183,6 +204,12 @@ static char *fgets_strip(char *buf, int size, FILE *f_in) if(fgets(buf,size,f_in) == NULL) return(NULL); + if(buf[0] == '#') + { + buf[0] = 0; + return(buf); + } + len = strlen(buf); while((--len > 0) && isspace(buf[len])) buf[len] = 0; @@ -194,6 +221,20 @@ static char *fgets_strip(char *buf, int size, FILE *f_in) } +static int LookupTune(const char *name) +{//==================================== + int ix; + + for(ix=0; ix<n_tunes; ix++) + { + if(strcmp(name, tunes[ix].name) == 0) + return(ix); + } + return(-1); +} // end of LookupTune + + + static void SetToneAdjust(voice_t *voice, int *tone_pts) {//===================================================== int ix; @@ -217,11 +258,11 @@ static void SetToneAdjust(voice_t *voice, int *tone_pts) height2 = tone_pts[pt+1]; if((freq2 - freq1) > 0) { - rate = double(height2-height1)/(freq2-freq1); + rate = (double)(height2-height1)/(freq2-freq1); for(ix=freq1; ix<freq2; ix++) { - y = height1 + int(rate * (ix-freq1)); + y = height1 + (int)(rate * (ix-freq1)); if(y > 255) y = 255; voice->tone_adjust[ix] = y; @@ -242,9 +283,9 @@ void ReadTonePoints(char *string, int *tone_pts) tone_pts[ix] = -1; sscanf(string,"%d %d %d %d %d %d %d %d %d %d", - &tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3], - &tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7], - &tone_pts[8],&tone_pts[9]); + &tone_pts[0],&tone_pts[1],&tone_pts[2],&tone_pts[3], + &tone_pts[4],&tone_pts[5],&tone_pts[6],&tone_pts[7], + &tone_pts[8],&tone_pts[9]); } @@ -269,7 +310,7 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*lea espeak_VOICE *voice_data; int priority; int age; - int n_variants = 3; // default, number of variants of this voice before using another voice + int n_variants = 4; // default, number of variants of this voice before using another voice int gender; #ifdef PLATFORM_WINDOWS @@ -298,8 +339,7 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*lea while(isspace(*p)) p++; strncpy0(vname,p,sizeof(vname)); } - else - if(memcmp(linebuf,"language",8)==0) + else if(memcmp(linebuf,"language",8)==0) { priority = DEFAULT_LANGUAGE_PRIORITY; vlanguage[0] = 0; @@ -316,13 +356,11 @@ static espeak_VOICE *ReadVoiceFile(FILE *f_in, const char *fname, const char*lea n_languages++; } } - else - if(memcmp(linebuf,"gender",6)==0) + else if(memcmp(linebuf,"gender",6)==0) { sscanf(&linebuf[6],"%s %d",vgender,&age); } - else - if(memcmp(linebuf,"variants",8)==0) + else if(memcmp(linebuf,"variants",8)==0) { sscanf(&linebuf[8],"%d",&n_variants); } @@ -369,29 +407,38 @@ void VoiceReset(int tone_only) // Set voice to the default values int pk; - static unsigned char default_heights[N_PEAKS] = {128,128,120,120,110,110,128,128,128}; - static unsigned char default_widths[N_PEAKS] = {128,128,128,160,171,171,128,128,128}; + static unsigned char default_heights[N_PEAKS] = {130,128,120,116,100,100,128,128,128}; // changed for v.1.47 + static unsigned char default_widths[N_PEAKS] = {140,128,128,160,171,171,128,128,128}; +// static unsigned char default_heights[N_PEAKS] = {128,128,120,120,110,110,128,128,128}; // previous version +// static unsigned char default_widths[N_PEAKS] = {128,128,128,160,171,171,128,128,128}; static int breath_widths[N_PEAKS] = {0,200,200,400,400,400,600,600,600}; - // default is: pitch 82,118 -// voice->pitch_base = 0x49000; // default, 73 << 12; -// voice->pitch_range = 0x0f30; // default = 0x1000 + // default is: pitch 80,118 voice->pitch_base = 0x47000; - voice->pitch_range = 3996; + voice->pitch_range = 4104; + +// default is: pitch 80,117 +// voice->pitch_base = 0x47000; +// voice->pitch_range = 3996; voice->formant_factor = 256; + voice->speed_percent = 100; voice->echo_delay = 0; voice->echo_amp = 0; voice->flutter = 64; voice->n_harmonic_peaks = 5; voice->peak_shape = 0; voice->voicing = 64; - voice->consonant_amp = 100; + voice->consonant_amp = 90; // change from 100 to 90 for v.1.47 voice->consonant_ampv = 100; + voice->samplerate = samplerate_native; memset(voice->klattv,0,sizeof(voice->klattv)); - memset(speed.fast_settings,0,sizeof(speed.fast_settings)); + + speed.fast_settings[0] = 450; + speed.fast_settings[1] = 800; + speed.fast_settings[2] = 175; #ifdef PLATFORM_RISCOS voice->roughness = 1; @@ -412,13 +459,12 @@ void VoiceReset(int tone_only) // adjust formant smoothing depending on sample rate formant_rate[pk] = (formant_rate_22050[pk] * 22050)/samplerate; } - voice->height[2] = 240; // reduce F2 slightly // This table provides the opportunity for tone control. // Adjustment of harmonic amplitudes, steps of 8Hz // value of 128 means no change // memset(voice->tone_adjust,128,sizeof(voice->tone_adjust)); -SetToneAdjust(voice,tone_points); + SetToneAdjust(voice,tone_points); // default values of speed factors voice->speedf1 = 256; @@ -452,11 +498,11 @@ static void VoiceFormant(char *p) return; if(freq >= 0) - voice->freq[formant] = int(freq * 2.56001); + voice->freq[formant] = (int)(freq * 2.56001); if(height >= 0) - voice->height[formant] = int(height * 2.56001); + voice->height[formant] = (int)(height * 2.56001); if(width >= 0) - voice->width[formant] = int(width * 2.56001); + voice->width[formant] = (int)(width * 2.56001); voice->freqadd[formant] = freqadd; } @@ -490,8 +536,24 @@ static void PhonemeReplacement(int type, char *p) static int Read8Numbers(char *data_in,int *data) {//============================================= // Read 8 integer numbers + memset(data, 0, 8+sizeof(int)); return(sscanf(data_in,"%d %d %d %d %d %d %d %d", - &data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7])); + &data[0],&data[1],&data[2],&data[3],&data[4],&data[5],&data[6],&data[7])); +} + + +static unsigned int StringToWord2(const char *string) +{//====================================================== +// Convert a language name string to a word such as L('e','n') + int ix; + int c; + unsigned int value = 0; + + for(ix=0; (ix<4) && ((c = string[ix]) != 0); ix++) + { + value = (value << 8) | (c & 0xff); + } + return(value); } @@ -503,13 +565,12 @@ voice_t *LoadVoice(const char *vname, int control) // bit 4 1 = vname = full path FILE *f_voice = NULL; - keywtab_t *k; char *p; int key; int ix; int n; int value; - int error = 0; + int value2; int langix = 0; int tone_only = control & 2; int language_set = 0; @@ -527,26 +588,35 @@ voice_t *LoadVoice(const char *vname, int control) char translator_name[40]; char new_dictionary[40]; char phonemes_name[40]; + char option_name[40]; const char *language_type; - char buf[200]; + char buf[sizeof(path_home)+30]; char path_voices[sizeof(path_home)+12]; - char langname[4]; + int dict_min = 0; int stress_amps[8]; int stress_lengths[8]; int stress_add[8]; + char names[8][40]; + char name1[40]; + char name2[80]; + const char *voice_dir; int pitch1; int pitch2; - static char voice_identifier[40]; // file name for voice_selected - static char voice_name[40]; // voice name for voice_selected - static char voice_languages[100]; // list of languages and priorities for voice_selected + static char voice_identifier[40]; // file name for current_voice_selected + static char voice_name[40]; // voice name for current_voice_selected + static char voice_languages[100]; // list of languages and priorities for current_voice_selected - strcpy(voicename,vname); - if(voicename[0]==0) - strcpy(voicename,"default"); + // which directory to look for a named voice. List of voice names, must end in a space. + static const char *voices_asia = + "az bn fa fa-pin hi hy hy-west id ka kn ku ml ms ne pa ta te tr vi vi-hue vi-sgn zh zh-yue "; + static const char *voices_europe = + "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 "; + + strncpy0(voicename, vname, sizeof(voicename)); if(control & 0x10) { strcpy(buf,vname); @@ -555,21 +625,36 @@ voice_t *LoadVoice(const char *vname, int control) } else { + if(voicename[0]==0) + strcpy(voicename,"default"); + sprintf(path_voices,"%s%cvoices%c",path_home,PATHSEP,PATHSEP); - sprintf(buf,"%s%s",path_voices,voicename); + sprintf(buf,"%s%s",path_voices,voicename); // first, look in the main voices directory if(GetFileLength(buf) <= 0) { - // look for the voice in a sub-directory of the language name - langname[0] = voicename[0]; - langname[1] = voicename[1]; - langname[2] = 0; - sprintf(buf,"%s%s%c%s",path_voices,langname,PATHSEP,voicename); - - if(GetFileLength(buf) <= 0) + // then look in the appropriate subdirectory + if((voicename[0]=='m') && (voicename[1]=='b')) + { + voice_dir = "mb"; // mbrola voices + } + else { - // look in "test" sub-directory - sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename); + sprintf(name2, "%s ", voicename); + if(strstr(voices_europe, voicename) != NULL) + voice_dir = "europe"; + else if(strstr(voices_asia, voicename) != NULL) + voice_dir = "asia"; + else + voice_dir = "other"; + + sprintf(buf,"%s%s%c%s", path_voices,voice_dir,PATHSEP,voicename); + + if(GetFileLength(buf) <= 0) + { + // if not found, look in "test" sub-directory + sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename); + } } } } @@ -604,9 +689,9 @@ voice_t *LoadVoice(const char *vname, int control) voice_name[0] = 0; voice_languages[0] = 0; - voice_selected.identifier = voice_identifier; - voice_selected.name = voice_name; - voice_selected.languages = voice_languages; + current_voice_selected.identifier = voice_identifier; + current_voice_selected.name = voice_name; + current_voice_selected.languages = voice_languages; } else { @@ -631,61 +716,54 @@ voice_t *LoadVoice(const char *vname, int control) if(buf[0] == 0) continue; - key = 0; - for(k=keyword_tab; k->mnem != NULL; k++) - { - if(strcmp(buf,k->mnem)==0) - { - key = k->data; - break; - } - } + key = LookupMnem(keyword_tab, buf); switch(key) { case V_LANGUAGE: + { + unsigned int len; + int priority; + + if(tone_only) + break; + + priority = DEFAULT_LANGUAGE_PRIORITY; + language_name[0] = 0; + + sscanf(p,"%s %d",language_name,&priority); + if(strcmp(language_name,"variant") == 0) + break; + + len = strlen(language_name) + 2; + // check for space in languages[] + if(len < (sizeof(voice_languages)-langix-1)) { - unsigned int len; - int priority; + voice_languages[langix] = priority; - if(tone_only) - break; - - priority = DEFAULT_LANGUAGE_PRIORITY; - language_name[0] = 0; - - sscanf(p,"%s %d",language_name,&priority); - if(strcmp(language_name,"variant") == 0) - break; - - len = strlen(language_name) + 2; - // check for space in languages[] - if(len < (sizeof(voice_languages)-langix-1)) - { - voice_languages[langix] = priority; - - strcpy(&voice_languages[langix+1],language_name); - langix += len; - } - - // only act on the first language line - if(language_set == 0) - { - language_type = strtok(language_name,"-"); - language_set = 1; - strcpy(translator_name,language_type); - strcpy(new_dictionary,language_type); - strcpy(phonemes_name,language_type); - SelectPhonemeTableName(phonemes_name); - - if(new_translator != NULL) - DeleteTranslator(new_translator); - - new_translator = SelectTranslator(translator_name); - langopts = &new_translator->langopts; - } + strcpy(&voice_languages[langix+1],language_name); + langix += len; } - break; + + // only act on the first language line + if(language_set == 0) + { + language_type = strtok(language_name,"-"); + language_set = 1; + strcpy(translator_name,language_type); + strcpy(new_dictionary,language_type); + strcpy(phonemes_name,language_type); + SelectPhonemeTableName(phonemes_name); + + if(new_translator != NULL) + DeleteTranslator(new_translator); + + new_translator = SelectTranslator(translator_name); + langopts = &new_translator->langopts; + strncpy0(voice->language_name, language_name, sizeof(voice->language_name)); + } + } + break; case V_NAME: if(tone_only == 0) @@ -696,14 +774,14 @@ voice_t *LoadVoice(const char *vname, int control) break; case V_GENDER: - { - int age; - char vgender[80]; - sscanf(p,"%s %d",vgender,&age); - voice_selected.gender = LookupMnem(genders,vgender); - voice_selected.age = age; - } - break; + { + int age = 0; + char vgender[80]; + sscanf(p,"%s %d",vgender,&age); + current_voice_selected.gender = LookupMnem(genders,vgender); + current_voice_selected.age = age; + } + break; case V_TRANSLATOR: if(tone_only) break; @@ -711,7 +789,7 @@ voice_t *LoadVoice(const char *vname, int control) sscanf(p,"%s",translator_name); if(new_translator != NULL) - DeleteTranslator(new_translator); + DeleteTranslator(new_translator); new_translator = SelectTranslator(translator_name); langopts = &new_translator->langopts; @@ -730,16 +808,16 @@ voice_t *LoadVoice(const char *vname, int control) break; case V_PITCH: - { - double factor; - // default is pitch 82 118 - n = sscanf(p,"%d %d",&pitch1,&pitch2); - voice->pitch_base = (pitch1 - 9) << 12; - voice->pitch_range = (pitch2 - pitch1) * 108; - factor = double(pitch1 - 82)/82; - voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch - } - break; + { + double factor; + // default is pitch 82 118 + n = sscanf(p,"%d %d",&pitch1,&pitch2); + voice->pitch_base = (pitch1 - 9) << 12; + voice->pitch_range = (pitch2 - pitch1) * 108; + factor = (double)(pitch1 - 82)/82; + voice->formant_factor = (int)((1+factor/4) * 256); // nominal formant shift for a different voice pitch + } + break; case V_STRESSLENGTH: // stressLength stress_lengths_set = Read8Numbers(p,stress_lengths); @@ -759,18 +837,52 @@ voice_t *LoadVoice(const char *vname, int control) langopts->intonation_group = option_tone_flags & 0xff; break; + case V_TUNES: + n = sscanf(p,"%s %s %s %s %s %s",names[0],names[1],names[2],names[3],names[4],names[5]); + langopts->intonation_group = 0; + for(ix=0; ix<n; ix++) + { + if(strcmp(names[ix],"NULL")==0) + continue; + + if((value = LookupTune(names[ix])) < 0) + fprintf(stderr,"Unknown tune '%s'\n",names[ix]); + else + langopts->tunes[ix] = value; + } + break; + case V_DICTRULES: // conditional dictionary rules and list entries + case V_NUMBERS: + case V_STRESSOPT: + // expect a list of numbers while(*p != 0) { while(isspace(*p)) p++; n = -1; - if(((n = atoi(p)) > 0) && (n < 32)) + if((n = atoi(p)) > 0) { p++; - conditional_rules |= (1 << n); + if(n < 32) + { + if(key==V_DICTRULES) + conditional_rules |= (1 << n); + else if(key==V_NUMBERS) + langopts->numbers |= (1 << n); + else if(key==V_STRESSOPT) + langopts->stress_flags |= (1 << n); + } + else + { + if((key==V_NUMBERS) && (n < 64)) + langopts->numbers |= (1 << (n-32)); + else + fprintf(stderr,"Bad option number %d\n", n); + } } while(isalnum(*p)) p++; } + ProcessLanguageOptions(langopts); break; case V_REPLACE: @@ -789,9 +901,9 @@ voice_t *LoadVoice(const char *vname, int control) case V_STRESSRULE: sscanf(p,"%d %d %d %d",&langopts->stress_rule, - &langopts->stress_flags, - &langopts->unstressed_wd1, - &langopts->unstressed_wd2); + &langopts->stress_flags, + &langopts->unstressed_wd1, + &langopts->unstressed_wd2); break; case V_CHARSET: @@ -799,15 +911,17 @@ voice_t *LoadVoice(const char *vname, int control) new_translator->charset_a0 = charsets[value]; break; - case V_NUMBERS: - sscanf(p,"%d %d",&langopts->numbers,&langopts->numbers2); - break; - case V_OPTION: - if(sscanf(p,"%d %d",&ix,&value) == 2) + value2 = 0; + if(((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0)) || + ((sscanf(p,"%d %d %d",&ix,&value,&value2) >= 2) && (ix < N_LOPTS))) + { + langopts->param[ix] = value; + langopts->param2[ix] = value2; + } + else { - if((ix >= 0) && (ix < N_LOPTS)) - langopts->param[ix] = value; + fprintf(stderr,"Bad voice option: %s %s\n",buf,p); } break; @@ -841,12 +955,12 @@ voice_t *LoadVoice(const char *vname, int control) break; case V_TONE: - { - int tone_data[12]; - ReadTonePoints(p,tone_data); - SetToneAdjust(voice,tone_data); - } - break; + { + int tone_data[12]; + ReadTonePoints(p,tone_data); + SetToneAdjust(voice,tone_data); + } + break; case V_VOICING: if(sscanf(p,"%d",&value)==1) @@ -854,33 +968,39 @@ voice_t *LoadVoice(const char *vname, int control) break; case V_BREATH: - voice->breath[0] = Read8Numbers(p,&voice->breath[1]); - for(ix=1; ix<8; ix++) - { - if(ix % 2) - voice->breath[ix] = -voice->breath[ix]; - } + voice->breath[0] = Read8Numbers(p,&voice->breath[1]); + for(ix=1; ix<8; ix++) + { + if(ix % 2) + voice->breath[ix] = -voice->breath[ix]; + } break; case V_BREATHW: - voice->breathw[0] = Read8Numbers(p,&voice->breathw[1]); + voice->breathw[0] = Read8Numbers(p,&voice->breathw[1]); break; case V_CONSONANTS: value = sscanf(p,"%d %d",&voice->consonant_amp, &voice->consonant_ampv); break; + case V_SPEED: + sscanf(p,"%d",&voice->speed_percent); + break; + case V_MBROLA: - { - int srate = 16000; - char name[40]; - char phtrans[40]; + { + int srate = 16000; - phtrans[0] = 0; - sscanf(p,"%s %s %d",name,phtrans,&srate); - LoadMbrolaTable(name,phtrans,srate); + name2[0] = 0; + sscanf(p,"%s %s %d",name1,name2,&srate); + if(LoadMbrolaTable(name1,name2,srate) != EE_OK) + { + fprintf(stderr,"mbrola voice not found\n"); } - break; + voice->samplerate = srate; + } + break; case V_KLATT: voice->klattv[0] = 1; // default source: IMPULSIVE @@ -890,7 +1010,48 @@ voice_t *LoadVoice(const char *vname, int control) case V_FAST: Read8Numbers(p,speed.fast_settings); - SetSpeed(2); + SetSpeed(3); + break; + + case V_DICTMIN: + sscanf(p,"%d",&dict_min); + break; + + case V_ALPHABET2: + { + ALPHABET *alphabet; + name1[0] = name2[0] = 0; + sscanf(p, "%s %s", name1, name2); + + if(strcmp(name1, "latin") == 0) + { + strncpy0(langopts->ascii_language,name2,sizeof(langopts->ascii_language)); + } + else if((alphabet = AlphabetFromName(name1)) != 0) + { + langopts->alt_alphabet = alphabet->offset; + langopts->alt_alphabet_lang = StringToWord2(name2); + } + else + { + fprintf(stderr,"alphabet name '%s' not found\n", name1); + } + } + break; + + case V_DICTDIALECT: + // specify a dialect to use for foreign words, eg, en-us for _^_EN + if(sscanf(p, "%s", name1) == 1) + { + if((ix = LookupMnem(dict_dialects, name1)) > 0) + { + langopts->dict_dialect |= (1 << ix); + } + else + { + fprintf(stderr, "dictdialect name '%s' not recognized\n", name1); + } + } break; default: @@ -914,6 +1075,8 @@ voice_t *LoadVoice(const char *vname, int control) new_translator = SelectTranslator(translator_name); } + SetSpeed(3); // for speed_percent + for(ix=0; ix<N_PEAKS; ix++) { voice->freq2[ix] = voice->freq[ix]; @@ -930,9 +1093,12 @@ voice_t *LoadVoice(const char *vname, int control) if((ix = SelectPhonemeTableName(phonemes_name)) < 0) { fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name); + ix = 0; } voice->phoneme_tab_ix = ix; - error = LoadDictionary(new_translator, new_dictionary, control & 4); + new_translator->phoneme_tab_ix = ix; + new_translator->dict_min_size = dict_min; + LoadDictionary(new_translator, new_dictionary, control & 4); if(dictionary_name[0]==0) return(NULL); // no dictionary loaded @@ -956,6 +1122,7 @@ voice_t *LoadVoice(const char *vname, int control) translator = new_translator; } + // relative lengths of different stress syllables for(ix=0; ix<stress_lengths_set; ix++) { @@ -975,37 +1142,39 @@ voice_t *LoadVoice(const char *vname, int control) } // end of LoadVoice -static char *ExtractVoiceVariantName(char *vname, int variant_num) -{//=============================================================== +static char *ExtractVoiceVariantName(char *vname, int variant_num, int add_dir) +{//=========================================================================== // Remove any voice variant suffix (name or number) from a voice name // Returns the voice variant name char *p; - static char variant_name[20]; + static char variant_name[40]; char variant_prefix[5]; variant_name[0] = 0; sprintf(variant_prefix,"!v%c",PATHSEP); + if(add_dir == 0) + variant_prefix[0] = 0; if(vname != NULL) { if((p = strchr(vname,'+')) != NULL) { // The voice name has a +variant suffix + variant_num = 0; *p++ = 0; // delete the suffix from the voice name - if(isdigit(*p)) + if(IsDigit09(*p)) { variant_num = atoi(p); // variant number } else { // voice variant name, not number - strcpy(variant_name,variant_prefix); - strncpy0(&variant_name[3],p,sizeof(variant_name)-3); - } + sprintf(variant_name, "%s%s", variant_prefix, p); + } } } - + if(variant_num > 0) { if(variant_num < 10) @@ -1029,7 +1198,7 @@ voice_t *LoadVoiceVariant(const char *vname, int variant_num) char buf[60]; strncpy0(buf,vname,sizeof(buf)); - variant_name = ExtractVoiceVariantName(buf,variant_num); + variant_name = ExtractVoiceVariantName(buf,variant_num, 1); if((v = LoadVoice(buf,0)) == NULL) return(NULL); @@ -1087,10 +1256,10 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s p = voice->languages; // list of languages+dialects for which this voice is suitable - if(strcmp(spec_language,"mbrola")==0) + if(spec_n_parts < 0) { - // only list mbrola voices - if(memcmp(voice->identifier,"mb/",3) == 0) + // match on the subdirectory + if(memcmp(voice->identifier, spec_language, spec_lang_len) == 0) return(100); return(0); } @@ -1168,15 +1337,14 @@ static int ScoreVoice(espeak_VOICE *voice_spec, const char *spec_language, int s // match on voice name score += 500; } - else - if(strcmp(voice_spec->name,voice->identifier)==0) + else if(strcmp(voice_spec->name,voice->identifier)==0) { score += 400; } } if(((voice_spec->gender == 1) || (voice_spec->gender == 2)) && - ((voice->gender == 1) || (voice->gender == 2))) + ((voice->gender == 1) || (voice->gender == 2))) { if(voice_spec->gender == voice->gender) score += 50; @@ -1224,6 +1392,7 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int int lang_len=0; espeak_VOICE *vp; char language[80]; + char buf[sizeof(path_home)+80]; // count number of parts in the specified language if((voice_select->languages != NULL) && (voice_select->languages[0] != 0)) @@ -1236,6 +1405,26 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int n_parts++; } } + + if((n_parts == 1) && (control & 1)) + { + if(strcmp(language, "mbrola") == 0) + { + language[2] = 0; // truncate to "mb" + lang_len = 2; + } + + sprintf(buf, "%s/voices/%s", path_home, language); + if(GetFileLength(buf) == -2) + { + // A subdirectory name has been specified. List all the voices in that subdirectory + language[lang_len++] = PATHSEP; + language[lang_len] = 0; + n_parts = -1; + } + + } + // select those voices which match the specified language nv = 0; for(ix=0; ix<n_voices_list; ix++) @@ -1257,7 +1446,7 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int return(0); // sort the selected voices by their score - qsort(voices,nv,sizeof(espeak_VOICE *),VoiceScoreSorter); + qsort(voices,nv,sizeof(espeak_VOICE *),(int (__cdecl *)(const void *,const void *))VoiceScoreSorter); return(nv); } // end of SetVoiceScores @@ -1265,15 +1454,17 @@ static int SetVoiceScores(espeak_VOICE *voice_select, espeak_VOICE **voices, int -espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name) -{//===================================================================== +espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2) +{//====================================================================== int ix; int match_fname = -1; int match_fname2 = -1; int match_name = -1; - const char *id; + const char *id; // this is the filename within espeak-data/voices + char *variant_name; int last_part_len; char last_part[41]; + char name[40]; if(voices == NULL) { @@ -1282,6 +1473,13 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name) voices = voices_list; } + strncpy0(name, name2, sizeof(name)); + if((variant_name = strchr(name, '+')) != NULL) + { + *variant_name = 0; + variant_name++; + } + sprintf(last_part,"%c%s",PATHSEP,name); last_part_len = strlen(last_part); @@ -1293,14 +1491,16 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name) break; } else - if(strcmp(name,id = voices[ix]->identifier)==0) { - match_fname = ix; // matching identifier, use this if no matching name - } - else - if(strcmp(last_part,&id[strlen(id)-last_part_len])==0) - { - match_fname2 = ix; + id = voices[ix]->identifier; + if(strcmp(name, id)==0) + { + match_fname = ix; // matching identifier, use this if no matching name + } + else if(strcmp(last_part,&id[strlen(id)-last_part_len])==0) + { + match_fname2 = ix; + } } } @@ -1352,15 +1552,15 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) { // no language is specified. Get language from the named voice static char buf[60]; - + if(voice_select2.name == NULL) { if((voice_select2.name = voice_select2.identifier) == NULL) voice_select2.name = "default"; } - + strncpy0(buf,voice_select2.name,sizeof(buf)); - variant_name = ExtractVoiceVariantName(buf,0); + variant_name = ExtractVoiceVariantName(buf,0,0); vp = SelectVoiceByName(voices_list,buf); if(vp != NULL) @@ -1371,7 +1571,7 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) { if(variant_name[0] != 0) { - sprintf(voice_id,"%s+%s",vp->identifier,&variant_name[3]); // omit the !v/ from variant_name + sprintf(voice_id,"%s+%s", vp->identifier, variant_name); return(voice_id); } @@ -1394,8 +1594,7 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) gender = 0; if((voice_select2.gender == 2) || ((voice_select2.age > 0) && (voice_select2.age < 13))) gender = 2; - else - if(voice_select2.gender == 1) + else if(voice_select2.gender == 1) gender = 1; #define AGE_OLD 60 @@ -1413,6 +1612,7 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) vp = voices[ix]; // is the main voice the required gender? skip=0; + if((gender != 0) && (vp->gender != gender)) { skip=1; @@ -1421,9 +1621,10 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) { skip=1; } + if(skip==0) { - voices2[ix2++] = vp; + voices2[ix2++] = vp; } for(j=0; (j < vp->xx1) && (n_variants < N_VOICE_VARIANTS);) @@ -1452,12 +1653,14 @@ char const *SelectVoice(espeak_VOICE *voice_select, int *found) } // index the sorted list by the required variant number + if(ix2 == 0) + return(NULL); vp = voices2[voice_select2.variant % ix2]; if(vp->variant != 0) { - variant_name = ExtractVoiceVariantName(NULL,vp->variant); - sprintf(voice_id,"%s+%s",vp->identifier,&variant_name[3]); + variant_name = ExtractVoiceVariantName(NULL, vp->variant, 0); + sprintf(voice_id,"%s+%s", vp->identifier, variant_name); return(voice_id); } @@ -1508,10 +1711,10 @@ static void GetVoices(const char *path) } else { - // a regular line, add it to the voices list + // a regular line, add it to the voices list if((f_voice = fopen(fname,"r")) == NULL) continue; - + // pass voice file name within the voices directory voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, &buf[20]); fclose(f_voice); @@ -1524,8 +1727,8 @@ static void GetVoices(const char *path) } #else #ifdef PLATFORM_WINDOWS - WIN32_FIND_DATAA FindFileData; - HANDLE hFind = INVALID_HANDLE_VALUE; + WIN32_FIND_DATAA FindFileData; + HANDLE hFind = INVALID_HANDLE_VALUE; #undef UNICODE // we need FindFirstFileA() which takes an 8-bit c-string sprintf(fname,"%s\\*",path); @@ -1534,29 +1737,33 @@ static void GetVoices(const char *path) return; do { - sprintf(fname,"%s%c%s",path,PATHSEP,FindFileData.cFileName); - - ftype = GetFileLength(fname); + if(n_voices_list >= (N_VOICES_LIST-2)) + break; // voices list is full - if((ftype == -2) && (FindFileData.cFileName[0] != '.')) + if(FindFileData.cFileName[0] != '.') { - // a sub-sirectory - GetVoices(fname); - } - else - if(ftype > 0) - { - // a regular line, add it to the voices list - if((f_voice = fopen(fname,"r")) == NULL) - continue; - - // pass voice file name within the voices directory - voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, FindFileData.cFileName); - fclose(f_voice); + sprintf(fname,"%s%c%s",path,PATHSEP,FindFileData.cFileName); + ftype = GetFileLength(fname); - if(voice_data != NULL) + if(ftype == -2) { - voices_list[n_voices_list++] = voice_data; + // a sub-sirectory + GetVoices(fname); + } + else if(ftype > 0) + { + // a regular line, add it to the voices list + if((f_voice = fopen(fname,"r")) == NULL) + continue; + + // pass voice file name within the voices directory + voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, FindFileData.cFileName); + fclose(f_voice); + + if(voice_data != NULL) + { + voices_list[n_voices_list++] = voice_data; + } } } } while(FindNextFileA(hFind, &FindFileData) != 0); @@ -1574,22 +1781,24 @@ static void GetVoices(const char *path) if(n_voices_list >= (N_VOICES_LIST-2)) break; // voices list is full + if(ent->d_name[0] == '.') + continue; + sprintf(fname,"%s%c%s",path,PATHSEP,ent->d_name); ftype = GetFileLength(fname); - if((ftype == -2) && (ent->d_name[0] != '.')) + if(ftype == -2) { // a sub-sirectory GetVoices(fname); } - else - if(ftype > 0) + else if(ftype > 0) { - // a regular line, add it to the voices list + // a regular line, add it to the voices list if((f_voice = fopen(fname,"r")) == NULL) continue; - + // pass voice file name within the voices directory voice_data = ReadVoiceFile(f_voice, fname+len_path_voices, ent->d_name); fclose(f_voice); @@ -1610,15 +1819,23 @@ static void GetVoices(const char *path) espeak_ERROR SetVoiceByName(const char *name) {//========================================= espeak_VOICE *v; + int ix; espeak_VOICE voice_selector; char *variant_name; static char buf[60]; strncpy0(buf,name,sizeof(buf)); - variant_name = ExtractVoiceVariantName(buf,0); + + variant_name = ExtractVoiceVariantName(buf, 0, 1); + + for(ix=0; ; ix++) + { + // convert voice name to lower case (ascii) + if((buf[ix] = tolower(buf[ix])) == 0) + break; + } memset(&voice_selector,0,sizeof(voice_selector)); -// voice_selector.name = buf; voice_selector.name = (char *)name; // include variant name in voice stack ?? // first check for a voice with this filename @@ -1632,7 +1849,8 @@ espeak_ERROR SetVoiceByName(const char *name) } DoVoiceChange(voice); - SetVoiceStack(&voice_selector); + voice_selector.languages = voice->language_name; + SetVoiceStack(&voice_selector, variant_name); return(EE_OK); } @@ -1648,7 +1866,8 @@ espeak_ERROR SetVoiceByName(const char *name) LoadVoice(variant_name,2); } DoVoiceChange(voice); - SetVoiceStack(&voice_selector); + voice_selector.languages = voice->language_name; + SetVoiceStack(&voice_selector, variant_name); return(EE_OK); } } @@ -1669,12 +1888,25 @@ espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector) LoadVoiceVariant(voice_id,0); DoVoiceChange(voice); - SetVoiceStack(voice_selector); + SetVoiceStack(voice_selector, ""); return(EE_OK); } // end of SetVoiceByProperties +void FreeVoiceList(void) +{//================= + int ix; + for(ix=0; ix<n_voices_list; ix++) + { + if(voices_list[ix] != NULL) + { + free(voices_list[ix]); + voices_list[ix] = NULL; + } + } + n_voices_list = 0; +} //======================================================================= @@ -1683,32 +1915,40 @@ espeak_ERROR SetVoiceByProperties(espeak_VOICE *voice_selector) #pragma GCC visibility push(default) -const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) +ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) {//======================================================================== -#ifndef PLATFORM_RISCOS - int ix; - int j; - espeak_VOICE *v; - static espeak_VOICE *voices[N_VOICES_LIST]; char path_voices[sizeof(path_home)+12]; - // free previous voice list data - for(ix=0; ix<n_voices_list; ix++) +#ifdef PLATFORM_RISCOS + if(n_voices_list == 0) { - if(voices_list[ix] != NULL) - free(voices_list[ix]); + sprintf(path_voices,"%s%cvoices",path_home,PATHSEP); + len_path_voices = strlen(path_voices)+1; + GetVoices(path_voices); + voices_list[n_voices_list] = NULL; // voices list terminator } - n_voices_list = 0; + return((const espeak_VOICE **)voices_list); + +#else + int ix; + int j; + espeak_VOICE *v; + static espeak_VOICE **voices = NULL; + + // free previous voice list data + FreeVoiceList(); sprintf(path_voices,"%s%cvoices",path_home,PATHSEP); len_path_voices = strlen(path_voices)+1; GetVoices(path_voices); voices_list[n_voices_list] = NULL; // voices list terminator + voices = (espeak_VOICE **)realloc(voices, sizeof(espeak_VOICE *)*(n_voices_list+1)); // sort the voices list - qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *),VoiceNameSorter); + qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *), + (int (__cdecl *)(const void *,const void *))VoiceNameSorter); if(voice_spec) @@ -1718,11 +1958,12 @@ const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) } else { - // list all: omit variant voices and mbrola voices + // list all: omit variant voices and mbrola voices and test voices j = 0; for(ix=0; (v = voices_list[ix]) != NULL; ix++) { - if((v->languages[0] != 0) && (strcmp(&v->languages[1],"variant") != 0) && (memcmp(v->identifier,"mb/",3) != 0)) + if((v->languages[0] != 0) && (strcmp(&v->languages[1],"variant") != 0) + && (memcmp(v->identifier,"mb/",3) != 0) && (memcmp(v->identifier,"test/",5) != 0)) { voices[j++] = v; } @@ -1731,14 +1972,13 @@ const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec) } return((const espeak_VOICE **)voices); #endif - return((const espeak_VOICE **)voices_list); } // end of espeak_ListVoices -espeak_VOICE *espeak_GetCurrentVoice(void) +ESPEAK_API espeak_VOICE *espeak_GetCurrentVoice(void) {//================================================== - return(&voice_selected); + return(¤t_voice_selected); } #pragma GCC visibility pop |
