summaryrefslogtreecommitdiff
path: root/navit/support/espeak/voices.c
diff options
context:
space:
mode:
Diffstat (limited to 'navit/support/espeak/voices.c')
-rw-r--r--[-rwxr-xr-x]navit/support/espeak/voices.c744
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(&current_voice_selected);
}
#pragma GCC visibility pop