Merge branch 'master' into android

This commit is contained in:
Reece H. Dunn
2013-03-14 17:08:01 +00:00
186 changed files with 16197 additions and 10825 deletions
+219 -161
View File
@@ -1,5 +1,5 @@
/***************************************************************************
* Copyright (C) 2005 to 2010 by Jonathan Duddington *
* Copyright (C) 2005 to 2013 by Jonathan Duddington *
* email: jonsd@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -48,7 +48,8 @@ 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};
@@ -62,7 +63,7 @@ int formant_rate[9]; // values adjusted for actual sample rate
#define DEFAULT_LANGUAGE_PRIORITY 5
#define N_VOICES_LIST 200
#define N_VOICES_LIST 250
static int n_voices_list = 0;
static espeak_VOICE *voices_list[N_VOICES_LIST];
static int len_path_voices;
@@ -99,6 +100,7 @@ enum {
V_STRESSADD,
V_DICTRULES,
V_STRESSRULE,
V_STRESSOPT,
V_CHARSET,
V_NUMBERS,
V_OPTION,
@@ -107,6 +109,7 @@ enum {
V_KLATT,
V_FAST,
V_SPEED,
V_DICTMIN,
// these need a phoneme table to have been specified
V_REPLACE,
@@ -118,7 +121,8 @@ enum {
static MNEM_TAB options_tab[] = {
{"reduce_t", LOPT_REDUCE_T},
{"bracket", LOPT_BRACKET_PAUSE},
{NULL, -1} };
{NULL, -1}
};
static MNEM_TAB keyword_tab[] = {
{"name", V_NAME},
@@ -128,7 +132,7 @@ static MNEM_TAB 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},
@@ -137,6 +141,7 @@ static MNEM_TAB keyword_tab[] = {
{"tunes", V_TUNES},
{"dictrules", V_DICTRULES},
{"stressrule", V_STRESSRULE},
{"stressopt", V_STRESSOPT},
{"charset", V_CHARSET},
{"replace", V_REPLACE},
{"words", V_WORDGAP},
@@ -155,6 +160,7 @@ static MNEM_TAB keyword_tab[] = {
{"klatt", V_KLATT},
{"fast_test2", V_FAST},
{"speed", V_SPEED},
{"dict_min", V_DICTMIN},
// these just set a value in langopts.param[]
{"l_dieresis", 0x100+LOPT_DIERESES},
@@ -165,7 +171,8 @@ static MNEM_TAB keyword_tab[] = {
{"l_sonorant_min", 0x100+LOPT_SONORANT_MIN},
{"l_length_mods", 0x100+LOPT_LENGTH_MODS},
{"apostrophe", 0x100+LOPT_APOSTROPHE},
{NULL, 0} };
{NULL, 0}
};
#define N_VOICE_VARIANTS 12
const char variants_either[N_VOICE_VARIANTS] = {1,2,12,3,13,4,14,5,11,0};
@@ -186,6 +193,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;
@@ -259,9 +272,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]);
}
@@ -315,8 +328,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;
@@ -333,13 +345,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);
}
@@ -386,8 +396,10 @@ 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] = {140,128,120,110,90,90,128,128,128}; // changed for v.1.47
// static unsigned char default_widths[N_PEAKS] = {128,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] = {140,128,128,160,171,171,128,128,128};
static int breath_widths[N_PEAKS] = {0,200,200,400,400,400,600,600,600};
@@ -408,7 +420,7 @@ void VoiceReset(int tone_only)
voice->n_harmonic_peaks = 5;
voice->peak_shape = 0;
voice->voicing = 64;
voice->consonant_amp = 100;
voice->consonant_amp = 85; // change to 85 for v.1.47 was 100
voice->consonant_ampv = 100;
voice->samplerate = samplerate_native;
memset(voice->klattv,0,sizeof(voice->klattv));
@@ -442,7 +454,7 @@ void VoiceReset(int tone_only)
// 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;
@@ -516,7 +528,7 @@ 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]));
}
@@ -553,14 +565,16 @@ voice_t *LoadVoice(const char *vname, int control)
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 name2[80];
const char *voice_dir;
int pitch1;
int pitch2;
@@ -569,10 +583,14 @@ voice_t *LoadVoice(const char *vname, int control)
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
static const char *voices_asia =
"fa fa-pin hi hy hy-west id ka kn ku ml ne pa ta tr vi vi-hue zh zh-yue ";
static const char *voices_europe =
"bg bs ca cs cy da el es et fi fr-be 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);
@@ -581,25 +599,34 @@ 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'))
{
// look in "extra" sub-directory
sprintf(buf,"%sextra%c%s",path_voices,PATHSEP,voicename);
voice_dir = "mb"; // mbrola voices
}
else
{
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)
{
// look in "test" sub-directory
// if not found, look in "test" sub-directory
sprintf(buf,"%stest%c%s",path_voices,PATHSEP,voicename);
}
}
@@ -668,48 +695,48 @@ voice_t *LoadVoice(const char *vname, int control)
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;
}
}
break;
case V_NAME:
if(tone_only == 0)
@@ -720,14 +747,14 @@ voice_t *LoadVoice(const char *vname, int control)
break;
case V_GENDER:
{
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;
{
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;
@@ -735,7 +762,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;
@@ -754,16 +781,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);
@@ -799,14 +826,32 @@ voice_t *LoadVoice(const char *vname, int control)
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++;
}
@@ -828,9 +873,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:
@@ -838,10 +883,6 @@ 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:
value2 = 0;
if((sscanf(p,"%s %d %d",option_name,&value,&value2) >= 2) && ((ix = LookupMnem(options_tab, option_name)) >= 0))
@@ -885,12 +926,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)
@@ -898,16 +939,16 @@ 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:
@@ -919,20 +960,20 @@ voice_t *LoadVoice(const char *vname, int control)
break;
case V_MBROLA:
{
int srate = 16000;
char name[40];
char phtrans[40];
{
int srate = 16000;
char name[40];
char phtrans[40];
phtrans[0] = 0;
sscanf(p,"%s %s %d",name,phtrans,&srate);
if(LoadMbrolaTable(name,phtrans,srate) != EE_OK)
{
fprintf(stderr,"mbrola voice not found\n");
}
voice->samplerate = srate;
phtrans[0] = 0;
sscanf(p,"%s %s %d",name,phtrans,&srate);
if(LoadMbrolaTable(name,phtrans,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
@@ -945,6 +986,10 @@ voice_t *LoadVoice(const char *vname, int control)
SetSpeed(3);
break;
case V_DICTMIN:
sscanf(p,"%d",&dict_min);
break;
default:
if((key & 0xff00) == 0x100)
{
@@ -987,6 +1032,7 @@ voice_t *LoadVoice(const char *vname, int control)
}
voice->phoneme_tab_ix = ix;
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
@@ -1011,6 +1057,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++)
{
@@ -1225,15 +1272,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;
@@ -1365,8 +1411,7 @@ espeak_VOICE *SelectVoiceByName(espeak_VOICE **voices, const char *name2)
{
match_fname = ix; // matching identifier, use this if no matching name
}
else
if(strcmp(last_part,&id[strlen(id)-last_part_len])==0)
else if(strcmp(last_part,&id[strlen(id)-last_part_len])==0)
{
match_fname2 = ix;
}
@@ -1463,8 +1508,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
@@ -1595,8 +1639,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);
@@ -1605,29 +1649,33 @@ static void GetVoices(const char *path)
return;
do {
sprintf(fname,"%s%c%s",path,PATHSEP,FindFileData.cFileName);
if(n_voices_list >= (N_VOICES_LIST-2))
break; // voices list is full
ftype = GetFileLength(fname);
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;
sprintf(fname,"%s%c%s",path,PATHSEP,FindFileData.cFileName);
ftype = GetFileLength(fname);
// 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)
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);
@@ -1648,17 +1696,19 @@ static void GetVoices(const char *path)
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
if((f_voice = fopen(fname,"r")) == NULL)
@@ -1691,15 +1741,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, 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
@@ -1798,7 +1856,7 @@ ESPEAK_API const espeak_VOICE **espeak_ListVoices(espeak_VOICE *voice_spec)
// sort the voices list
qsort(voices_list,n_voices_list,sizeof(espeak_VOICE *),
(int (__cdecl *)(const void *,const void *))VoiceNameSorter);
(int (__cdecl *)(const void *,const void *))VoiceNameSorter);
if(voice_spec)