[1.43.63]

Phoneme definitions.  Add "equivalents" table to translate phonemes from a foreign language (eg. English) into the equivalant phonemes of this language. This is used when *_rules and *_list files indicate that a word uses pronunciation rules from a different language.

Unpronouncable words can be recognised by rules in *_rule files.  This feature is now used for en, de, es.

Lang=ta, hi.  Letter-names for combining vowel characters are distinguished from stand-alone vowel characters by a preceding beep.


git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@251 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
jonsd
2010-08-02 09:09:25 +00:00
parent ebf0535e6d
commit 4423576af2
58 changed files with 1641 additions and 728 deletions
+171 -27
View File
@@ -149,6 +149,7 @@ enum {
kPROCEDURE,
kENDPHONEME,
kENDPROCEDURE,
kEQUIVALENTS,
kPHONEMENUMBER,
kPHONEMETABLE,
kINCLUDE,
@@ -243,6 +244,7 @@ static keywtab_t keywords[] = {
{"procedure", tSTATEMENT, kPROCEDURE},
{"endphoneme", tSTATEMENT, kENDPHONEME},
{"endprocedure", tSTATEMENT, kENDPROCEDURE},
{"equivalents", tSTATEMENT, kEQUIVALENTS},
{"import_phoneme", tSTATEMENT, kIMPORT_PH},
{"stress_type",tSTATEMENT, kSTRESSTYPE},
{"starttype", tSTATEMENT, kSTARTTYPE},
@@ -363,6 +365,10 @@ static PHONEME_TAB *phoneme_tab2;
static int phoneme_flags;
static int place_articulation;
static char *p_equivalence;
static char equivalence_buf[20000];
#define N_PROCS 50
int n_procs;
int proc_addr[N_PROCS];
@@ -2479,6 +2485,23 @@ static int CompileSwitch(int type)
static PHONEME_TAB_LIST *FindPhonemeTable(const char *string)
{//==========================================================
int ix;
for(ix=0; ix<n_phoneme_tabs; ix++)
{
if(strcmp(phoneme_tab_list2[ix].name, string) == 0)
{
return(&phoneme_tab_list2[ix]);
}
}
error("Unknown phoneme table: '%s'",string);
return(NULL);
} // end of FindPhonemeTable
static PHONEME_TAB *FindPhoneme(const char *string)
{//================================================
PHONEME_TAB_LIST *phtab = NULL;
@@ -2487,7 +2510,7 @@ static PHONEME_TAB *FindPhoneme(const char *string)
char *phname;
char buf[200];
// is this the name of a phoneme which is ijn scope
// is this the name of a phoneme which is in scope
if((strlen(string) <= 4) && ((ix = LookupPhoneme(string,0)) != -1))
{
return(&phoneme_tab2[ix]);
@@ -2500,17 +2523,9 @@ static PHONEME_TAB *FindPhoneme(const char *string)
*phname++ = 0;
}
for(ix=0; ix<n_phoneme_tabs; ix++)
{
if(strcmp(phoneme_tab_list2[ix].name,buf) == 0)
{
phtab = &phoneme_tab_list2[ix];
break;
}
}
phtab = FindPhonemeTable(buf);
if(phtab == NULL)
{
error("Unknown phoneme table: '%s'",buf);
return(NULL); // phoneme table not found
}
@@ -3025,6 +3040,7 @@ static void WritePhonemeTables()
fputc(phoneme_tab_list2[ix].includes,f_phtab);
fputc(0,f_phtab);
fputc(0,f_phtab);
Write4Bytes(f_phtab, phoneme_tab_list2[ix].equivalence_tables); // byte index into phondata for equivalence tables
fwrite(phoneme_tab_list2[ix].name,1,N_PHONEME_TAB_NAME,f_phtab);
@@ -3047,6 +3063,8 @@ static void WritePhonemeTables()
static void EndPhonemeTable()
{//==========================
int ix;
int *pw;
int length;
if(n_phoneme_tabs == 0)
return;
@@ -3061,10 +3079,24 @@ static void EndPhonemeTable()
fprintf(f_errors,"%3d: Phoneme [%s] not declared, referenced at line %d\n",linenum,
WordToString(phoneme_tab2[ix].mnemonic),int(phoneme_tab2[ix].program));
error_count++;
phoneme_tab2[ix].type = 0; // prevent the error message repeating
}
}
n_phcodes_list[n_phoneme_tabs-1] = n_phcodes;
if((length = p_equivalence - equivalence_buf) > 0)
{
// terminate the list of phoneme equivalence tables
pw = (int *)p_equivalence;
pw[0] = 0;
// write the equivalence data into phondata, and remember it's address
ix = ftell(f_phdata);
fprintf(f_phcontents,"Q 0x%.5x %s\n", ix, phoneme_tab_list2[n_phoneme_tabs-1].name);
phoneme_tab_list2[n_phoneme_tabs-1].equivalence_tables = ix;
fwrite(equivalence_buf, length+4, 1, f_phdata);
}
}
@@ -3092,11 +3124,12 @@ static void StartPhonemeTable(const char *name)
if(gui_flag)
progress->Update(n_phoneme_tabs);
memset(&phoneme_tab_list2[n_phoneme_tabs], 0, sizeof(PHONEME_TAB_LIST));
phoneme_tab_list2[n_phoneme_tabs].phoneme_tab_ptr = phoneme_tab2 = p;
memset(phoneme_tab_list2[n_phoneme_tabs].name, 0, N_PHONEME_TAB_NAME);
strncpy0(phoneme_tab_list2[n_phoneme_tabs].name, name, N_PHONEME_TAB_NAME);
n_phcodes = 1;
phoneme_tab_list2[n_phoneme_tabs].includes = 0;
p_equivalence = equivalence_buf;
if(n_phoneme_tabs > 0)
{
@@ -3131,6 +3164,111 @@ static void StartPhonemeTable(const char *name)
} // end of StartPhonemeTable
static void CompileEquivalents()
{//=============================
// a list of phonemes in another language and the equivalent phoneme strings in this language
int ix;
int n_names;
int n_bytes;
int foreign_phoneme;
int foreign_error = 0;
int remove_stress = 0;
char *p_start;
char *p;
int foreign_table;
char foreign_table_name[40];
char line_buf[80];
char names[6][80];
char phcode[7];
char save_voice_name[80];
NextItem(tSTRING);
strcpy(foreign_table_name, item_string);
strcpy(save_voice_name,voice_name2);
if((foreign_table = SelectPhonemeTableName(foreign_table_name)) < 0)
{
error("Unknown phoneme table '%s'", foreign_table_name);
foreign_error = 1;
foreign_phoneme = 0;
}
p_start = p_equivalence;
p_equivalence += 8;
p_start[0] = foreign_table;
linenum--;
while(!feof(f_in))
{
linenum++;
if(fgets(line_buf, sizeof(line_buf), f_in) == NULL)
break;
if((p = strstr(line_buf,"//")) != NULL)
*p = 0;
for(ix=0; ix<6; ix++)
names[ix][0] = 0;
n_names = sscanf(line_buf,"%s %s %s %s %s %s",names[0],names[1],names[2],names[3],names[4],names[5]);
if(n_names < 1)
continue;
if(strcmp(names[0],"endphoneme") == 0)
break;
if(strcmp(names[0],"remove_stress") == 0)
{
remove_stress = 1;
continue;
}
if(p_equivalence > &equivalence_buf[sizeof(equivalence_buf) - 16])
{
error("'equivalents' tables are too large",NULL);
break;
}
if(foreign_error == 0)
{
phcode[0] = foreign_phoneme = LookupPhonemeString(names[0]);
if(foreign_phoneme == 0)
{
sprintf(line_buf,"%s/%s", foreign_table_name, names[0]);
error("Unknown phoneme '%s'", line_buf);
}
}
for(ix=1; ix<n_names; ix++)
{
phcode[ix] = LookupPhoneme(names[ix], 1);
}
// only write a translation if it has an effect
if((n_names > 2) || (phcode[0] != phcode[1]))
{
// write: foreign phoneme number, then a string of local phoneme numbers
memcpy(p_equivalence, phcode, n_names);
p_equivalence += n_names;
*p_equivalence++ = 0;
}
}
*p_equivalence++ = 0;
p_equivalence = (char *)((int)(p_equivalence + 3) & ~0x3); // align to word boundary
n_bytes = p_equivalence - p_start;
p_start[1] = remove_stress;
n_bytes = n_bytes / 4;
p_start[2] = n_bytes >> 8; // index of next table
p_start[3] = n_bytes;
LoadVoice(voice_name2,0); // reset the original phoneme table
LoadVoiceVariant(save_voice_name,0);
} // end of CompileEquivalents
static void CompilePhonemeFiles()
{//==============================
int item;
@@ -3161,8 +3299,9 @@ static void CompilePhonemeFiles()
item = NextItem(tKEYWORD);
if(item == kINCLUDE)
switch(item)
{
case kINCLUDE:
NextItem(tSTRING);
sprintf(buf,"%s%s",path_source,item_string);
if((stack_ix < N_STACK) && (f = fopen_log(f_errors,buf,"rb")) != NULL)
@@ -3176,32 +3315,36 @@ static void CompilePhonemeFiles()
strncpy0(current_fname,item_string,sizeof(current_fname));
linenum = 1;
}
}
else
if(item == kPHONEMETABLE)
{
break;
case kPHONEMETABLE:
EndPhonemeTable();
NextItem(tSTRING); // name of the new phoneme table
StartPhonemeTable(item_string);
}
else
if(item == kPHONEMESTART)
{
break;
case kPHONEMESTART:
if(n_phoneme_tabs == 0)
{
Error("phonemetable is missing");
return;
}
CompilePhoneme(1);
}
else
if(item == kPROCEDURE)
{
break;
case kPROCEDURE:
CompilePhoneme(0);
break;
case kEQUIVALENTS:
CompileEquivalents();
break;
default:
if(!feof(f_in))
Error("Keyword 'phoneme' expected");
break;
}
else
if(!feof(f_in))
Error("Keyword 'phoneme' expected");
}
phoneme_tab2[n_phcodes+1].mnemonic = 0; // terminator
} // end of CompilePhonemeFiles
@@ -3275,6 +3418,7 @@ memset(markers_used,0,sizeof(markers_used));
"# S - A SPECT_SEQ structure\n"
"# W - A wavefile segment\n"
"# E - An envelope\n"
"# Q - Phoneme equivalence tables\n"
"#\n"
"# Address is the displacement within phondata of this item\n"
"#\n"