Change Translator from Class to Struct, so avoiding use of Classes in eSpeak. Make more functions and variables "extern". git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@209 d46cf337-b52f-0410-862d-fd96e6ae7743master
static FILE *f_log = NULL; | static FILE *f_log = NULL; | ||||
extern char *dir_dictionary; | extern char *dir_dictionary; | ||||
int linenum; | |||||
static int linenum; | |||||
static int error_count; | static int error_count; | ||||
static int transpose_offset; // transpose character range for LookupDictList() | static int transpose_offset; // transpose character range for LookupDictList() | ||||
static int transpose_min; | static int transpose_min; | ||||
static int text_mode = 0; | static int text_mode = 0; | ||||
static int debug_flag = 0; | static int debug_flag = 0; | ||||
int hash_counts[N_HASH_DICT]; | |||||
char *hash_chains[N_HASH_DICT]; | |||||
char letterGroupsDefined[N_LETTER_GROUPS]; | |||||
static int hash_counts[N_HASH_DICT]; | |||||
static char *hash_chains[N_HASH_DICT]; | |||||
static char letterGroupsDefined[N_LETTER_GROUPS]; | |||||
MNEM_TAB mnem_flags[] = { | MNEM_TAB mnem_flags[] = { | ||||
// these in the first group put a value in bits0-3 of dictionary_flags | // these in the first group put a value in bits0-3 of dictionary_flags | ||||
} | } | ||||
static const char *LookupMnem2(MNEM_TAB *table, int value) | |||||
{//======================================================= | |||||
while(table->mnem != NULL) | |||||
{ | |||||
if(table->value == value) | |||||
return(table->mnem); | |||||
table++; | |||||
} | |||||
return(""); | |||||
} | |||||
char *print_dictionary_flags(unsigned int *flags) | |||||
{//============================================== | |||||
static char buf[20]; | |||||
sprintf(buf,"%s 0x%x/%x",LookupMnem2(mnem_flags,(flags[0] & 0xf)+0x40), flags[0], flags[1]); | |||||
return(buf); | |||||
} | |||||
static FILE *fopen_log(const char *fname,const char *access) | static FILE *fopen_log(const char *fname,const char *access) | ||||
{//================================================== | {//================================================== | ||||
// performs fopen, but produces error message to f_log if it fails | // performs fopen, but produces error message to f_log if it fails | ||||
int compile_line(char *linebuf, char *dict_line, int *hash) | |||||
{//======================================================== | |||||
static int compile_line(char *linebuf, char *dict_line, int *hash) | |||||
{//=============================================================== | |||||
// Compile a line in the language_list file | // Compile a line in the language_list file | ||||
unsigned char c; | unsigned char c; | ||||
char *p; | char *p; | ||||
{ | { | ||||
// this assumes that the lower case char is the same length as the upper case char | // this assumes that the lower case char is the same length as the upper case char | ||||
// OK, except for Turkish "I", but use towlower() rather than towlower2() | // OK, except for Turkish "I", but use towlower() rather than towlower2() | ||||
ix = utf8_in(&c2,p,0); | |||||
ix = utf8_in(&c2,p); | |||||
if(c2 == 0) | if(c2 == 0) | ||||
break; | break; | ||||
if(iswupper(c2)) | if(iswupper(c2)) | ||||
void compile_dictlist_start(void) | |||||
{//============================== | |||||
static void compile_dictlist_start(void) | |||||
{//===================================== | |||||
// initialise dictionary list | // initialise dictionary list | ||||
int ix; | int ix; | ||||
char *p; | char *p; | ||||
} | } | ||||
void compile_dictlist_end(FILE *f_out) | |||||
{//=================================== | |||||
static void compile_dictlist_end(FILE *f_out) | |||||
{//========================================== | |||||
// Write out the compiled dictionary list | // Write out the compiled dictionary list | ||||
int hash; | int hash; | ||||
int length; | int length; | ||||
int compile_dictlist_file(const char *path, const char* filename) | |||||
{//============================================================== | |||||
static int compile_dictlist_file(const char *path, const char* filename) | |||||
{//===================================================================== | |||||
int length; | int length; | ||||
int hash; | int hash; | ||||
char *p; | char *p; | ||||
char rule_cond[80]; | |||||
char rule_pre[80]; | |||||
char rule_post[80]; | |||||
char rule_match[80]; | |||||
char rule_phonemes[80]; | |||||
char group_name[LEN_GROUP_NAME+1]; | |||||
static char rule_cond[80]; | |||||
static char rule_pre[80]; | |||||
static char rule_post[80]; | |||||
static char rule_match[80]; | |||||
static char rule_phonemes[80]; | |||||
static char group_name[LEN_GROUP_NAME+1]; | |||||
#define N_RULES 2000 // max rules for each group | #define N_RULES 2000 // max rules for each group | ||||
int hexdigit(char c) | |||||
{//================= | |||||
if(isdigit(c)) | |||||
return(c - '0'); | |||||
return(tolower(c) - 'a' + 10); | |||||
} | |||||
void copy_rule_string(char *string, int &state) | |||||
{//============================================ | |||||
static void copy_rule_string(char *string, int &state) | |||||
{//=================================================== | |||||
// state 0: conditional, 1=pre, 2=match, 3=post, 4=phonemes | // state 0: conditional, 1=pre, 2=match, 3=post, 4=phonemes | ||||
static char *outbuf[5] = {rule_cond, rule_pre, rule_match, rule_post, rule_phonemes}; | static char *outbuf[5] = {rule_cond, rule_pre, rule_match, rule_post, rule_phonemes}; | ||||
static int next_state[5] = {2,2,4,4,4}; | static int next_state[5] = {2,2,4,4,4}; | ||||
char *compile_rule(char *input) | |||||
{//============================ | |||||
static char *compile_rule(char *input) | |||||
{//=================================== | |||||
int ix; | int ix; | ||||
unsigned char c; | unsigned char c; | ||||
int wc; | int wc; | ||||
len_name = strlen(group_name); | len_name = strlen(group_name); | ||||
if((len_name > 0) && (memcmp(rule_match,group_name,len_name) != 0)) | if((len_name > 0) && (memcmp(rule_match,group_name,len_name) != 0)) | ||||
{ | { | ||||
utf8_in(&wc,rule_match,0); | |||||
utf8_in(&wc,rule_match); | |||||
if((group_name[0] == '9') && IsDigit(wc)) | if((group_name[0] == '9') && IsDigit(wc)) | ||||
{ | { | ||||
// numeric group, rule_match starts with a digit, so OK | // numeric group, rule_match starts with a digit, so OK | ||||
#ifdef OUTPUT_FORMAT | #ifdef OUTPUT_FORMAT | ||||
void print_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | |||||
{//====================================================================== | |||||
static void print_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | |||||
{//============================================================================= | |||||
int rule; | int rule; | ||||
int ix; | int ix; | ||||
unsigned char c; | unsigned char c; | ||||
//#define LIST_GROUP_INFO | //#define LIST_GROUP_INFO | ||||
void output_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | |||||
{//======================================================================= | |||||
static void output_rule_group(FILE *f_out, int n_rules, char **rules, char *name) | |||||
{//============================================================================== | |||||
int ix; | int ix; | ||||
int len1; | int len1; | ||||
int len2; | int len2; | ||||
if(strlen(group_name) > 2) | if(strlen(group_name) > 2) | ||||
{ | { | ||||
if(utf8_in(&c,group_name,0) < 2) | |||||
if(utf8_in(&c,group_name) < 2) | |||||
{ | { | ||||
fprintf(f_log,"%5d: Group name longer than 2 bytes (UTF8)",linenum); | fprintf(f_log,"%5d: Group name longer than 2 bytes (UTF8)",linenum); | ||||
error_count++; | error_count++; | ||||
ix = 0; | ix = 0; | ||||
while((unsigned char)(*p) > 0x20) // not space or zero-byte | while((unsigned char)(*p) > 0x20) // not space or zero-byte | ||||
{ | { | ||||
p += utf8_in(&c,p,0); | |||||
p += utf8_in(&c,p); | |||||
replace1 += (c << ix); | replace1 += (c << ix); | ||||
ix += 16; | ix += 16; | ||||
} | } | ||||
ix = 0; | ix = 0; | ||||
while((unsigned char)(*p) > 0x20) | while((unsigned char)(*p) > 0x20) | ||||
{ | { | ||||
p += utf8_in(&c,p,0); | |||||
p += utf8_in(&c,p); | |||||
replace2 += (c << ix); | replace2 += (c << ix); | ||||
ix += 16; | ix += 16; | ||||
} | } | ||||
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *fname_err, int flags) | int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *fname_err, int flags) | ||||
{//===================================================================================================== | {//===================================================================================================== | ||||
// fname: space to write the filename in case of error | // fname: space to write the filename in case of error | ||||
compile_dictlist_start(); | compile_dictlist_start(); | ||||
fprintf(f_log,"Using phonemetable: '%s'\n",PhonemeTabName()); | |||||
fprintf(f_log,"Using phonemetable: '%s'\n",phoneme_tab_list[phoneme_tab_number].name); | |||||
compile_dictlist_file(path,"roots"); | compile_dictlist_file(path,"roots"); | ||||
if(translator->langopts.listx) | if(translator->langopts.listx) | ||||
{ | { | ||||
Write4Bytes(f_out,offset_rules); | Write4Bytes(f_out,offset_rules); | ||||
fclose(f_out); | fclose(f_out); | ||||
translator->LoadDictionary(dict_name,0); | |||||
LoadDictionary(translator, dict_name, 0); | |||||
return(error_count); | return(error_count); | ||||
} // end of compile_dictionary | } // end of compile_dictionary |
} | } | ||||
//> | //> | ||||
//<event_display | //<event_display | ||||
void event_display(espeak_EVENT* event) | |||||
static void event_display(espeak_EVENT* event) | |||||
{ | { | ||||
ENTER("event_display"); | ENTER("event_display"); | ||||
#include "translate.h" | #include "translate.h" | ||||
#include "options.h" | #include "options.h" | ||||
extern char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | |||||
//****************************************************************************************************** | //****************************************************************************************************** | ||||
// convert word to lower-case | // convert word to lower-case | ||||
for(ix=0, p=&word2[1];;) | for(ix=0, p=&word2[1];;) | ||||
{ | { | ||||
ix += utf8_in(&c,&word[ix],0); | |||||
ix += utf8_in(&c,&word[ix]); | |||||
c = towlower(c); | c = towlower(c); | ||||
p += utf8_out(c,p); | p += utf8_out(c,p); | ||||
if(c == 0) | if(c == 0) | ||||
// translate | // translate | ||||
memset(&winfo,0,sizeof(winfo)); | memset(&winfo,0,sizeof(winfo)); | ||||
translator->TranslateWord(&word2[1],0,&winfo); | |||||
TranslateWord(translator,&word2[1],0,&winfo); | |||||
DecodePhonemes2(translator->word_phonemes,phonemes); // also need to change some phoneme names | |||||
DecodePhonemes2(word_phonemes,phonemes); // also need to change some phoneme names | |||||
if(strcmp(phonemes,pronounce2) == 0) | if(strcmp(phonemes,pronounce2) == 0) | ||||
{ | { | ||||
// translate | // translate | ||||
memset(&winfo,0,sizeof(winfo)); | memset(&winfo,0,sizeof(winfo)); | ||||
translator->TranslateWord(&word2[1],0,&winfo); | |||||
DecodePhonemes(translator->word_phonemes,phonemes); | |||||
TranslateWord(translator, &word2[1],0,&winfo); | |||||
DecodePhonemes(word_phonemes,phonemes); | |||||
// find the stress position in the translation | // find the stress position in the translation | ||||
max_stress = 0; | max_stress = 0; | ||||
check_root = 0; | check_root = 0; | ||||
ph = phoneme_tab[phonPAUSE]; | ph = phoneme_tab[phonPAUSE]; | ||||
for(p=translator->word_phonemes; *p != 0; p++) | |||||
for(p=word_phonemes; *p != 0; p++) | |||||
{ | { | ||||
ph = phoneme_tab[(unsigned int)*p]; | ph = phoneme_tab[(unsigned int)*p]; | ||||
if(ph == NULL) | if(ph == NULL) | ||||
n_chars = 0; | n_chars = 0; | ||||
for(k=0; k<ix; ) | for(k=0; k<ix; ) | ||||
{ | { | ||||
k += utf8_in(&wc,&buf[k],0); | |||||
k += utf8_in(&wc,&buf[k]); | |||||
wc = towlower(wc); // convert to lower case | wc = towlower(wc); // convert to lower case | ||||
if(iswalpha(wc)) | if(iswalpha(wc)) | ||||
{ | { |
//<sleep_until_start_request_or_inactivity | //<sleep_until_start_request_or_inactivity | ||||
int sleep_until_start_request_or_inactivity() | |||||
static int sleep_until_start_request_or_inactivity() | |||||
{ | { | ||||
SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER"); | SHOW_TIME("fifo > sleep_until_start_request_or_inactivity > ENTER"); | ||||
int a_start_is_required=0; | int a_start_is_required=0; |
short pitch2; | short pitch2; | ||||
} SYLLABLE; | } SYLLABLE; | ||||
SYLLABLE *syllable_tab; | |||||
static SYLLABLE *syllable_tab; | |||||
static int tone_pitch_env; /* used to return pitch envelope */ | static int tone_pitch_env; /* used to return pitch envelope */ | ||||
void Translator::CalcPitches_Tone(int clause_tone) | |||||
{//=============================================== | |||||
static void CalcPitches_Tone(Translator *tr, int clause_tone) | |||||
{//========================================================== | |||||
// clause_tone: 0=. 1=, 2=?, 3=! 4=none | // clause_tone: 0=. 1=, 2=?, 3=! 4=none | ||||
PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
int ix; | int ix; | ||||
phoneme_list[final_stressed].tone = 7; | phoneme_list[final_stressed].tone = 7; | ||||
// language specific, changes to tones | // language specific, changes to tones | ||||
if(translator_name == L('v','i')) | |||||
if(tr->translator_name == L('v','i')) | |||||
{ | { | ||||
// LANG=vi | // LANG=vi | ||||
p = &phoneme_list[final_stressed]; | p = &phoneme_list[final_stressed]; | ||||
if(p->tone_ph == 0) | if(p->tone_ph == 0) | ||||
p->tone_ph = LookupPh("7"); // change default tone (tone 1) to falling tone at end of clause | |||||
p->tone_ph = PhonemeCode('7'); // change default tone (tone 1) to falling tone at end of clause | |||||
} | } | ||||
tph = phoneme_tab[tone_ph]; | tph = phoneme_tab[tone_ph]; | ||||
// Mandarin | // Mandarin | ||||
if(translator_name == L('z','h')) | |||||
if(tr->translator_name == L('z','h')) | |||||
{ | { | ||||
if(tone_ph == 0) | if(tone_ph == 0) | ||||
{ | { | ||||
if(pause || tone_promoted) | if(pause || tone_promoted) | ||||
{ | { | ||||
tone_ph = LookupPh("55"); // no previous vowel, use tone 1 | |||||
tone_ph = PhonemeCode2('5','5'); // no previous vowel, use tone 1 | |||||
tone_promoted = 1; | tone_promoted = 1; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
tone_ph = LookupPh("11"); // default tone 5 | |||||
tone_ph = PhonemeCode2('1','1'); // default tone 5 | |||||
} | } | ||||
p->tone_ph = tone_ph; | p->tone_ph = tone_ph; | ||||
if(prevw_tph->mnemonic == 0x343132) // [214] | if(prevw_tph->mnemonic == 0x343132) // [214] | ||||
{ | { | ||||
if(tph->mnemonic == 0x343132) // [214] | if(tph->mnemonic == 0x343132) // [214] | ||||
prev_p->tone_ph = LookupPh("35"); | |||||
prev_p->tone_ph = PhonemeCode2('3','5'); | |||||
else | else | ||||
prev_p->tone_ph = LookupPh("21"); | |||||
prev_p->tone_ph = PhonemeCode2('2','1'); | |||||
} | } | ||||
if((prev_tph->mnemonic == 0x3135) && (tph->mnemonic == 0x3135)) // [51] + [51] | if((prev_tph->mnemonic == 0x3135) && (tph->mnemonic == 0x3135)) // [51] + [51] | ||||
{ | { | ||||
prev_p->tone_ph = LookupPh("53"); | |||||
prev_p->tone_ph = PhonemeCode2('5','3'); | |||||
} | } | ||||
if(tph->mnemonic == 0x3131) // [11] Tone 5 | if(tph->mnemonic == 0x3131) // [11] Tone 5 | ||||
{ | { | ||||
// tone 5, change its level depending on the previous tone (across word boundaries) | // tone 5, change its level depending on the previous tone (across word boundaries) | ||||
if(prevw_tph->mnemonic == 0x3535) | if(prevw_tph->mnemonic == 0x3535) | ||||
p->tone_ph = LookupPh("22"); | |||||
p->tone_ph = PhonemeCode2('2','2'); | |||||
if(prevw_tph->mnemonic == 0x3533) | if(prevw_tph->mnemonic == 0x3533) | ||||
p->tone_ph = LookupPh("33"); | |||||
p->tone_ph = PhonemeCode2('3','3'); | |||||
if(prevw_tph->mnemonic == 0x343132) | if(prevw_tph->mnemonic == 0x343132) | ||||
p->tone_ph = LookupPh("44"); | |||||
p->tone_ph = PhonemeCode2('4','4'); | |||||
// tone 5 is unstressed (shorter) | // tone 5 is unstressed (shorter) | ||||
p->tone = 1; // diminished stress | p->tone = 1; // diminished stress | ||||
void Translator::CalcPitches(int clause_type) | |||||
{//========================================== | |||||
void CalcPitches(Translator *tr, int clause_type) | |||||
{//============================================== | |||||
// clause_type: 0=. 1=, 2=?, 3=! 4=none | // clause_type: 0=. 1=, 2=?, 3=! 4=none | ||||
PHONEME_LIST *p; | PHONEME_LIST *p; | ||||
SYLLABLE *syl; | SYLLABLE *syl; | ||||
if(langopts.tone_language == 1) | |||||
if(tr->langopts.tone_language == 1) | |||||
{ | { | ||||
CalcPitches_Tone(clause_type); | |||||
CalcPitches_Tone(tr,clause_type); | |||||
return; | return; | ||||
} | } | ||||
option = langopts.intonation_group; | |||||
option = tr->langopts.intonation_group; | |||||
if(option >= INTONATION_TYPES) | if(option >= INTONATION_TYPES) | ||||
option = 0; | option = 0; | ||||
group_tone = punct_to_tone[option][clause_type]; | |||||
group_tone_emph = punct_to_tone[option][5]; // emphatic form of statement | |||||
group_tone_comma = punct_to_tone[option][1]; // emphatic form of statement | |||||
group_tone = tr->punct_to_tone[option][clause_type]; | |||||
group_tone_emph = tr->punct_to_tone[option][5]; // emphatic form of statement | |||||
group_tone_comma = tr->punct_to_tone[option][1]; // emphatic form of statement | |||||
if(clause_type == 4) | if(clause_type == 4) | ||||
no_tonic = 1; /* incomplete clause, used for abbreviations such as Mr. Dr. Mrs. */ | no_tonic = 1; /* incomplete clause, used for abbreviations such as Mr. Dr. Mrs. */ |
*/ | */ | ||||
int parwave(klatt_frame_ptr frame) | |||||
static int parwave(klatt_frame_ptr frame) | |||||
{ | { | ||||
double temp; | double temp; | ||||
double outbypas; | double outbypas; | ||||
to zero. | to zero. | ||||
*/ | */ | ||||
void reset_resonators() | |||||
static void reset_resonators() | |||||
{ | { | ||||
int r_ix; | int r_ix; | ||||
} | } | ||||
} | } | ||||
void parwave_init() | |||||
static void parwave_init() | |||||
{ | { | ||||
kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000; | kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000; | ||||
kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000; | kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000; |
} ACCENTS; | } ACCENTS; | ||||
// these are tokens to look up in the *_list file. | // these are tokens to look up in the *_list file. | ||||
ACCENTS accents_tab[] = { | |||||
static ACCENTS accents_tab[] = { | |||||
{"_lig", 1}, | {"_lig", 1}, | ||||
{"_smc", 1}, // smallcap | {"_smc", 1}, // smallcap | ||||
{"_tur", 1}, // turned | {"_tur", 1}, // turned | ||||
// characters U+00e0 to U+017f | // characters U+00e0 to U+017f | ||||
const unsigned short letter_accents_0e0[] = { | |||||
static const unsigned short letter_accents_0e0[] = { | |||||
LETTER('a',M_GRAVE,0), // U+00e0 | LETTER('a',M_GRAVE,0), // U+00e0 | ||||
LETTER('a',M_ACUTE,0), | LETTER('a',M_ACUTE,0), | ||||
LETTER('a',M_CIRCUMFLEX,0), | LETTER('a',M_CIRCUMFLEX,0), | ||||
// characters U+0250 to U+029F | // characters U+0250 to U+029F | ||||
const unsigned short letter_accents_250[] = { | |||||
static const unsigned short letter_accents_250[] = { | |||||
LETTER('a',M_TURNED,0), // U+250 | LETTER('a',M_TURNED,0), // U+250 | ||||
LETTER(L_ALPHA,0,0), | LETTER(L_ALPHA,0,0), | ||||
LETTER(L_ALPHA,M_TURNED,0), | LETTER(L_ALPHA,M_TURNED,0), | ||||
LIGATURE('t','s',M_CURL), | LIGATURE('t','s',M_CURL), | ||||
}; | }; | ||||
int Translator::LookupLetter2(unsigned int letter, char *ph_buf) | |||||
{//============================================================= | |||||
static int LookupLetter2(Translator *tr, unsigned int letter, char *ph_buf) | |||||
{//======================================================================== | |||||
int len; | int len; | ||||
char single_letter[10]; | char single_letter[10]; | ||||
single_letter[len+2] = ' '; | single_letter[len+2] = ' '; | ||||
single_letter[len+3] = 0; | single_letter[len+3] = 0; | ||||
if(Lookup(&single_letter[1],ph_buf) == 0) | |||||
if(Lookup(tr, &single_letter[1], ph_buf) == 0) | |||||
{ | { | ||||
single_letter[1] = ' '; | single_letter[1] = ' '; | ||||
if(Lookup(&single_letter[2],ph_buf) == 0) | |||||
if(Lookup(tr, &single_letter[2], ph_buf) == 0) | |||||
{ | { | ||||
TranslateRules(&single_letter[2], ph_buf, 20, NULL,0,NULL); | |||||
TranslateRules(tr, &single_letter[2], ph_buf, 20, NULL,0,NULL); | |||||
} | } | ||||
} | } | ||||
return(ph_buf[0]); | return(ph_buf[0]); | ||||
} | } | ||||
void Translator::LookupAccentedLetter(unsigned int letter, char *ph_buf) | |||||
{//===================================================================== | |||||
void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf) | |||||
{//========================================================================= | |||||
// lookup the character in the accents table | // lookup the character in the accents table | ||||
int accent_data = 0; | int accent_data = 0; | ||||
int accent1 = 0; | int accent1 = 0; | ||||
} | } | ||||
if(Lookup(accents_tab[accent1].name, ph_accent1) != 0) | |||||
if(Lookup(tr, accents_tab[accent1].name, ph_accent1) != 0) | |||||
{ | { | ||||
if(LookupLetter2(basic_letter, ph_letter1) != 0) | |||||
if(LookupLetter2(tr, basic_letter, ph_letter1) != 0) | |||||
{ | { | ||||
if(accent2 != 0) | if(accent2 != 0) | ||||
{ | { | ||||
if(Lookup(accents_tab[accent2].name, ph_accent2) == 0) | |||||
if(Lookup(tr, accents_tab[accent2].name, ph_accent2) == 0) | |||||
{ | { | ||||
// break; | // break; | ||||
} | } | ||||
if(letter2 != 0) | if(letter2 != 0) | ||||
{ | { | ||||
//ligature | //ligature | ||||
LookupLetter2(letter2, ph_letter2); | |||||
LookupLetter2(tr, letter2, ph_letter2); | |||||
sprintf(ph_buf,"%s%c%s%c%s%s",ph_accent1, phonPAUSE_VSHORT, ph_letter1, phonSTRESS_P, ph_letter2, ph_accent2); | sprintf(ph_buf,"%s%c%s%c%s%s",ph_accent1, phonPAUSE_VSHORT, ph_letter1, phonSTRESS_P, ph_letter2, ph_accent2); | ||||
} | } | ||||
else | else | ||||
if(accent1 == 0) | if(accent1 == 0) | ||||
strcpy(ph_buf, ph_letter1); | strcpy(ph_buf, ph_letter1); | ||||
else | else | ||||
if((langopts.accents & 1) || (accents_tab[accent1].flags & 1)) | |||||
if((tr->langopts.accents & 1) || (accents_tab[accent1].flags & 1)) | |||||
sprintf(ph_buf,"%s%c%c%s", ph_accent1, phonPAUSE_VSHORT, phonSTRESS_P, ph_letter1); | sprintf(ph_buf,"%s%c%c%s", ph_accent1, phonPAUSE_VSHORT, phonSTRESS_P, ph_letter1); | ||||
else | else | ||||
sprintf(ph_buf,"%c%s%c%s%c", phonSTRESS_2, ph_letter1, phonPAUSE_VSHORT, ph_accent1, phonPAUSE_VSHORT); | sprintf(ph_buf,"%c%s%c%s%c", phonSTRESS_2, ph_letter1, phonPAUSE_VSHORT, ph_accent1, phonPAUSE_VSHORT); | ||||
void Translator::LookupLetter(unsigned int letter, int next_byte, char *ph_buf1) | |||||
{//============================================================================= | |||||
void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_buf1) | |||||
{//================================================================================= | |||||
int len; | int len; | ||||
unsigned char *p; | unsigned char *p; | ||||
static char single_letter[10] = {0,0}; | static char single_letter[10] = {0,0}; | ||||
if(next_byte == -1) | if(next_byte == -1) | ||||
{ | { | ||||
// speaking normal text, not individual characters | // speaking normal text, not individual characters | ||||
if(Lookup(&single_letter[2],ph_buf1) != 0) | |||||
if(Lookup(tr, &single_letter[2], ph_buf1) != 0) | |||||
return; | return; | ||||
single_letter[1] = '_'; | single_letter[1] = '_'; | ||||
if(Lookup(&single_letter[1],ph_buf3) != 0) | |||||
if(Lookup(tr, &single_letter[1], ph_buf3) != 0) | |||||
return; // the character is specified as _* so ignore it when speaking normal text | return; // the character is specified as _* so ignore it when speaking normal text | ||||
// check whether this character is specified for English | // check whether this character is specified for English | ||||
SetTranslator2("en"); | SetTranslator2("en"); | ||||
if(translator2->Lookup(&single_letter[2], ph_buf3) != 0) | |||||
if(Lookup(translator2, &single_letter[2], ph_buf3) != 0) | |||||
{ | { | ||||
// yes, switch to English and re-translate the word | // yes, switch to English and re-translate the word | ||||
sprintf(ph_buf1,"%c",phonSWITCH); | sprintf(ph_buf1,"%c",phonSWITCH); | ||||
{ | { | ||||
// lookup space as _&32 etc. | // lookup space as _&32 etc. | ||||
sprintf(&single_letter[1],"_#%d ",letter); | sprintf(&single_letter[1],"_#%d ",letter); | ||||
Lookup(&single_letter[1],ph_buf1); | |||||
Lookup(tr, &single_letter[1], ph_buf1); | |||||
return; | return; | ||||
} | } | ||||
dict_flags[1] = 0; | dict_flags[1] = 0; | ||||
ptr = &single_letter[1]; | ptr = &single_letter[1]; | ||||
if(Lookup(&single_letter[1],ph_buf3) == 0) | |||||
if(Lookup(tr, &single_letter[1], ph_buf3) == 0) | |||||
{ | { | ||||
single_letter[1] = ' '; | single_letter[1] = ' '; | ||||
if(Lookup(&single_letter[2],ph_buf3) == 0) | |||||
if(Lookup(tr, &single_letter[2], ph_buf3) == 0) | |||||
{ | { | ||||
TranslateRules(&single_letter[2], ph_buf3, sizeof(ph_buf3), NULL,FLAG_NO_TRACE,NULL); | |||||
TranslateRules(tr, &single_letter[2], ph_buf3, sizeof(ph_buf3), NULL,FLAG_NO_TRACE,NULL); | |||||
} | } | ||||
} | } | ||||
if(ph_buf3[0] == 0) | if(ph_buf3[0] == 0) | ||||
{ | { | ||||
LookupAccentedLetter(letter, ph_buf3); | |||||
LookupAccentedLetter(tr, letter, ph_buf3); | |||||
} | } | ||||
if(ph_buf3[0] == 0) | if(ph_buf3[0] == 0) | ||||
int Translator::TranslateLetter(char *word, char *phonemes, int control, int word_length) | |||||
int TranslateLetter(Translator *tr, char *word, char *phonemes, int control, int word_length) | |||||
{//====================================================================================== | {//====================================================================================== | ||||
// get pronunciation for an isolated letter | // get pronunciation for an isolated letter | ||||
// return number of bytes used by the letter | // return number of bytes used by the letter | ||||
ph_buf[0] = 0; | ph_buf[0] = 0; | ||||
capital[0] = 0; | capital[0] = 0; | ||||
n_bytes = utf8_in(&letter,word,0); | |||||
n_bytes = utf8_in(&letter,word); | |||||
if((letter & 0xfff00) == 0x0e000) | if((letter & 0xfff00) == 0x0e000) | ||||
{ | { | ||||
// include CAPITAL information | // include CAPITAL information | ||||
if(iswupper(letter)) | if(iswupper(letter)) | ||||
{ | { | ||||
Lookup("_cap",capital); | |||||
Lookup(tr, "_cap", capital); | |||||
} | } | ||||
} | } | ||||
letter = towlower2(letter); | letter = towlower2(letter); | ||||
LookupLetter(letter, word[n_bytes], ph_buf); | |||||
LookupLetter(tr, letter, word[n_bytes], ph_buf); | |||||
if(ph_buf[0] == phonSWITCH) | if(ph_buf[0] == phonSWITCH) | ||||
{ | { | ||||
return(0); | return(0); | ||||
} | } | ||||
if((ph_buf[0] == 0) && (translator_name != L('e','n'))) | |||||
if((ph_buf[0] == 0) && (tr->translator_name != L('e','n'))) | |||||
{ | { | ||||
// speak as English, check whether there is a translation for this character | // speak as English, check whether there is a translation for this character | ||||
SetTranslator2("en"); | SetTranslator2("en"); | ||||
save_option_phonemes = option_phonemes; | save_option_phonemes = option_phonemes; | ||||
option_phonemes = 0; | option_phonemes = 0; | ||||
translator2->LookupLetter(letter, word[n_bytes], ph_buf); | |||||
LookupLetter(translator2, letter, word[n_bytes], ph_buf); | |||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | ||||
option_phonemes = save_option_phonemes; | option_phonemes = save_option_phonemes; | ||||
{ | { | ||||
// character name not found | // character name not found | ||||
if(iswalpha(letter)) | if(iswalpha(letter)) | ||||
Lookup("_?A",ph_buf); | |||||
Lookup(tr, "_?A", ph_buf); | |||||
if((ph_buf[0]==0) && !iswspace(letter)) | if((ph_buf[0]==0) && !iswspace(letter)) | ||||
Lookup("_??",ph_buf); | |||||
Lookup(tr, "_??", ph_buf); | |||||
if(ph_buf[0] != 0) | if(ph_buf[0] != 0) | ||||
{ | { | ||||
{ | { | ||||
pbuf += strlen(pbuf); | pbuf += strlen(pbuf); | ||||
*pbuf++ = phonPAUSE_VSHORT; | *pbuf++ = phonPAUSE_VSHORT; | ||||
LookupLetter(*p2, 0, pbuf); | |||||
LookupLetter(tr, *p2, 0, pbuf); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
len = strlen(phonemes); | len = strlen(phonemes); | ||||
if(langopts.accents & 2) | |||||
if(tr->langopts.accents & 2) | |||||
sprintf(ph_buf2,"%c%s%s",0xff,ph_buf,capital); | sprintf(ph_buf2,"%c%s%s",0xff,ph_buf,capital); | ||||
else | else | ||||
sprintf(ph_buf2,"%c%s%s",0xff,capital,ph_buf); // the 0xff marker will be removed or replaced in SetSpellingStress() | sprintf(ph_buf2,"%c%s%s",0xff,capital,ph_buf); // the 0xff marker will be removed or replaced in SetSpellingStress() | ||||
void Translator::SetSpellingStress(char *phonemes, int control, int n_chars) | |||||
{//========================================================================= | |||||
void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars) | |||||
{//============================================================================= | |||||
// Individual letter names, reduce the stress of some. | // Individual letter names, reduce the stress of some. | ||||
int ix; | int ix; | ||||
unsigned int c; | unsigned int c; | ||||
{ | { | ||||
count++; | count++; | ||||
if(langopts.spelling_stress == 1) | |||||
if(tr->langopts.spelling_stress == 1) | |||||
{ | { | ||||
// stress on initial letter when spelling | // stress on initial letter when spelling | ||||
if(count > 1) | if(count > 1) | ||||
int Translator::TranslateRoman(char *word, char *ph_out) | |||||
int TranslateRoman(Translator *tr, char *word, char *ph_out) | |||||
{//===================================================== | {//===================================================== | ||||
int c; | int c; | ||||
char *p; | char *p; | ||||
if(acc < 2) | if(acc < 2) | ||||
return(0); | return(0); | ||||
if(acc > langopts.max_roman) | |||||
if(acc > tr->langopts.max_roman) | |||||
return(0); | return(0); | ||||
Lookup("_roman",ph_roman); // precede by "roman" if _rom is defined in *_list | |||||
Lookup(tr, "_roman",ph_roman); // precede by "roman" if _rom is defined in *_list | |||||
p = &ph_out[0]; | p = &ph_out[0]; | ||||
if((langopts.numbers & NUM_ROMAN_AFTER) == 0) | |||||
if((tr->langopts.numbers & NUM_ROMAN_AFTER) == 0) | |||||
{ | { | ||||
strcpy(ph_out,ph_roman); | strcpy(ph_out,ph_roman); | ||||
p = &ph_out[strlen(ph_out)]; | p = &ph_out[strlen(ph_out)]; | ||||
} | } | ||||
sprintf(number_chars," %d ",acc); | sprintf(number_chars," %d ",acc); | ||||
TranslateNumber(&number_chars[1],p,&flags,0); | |||||
TranslateNumber(tr, &number_chars[1], p, &flags, 0); | |||||
if(langopts.numbers & NUM_ROMAN_AFTER) | |||||
if(tr->langopts.numbers & NUM_ROMAN_AFTER) | |||||
strcat(ph_out,ph_roman); | strcat(ph_out,ph_roman); | ||||
return(1); | return(1); | ||||
} // end of TranslateRoman | } // end of TranslateRoman | ||||
int Translator::LookupNum2(int value, int control, char *ph_out) | |||||
{//============================================================= | |||||
static const char *M_Variant(int value) | |||||
{//==================================== | |||||
// returns M, or perhaps MA for some cases | |||||
if(((value % 100)>20) || ((value % 100)<10)) // but not teens, 10 to 19 | |||||
{ | |||||
if ((translator->langopts.numbers2 & 0x40) && | |||||
((value % 10)>=2) && | |||||
((value % 10)<=4)) | |||||
{ | |||||
// for Polish language - two forms of plural! | |||||
return("0MA"); | |||||
} | |||||
if((translator->langopts.numbers2 & 0x80) && | |||||
((value % 10)==1)) | |||||
{ | |||||
return("1MA"); | |||||
} | |||||
} | |||||
return("0M"); | |||||
} | |||||
static int LookupThousands(Translator *tr, int value, int thousandplex, char *ph_out) | |||||
{//================================================================================== | |||||
int found; | |||||
char string[12]; | |||||
char ph_of[12]; | |||||
char ph_thousands[40]; | |||||
ph_of[0] = 0; | |||||
// first look fora match with the exact value of thousands | |||||
sprintf(string,"_%dM%d",value,thousandplex); | |||||
if((found = Lookup(tr, string, ph_thousands)) == 0) | |||||
{ | |||||
if((value % 100) >= 20) | |||||
{ | |||||
Lookup(tr, "_0of", ph_of); | |||||
} | |||||
sprintf(string,"_%s%d",M_Variant(value),thousandplex); | |||||
if(Lookup(tr, string, ph_thousands) == 0) | |||||
{ | |||||
// repeat "thousand" if higher order names are not available | |||||
sprintf(string,"_%dM1",value); | |||||
if((found = Lookup(tr, string, ph_thousands)) == 0) | |||||
Lookup(tr, "_0M1", ph_thousands); | |||||
} | |||||
} | |||||
sprintf(ph_out,"%s%s",ph_of,ph_thousands); | |||||
return(found); | |||||
} | |||||
static int LookupNum2(Translator *tr, int value, int control, char *ph_out) | |||||
{//======================================================================== | |||||
// Lookup a 2 digit number | // Lookup a 2 digit number | ||||
// control bit 0: use special form of '1' | // control bit 0: use special form of '1' | ||||
// control bit 2: use feminine form of '2' | // control bit 2: use feminine form of '2' | ||||
if((value == 1) && (control & 1)) | if((value == 1) && (control & 1)) | ||||
{ | { | ||||
if(Lookup("_1a",ph_out) != 0) | |||||
if(Lookup(tr, "_1a", ph_out) != 0) | |||||
return(0); | return(0); | ||||
} | } | ||||
// is there a special pronunciation for this 2-digit number | // is there a special pronunciation for this 2-digit number | ||||
if(control & 4) | if(control & 4) | ||||
{ | { | ||||
sprintf(string,"_%df",value); | sprintf(string,"_%df",value); | ||||
found = Lookup(string,ph_digits); | |||||
found = Lookup(tr, string, ph_digits); | |||||
} | } | ||||
if(found == 0) | if(found == 0) | ||||
{ | { | ||||
sprintf(string,"_%d",value); | sprintf(string,"_%d",value); | ||||
found = Lookup(string,ph_digits); | |||||
found = Lookup(tr, string, ph_digits); | |||||
} | } | ||||
// no, speak as tens+units | // no, speak as tens+units | ||||
if((control & 2) && (value < 10)) | if((control & 2) && (value < 10)) | ||||
{ | { | ||||
// speak leading zero | // speak leading zero | ||||
Lookup("_0",ph_tens); | |||||
Lookup(tr, "_0", ph_tens); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
if((value % 10) == 0) | if((value % 10) == 0) | ||||
{ | { | ||||
sprintf(string,"_%d0",value / 10); | sprintf(string,"_%d0",value / 10); | ||||
found = Lookup(string,ph_tens); | |||||
found = Lookup(tr, string, ph_tens); | |||||
} | } | ||||
if(!found) | if(!found) | ||||
{ | { | ||||
sprintf(string,"_%dX",value / 10); | sprintf(string,"_%dX",value / 10); | ||||
Lookup(string,ph_tens); | |||||
Lookup(tr, string, ph_tens); | |||||
} | } | ||||
if((value % 10) == 0) | if((value % 10) == 0) | ||||
{ | { | ||||
// is there a variant form of this number? | // is there a variant form of this number? | ||||
sprintf(string,"_%df",units); | sprintf(string,"_%df",units); | ||||
found = Lookup(string,ph_digits); | |||||
found = Lookup(tr, string, ph_digits); | |||||
} | } | ||||
if(found == 0) | if(found == 0) | ||||
{ | { | ||||
sprintf(string,"_%d",units); | sprintf(string,"_%d",units); | ||||
Lookup(string,ph_digits); | |||||
Lookup(tr, string, ph_digits); | |||||
} | } | ||||
} | } | ||||
if(langopts.numbers & 0x30) | |||||
if(tr->langopts.numbers & 0x30) | |||||
{ | { | ||||
Lookup("_0and",ph_and); | |||||
if(langopts.numbers & 0x10) | |||||
Lookup(tr, "_0and", ph_and); | |||||
if(tr->langopts.numbers & 0x10) | |||||
sprintf(ph_out,"%s%s%s",ph_digits,ph_and,ph_tens); | sprintf(ph_out,"%s%s%s",ph_digits,ph_and,ph_tens); | ||||
else | else | ||||
sprintf(ph_out,"%s%s%s",ph_tens,ph_and,ph_digits); | sprintf(ph_out,"%s%s%s",ph_tens,ph_and,ph_digits); | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if(langopts.numbers & 0x200) | |||||
if(tr->langopts.numbers & 0x200) | |||||
{ | { | ||||
// remove vowel from the end of tens if units starts with a vowel (LANG=Italian) | // remove vowel from the end of tens if units starts with a vowel (LANG=Italian) | ||||
if((ix = strlen(ph_tens)-1) >= 0) | if((ix = strlen(ph_tens)-1) >= 0) | ||||
sprintf(ph_out,"%s%s",ph_tens,ph_digits); | sprintf(ph_out,"%s%s",ph_tens,ph_digits); | ||||
} | } | ||||
if(langopts.numbers & 0x100) | |||||
if(tr->langopts.numbers & 0x100) | |||||
{ | { | ||||
// only one primary stress | // only one primary stress | ||||
found = 0; | found = 0; | ||||
} // end of LookupNum2 | } // end of LookupNum2 | ||||
int Translator::LookupNum3(int value, char *ph_out, int suppress_null, int thousandplex, int prev_thousands) | |||||
{//========================================================================================================= | |||||
static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null, int thousandplex, int prev_thousands) | |||||
{//==================================================================================================================== | |||||
// Translate a 3 digit number | // Translate a 3 digit number | ||||
int found; | int found; | ||||
int hundreds; | int hundreds; | ||||
ph_thousands[0] = 0; | ph_thousands[0] = 0; | ||||
ph_thousand_and[0] = 0; | ph_thousand_and[0] = 0; | ||||
Lookup("_0C",ph_100); | |||||
Lookup(tr, "_0C", ph_100); | |||||
if(((langopts.numbers & 0x0800) != 0) && (hundreds == 19)) | |||||
if(((tr->langopts.numbers & 0x0800) != 0) && (hundreds == 19)) | |||||
{ | { | ||||
// speak numbers such as 1984 as years: nineteen-eighty-four | // speak numbers such as 1984 as years: nineteen-eighty-four | ||||
// ph_100[0] = 0; // don't say "hundred", we also need to surpess "and" | // ph_100[0] = 0; // don't say "hundred", we also need to surpess "and" | ||||
{ | { | ||||
ph_digits[0] = 0; | ph_digits[0] = 0; | ||||
if(LookupThousands(hundreds / 10, thousandplex+1, ph_10T) == 0) | |||||
if(LookupThousands(tr, hundreds / 10, thousandplex+1, ph_10T) == 0) | |||||
{ | { | ||||
x = 0; | x = 0; | ||||
if(langopts.numbers2 & (1 << (thousandplex+1))) | |||||
if(tr->langopts.numbers2 & (1 << (thousandplex+1))) | |||||
x = 4; | x = 4; | ||||
LookupNum2(hundreds/10, x, ph_digits); | |||||
LookupNum2(tr, hundreds/10, x, ph_digits); | |||||
} | } | ||||
if(langopts.numbers2 & 0x200) | |||||
if(tr->langopts.numbers2 & 0x200) | |||||
sprintf(ph_thousands,"%s%s%c",ph_10T,ph_digits,phonPAUSE_NOLINK); // say "thousands" before its number, not after | sprintf(ph_thousands,"%s%s%c",ph_10T,ph_digits,phonPAUSE_NOLINK); // say "thousands" before its number, not after | ||||
else | else | ||||
sprintf(ph_thousands,"%s%s%c",ph_digits,ph_10T,phonPAUSE_NOLINK); | sprintf(ph_thousands,"%s%s%c",ph_digits,ph_10T,phonPAUSE_NOLINK); | ||||
ph_digits[0] = 0; | ph_digits[0] = 0; | ||||
if(hundreds > 0) | if(hundreds > 0) | ||||
{ | { | ||||
if((langopts.numbers & 0x100000) && (prev_thousands || (ph_thousands[0] != 0))) | |||||
if((tr->langopts.numbers & 0x100000) && (prev_thousands || (ph_thousands[0] != 0))) | |||||
{ | { | ||||
Lookup("_0and",ph_thousand_and); | |||||
Lookup(tr, "_0and", ph_thousand_and); | |||||
} | } | ||||
suppress_null = 1; | suppress_null = 1; | ||||
if((value % 1000) == 100) | if((value % 1000) == 100) | ||||
{ | { | ||||
// is there a special pronunciation for exactly 100 ? | // is there a special pronunciation for exactly 100 ? | ||||
found = Lookup("_1C0",ph_digits); | |||||
found = Lookup(tr, "_1C0", ph_digits); | |||||
} | } | ||||
if(!found) | if(!found) | ||||
{ | { | ||||
sprintf(string,"_%dC",hundreds); | sprintf(string,"_%dC",hundreds); | ||||
found = Lookup(string,ph_digits); // is there a specific pronunciation for n-hundred ? | |||||
found = Lookup(tr, string, ph_digits); // is there a specific pronunciation for n-hundred ? | |||||
} | } | ||||
if(found) | if(found) | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if((hundreds > 1) || ((langopts.numbers & 0x400) == 0)) | |||||
if((hundreds > 1) || ((tr->langopts.numbers & 0x400) == 0)) | |||||
{ | { | ||||
LookupNum2(hundreds,0,ph_digits); | |||||
LookupNum2(tr, hundreds, 0, ph_digits); | |||||
} | } | ||||
} | } | ||||
} | } | ||||
} | } | ||||
ph_hundred_and[0] = 0; | ph_hundred_and[0] = 0; | ||||
if((langopts.numbers & 0x40) && ((value % 100) != 0)) | |||||
if((tr->langopts.numbers & 0x40) && ((value % 100) != 0)) | |||||
{ | { | ||||
if((value > 100) || (prev_thousands && (thousandplex==0))) | if((value > 100) || (prev_thousands && (thousandplex==0))) | ||||
{ | { | ||||
Lookup("_0and",ph_hundred_and); | |||||
Lookup(tr, "_0and", ph_hundred_and); | |||||
} | } | ||||
} | } | ||||
if(value == 0) | if(value == 0) | ||||
{ | { | ||||
if(suppress_null == 0) | if(suppress_null == 0) | ||||
Lookup("_0",buf2); | |||||
Lookup(tr, "_0", buf2); | |||||
} | } | ||||
else | else | ||||
{ | { | ||||
x = 1; // allow "eins" for 1 rather than "ein" | x = 1; // allow "eins" for 1 rather than "ein" | ||||
else | else | ||||
{ | { | ||||
if(langopts.numbers2 & (1 << thousandplex)) | |||||
if(tr->langopts.numbers2 & (1 << thousandplex)) | |||||
x = 4; // use variant (feminine) for before thousands and millions | x = 4; // use variant (feminine) for before thousands and millions | ||||
} | } | ||||
if(LookupNum2(value,x,buf2) != 0) | |||||
if(LookupNum2(tr, value, x, buf2) != 0) | |||||
{ | { | ||||
if(langopts.numbers & 0x80) | |||||
if(tr->langopts.numbers & 0x80) | |||||
ph_hundred_and[0] = 0; // don't put 'and' after 'hundred' if there's 'and' between tens and units | ph_hundred_and[0] = 0; // don't put 'and' after 'hundred' if there's 'and' between tens and units | ||||
} | } | ||||
} | } | ||||
static const char *M_Variant(int value) | |||||
{//==================================== | |||||
// returns M, or perhaps MA for some cases | |||||
if(((value % 100)>20) || ((value % 100)<10)) // but not teens, 10 to 19 | |||||
{ | |||||
if ((translator->langopts.numbers2 & 0x40) && | |||||
((value % 10)>=2) && | |||||
((value % 10)<=4)) | |||||
{ | |||||
// for Polish language - two forms of plural! | |||||
return("0MA"); | |||||
} | |||||
if((translator->langopts.numbers2 & 0x80) && | |||||
((value % 10)==1)) | |||||
{ | |||||
return("1MA"); | |||||
} | |||||
} | |||||
return("0M"); | |||||
} | |||||
int Translator::LookupThousands(int value, int thousandplex, char *ph_out) | |||||
{//======================================================================= | |||||
int found; | |||||
char string[12]; | |||||
char ph_of[12]; | |||||
char ph_thousands[40]; | |||||
ph_of[0] = 0; | |||||
// first look fora match with the exact value of thousands | |||||
sprintf(string,"_%dM%d",value,thousandplex); | |||||
if((found = Lookup(string,ph_thousands)) == 0) | |||||
{ | |||||
if((value % 100) >= 20) | |||||
{ | |||||
Lookup("_0of",ph_of); | |||||
} | |||||
sprintf(string,"_%s%d",M_Variant(value),thousandplex); | |||||
if(Lookup(string,ph_thousands) == 0) | |||||
{ | |||||
// repeat "thousand" if higher order names are not available | |||||
sprintf(string,"_%dM1",value); | |||||
if((found = Lookup(string,ph_thousands)) == 0) | |||||
Lookup("_0M1",ph_thousands); | |||||
} | |||||
} | |||||
sprintf(ph_out,"%s%s",ph_of,ph_thousands); | |||||
return(found); | |||||
} | |||||
int Translator::TranslateNumber_1(char *word, char *ph_out, unsigned int *flags, int wflags) | |||||
{//========================================================================================= | |||||
static int TranslateNumber_1(Translator *tr, char *word, char *ph_out, unsigned int *flags, int wflags) | |||||
{//==================================================================================================== | |||||
// Number translation with various options | // Number translation with various options | ||||
// the "word" may be up to 4 digits | // the "word" may be up to 4 digits | ||||
// "words" of 3 digits may be preceded by another number "word" for thousands or millions | // "words" of 3 digits may be preceded by another number "word" for thousands or millions | ||||
ph_buf2[0] = 0; | ph_buf2[0] = 0; | ||||
// is there a previous thousands part (as a previous "word") ? | // is there a previous thousands part (as a previous "word") ? | ||||
if((n_digits == 3) && (word[-2] == langopts.thousands_sep) && isdigit(word[-3])) | |||||
if((n_digits == 3) && (word[-2] == tr->langopts.thousands_sep) && isdigit(word[-3])) | |||||
{ | { | ||||
prev_thousands = 1; | prev_thousands = 1; | ||||
} | } | ||||
else | else | ||||
if((langopts.thousands_sep == ' ') || (langopts.numbers & 0x1000)) | |||||
if((tr->langopts.thousands_sep == ' ') || (tr->langopts.numbers & 0x1000)) | |||||
{ | { | ||||
// thousands groups can be separated by spaces | // thousands groups can be separated by spaces | ||||
if((n_digits == 3) && isdigit(word[-2])) | if((n_digits == 3) && isdigit(word[-2])) | ||||
} | } | ||||
} | } | ||||
if((word[0] == '0') && (prev_thousands == 0) && (word[1] != langopts.decimal_sep)) | |||||
if((word[0] == '0') && (prev_thousands == 0) && (word[1] != tr->langopts.decimal_sep)) | |||||
{ | { | ||||
if((n_digits == 2) && (word[3] == ':') && isdigit(word[5]) && isspace(word[7])) | if((n_digits == 2) && (word[3] == ':') && isdigit(word[5]) && isspace(word[7])) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
if((langopts.numbers & 0x1000) && (word[n_digits] == ' ')) | |||||
if((tr->langopts.numbers & 0x1000) && (word[n_digits] == ' ')) | |||||
thousands_inc = 1; | thousands_inc = 1; | ||||
else | else | ||||
if(word[n_digits] == langopts.thousands_sep) | |||||
if(word[n_digits] == tr->langopts.thousands_sep) | |||||
thousands_inc = 2; | thousands_inc = 2; | ||||
if(thousands_inc > 0) | if(thousands_inc > 0) | ||||
while(isdigit(word[ix]) && isdigit(word[ix+1]) && isdigit(word[ix+2])) | while(isdigit(word[ix]) && isdigit(word[ix+1]) && isdigit(word[ix+2])) | ||||
{ | { | ||||
thousandplex++; | thousandplex++; | ||||
if(word[ix+3] == langopts.thousands_sep) | |||||
if(word[ix+3] == tr->langopts.thousands_sep) | |||||
ix += (3 + thousands_inc); | ix += (3 + thousands_inc); | ||||
else | else | ||||
break; | break; | ||||
suppress_null = 1; | suppress_null = 1; | ||||
} | } | ||||
if((word[n_digits] == langopts.decimal_sep) && isdigit(word[n_digits+1])) | |||||
if((word[n_digits] == tr->langopts.decimal_sep) && isdigit(word[n_digits+1])) | |||||
{ | { | ||||
// this "word" ends with a decimal point | // this "word" ends with a decimal point | ||||
Lookup("_dpt",ph_append); | |||||
Lookup(tr, "_dpt", ph_append); | |||||
decimal_point = 1; | decimal_point = 1; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
if((thousandplex > 0) && (value < 1000)) | if((thousandplex > 0) && (value < 1000)) | ||||
{ | { | ||||
if((suppress_null == 0) && (LookupThousands(value,thousandplex,ph_append))) | |||||
if((suppress_null == 0) && (LookupThousands(tr,value,thousandplex,ph_append))) | |||||
{ | { | ||||
// found an exact match for N thousand | // found an exact match for N thousand | ||||
value = 0; | value = 0; | ||||
if((thousandplex > 1) && prev_thousands && (prev_value > 0)) | if((thousandplex > 1) && prev_thousands && (prev_value > 0)) | ||||
{ | { | ||||
sprintf(string,"_%s%d",M_Variant(value),thousandplex+1); | sprintf(string,"_%s%d",M_Variant(value),thousandplex+1); | ||||
if(Lookup(string,buf1)==0) | |||||
if(Lookup(tr, string, buf1)==0) | |||||
{ | { | ||||
// speak this thousandplex if there was no word for the previous thousandplex | // speak this thousandplex if there was no word for the previous thousandplex | ||||
sprintf(string,"_0M%d",thousandplex); | sprintf(string,"_0M%d",thousandplex); | ||||
Lookup(string,ph_append); | |||||
Lookup(tr, string, ph_append); | |||||
} | } | ||||
} | } | ||||
if((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0)) | if((ph_append[0] == 0) && (word[n_digits] == '.') && (thousandplex == 0)) | ||||
{ | { | ||||
Lookup("_.",ph_append); | |||||
Lookup(tr, "_.", ph_append); | |||||
} | } | ||||
LookupNum3(value, ph_buf, suppress_null, thousandplex, prev_thousands); | |||||
if((thousandplex > 0) && (langopts.numbers2 & 0x200)) | |||||
LookupNum3(tr, value, ph_buf, suppress_null, thousandplex, prev_thousands); | |||||
if((thousandplex > 0) && (tr->langopts.numbers2 & 0x200)) | |||||
sprintf(ph_out,"%s%s%s",ph_append,ph_buf2,ph_buf); // say "thousands" before its number | sprintf(ph_out,"%s%s%s",ph_append,ph_buf2,ph_buf); // say "thousands" before its number | ||||
else | else | ||||
sprintf(ph_out,"%s%s%s",ph_buf2,ph_buf,ph_append); | sprintf(ph_out,"%s%s%s",ph_buf2,ph_buf,ph_append); | ||||
if(decimal_count > 1) | if(decimal_count > 1) | ||||
{ | { | ||||
max_decimal_count = 2; | max_decimal_count = 2; | ||||
switch(langopts.numbers & 0xe000) | |||||
switch(tr->langopts.numbers & 0xe000) | |||||
{ | { | ||||
case 0x8000: | case 0x8000: | ||||
max_decimal_count = 5; | max_decimal_count = 5; | ||||
// French/Polish decimal fraction | // French/Polish decimal fraction | ||||
while(word[n_digits] == '0') | while(word[n_digits] == '0') | ||||
{ | { | ||||
Lookup("_0",buf1); | |||||
Lookup(tr, "_0", buf1); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
decimal_count--; | decimal_count--; | ||||
n_digits++; | n_digits++; | ||||
} | } | ||||
if((decimal_count <= max_decimal_count) && isdigit(word[n_digits])) | if((decimal_count <= max_decimal_count) && isdigit(word[n_digits])) | ||||
{ | { | ||||
LookupNum3(atoi(&word[n_digits]),buf1,0,0,0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } | ||||
// Italian decimal fractions | // Italian decimal fractions | ||||
if((decimal_count < 4) || ((decimal_count==4) && (word[n_digits] != '0'))) | if((decimal_count < 4) || ((decimal_count==4) && (word[n_digits] != '0'))) | ||||
{ | { | ||||
LookupNum3(atoi(&word[n_digits]),buf1,0,0,0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
if(word[n_digits]=='0') | if(word[n_digits]=='0') | ||||
{ | { | ||||
// decimal part has leading zeros, so add a "hundredths" or "thousandths" suffix | // decimal part has leading zeros, so add a "hundredths" or "thousandths" suffix | ||||
sprintf(string,"_0Z%d",decimal_count); | sprintf(string,"_0Z%d",decimal_count); | ||||
Lookup(string,buf1); | |||||
Lookup(tr, string, buf1); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
} | } | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
// Romanian decimal fractions | // Romanian decimal fractions | ||||
if((decimal_count <= 4) && (word[n_digits] != '0')) | if((decimal_count <= 4) && (word[n_digits] != '0')) | ||||
{ | { | ||||
LookupNum3(atoi(&word[n_digits]),buf1,0,0,0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0,0,0); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } | ||||
while(isdigit(c = word[n_digits]) && (strlen(ph_out) < (N_WORD_PHONEMES - 10))) | while(isdigit(c = word[n_digits]) && (strlen(ph_out) < (N_WORD_PHONEMES - 10))) | ||||
{ | { | ||||
value = word[n_digits++] - '0'; | value = word[n_digits++] - '0'; | ||||
LookupNum2(value, 1, buf1); | |||||
LookupNum2(tr, value, 1, buf1); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
} | } | ||||
// something after the decimal part ? | // something after the decimal part ? | ||||
if(Lookup("_dpt2",buf1)) | |||||
if(Lookup(tr, "_dpt2", buf1)) | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
if((c == langopts.decimal_sep) && isdigit(word[n_digits+1])) | |||||
if((c == tr->langopts.decimal_sep) && isdigit(word[n_digits+1])) | |||||
{ | { | ||||
Lookup("_dpt",buf1); | |||||
Lookup(tr, "_dpt", buf1); | |||||
strcat(ph_out,buf1); | strcat(ph_out,buf1); | ||||
} | } | ||||
else | else | ||||
char *p; | char *p; | ||||
p = &word[n_digits+1]; | p = &word[n_digits+1]; | ||||
p += utf8_in(&next_char,p,0); | |||||
if((langopts.numbers & NUM_NOPAUSE) && (next_char == ' ')) | |||||
utf8_in(&next_char,p,0); | |||||
p += utf8_in(&next_char,p); | |||||
if((tr->langopts.numbers & NUM_NOPAUSE) && (next_char == ' ')) | |||||
utf8_in(&next_char,p); | |||||
if(!iswalpha(next_char)) | if(!iswalpha(next_char)) | ||||
strcat(ph_out,str_pause); // don't add pause for 100s, 6th, etc. | strcat(ph_out,str_pause); // don't add pause for 100s, 6th, etc. | ||||
int Translator::TranslateNumber(char *word1, char *ph_out, unsigned int *flags, int wflags) | |||||
{//======================================================================================= | |||||
int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, int wflags) | |||||
{//============================================================================================ | |||||
if(option_sayas == SAYAS_DIGITS1) | if(option_sayas == SAYAS_DIGITS1) | ||||
return(0); // speak digits individually | return(0); // speak digits individually | ||||
if((langopts.numbers & 0x3) == 1) | |||||
return(TranslateNumber_1(word1,ph_out,flags,wflags)); | |||||
if((tr->langopts.numbers & 0x3) == 1) | |||||
return(TranslateNumber_1(tr, word1, ph_out, flags, wflags)); | |||||
return(0); | return(0); | ||||
} // end of TranslateNumber | } // end of TranslateNumber |
extern REPLACE_PHONEMES replace_phonemes[N_REPLACE_PHONEMES]; | extern REPLACE_PHONEMES replace_phonemes[N_REPLACE_PHONEMES]; | ||||
#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name | |||||
#define PH3(c1,c2,c3) (c3<<16)+(c2<<8)+c1 | |||||
#define PhonemeCode2(c1,c2) PhonemeCode((c2<<8)+c1) | |||||
int LookupPhonemeString(const char *string); | |||||
int PhonemeCode(unsigned int mnem); | |||||
char *EncodePhonemes(char *p, char *outptr, unsigned char *bad_phoneme); | char *EncodePhonemes(char *p, char *outptr, unsigned char *bad_phoneme); | ||||
void DecodePhonemes(const char *inptr, char *outptr); | void DecodePhonemes(const char *inptr, char *outptr); | ||||
const char *PhonemeTabName(void); | |||||
int LookupPh(const char *string); | |||||
extern const char *WordToString(unsigned int word); | extern const char *WordToString(unsigned int word); | ||||
extern PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS]; | |||||
extern int phoneme_tab_number; |
const unsigned char pause_phonemes[8] = {0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG}; | const unsigned char pause_phonemes[8] = {0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG}; | ||||
int Translator::ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//====================================================================================================== | |||||
extern int n_ph_list2; | |||||
extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | |||||
static int ChangePhonemes(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//================================================================================================================= | |||||
// Called for each phoneme in the phoneme list, to allow a language to make changes | // Called for each phoneme in the phoneme list, to allow a language to make changes | ||||
// ph The current phoneme | // ph The current phoneme | ||||
if(tr->translator_name == L('r','u')) | |||||
return(ChangePhonemes_ru(tr, phlist, n_ph, index, ph, ch)); | |||||
return(0); | return(0); | ||||
} | } | ||||
int Translator::SubstitutePhonemes(PHONEME_LIST2 *plist_out) | |||||
{//========================================================= | |||||
static int SubstitutePhonemes(Translator *tr, PHONEME_LIST2 *plist_out) | |||||
{//==================================================================== | |||||
// Copy the phonemes list and perform any substitutions that are required for the | // Copy the phonemes list and perform any substitutions that are required for the | ||||
// current voice | // current voice | ||||
int ix; | int ix; | ||||
if((plist2+1)->sourceix || ((next != 0) && (next->type == phPAUSE))) | if((plist2+1)->sourceix || ((next != 0) && (next->type == phPAUSE))) | ||||
word_end = 1; // this phoneme is the end of a word | word_end = 1; // this phoneme is the end of a word | ||||
if(langopts.phoneme_change != 0) | |||||
if(tr->langopts.phoneme_change != 0) | |||||
{ | { | ||||
// this language does changes to phonemes after translation | // this language does changes to phonemes after translation | ||||
ch.vowel_this = syllable; | ch.vowel_this = syllable; | ||||
ch.vowel_stressed = syllable_stressed; | ch.vowel_stressed = syllable_stressed; | ||||
ChangePhonemes(ph_list2, n_ph_list2, ix, phoneme_tab[ph_list2[ix].phcode], &ch); | |||||
ChangePhonemes(tr, ph_list2, n_ph_list2, ix, phoneme_tab[ph_list2[ix].phcode], &ch); | |||||
} | } | ||||
// check whether a Voice has specified that we should replace this phoneme | // check whether a Voice has specified that we should replace this phoneme | ||||
void Translator::MakePhonemeList(int post_pause, int start_sentence) | |||||
{//============================================================================================ | |||||
void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) | |||||
{//===================================================================== | |||||
int ix=0; | int ix=0; | ||||
int j; | int j; | ||||
PHONEME_LIST2 *plist2 = &ph_list2_null; | PHONEME_LIST2 *plist2 = &ph_list2_null; | ||||
PHONEME_LIST2 *plist2_inserted = NULL; | PHONEME_LIST2 *plist2_inserted = NULL; | ||||
plist2 = ph_list2; | |||||
phlist = phoneme_list; | phlist = phoneme_list; | ||||
end_sourceix = ph_list2[n_ph_list2-1].sourceix; | |||||
end_sourceix = plist2[n_ph_list2-1].sourceix; | |||||
// is the last word of the clause unstressed ? | // is the last word of the clause unstressed ? | ||||
max_stress = 0; | max_stress = 0; | ||||
for(j=n_ph_list2-3; j>=0; j--) | |||||
for(j = n_ph_list2-3; j>=0; j--) | |||||
{ | { | ||||
// start with the last phoneme (before the terminating pauses) and move forwards | // start with the last phoneme (before the terminating pauses) and move forwards | ||||
if((ph_list2[j].stress & 0x7f) > max_stress) | |||||
max_stress = ph_list2[j].stress & 0x7f; | |||||
if(ph_list2[j].sourceix != 0) | |||||
if((plist2[j].stress & 0x7f) > max_stress) | |||||
max_stress = plist2[j].stress & 0x7f; | |||||
if(plist2[j].sourceix != 0) | |||||
break; | break; | ||||
} | } | ||||
if(max_stress < 4) | if(max_stress < 4) | ||||
// the last word is unstressed, look for a previous word that can be stressed | // the last word is unstressed, look for a previous word that can be stressed | ||||
while(--j >= 0) | while(--j >= 0) | ||||
{ | { | ||||
if(ph_list2[j].synthflags & SFLAG_PROMOTE_STRESS) // dictionary flags indicated that this stress can be promoted | |||||
if(plist2[j].synthflags & SFLAG_PROMOTE_STRESS) // dictionary flags indicated that this stress can be promoted | |||||
{ | { | ||||
ph_list2[j].stress = 4; // promote to stressed | |||||
plist2[j].stress = 4; // promote to stressed | |||||
break; | break; | ||||
} | } | ||||
if(ph_list2[j].stress >= 4) | |||||
if(plist2[j].stress >= 4) | |||||
{ | { | ||||
// found a stressed syllable, so stop looking | // found a stressed syllable, so stop looking | ||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if((regression = langopts.param[LOPT_REGRESSIVE_VOICING]) != 0) | |||||
if((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0) | |||||
{ | { | ||||
// set consonant clusters to all voiced or all unvoiced | // set consonant clusters to all voiced or all unvoiced | ||||
// Regressive | // Regressive | ||||
for(j=n_ph_list2-1; j>=0; j--) | for(j=n_ph_list2-1; j>=0; j--) | ||||
{ | { | ||||
ph = phoneme_tab[ph_list2[j].phcode]; | |||||
ph = phoneme_tab[plist2[j].phcode]; | |||||
if(ph == NULL) | if(ph == NULL) | ||||
continue; | continue; | ||||
else | else | ||||
if((voicing==2) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING)) | if((voicing==2) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING)) | ||||
{ | { | ||||
ph_list2[j].phcode = ph->alternative_ph; // change to voiced equivalent | |||||
plist2[j].phcode = ph->alternative_ph; // change to voiced equivalent | |||||
} | } | ||||
} | } | ||||
else | else | ||||
else | else | ||||
if((voicing==1) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING)) | if((voicing==1) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING)) | ||||
{ | { | ||||
ph_list2[j].phcode = ph->alternative_ph; // change to unvoiced equivalent | |||||
plist2[j].phcode = ph->alternative_ph; // change to unvoiced equivalent | |||||
} | } | ||||
} | } | ||||
else | else | ||||
voicing = 0; | voicing = 0; | ||||
} | } | ||||
} | } | ||||
if((regression & 0x4) && (ph_list2[j].sourceix)) | |||||
if((regression & 0x4) && (plist2[j].sourceix)) | |||||
{ | { | ||||
// stop propagation at a word boundary | // stop propagation at a word boundary | ||||
voicing = 0; | voicing = 0; | ||||
} | } | ||||
} | } | ||||
n_ph_list2 = SubstitutePhonemes(ph_list3) - 2; | |||||
n_ph_list2 = SubstitutePhonemes(tr,ph_list3) - 2; | |||||
// transfer all the phonemes of the clause into phoneme_list | // transfer all the phonemes of the clause into phoneme_list | ||||
ph = phoneme_tab[phonPAUSE]; | ph = phoneme_tab[phonPAUSE]; | ||||
switched_language = 0; | switched_language = 0; | ||||
for(j=0; insert_ph || ((j<n_ph_list2) && (ix < N_PHONEME_LIST-3)); j++) | |||||
for(j=0; insert_ph || ((j < n_ph_list2) && (ix < N_PHONEME_LIST-3)); j++) | |||||
{ | { | ||||
prev = ph; | prev = ph; | ||||
{ | { | ||||
// in a sequence of unstressed syllables, reduce alternate syllables to 'diminished' | // in a sequence of unstressed syllables, reduce alternate syllables to 'diminished' | ||||
// stress. But not for the last phoneme of a stressed word | // stress. But not for the last phoneme of a stressed word | ||||
if((langopts.stress_flags & 0x2) || ((word_stress > 3) && ((plist2+1)->sourceix!=0))) | |||||
if((tr->langopts.stress_flags & 0x2) || ((word_stress > 3) && ((plist2+1)->sourceix!=0))) | |||||
{ | { | ||||
// An unstressed final vowel of a stressed word | // An unstressed final vowel of a stressed word | ||||
unstress_count=1; // try again for next syllable | unstress_count=1; // try again for next syllable | ||||
plist2->synthflags &= ~SFLAG_SYLLABLE; | plist2->synthflags &= ~SFLAG_SYLLABLE; | ||||
} | } | ||||
if(langopts.param[LOPT_REDUCE_T]) | |||||
if(tr->langopts.param[LOPT_REDUCE_T]) | |||||
{ | { | ||||
if((ph->mnemonic == 't') && (plist2->sourceix == 0) && ((prev->type == phVOWEL) || (prev->mnemonic == 'n'))) | if((ph->mnemonic == 't') && (plist2->sourceix == 0) && ((prev->type == phVOWEL) || (prev->mnemonic == 'n'))) | ||||
{ | { | ||||
} | } | ||||
while((ph->reduce_to != 0) && (!(plist2->synthflags & SFLAG_DICTIONARY) || (langopts.param[LOPT_REDUCE] & 1))) | |||||
while((ph->reduce_to != 0) && (!(plist2->synthflags & SFLAG_DICTIONARY) || (tr->langopts.param[LOPT_REDUCE] & 1))) | |||||
{ | { | ||||
int reduce_level; | int reduce_level; | ||||
int stress_level; | int stress_level; | ||||
if(stress_level < reduce_level) | if(stress_level < reduce_level) | ||||
reduce =1; | reduce =1; | ||||
if((word_stress < 4) && (langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= word_stress)) | |||||
if((word_stress < 4) && (tr->langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= word_stress)) | |||||
{ | { | ||||
// don't reduce the most stressed syllable in an unstressed word | // don't reduce the most stressed syllable in an unstressed word | ||||
reduce = 0; | reduce = 0; | ||||
{ | { | ||||
int x; | int x; | ||||
if(langopts.vowel_pause && (ph->type != phPAUSE)) | |||||
if(tr->langopts.vowel_pause && (ph->type != phPAUSE)) | |||||
{ | { | ||||
if((ph->type != phVOWEL) && (langopts.vowel_pause & 0x200)) | |||||
if((ph->type != phVOWEL) && (tr->langopts.vowel_pause & 0x200)) | |||||
{ | { | ||||
// add a pause after a word which ends in a consonant | // add a pause after a word which ends in a consonant | ||||
insert_ph = phonPAUSE_NOLINK; | insert_ph = phonPAUSE_NOLINK; | ||||
if(next->type == phVOWEL) | if(next->type == phVOWEL) | ||||
{ | { | ||||
if((x = langopts.vowel_pause & 0x0c) != 0) | |||||
if((x = tr->langopts.vowel_pause & 0x0c) != 0) | |||||
{ | { | ||||
// break before a word which starts with a vowel | // break before a word which starts with a vowel | ||||
if(x == 0xc) | if(x == 0xc) | ||||
insert_ph = phonPAUSE_VSHORT; | insert_ph = phonPAUSE_VSHORT; | ||||
} | } | ||||
if((ph->type == phVOWEL) && ((x = langopts.vowel_pause & 0x03) != 0)) | |||||
if((ph->type == phVOWEL) && ((x = tr->langopts.vowel_pause & 0x03) != 0)) | |||||
{ | { | ||||
// adjacent vowels over a word boundary | // adjacent vowels over a word boundary | ||||
if(x == 2) | if(x == 2) | ||||
insert_ph = phonPAUSE_VSHORT; | insert_ph = phonPAUSE_VSHORT; | ||||
} | } | ||||
if(((plist2+1)->stress >= 4) && (langopts.vowel_pause & 0x100)) | |||||
if(((plist2+1)->stress >= 4) && (tr->langopts.vowel_pause & 0x100)) | |||||
{ | { | ||||
// pause before a words which starts with a stressed vowel | // pause before a words which starts with a stressed vowel | ||||
insert_ph = phonPAUSE_SHORT; | insert_ph = phonPAUSE_SHORT; | ||||
if(plist2 != plist2_inserted) | if(plist2 != plist2_inserted) | ||||
{ | { | ||||
if((x = (langopts.word_gap & 0x7)) != 0) | |||||
if((x = (tr->langopts.word_gap & 0x7)) != 0) | |||||
{ | { | ||||
if((x > 1) || ((insert_ph != phonPAUSE_SHORT) && (insert_ph != phonPAUSE_NOLINK))) | if((x > 1) || ((insert_ph != phonPAUSE_SHORT) && (insert_ph != phonPAUSE_NOLINK))) | ||||
{ | { | ||||
} | } | ||||
} | } | ||||
else | else | ||||
if(((langopts.word_gap & 8)==0) || ((plist2+1)->sourceix == 0)) | |||||
if(((tr->langopts.word_gap & 8)==0) || ((plist2+1)->sourceix == 0)) | |||||
{ | { | ||||
// This phoneme can be linked to a following vowel by inserting a linking phoneme | // This phoneme can be linked to a following vowel by inserting a linking phoneme | ||||
if(next->type == phVOWEL) | if(next->type == phVOWEL) |
#define N_XML_BUF 256 | #define N_XML_BUF 256 | ||||
const char *xmlbase = ""; // base URL from <speak> | |||||
static const char *xmlbase = ""; // base URL from <speak> | |||||
int namedata_ix=0; | |||||
int n_namedata = 0; | |||||
static int namedata_ix=0; | |||||
static int n_namedata = 0; | |||||
char *namedata = NULL; | char *namedata = NULL; | ||||
FILE *f_input = NULL; | |||||
int ungot_char2 = 0; | |||||
static FILE *f_input = NULL; | |||||
static int ungot_char2 = 0; | |||||
char *p_textinput; | char *p_textinput; | ||||
wchar_t *p_wchar_input; | wchar_t *p_wchar_input; | ||||
int ungot_char; | |||||
const char *ungot_word = NULL; | |||||
int end_of_input; | |||||
static int ungot_char; | |||||
static const char *ungot_word = NULL; | |||||
static int end_of_input; | |||||
int ignore_text=0; // set during <sub> ... </sub> to ignore text which has been replaced by an alias | |||||
int clear_skipping_text = 0; // next clause should clear the skipping_text flag | |||||
static int ignore_text=0; // set during <sub> ... </sub> to ignore text which has been replaced by an alias | |||||
static int clear_skipping_text = 0; // next clause should clear the skipping_text flag | |||||
int count_characters = 0; | int count_characters = 0; | ||||
int sayas_mode; | |||||
int ssml_ignore_l_angle = 0; | |||||
static int sayas_mode; | |||||
static int ssml_ignore_l_angle = 0; | |||||
static const char *punct_stop = ".:!?"; // pitch fall if followed by space | static const char *punct_stop = ".:!?"; // pitch fall if followed by space | ||||
static const char *punct_close = ")]}>;'\""; // always pitch fall unless followed by alnum | static const char *punct_close = ")]}>;'\""; // always pitch fall unless followed by alnum | ||||
static const char *tone_punct_off = "\001T"; | static const char *tone_punct_off = "\001T"; | ||||
// punctuations symbols that can end a clause | // punctuations symbols that can end a clause | ||||
const unsigned short punct_chars[] = {',','.','?','!',':',';', | |||||
static const unsigned short punct_chars[] = {',','.','?','!',':',';', | |||||
0x2013, // en-dash | 0x2013, // en-dash | ||||
0x2014, // em-dash | 0x2014, // em-dash | ||||
0x2026, // elipsis | 0x2026, // elipsis | ||||
} SSML_STACK; | } SSML_STACK; | ||||
#define N_SSML_STACK 20 | #define N_SSML_STACK 20 | ||||
int n_ssml_stack; | |||||
SSML_STACK ssml_stack[N_SSML_STACK]; | |||||
static int n_ssml_stack; | |||||
static SSML_STACK ssml_stack[N_SSML_STACK]; | |||||
char current_voice_id[40] = {0}; | |||||
static char current_voice_id[40] = {0}; | |||||
#define N_PARAM_STACK 20 | #define N_PARAM_STACK 20 | ||||
int n_param_stack; | |||||
static int n_param_stack; | |||||
PARAM_STACK param_stack[N_PARAM_STACK]; | PARAM_STACK param_stack[N_PARAM_STACK]; | ||||
int speech_parameters[N_SPEECH_PARAM]; // current values, from param_stack | |||||
static int speech_parameters[N_SPEECH_PARAM]; // current values, from param_stack | |||||
const int param_defaults[N_SPEECH_PARAM] = { | const int param_defaults[N_SPEECH_PARAM] = { | ||||
0, // silence (internal use) | 0, // silence (internal use) | ||||
} | } | ||||
const char *WordToString2(unsigned int word) | |||||
{//======================================== | |||||
static const char *WordToString2(unsigned int word) | |||||
{//================================================ | |||||
// Convert a language mnemonic word into a string | // Convert a language mnemonic word into a string | ||||
int ix; | int ix; | ||||
static char buf[5]; | static char buf[5]; | ||||
} | } | ||||
const char *Translator::LookupSpecial(const char *string, char* text_out) | |||||
{//====================================================================== | |||||
static const char *LookupSpecial(Translator *tr, const char *string, char* text_out) | |||||
{//================================================================================= | |||||
unsigned int flags[2]; | unsigned int flags[2]; | ||||
char phonemes[55]; | char phonemes[55]; | ||||
char phonemes2[55]; | char phonemes2[55]; | ||||
char *string1 = (char *)string; | char *string1 = (char *)string; | ||||
if(LookupDictList(&string1,phonemes,flags,0,NULL)) | |||||
if(LookupDictList(tr,&string1,phonemes,flags,0,NULL)) | |||||
{ | { | ||||
SetWordStress(phonemes,flags[0],-1,0); | |||||
SetWordStress(tr, phonemes, flags[0], -1, 0); | |||||
DecodePhonemes(phonemes,phonemes2); | DecodePhonemes(phonemes,phonemes2); | ||||
sprintf(text_out,"[[%s]]",phonemes2); | sprintf(text_out,"[[%s]]",phonemes2); | ||||
option_phoneme_input |= 2; | option_phoneme_input |= 2; | ||||
} | } | ||||
const char *Translator::LookupCharName(int c) | |||||
{//========================================== | |||||
static const char *LookupCharName(Translator *tr, int c) | |||||
{//===================================================== | |||||
// Find the phoneme string (in ascii) to speak the name of character c | // Find the phoneme string (in ascii) to speak the name of character c | ||||
// Used for punctuation characters and symbols | // Used for punctuation characters and symbols | ||||
single_letter[2+ix]=0; | single_letter[2+ix]=0; | ||||
string = &single_letter[1]; | string = &single_letter[1]; | ||||
if(LookupDictList(&string, phonemes, flags, 0, NULL) == 0) | |||||
if(LookupDictList(tr, &string, phonemes, flags, 0, NULL) == 0) | |||||
{ | { | ||||
// try _* then * | // try _* then * | ||||
string = &single_letter[2]; | string = &single_letter[2]; | ||||
if(LookupDictList(&string, phonemes, flags, 0, NULL) == 0) | |||||
if(LookupDictList(tr, &string, phonemes, flags, 0, NULL) == 0) | |||||
{ | { | ||||
// now try the rules | // now try the rules | ||||
single_letter[1] = ' '; | single_letter[1] = ' '; | ||||
TranslateRules(&single_letter[2], phonemes, sizeof(phonemes), NULL,0,NULL); | |||||
TranslateRules(tr, &single_letter[2], phonemes, sizeof(phonemes), NULL,0,NULL); | |||||
} | } | ||||
} | } | ||||
if((phonemes[0] == 0) && (translator_name != L('e','n'))) | |||||
if((phonemes[0] == 0) && (tr->translator_name != L('e','n'))) | |||||
{ | { | ||||
// not found, try English | // not found, try English | ||||
SetTranslator2("en"); | SetTranslator2("en"); | ||||
string = &single_letter[1]; | string = &single_letter[1]; | ||||
single_letter[1] = '_'; | single_letter[1] = '_'; | ||||
if(translator2->LookupDictList(&string, phonemes, flags, 0, NULL) == 0) | |||||
if(LookupDictList(translator2, &string, phonemes, flags, 0, NULL) == 0) | |||||
{ | { | ||||
string = &single_letter[2]; | string = &single_letter[2]; | ||||
translator2->LookupDictList(&string, phonemes, flags, 0, NULL); | |||||
LookupDictList(translator2, &string, phonemes, flags, 0, NULL); | |||||
} | } | ||||
if(phonemes[0]) | if(phonemes[0]) | ||||
{ | { | ||||
{ | { | ||||
if(lang_name) | if(lang_name) | ||||
{ | { | ||||
translator2->SetWordStress(phonemes,flags[0],-1,0); | |||||
SetWordStress(translator2, phonemes, flags[0], -1, 0); | |||||
DecodePhonemes(phonemes,phonemes2); | DecodePhonemes(phonemes,phonemes2); | ||||
sprintf(buf,"[[_^_%s %s _^_%s]]","en",phonemes2,WordToString2(translator_name)); | |||||
sprintf(buf,"[[_^_%s %s _^_%s]]","en",phonemes2,WordToString2(tr->translator_name)); | |||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
SetWordStress(phonemes,flags[0],-1,0); | |||||
SetWordStress(tr, phonemes, flags[0], -1, 0); | |||||
DecodePhonemes(phonemes,phonemes2); | DecodePhonemes(phonemes,phonemes2); | ||||
sprintf(buf,"[[%s]] ",phonemes2); | sprintf(buf,"[[%s]] ",phonemes2); | ||||
} | } | ||||
int Translator::AnnouncePunctuation(int c1, int c2, char *buf, int bufix) | |||||
{//====================================================================== | |||||
static int AnnouncePunctuation(Translator *tr, int c1, int c2, char *buf, int bufix) | |||||
{//================================================================================= | |||||
// announce punctuation names | // announce punctuation names | ||||
// c1: the punctuation character | // c1: the punctuation character | ||||
// c2: the following character | // c2: the following character | ||||
found = 1; | found = 1; | ||||
} | } | ||||
else | else | ||||
if((punctname = LookupCharName(c1)) != NULL) | |||||
if((punctname = LookupCharName(tr, c1)) != NULL) | |||||
{ | { | ||||
found = 1; | found = 1; | ||||
if(bufix==0) | if(bufix==0) | ||||
static char ignore_if_self_closing[] = {0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,0,0}; | static char ignore_if_self_closing[] = {0,1,1,1,1,0,0,0,0,1,1,0,1,0,1,0,0}; | ||||
MNEM_TAB ssmltags[] = { | |||||
static MNEM_TAB ssmltags[] = { | |||||
{"speak", SSML_SPEAK}, | {"speak", SSML_SPEAK}, | ||||
{"voice", SSML_VOICE}, | {"voice", SSML_VOICE}, | ||||
{"prosody", SSML_PROSODY}, | {"prosody", SSML_PROSODY}, | ||||
} // end of attr_prosody_value | } // end of attr_prosody_value | ||||
int AddNameData(const char *name, int wide) | |||||
{//======================================== | |||||
static int AddNameData(const char *name, int wide) | |||||
{//=============================================== | |||||
// Add the name to the namedata and return its position | // Add the name to the namedata and return its position | ||||
int ix; | int ix; | ||||
int len; | int len; | ||||
} // end of ProcessSsmlTag | } // end of ProcessSsmlTag | ||||
MNEM_TAB xml_char_mnemonics[] = { | |||||
static MNEM_TAB xml_char_mnemonics[] = { | |||||
{"gt",'>'}, | {"gt",'>'}, | ||||
{"lt",'<'}, | {"lt",'<'}, | ||||
{"amp", '&'}, | {"amp", '&'}, | ||||
{NULL,-1}}; | {NULL,-1}}; | ||||
int Translator::ReadClause(FILE *f_in, char *buf, short *charix, int n_buf, int *tone_type) | |||||
{//======================================================================================== | |||||
int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int n_buf, int *tone_type) | |||||
{//============================================================================================ | |||||
/* Find the end of the current clause. | /* Find the end of the current clause. | ||||
Write the clause into buf | Write the clause into buf | ||||
clear_skipping_text = 0; | clear_skipping_text = 0; | ||||
} | } | ||||
clause_upper_count = 0; | |||||
clause_lower_count = 0; | |||||
tr->clause_upper_count = 0; | |||||
tr->clause_lower_count = 0; | |||||
end_of_input = 0; | end_of_input = 0; | ||||
*tone_type = 0; | *tone_type = 0; | ||||
{ | { | ||||
char *p_word; | char *p_word; | ||||
if(translator_name == 0x6a626f) | |||||
if(tr->translator_name == 0x6a626f) | |||||
{ | { | ||||
// language jbo : lojban | // language jbo : lojban | ||||
// treat "i" or ".i" as end-of-sentence | // treat "i" or ".i" as end-of-sentence | ||||
if(iswupper(c1)) | if(iswupper(c1)) | ||||
{ | { | ||||
clause_upper_count++; | |||||
tr->clause_upper_count++; | |||||
if((option_capitals == 2) && (sayas_mode == 0) && !iswupper(cprev)) | if((option_capitals == 2) && (sayas_mode == 0) && !iswupper(cprev)) | ||||
{ | { | ||||
char text_buf[40]; | char text_buf[40]; | ||||
char text_buf2[30]; | char text_buf2[30]; | ||||
if(LookupSpecial("_cap",text_buf2) != NULL) | |||||
if(LookupSpecial(tr, "_cap", text_buf2) != NULL) | |||||
{ | { | ||||
sprintf(text_buf,"%s%s%s",tone_punct_on,text_buf2,tone_punct_off); | sprintf(text_buf,"%s%s%s",tone_punct_on,text_buf2,tone_punct_off); | ||||
j = strlen(text_buf); | j = strlen(text_buf); | ||||
} | } | ||||
else | else | ||||
if(iswalpha(c1)) | if(iswalpha(c1)) | ||||
clause_lower_count++; | |||||
tr->clause_lower_count++; | |||||
if(option_phoneme_input) | if(option_phoneme_input) | ||||
{ | { | ||||
// if a list of allowed punctuation has been set up, check whether the character is in it | // if a list of allowed punctuation has been set up, check whether the character is in it | ||||
if((option_punctuation == 1) || (wcschr(option_punctlist,c1) != NULL)) | if((option_punctuation == 1) || (wcschr(option_punctlist,c1) != NULL)) | ||||
{ | { | ||||
if((terminator = AnnouncePunctuation(c1, c2, buf, ix)) >= 0) | |||||
if((terminator = AnnouncePunctuation(tr, c1, c2, buf, ix)) >= 0) | |||||
return(terminator); | return(terminator); | ||||
} | } | ||||
} | } | ||||
if((nl_count==0) && (c1 == '.')) | if((nl_count==0) && (c1 == '.')) | ||||
{ | { | ||||
if(iswdigit(cprev) && (langopts.numbers & 0x10000)) | |||||
if(iswdigit(cprev) && (tr->langopts.numbers & 0x10000)) | |||||
{ | { | ||||
// dot after a number indicates an ordinal number | // dot after a number indicates an ordinal number | ||||
c2 = ' '; | c2 = ' '; | ||||
{//================= | {//================= | ||||
int param; | int param; | ||||
ungot_char = 0; | |||||
n_ssml_stack =1; | n_ssml_stack =1; | ||||
n_param_stack = 1; | n_param_stack = 1; | ||||
ssml_stack[0].tag_type = 0; | ssml_stack[0].tag_type = 0; |
} | } | ||||
void Translator::CalcLengths() | |||||
{//=========================== | |||||
void CalcLengths(Translator *tr) | |||||
{//============================== | |||||
int ix; | int ix; | ||||
int ix2; | int ix2; | ||||
PHONEME_LIST *prev; | PHONEME_LIST *prev; | ||||
if(prev->type == phSTOP) | if(prev->type == phSTOP) | ||||
p->prepause = 60; | p->prepause = 60; | ||||
if((langopts.word_gap & 0x10) && (p->newword)) | |||||
if((tr->langopts.word_gap & 0x10) && (p->newword)) | |||||
p->prepause = 60; | p->prepause = 60; | ||||
if(p->ph->phflags & phLENGTHENSTOP) | if(p->ph->phflags & phLENGTHENSTOP) | ||||
p->prepause += 30; | p->prepause += 30; | ||||
if(p->synthflags & SFLAG_LENGTHEN) | if(p->synthflags & SFLAG_LENGTHEN) | ||||
p->prepause += langopts.long_stop; | |||||
p->prepause += tr->langopts.long_stop; | |||||
break; | break; | ||||
case phVFRICATIVE: | case phVFRICATIVE: | ||||
else | else | ||||
p->length = 256; | p->length = 256; | ||||
if((langopts.word_gap & 0x10) && (p->newword)) | |||||
if((tr->langopts.word_gap & 0x10) && (p->newword)) | |||||
p->prepause = 30; | p->prepause = 30; | ||||
break; | break; | ||||
p->prepause = 0; | p->prepause = 0; | ||||
} | } | ||||
} | } | ||||
if((langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20)) | |||||
if((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20)) | |||||
p->prepause = 20; | p->prepause = 20; | ||||
break; | break; | ||||
case phLIQUID: | case phLIQUID: | ||||
case phNASAL: | case phNASAL: | ||||
p->amp = stress_amps[1]; // unless changed later | |||||
p->amp = tr->stress_amps[1]; // unless changed later | |||||
p->length = 256; // TEMPORARY | p->length = 256; // TEMPORARY | ||||
min_drop = 0; | min_drop = 0; | ||||
if(stress > 7) stress = 7; | if(stress > 7) stress = 7; | ||||
if(pre_sonorant) | if(pre_sonorant) | ||||
p->amp = stress_amps[stress]-1; | |||||
p->amp = tr->stress_amps[stress]-1; | |||||
else | else | ||||
p->amp = stress_amps[stress]; | |||||
p->amp = tr->stress_amps[stress]; | |||||
if(emphasized) | if(emphasized) | ||||
p->amp = 25; | p->amp = 25; | ||||
if(ix >= (n_phoneme_list-3)) | if(ix >= (n_phoneme_list-3)) | ||||
{ | { | ||||
// last phoneme of a clause, limit its amplitude | // last phoneme of a clause, limit its amplitude | ||||
if(p->amp > langopts.param[LOPT_MAXAMP_EOC]) | |||||
p->amp = langopts.param[LOPT_MAXAMP_EOC]; | |||||
if(p->amp > tr->langopts.param[LOPT_MAXAMP_EOC]) | |||||
p->amp = tr->langopts.param[LOPT_MAXAMP_EOC]; | |||||
} | } | ||||
// is the last syllable of a word ? | // is the last syllable of a word ? | ||||
if(more_syllables==0) | if(more_syllables==0) | ||||
{ | { | ||||
len = langopts.length_mods0[next2->ph->length_mod *10+ next->ph->length_mod]; | |||||
len = tr->langopts.length_mods0[next2->ph->length_mod *10+ next->ph->length_mod]; | |||||
if((next->newword) && (langopts.word_gap & 0x20)) | |||||
if((next->newword) && (tr->langopts.word_gap & 0x20)) | |||||
{ | { | ||||
// consider as a pause + first phoneme of the next word | // consider as a pause + first phoneme of the next word | ||||
length_mod = (len + langopts.length_mods0[next->ph->length_mod *10+ 1])/2; | |||||
length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2; | |||||
} | } | ||||
else | else | ||||
length_mod = len; | length_mod = len; | ||||
} | } | ||||
else | else | ||||
{ | { | ||||
length_mod = langopts.length_mods[next2->ph->length_mod *10+ next->ph->length_mod]; | |||||
length_mod = tr->langopts.length_mods[next2->ph->length_mod *10+ next->ph->length_mod]; | |||||
if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS)) | if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS)) | ||||
length_mod -= 15; | length_mod -= 15; | ||||
length_mod += 20; | length_mod += 20; | ||||
} | } | ||||
if((len = stress_lengths[stress]) == 0) | |||||
len = stress_lengths[6]; | |||||
if((len = tr->stress_lengths[stress]) == 0) | |||||
len = tr->stress_lengths[6]; | |||||
length_mod = (length_mod * len)/128; | length_mod = (length_mod * len)/128; | ||||
{ | { | ||||
// this is the last syllable in the clause, lengthen it - more for short vowels | // this is the last syllable in the clause, lengthen it - more for short vowels | ||||
len = p->ph->std_length; | len = p->ph->std_length; | ||||
if(langopts.stress_flags & 0x40000) | |||||
if(tr->langopts.stress_flags & 0x40000) | |||||
len=200; // don't lengthen short vowels more than long vowels at end-of-clause | len=200; // don't lengthen short vowels more than long vowels at end-of-clause | ||||
length_mod = length_mod * (256 + (280 - len)/3)/256; | length_mod = length_mod * (256 + (280 - len)/3)/256; | ||||
} | } |
int letter; | int letter; | ||||
int ix; | int ix; | ||||
ix = utf8_in(&letter,key,0); | |||||
ix = utf8_in(&letter,key); | |||||
if(key[ix] == 0) | if(key[ix] == 0) | ||||
{ | { | ||||
// a single character | // a single character |
option_linelength = 0; | option_linelength = 0; | ||||
option_phonemes = 0; | option_phonemes = 0; | ||||
option_waveout = 0; | option_waveout = 0; | ||||
option_harmonic1 = 8; | |||||
option_multibyte = 0; // auto | option_multibyte = 0; // auto | ||||
option_capitals = 0; | option_capitals = 0; | ||||
option_punctuation = 0; | option_punctuation = 0; | ||||
option_phonemes = 0; | option_phonemes = 0; | ||||
option_waveout = 0; | option_waveout = 0; | ||||
option_quiet = 0; | option_quiet = 0; | ||||
option_harmonic1 = 8; | |||||
option_multibyte = 0; // auto | option_multibyte = 0; // auto | ||||
option_capitals = 0; | option_capitals = 0; | ||||
option_punctuation = 0; | option_punctuation = 0; | ||||
{ | { | ||||
RiscosCloseSound(); | RiscosCloseSound(); | ||||
RemoveCallback(); | RemoveCallback(); | ||||
delete translator; | |||||
DeleteTranslator(translator); | |||||
FreePhData(); | FreePhData(); | ||||
} /* end of terminate_module */ | } /* end of terminate_module */ | ||||
#endif // USE_MBROLA_LIB | #endif // USE_MBROLA_LIB | ||||
MBROLA_TAB *mbrola_tab = NULL; | |||||
int mbrola_control = 0; | |||||
static MBROLA_TAB *mbrola_tab = NULL; | |||||
static int mbrola_control = 0; | |||||
} // end of LoadMbrolaTable | } // end of LoadMbrolaTable | ||||
int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev, PHONEME_TAB *ph_next, int *name2, int *split, int *control) | |||||
{//============================================================================================================== | |||||
static int GetMbrName(PHONEME_LIST *plist, PHONEME_TAB *ph, PHONEME_TAB *ph_prev, PHONEME_TAB *ph_next, int *name2, int *split, int *control) | |||||
{//========================================================================================================================================== | |||||
// Look up a phoneme in the mbrola phoneme name translation table | // Look up a phoneme in the mbrola phoneme name translation table | ||||
// It may give none, 1, or 2 mbrola phonemes | // It may give none, 1, or 2 mbrola phonemes | ||||
int mnem = ph->mnemonic; | int mnem = ph->mnemonic; | ||||
#ifdef PLATFORM_WINDOWS | #ifdef PLATFORM_WINDOWS | ||||
int MbrolaSynth(char *p_mbrola) | |||||
{//============================ | |||||
static int MbrolaSynth(char *p_mbrola) | |||||
{//=================================== | |||||
// p_mbrola is a string of mbrola pho lines - Windows | // p_mbrola is a string of mbrola pho lines - Windows | ||||
int len; | int len; | ||||
int finished; | int finished; | ||||
} // end of SynthMbrola | } // end of SynthMbrola | ||||
#else | #else | ||||
int MbrolaSynth(char *p_mbrola) | |||||
{//============================ | |||||
static int MbrolaSynth(char *p_mbrola) | |||||
{//=================================== | |||||
// p_mbrola is a string of mbrola pho lines - Linux | // p_mbrola is a string of mbrola pho lines - Linux | ||||
// This is wrong | // This is wrong | ||||
#ifdef TEST_MBROLA | #ifdef TEST_MBROLA | ||||
PHONEME_LIST mbrola_phlist; | |||||
int mbrola_n_ph; | |||||
int mbrola_phix; | |||||
static PHONEME_LIST mbrola_phlist; | |||||
static int mbrola_n_ph; | |||||
static int mbrola_phix; | |||||
int MbrolaFill(int fill_zeros) | int MbrolaFill(int fill_zeros) |
int n_phoneme_tables; | int n_phoneme_tables; | ||||
PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS]; | PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS]; | ||||
static int phoneme_tab_number = 0; | |||||
int phoneme_tab_number = 0; | |||||
int wavefile_ix; // a wavefile to play along with the synthesis | int wavefile_ix; // a wavefile to play along with the synthesis | ||||
int wavefile_amp; | int wavefile_amp; | ||||
int vowel_transition0; | int vowel_transition0; | ||||
int vowel_transition1; | int vowel_transition1; | ||||
void FormantTransitions(frameref_t *seq, int &n_frames, PHONEME_TAB *this_ph, PHONEME_TAB *other_ph, int which); | |||||
int FormantTransition2(frameref_t *seq, int &n_frames, unsigned int data1, unsigned int data2, PHONEME_TAB *other_ph, int which); | int FormantTransition2(frameref_t *seq, int &n_frames, unsigned int data1, unsigned int data2, PHONEME_TAB *other_ph, int which); | ||||
const char *PhonemeTabName(void) | |||||
{//============================= | |||||
return(phoneme_tab_list[phoneme_tab_number].name); | |||||
} | |||||
static int ReadPhFile(char **ptr, const char *fname) | static int ReadPhFile(char **ptr, const char *fname) | ||||
{//================================================= | {//================================================= | ||||
} | } | ||||
int LookupPh(const char *string) | |||||
{//============================= | |||||
int PhonemeCode(unsigned int mnem) | |||||
{//=============================== | |||||
int ix; | |||||
for(ix=0; ix<n_phoneme_tab; ix++) | |||||
{ | |||||
if(phoneme_tab[ix] == NULL) | |||||
continue; | |||||
if(phoneme_tab[ix]->mnemonic == mnem) | |||||
return(phoneme_tab[ix]->code); | |||||
} | |||||
return(0); | |||||
} | |||||
int LookupPhonemeString(const char *string) | |||||
{//======================================== | |||||
int ix; | int ix; | ||||
unsigned char c; | unsigned char c; | ||||
unsigned int mnem; | unsigned int mnem; | ||||
mnem |= (c << (ix*8)); | mnem |= (c << (ix*8)); | ||||
} | } | ||||
for(ix=0; ix<n_phoneme_tab; ix++) | |||||
{ | |||||
if(phoneme_tab[ix] == NULL) | |||||
continue; | |||||
if(phoneme_tab[ix]->mnemonic == mnem) | |||||
return(ix); | |||||
} | |||||
return(0); | |||||
return(PhonemeCode(mnem)); | |||||
} | } | ||||
static unsigned int LookupSound2(int index, unsigned int other_phcode, int control) | static unsigned int LookupSound2(int index, unsigned int other_phcode, int control) | ||||
{//================================================================================ | {//================================================================================ | ||||
// control=1 get formant transition data only | // control=1 get formant transition data only | ||||
if(*match_level == 0) | if(*match_level == 0) | ||||
seq_len_adjust = FormantTransition2(frames,nf,vowel_transition0,vowel_transition1,prev_ph,which); | seq_len_adjust = FormantTransition2(frames,nf,vowel_transition0,vowel_transition1,prev_ph,which); | ||||
} | } | ||||
// FormantTransitions(frames,nf,this_ph,other_ph,which); | |||||
} | } | ||||
nf1 = nf - 1; | nf1 = nf - 1; |
} | } | ||||
void SynthesizeInit() | void SynthesizeInit() | ||||
{//================== | {//================== | ||||
last_pitch_cmd = 0; | last_pitch_cmd = 0; | ||||
} | } | ||||
int VowelCloseness(frame_t *fr) | |||||
{//============================ | |||||
static int VowelCloseness(frame_t *fr) | |||||
{//=================================== | |||||
// return a value 0-3 depending on the vowel's f1 | // return a value 0-3 depending on the vowel's f1 | ||||
int f1; | int f1; | ||||
} | } | ||||
void SwitchDictionary() | |||||
{//==================== | |||||
} | |||||
int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume) | ||||
{//============================================================ | {//============================================================ | ||||
// read the next clause from the input text file, translate it, and generate | // read the next clause from the input text file, translate it, and generate | ||||
// entries in the wavegen command queue | // entries in the wavegen command queue | ||||
p_text = translator->TranslateClause(f_text,p_text,&clause_tone,&voice_change); | |||||
p_text = TranslateClause(translator, f_text, p_text, &clause_tone, &voice_change); | |||||
translator->CalcPitches(clause_tone); | |||||
translator->CalcLengths(); | |||||
CalcPitches(translator, clause_tone); | |||||
CalcLengths(translator); | |||||
translator->GetTranslatedPhonemeString(translator->phon_out,sizeof(translator->phon_out)); | |||||
GetTranslatedPhonemeString(translator->phon_out,sizeof(translator->phon_out)); | |||||
if(option_phonemes > 0) | if(option_phonemes > 0) | ||||
{ | { | ||||
fprintf(f_trans,"%s\n",translator->phon_out); | fprintf(f_trans,"%s\n",translator->phon_out); |
espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int srate); | ||||
void SetParameter(int parameter, int value, int relative); | void SetParameter(int parameter, int value, int relative); | ||||
void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola); | void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola); | ||||
int MbrolaSynth(char *p_mbrola); | |||||
//int MbrolaSynth(char *p_mbrola); | |||||
int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp); | int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp); | ||||
int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph, | int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph, | ||||
int which, PHONEME_LIST *plist, int modulation); | int which, PHONEME_LIST *plist, int modulation); |
#include "StdAfx.h" | #include "StdAfx.h" | ||||
#include <stdio.h> | |||||
#include <ctype.h> | |||||
#include <wctype.h> | |||||
#include <stdlib.h> | |||||
#include <string.h> | |||||
#include <locale.h> | |||||
#include "speak_lib.h" | |||||
#include "speech.h" | |||||
#include "phoneme.h" | |||||
#include "synthesize.h" | |||||
#include "translate.h" | |||||
#include "tr_languages.h" | |||||
Translator_English::Translator_English() : Translator() | |||||
{//=================================== | |||||
// static int stress_lengths2[8] = {182,140, 220,220, 220,240, 248,270}; | |||||
static const short stress_lengths2[8] = {182,140, 220,220, 0,0, 248,275}; | |||||
memcpy(stress_lengths,stress_lengths2,sizeof(stress_lengths)); | |||||
langopts.stress_rule = 0; | |||||
langopts.numbers = 0x841 + NUM_ROMAN; | |||||
langopts.param[LOPT_COMBINE_WORDS] = 2; // allow "mc" to cmbine with the following word | |||||
} | |||||
static unsigned char initials_bitmap[86] = { | |||||
0x00, 0x00, 0x00, 0x00, 0x22, 0x08, 0x00, 0x88, // 0 | |||||
0x20, 0x24, 0x20, 0x80, 0x10, 0x00, 0x00, 0x00, | |||||
0x00, 0x28, 0x08, 0x00, 0x88, 0x22, 0x04, 0x00, // 16 | |||||
0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x88, 0x22, 0x04, 0x00, 0x02, 0x00, 0x04, // 32 | |||||
0x20, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, | |||||
0x00, 0x28, 0x8a, 0x03, 0x00, 0x00, 0x40, 0x00, // 48 | |||||
0x02, 0x00, 0x41, 0xca, 0x9b, 0x06, 0x20, 0x80, | |||||
0x91, 0x00, 0x00, 0x00, 0x00, 0x20, 0x08, 0x00, // 64 | |||||
0x08, 0x20, 0x00, 0x00, 0x04, 0x00, 0x00, 0x00, | |||||
0x00, 0x00, 0x22, 0x00, 0x01, 0x00, }; | |||||
int Translator_English::Unpronouncable(char *word) | |||||
{//=============================================== | |||||
/* Determines whether a word in 'unpronouncable', i.e. whether it should | |||||
be spoken as individual letters. | |||||
This function is language specific. | |||||
*/ | |||||
int c; | |||||
int vowel_posn=9; | |||||
int index; | |||||
int count; | |||||
int ix; | |||||
int apostrophe=0; | |||||
// words which we pass through to the dictionary, even though they look unpronouncable | |||||
static const char *exceptions[] = { | |||||
"'s ", "st ","nd ","rd ","th ",NULL }; | |||||
if((*word == ' ') || (*word == 0)) | |||||
return(0); | |||||
for(ix=0; exceptions[ix] != NULL; ix++) | |||||
{ | |||||
// Seemingly uncpronouncable words, but to be looked in the dictionary rules instead | |||||
if(memcmp(word,exceptions[ix],3)==0) | |||||
return(0); | |||||
} | |||||
index=0; | |||||
count=0; | |||||
for(;;) | |||||
{ | |||||
index += utf8_in(&c,&word[index],0); | |||||
count++; | |||||
if((c==0) || (c==' ')) | |||||
break; | |||||
if(IsVowel(c) || (c == 'y')) | |||||
{ | |||||
vowel_posn = count; | |||||
break; | |||||
} | |||||
if(c == '\'') | |||||
apostrophe = 1; | |||||
else | |||||
if(!IsAlpha(c)) | |||||
return(0); // letter (not vowel) outside Latin character range or apostrophe, abort test | |||||
} | |||||
if((vowel_posn > 5) || ((word[0]!='s') && (vowel_posn > 4))) | |||||
return(1); // no vowel, or no vowel in first four letters | |||||
/* there is at least one vowel, is the initial letter combination valid ? */ | |||||
if(vowel_posn < 3) | |||||
return(0); /* vowel in first two letters, OK */ | |||||
if(apostrophe) | |||||
return(0); // first two letters not a-z, abort test | |||||
index = (word[0]-'a') * 26 + (word[1]-'a'); | |||||
if(initials_bitmap[index >> 3] & (1L << (index & 7))) | |||||
return(0); | |||||
else | |||||
return(1); /****/ | |||||
} /* end of Unpronounceable */ | |||||
#include "phoneme.h" | #include "phoneme.h" | ||||
#include "synthesize.h" | #include "synthesize.h" | ||||
#include "translate.h" | #include "translate.h" | ||||
#include "tr_languages.h" | |||||
#define OFFSET_MALAYALAM 0xd00 | #define OFFSET_MALAYALAM 0xd00 | ||||
#define OFFSET_KOREAN 0x1100 | #define OFFSET_KOREAN 0x1100 | ||||
static void Translator_Russian(Translator *tr); | |||||
static void SetLetterVowel(Translator *tr, int c) | |||||
{//============================================== | |||||
tr->letter_bits[c] = (tr->letter_bits[c] & 0x40) | 0x81; // keep value for group 6 (front vowels e,i,y) | |||||
} | |||||
static void ResetLetterBits(Translator *tr, int groups) | |||||
{//==================================================== | |||||
// Clear all the specified groups | |||||
unsigned int ix; | |||||
unsigned int mask; | |||||
mask = ~groups; | |||||
for(ix=0; ix<sizeof(tr->letter_bits); ix++) | |||||
{ | |||||
tr->letter_bits[ix] &= mask; | |||||
} | |||||
} | |||||
static void SetLetterBits(Translator *tr, int group, const char *string) | |||||
{//===================================================================== | |||||
int bits; | |||||
unsigned char c; | |||||
bits = (1L << group); | |||||
while((c = *string++) != 0) | |||||
tr->letter_bits[c] |= bits; | |||||
} | |||||
static void SetLetterBitsRange(Translator *tr, int group, int first, int last) | |||||
{//=========================================================================== | |||||
int bits; | |||||
int ix; | |||||
bits = (1L << group); | |||||
for(ix=first; ix<=last; ix++) | |||||
{ | |||||
tr->letter_bits[ix] |= bits; | |||||
} | |||||
} | |||||
static Translator* NewTranslator(void) | |||||
{//=================================== | |||||
Translator *tr; | |||||
int ix; | |||||
static const unsigned char stress_amps2[] = {17,17, 20,20, 20,22, 22,20 }; | |||||
static const short stress_lengths2[8] = {182,140, 220,220, 220,240, 260,280}; | |||||
static const wchar_t empty_wstring[1] = {0}; | |||||
static const wchar_t punct_in_word[2] = {'\'', 0}; // allow hyphen within words | |||||
tr = (Translator *)Alloc(sizeof(Translator)); | |||||
if(tr == NULL) | |||||
return(NULL); | |||||
tr->charset_a0 = charsets[1]; // ISO-8859-1, this is for when the input is not utf8 | |||||
dictionary_name[0] = 0; | |||||
tr->dict_condition=0; | |||||
tr->data_dictrules = NULL; // language_1 translation rules file | |||||
tr->data_dictlist = NULL; // language_2 dictionary lookup file | |||||
tr->transpose_offset = 0; | |||||
// only need lower case | |||||
tr->letter_bits_offset = 0; | |||||
memset(tr->letter_bits,0,sizeof(tr->letter_bits)); | |||||
memset(tr->letter_groups,0,sizeof(tr->letter_groups)); | |||||
// 0-5 sets of characters matched by A B C E F G in pronunciation rules | |||||
// these may be set differently for different languages | |||||
SetLetterBits(tr,0,"aeiou"); // A vowels, except y | |||||
SetLetterBits(tr,1,"bcdfgjklmnpqstvxz"); // B hard consonants, excluding h,r,w | |||||
SetLetterBits(tr,2,"bcdfghjklmnpqrstvwxz"); // C all consonants | |||||
SetLetterBits(tr,3,"hlmnr"); // H 'soft' consonants | |||||
SetLetterBits(tr,4,"cfhkpqstx"); // F voiceless consonants | |||||
SetLetterBits(tr,5,"bdgjlmnrvwyz"); // G voiced | |||||
SetLetterBits(tr,6,"eiy"); // Letter group Y, front vowels | |||||
SetLetterBits(tr,7,"aeiouy"); // vowels, including y | |||||
tr->char_plus_apostrophe = empty_wstring; | |||||
tr->punct_within_word = punct_in_word; | |||||
for(ix=0; ix<8; ix++) | |||||
{ | |||||
tr->stress_amps[ix] = stress_amps2[ix]; | |||||
tr->stress_amps_r[ix] = stress_amps2[ix] - 1; | |||||
tr->stress_lengths[ix] = stress_lengths2[ix]; | |||||
} | |||||
memset(&(tr->langopts),0,sizeof(tr->langopts)); | |||||
tr->langopts.stress_rule = 2; | |||||
tr->langopts.unstressed_wd1 = 1; | |||||
tr->langopts.unstressed_wd2 = 3; | |||||
tr->langopts.param[LOPT_SONORANT_MIN] = 95; | |||||
tr->langopts.param[LOPT_MAXAMP_EOC] = 19; | |||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 's'; // don't count this character at start of word | |||||
tr->langopts.max_initial_consonants = 3; | |||||
tr->langopts.replace_chars = NULL; | |||||
SetLengthMods(tr,201); | |||||
// tr->langopts.length_mods = length_mods_en; | |||||
// tr->langopts.length_mods0 = length_mods_en0; | |||||
tr->langopts.long_stop = 100; | |||||
tr->langopts.max_roman = 49; | |||||
tr->langopts.thousands_sep = ','; | |||||
tr->langopts.decimal_sep = '.'; | |||||
memcpy(tr->punct_to_tone, punctuation_to_tone, sizeof(tr->punct_to_tone)); | |||||
return(tr); | |||||
} | |||||
static const unsigned int replace_cyrillic_latin[] = | static const unsigned int replace_cyrillic_latin[] = | ||||
{0x430,'a', | {0x430,'a', | ||||
while(*name != 0) | while(*name != 0) | ||||
name2 = (name2 << 8) + *name++; | name2 = (name2 << 8) + *name++; | ||||
tr = NewTranslator(); | |||||
switch(name2) | switch(name2) | ||||
{ | { | ||||
case L('a','f'): | case L('a','f'): | ||||
{ | { | ||||
static const short stress_lengths_af[8] = {170,140, 220,220, 0, 0, 250,270}; | static const short stress_lengths_af[8] = {170,140, 220,220, 0, 0, 250,270}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_af,NULL); | SetupTranslator(tr,stress_lengths_af,NULL); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
static const short stress_lengths_bn[8] = {180, 180, 210, 210, 0, 0, 230, 240}; | static const short stress_lengths_bn[8] = {180, 180, 210, 210, 0, 0, 230, 240}; | ||||
static const unsigned char stress_amps_bn[8] = {18,18, 18,18, 20,20, 22,22 }; | static const unsigned char stress_amps_bn[8] = {18,18, 18,18, 20,20, 22,22 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_bn,stress_amps_bn); | SetupTranslator(tr,stress_lengths_bn,stress_amps_bn); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_cy[8] = {170,220, 180,180, 0, 0, 250,270}; | static const short stress_lengths_cy[8] = {170,220, 180,180, 0, 0, 250,270}; | ||||
static const unsigned char stress_amps_cy[8] = {17,15, 18,18, 0,0, 22,20 }; // 'diminished' is used to mark a quieter, final unstressed syllable | static const unsigned char stress_amps_cy[8] = {17,15, 18,18, 0,0, 22,20 }; // 'diminished' is used to mark a quieter, final unstressed syllable | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_cy,stress_amps_cy); | SetupTranslator(tr,stress_lengths_cy,stress_amps_cy); | ||||
tr->charset_a0 = charsets[14]; // ISO-8859-14 | tr->charset_a0 = charsets[14]; // ISO-8859-14 | ||||
case L('d','a'): // Danish | case L('d','a'): // Danish | ||||
{ | { | ||||
static const short stress_lengths_da[8] = {160,140, 200,200, 0,0, 220,210}; | static const short stress_lengths_da[8] = {160,140, 200,200, 0,0, 220,210}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_da,NULL); | SetupTranslator(tr,stress_lengths_da,NULL); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
case L('d','e'): | case L('d','e'): | ||||
{ | { | ||||
static const short stress_lengths_de[8] = {150,130, 190,190, 0, 0, 260,275}; | static const short stress_lengths_de[8] = {150,130, 190,190, 0, 0, 260,275}; | ||||
tr = new Translator(); | |||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
tr->langopts.word_gap = 0x8; // don't use linking phonemes | tr->langopts.word_gap = 0x8; // don't use linking phonemes | ||||
tr->langopts.vowel_pause = 0x30; | tr->langopts.vowel_pause = 0x30; | ||||
break; | break; | ||||
case L('e','n'): | case L('e','n'): | ||||
tr = new Translator_English(); | |||||
{ | |||||
static const short stress_lengths_en[8] = {182,140, 220,220, 0,0, 248,275}; | |||||
SetupTranslator(tr,stress_lengths_en,NULL); | |||||
tr->langopts.stress_rule = 0; | |||||
tr->langopts.numbers = 0x841 + NUM_ROMAN; | |||||
tr->langopts.param[LOPT_COMBINE_WORDS] = 2; // allow "mc" to cmbine with the following word | |||||
} | |||||
break; | break; | ||||
case L('e','l'): // Greek | case L('e','l'): // Greek | ||||
static const char el_consonants[]={0x32,0x33,0x34,0x36,0x38,0x3a,0x3b,0x3c,0x3d,0x3e,0x40,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0}; | static const char el_consonants[]={0x32,0x33,0x34,0x36,0x38,0x3a,0x3b,0x3c,0x3d,0x3e,0x40,0x41,0x42,0x43,0x44,0x46,0x47,0x48,0}; | ||||
static const wchar_t el_char_apostrophe[] = {0x3c3,0}; // σ | static const wchar_t el_char_apostrophe[] = {0x3c3,0}; // σ | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_el,stress_amps_el); | SetupTranslator(tr,stress_lengths_el,stress_amps_el); | ||||
tr->charset_a0 = charsets[7]; // ISO-8859-7 | tr->charset_a0 = charsets[7]; // ISO-8859-7 | ||||
static const unsigned char stress_amps_eo[] = {16,14, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_eo[] = {16,14, 20,20, 20,22, 22,21 }; | ||||
static const wchar_t eo_char_apostrophe[2] = {'l',0}; | static const wchar_t eo_char_apostrophe[2] = {'l',0}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_eo,stress_amps_eo); | SetupTranslator(tr,stress_lengths_eo,stress_amps_eo); | ||||
tr->charset_a0 = charsets[3]; // ISO-8859-3 | tr->charset_a0 = charsets[3]; // ISO-8859-3 | ||||
static const unsigned char stress_amps_es[8] = {16,12, 18,18, 20,20, 20,20 }; // 'diminished' is used to mark a quieter, final unstressed syllable | static const unsigned char stress_amps_es[8] = {16,12, 18,18, 20,20, 20,20 }; // 'diminished' is used to mark a quieter, final unstressed syllable | ||||
static const wchar_t ca_punct_within_word[] = {'\'',0xb7,0}; // ca: allow middle-dot within word | static const wchar_t ca_punct_within_word[] = {'\'',0xb7,0}; // ca: allow middle-dot within word | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_es,stress_amps_es); | SetupTranslator(tr,stress_lengths_es,stress_amps_es); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const unsigned char stress_amps_fi[8] = {18,16, 22,22, 20,22, 22,22 }; | static const unsigned char stress_amps_fi[8] = {18,16, 22,22, 20,22, 22,22 }; | ||||
static const short stress_lengths_fi[8] = {150,180, 200,200, 0,0, 210,250}; | static const short stress_lengths_fi[8] = {150,180, 200,200, 0,0, 210,250}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_fi,stress_amps_fi); | SetupTranslator(tr,stress_lengths_fi,stress_amps_fi); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
static const short stress_lengths_fr[8] = {190, 170, 190, 200, 0, 0, 235, 240}; | static const short stress_lengths_fr[8] = {190, 170, 190, 200, 0, 0, 235, 240}; | ||||
static const unsigned char stress_amps_fr[8] = {18,16, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_fr[8] = {18,16, 20,20, 20,22, 22,21 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_fr,stress_amps_fr); | SetupTranslator(tr,stress_lengths_fr,stress_amps_fr); | ||||
tr->langopts.stress_rule = 3; // stress on final syllable | tr->langopts.stress_rule = 3; // stress on final syllable | ||||
tr->langopts.stress_flags = 0x0024; // don't use secondary stress | tr->langopts.stress_flags = 0x0024; // don't use secondary stress | ||||
#ifdef deleted | #ifdef deleted | ||||
case L('g','a'): // Irish Gaelic | case L('g','a'): // Irish Gaelic | ||||
{ | { | ||||
tr = new Translator(); | |||||
tr->langopts.stress_rule = 1; | tr->langopts.stress_rule = 1; | ||||
} | } | ||||
break; | break; | ||||
static const short stress_lengths_hi[8] = {190, 190, 210, 210, 0, 0, 230, 250}; | static const short stress_lengths_hi[8] = {190, 190, 210, 210, 0, 0, 230, 250}; | ||||
static const unsigned char stress_amps_hi[8] = {17,14, 20,19, 20,22, 22,21 }; | static const unsigned char stress_amps_hi[8] = {17,14, 20,19, 20,22, 22,21 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_hi,stress_amps_hi); | SetupTranslator(tr,stress_lengths_hi,stress_amps_hi); | ||||
tr->charset_a0 = charsets[19]; // ISCII | tr->charset_a0 = charsets[19]; // ISCII | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_hr[8] = {180,160, 200,200, 0,0, 220,230}; | static const short stress_lengths_hr[8] = {180,160, 200,200, 0,0, 220,230}; | ||||
static const short stress_lengths_sr[8] = {160,150, 200,200, 0,0, 250,260}; | static const short stress_lengths_sr[8] = {160,150, 200,200, 0,0, 250,260}; | ||||
tr = new Translator(); | |||||
if(name2 == L('s','r')) | if(name2 == L('s','r')) | ||||
SetupTranslator(tr,stress_lengths_sr,stress_amps_hr); | SetupTranslator(tr,stress_lengths_sr,stress_amps_hr); | ||||
else | else | ||||
static const unsigned char stress_amps_hu[8] = {17,17, 19,19, 20,22, 22,21 }; | static const unsigned char stress_amps_hu[8] = {17,17, 19,19, 20,22, 22,21 }; | ||||
static const short stress_lengths_hu[8] = {185,195, 195,190, 0,0, 210,220}; | static const short stress_lengths_hu[8] = {185,195, 195,190, 0,0, 210,220}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_hu,stress_amps_hu); | SetupTranslator(tr,stress_lengths_hu,stress_amps_hu); | ||||
tr->charset_a0 = charsets[2]; // ISO-8859-2 | tr->charset_a0 = charsets[2]; // ISO-8859-2 | ||||
static const char hy_vowels[] = {0x31, 0x35, 0x37, 0x38, 0x3b, 0x48, 0x55, 0}; | static const char hy_vowels[] = {0x31, 0x35, 0x37, 0x38, 0x3b, 0x48, 0x55, 0}; | ||||
static const char hy_consonants[] = {0x32,0x33,0x34,0x36,0x39,0x3a,0x3c,0x3d,0x3e,0x3f, | static const char hy_consonants[] = {0x32,0x33,0x34,0x36,0x39,0x3a,0x3c,0x3d,0x3e,0x3f, | ||||
0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x56,0}; | 0x40,0x41,0x42,0x43,0x44,0x45,0x46,0x47,0x49,0x4a,0x4b,0x4c,0x4d,0x4e,0x4f,0x50,0x51,0x52,0x53,0x54,0x56,0}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_hy,NULL); | SetupTranslator(tr,stress_lengths_hy,NULL); | ||||
tr->langopts.stress_rule = 3; // default stress on final syllable | tr->langopts.stress_rule = 3; // default stress on final syllable | ||||
{ | { | ||||
static const short stress_lengths_id[8] = {160, 200, 180, 180, 0, 0, 220, 240}; | static const short stress_lengths_id[8] = {160, 200, 180, 180, 0, 0, 220, 240}; | ||||
static const unsigned char stress_amps_id[8] = {16,18, 18,18, 20,22, 22,21 }; | static const unsigned char stress_amps_id[8] = {16,18, 18,18, 20,22, 22,21 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_id,stress_amps_id); | SetupTranslator(tr,stress_lengths_id,stress_amps_id); | ||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
tr->langopts.numbers = 0x1009 + NUM_ROMAN; | tr->langopts.numbers = 0x1009 + NUM_ROMAN; | ||||
static const short stress_lengths_is[8] = {180,160, 200,200, 0,0, 240,250}; | static const short stress_lengths_is[8] = {180,160, 200,200, 0,0, 240,250}; | ||||
static const wchar_t is_lettergroup_B[] = {'c','f','h','k','p','t','x',0xfe,0}; // voiceless conants, including 'þ' ?? 's' | static const wchar_t is_lettergroup_B[] = {'c','f','h','k','p','t','x',0xfe,0}; // voiceless conants, including 'þ' ?? 's' | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_is,NULL); | SetupTranslator(tr,stress_lengths_is,NULL); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
tr->langopts.stress_flags = 0x10; | tr->langopts.stress_flags = 0x10; | ||||
static const short stress_lengths_it[8] = {150, 140, 170, 170, 0, 0, 300, 330}; | static const short stress_lengths_it[8] = {150, 140, 170, 170, 0, 0, 300, 330}; | ||||
static const unsigned char stress_amps_it[8] = {15,14, 19,19, 20,22, 22,20 }; | static const unsigned char stress_amps_it[8] = {15,14, 19,19, 20,22, 22,20 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_it,stress_amps_it); | SetupTranslator(tr,stress_lengths_it,stress_amps_it); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
} | } | ||||
break; | break; | ||||
case L('j','a'): // TEST | |||||
tr = new Translator(); | |||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 1; // disable check for unpronouncable words | |||||
break; | |||||
case L_jbo: // Lojban | case L_jbo: // Lojban | ||||
{ | { | ||||
static const short stress_lengths_jbo[8] = {145,145, 170,160, 0,0, 330,350}; | static const short stress_lengths_jbo[8] = {145,145, 170,160, 0,0, 330,350}; | ||||
static const wchar_t jbo_punct_within_word[] = {'.',',','\'',0x2c8,0}; // allow period and comma within a word, also stress marker (from LOPT_SYLLABLE_CAPS) | static const wchar_t jbo_punct_within_word[] = {'.',',','\'',0x2c8,0}; // allow period and comma within a word, also stress marker (from LOPT_SYLLABLE_CAPS) | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_jbo,NULL); | SetupTranslator(tr,stress_lengths_jbo,NULL); | ||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
tr->langopts.vowel_pause = 0x20c; // pause before a word which starts with a vowel, or after a word which ends in a consonant | tr->langopts.vowel_pause = 0x20c; // pause before a word which starts with a vowel, or after a word which ends in a consonant | ||||
{ | { | ||||
static const char ko_ivowels[] = {0x63,0x64,0x67,0x68,0x6d,0x72,0x74,0x75,0}; // y and i vowels | static const char ko_ivowels[] = {0x63,0x64,0x67,0x68,0x6d,0x72,0x74,0x75,0}; // y and i vowels | ||||
static const char ko_voiced[] = {0x02,0x05,0x06,0xab,0xaf,0xb7,0xbc,0}; // voiced consonants, l,m,n,N | static const char ko_voiced[] = {0x02,0x05,0x06,0xab,0xaf,0xb7,0xbc,0}; // voiced consonants, l,m,n,N | ||||
tr = new Translator(); | |||||
tr->letter_bits_offset = OFFSET_KOREAN; | tr->letter_bits_offset = OFFSET_KOREAN; | ||||
memset(tr->letter_bits,0,sizeof(tr->letter_bits)); | memset(tr->letter_bits,0,sizeof(tr->letter_bits)); | ||||
static const unsigned char stress_amps_ku[8] = {18,18, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_ku[8] = {18,18, 20,20, 20,22, 22,21 }; | ||||
static const short stress_lengths_ku[8] = {180,180, 190,180, 0,0, 230,240}; | static const short stress_lengths_ku[8] = {180,180, 190,180, 0,0, 230,240}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_ku,stress_amps_ku); | SetupTranslator(tr,stress_lengths_ku,stress_amps_ku); | ||||
tr->charset_a0 = charsets[9]; // ISO-8859-9 - Latin5 | tr->charset_a0 = charsets[9]; // ISO-8859-9 - Latin5 | ||||
case L('l','a'): //Latin | case L('l','a'): //Latin | ||||
{ | { | ||||
tr = new Translator(); | |||||
tr->charset_a0 = charsets[4]; // ISO-8859-4, includes a,e,i,o,u-macron | tr->charset_a0 = charsets[4]; // ISO-8859-4, includes a,e,i,o,u-macron | ||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
tr->langopts.stress_flags = 0x20; | tr->langopts.stress_flags = 0x20; | ||||
{ | { | ||||
static const unsigned char stress_amps_lv[8] = {17,13, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_lv[8] = {17,13, 20,20, 20,22, 22,21 }; | ||||
static const short stress_lengths_lv[8] = {180,130, 210,210, 0,0, 210,210}; | static const short stress_lengths_lv[8] = {180,130, 210,210, 0,0, 210,210}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_lv,stress_amps_lv); | SetupTranslator(tr,stress_lengths_lv,stress_amps_lv); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
static const unsigned char stress_amps_mk[8] = {17,17, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_mk[8] = {17,17, 20,20, 20,22, 22,21 }; | ||||
static const short stress_lengths_mk[8] = {180,160, 200,200, 0,0, 220,230}; | static const short stress_lengths_mk[8] = {180,160, 200,200, 0,0, 220,230}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_mk,stress_amps_mk); | SetupTranslator(tr,stress_lengths_mk,stress_amps_mk); | ||||
tr->charset_a0 = charsets[5]; // ISO-8859-5 | tr->charset_a0 = charsets[5]; // ISO-8859-5 | ||||
tr->letter_groups[0] = vowels_cyrillic; | tr->letter_groups[0] = vowels_cyrillic; | ||||
case L('n','l'): // Dutch | case L('n','l'): // Dutch | ||||
{ | { | ||||
static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; | static const short stress_lengths_nl[8] = {160,135, 210,210, 0, 0, 260,280}; | ||||
tr = new Translator(); | |||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
tr->langopts.vowel_pause = 1; | tr->langopts.vowel_pause = 1; | ||||
case L('n','o'): // Norwegian | case L('n','o'): // Norwegian | ||||
{ | { | ||||
static const short stress_lengths_no[8] = {160,140, 200,200, 0,0, 220,210}; | static const short stress_lengths_no[8] = {160,140, 200,200, 0,0, 220,210}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_no,NULL); | |||||
SetupTranslator(tr,stress_lengths_no,NULL); | |||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
SetLetterVowel(tr,'y'); | SetLetterVowel(tr,'y'); | ||||
tr->langopts.numbers = 0x11849; | tr->langopts.numbers = 0x11849; | ||||
{ | { | ||||
static const unsigned char stress_amps_om[] = {18,15, 20,20, 20,22, 22,22 }; | static const unsigned char stress_amps_om[] = {18,15, 20,20, 20,22, 22,22 }; | ||||
static const short stress_lengths_om[8] = {200,200, 200,200, 0,0, 200,200}; | static const short stress_lengths_om[8] = {200,200, 200,200, 0,0, 200,200}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_om,stress_amps_om); | |||||
SetupTranslator(tr,stress_lengths_om,stress_amps_om); | |||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
tr->langopts.stress_flags = 0x16 + 0x80000; | tr->langopts.stress_flags = 0x16 + 0x80000; | ||||
} | } | ||||
static const short stress_lengths_pl[8] = {160, 190, 175, 175, 0, 0, 200, 210}; | static const short stress_lengths_pl[8] = {160, 190, 175, 175, 0, 0, 200, 210}; | ||||
static const unsigned char stress_amps_pl[8] = {17,13, 19,19, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable | static const unsigned char stress_amps_pl[8] = {17,13, 19,19, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_pl,stress_amps_pl); | SetupTranslator(tr,stress_lengths_pl,stress_amps_pl); | ||||
tr->charset_a0 = charsets[2]; // ISO-8859-2 | tr->charset_a0 = charsets[2]; // ISO-8859-2 | ||||
{ | { | ||||
static const short stress_lengths_pt[8] = {180, 125, 210, 210, 0, 0, 270, 295}; | static const short stress_lengths_pt[8] = {180, 125, 210, 210, 0, 0, 270, 295}; | ||||
static const unsigned char stress_amps_pt[8] = {16,13, 19,19, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable | static const unsigned char stress_amps_pt[8] = {16,13, 19,19, 20,22, 22,21 }; // 'diminished' is used to mark a quieter, final unstressed syllable | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_pt,stress_amps_pt); | SetupTranslator(tr,stress_lengths_pt,stress_amps_pt); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_ro[8] = {170, 170, 180, 180, 0, 0, 240, 260}; | static const short stress_lengths_ro[8] = {170, 170, 180, 180, 0, 0, 240, 260}; | ||||
static const unsigned char stress_amps_ro[8] = {15,13, 18,18, 20,22, 22,21 }; | static const unsigned char stress_amps_ro[8] = {15,13, 18,18, 20,22, 22,21 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_ro,stress_amps_ro); | SetupTranslator(tr,stress_lengths_ro,stress_amps_ro); | ||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
break; | break; | ||||
case L('r','u'): // Russian | case L('r','u'): // Russian | ||||
tr = new Translator_Russian(); | |||||
Translator_Russian(tr); | |||||
break; | break; | ||||
case L('r','w'): // Kiryarwanda | case L('r','w'): // Kiryarwanda | ||||
{ | { | ||||
tr = new Translator(); | |||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
tr->langopts.stress_flags = 0x16; | tr->langopts.stress_flags = 0x16; | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
{ | { | ||||
static const char *sk_voiced = "bdgjlmnrvwzaeiouy"; | static const char *sk_voiced = "bdgjlmnrvwzaeiouy"; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_sk,stress_amps_sk); | SetupTranslator(tr,stress_lengths_sk,stress_amps_sk); | ||||
tr->charset_a0 = charsets[2]; // ISO-8859-2 | tr->charset_a0 = charsets[2]; // ISO-8859-2 | ||||
{ | { | ||||
static const short stress_lengths_sq[8] = {150, 150, 180, 180, 0, 0, 300, 300}; | static const short stress_lengths_sq[8] = {150, 150, 180, 180, 0, 0, 300, 300}; | ||||
static const unsigned char stress_amps_sq[8] = {16,12, 16,16, 20,20, 21,19 }; | static const unsigned char stress_amps_sq[8] = {16,12, 16,16, 20,20, 21,19 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_sq,stress_amps_sq); | SetupTranslator(tr,stress_lengths_sq,stress_amps_sq); | ||||
tr->langopts.stress_rule = 2; | tr->langopts.stress_rule = 2; | ||||
{ | { | ||||
static const unsigned char stress_amps_sv[] = {16,16, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_sv[] = {16,16, 20,20, 20,22, 22,21 }; | ||||
static const short stress_lengths_sv[8] = {160,135, 220,220, 0,0, 250,280}; | static const short stress_lengths_sv[8] = {160,135, 220,220, 0,0, 250,280}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_sv,stress_amps_sv); | SetupTranslator(tr,stress_lengths_sv,stress_amps_sv); | ||||
tr->langopts.stress_rule = 0; | tr->langopts.stress_rule = 0; | ||||
SetLetterVowel(tr,'y'); | SetLetterVowel(tr,'y'); | ||||
// SetLetterBits(tr,6,"eiyäö"); // soft vowels NOTE accented letters don't work in SetLetterBits | |||||
tr->langopts.numbers = 0x1909; | tr->langopts.numbers = 0x1909; | ||||
tr->langopts.accents = 1; | tr->langopts.accents = 1; | ||||
} | } | ||||
{ | { | ||||
static const short stress_lengths_sw[8] = {160, 170, 200, 200, 0, 0, 320, 340}; | static const short stress_lengths_sw[8] = {160, 170, 200, 200, 0, 0, 320, 340}; | ||||
static const unsigned char stress_amps_sw[] = {16,12, 19,19, 20,22, 22,21 }; | static const unsigned char stress_amps_sw[] = {16,12, 19,19, 20,22, 22,21 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_sw,stress_amps_sw); | SetupTranslator(tr,stress_lengths_sw,stress_amps_sw); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_ta[8] = {200, 200, 210, 210, 0, 0, 230, 230}; | static const short stress_lengths_ta[8] = {200, 200, 210, 210, 0, 0, 230, 230}; | ||||
static const unsigned char stress_amps_ta[8] = {18,18, 18,18, 20,20, 22,22 }; | static const unsigned char stress_amps_ta[8] = {18,18, 18,18, 20,20, 22,22 }; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_ta,stress_amps_ta); | SetupTranslator(tr,stress_lengths_ta,stress_amps_ta); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_th[8] = {230,150, 230,230, 230,0, 230,250}; | static const short stress_lengths_th[8] = {230,150, 230,230, 230,0, 230,250}; | ||||
static const unsigned char stress_amps_th[] = {22,16, 22,22, 22,22, 22,22 }; | static const unsigned char stress_amps_th[] = {22,16, 22,22, 22,22, 22,22 }; | ||||
tr = new Translator; | |||||
SetupTranslator(tr,stress_lengths_th,stress_amps_th); | SetupTranslator(tr,stress_lengths_th,stress_amps_th); | ||||
tr->langopts.stress_rule = 0; // stress on final syllable of a "word" | tr->langopts.stress_rule = 0; // stress on final syllable of a "word" | ||||
static const unsigned char stress_amps_tr[8] = {18,18, 20,20, 20,22, 22,21 }; | static const unsigned char stress_amps_tr[8] = {18,18, 20,20, 20,22, 22,21 }; | ||||
static const short stress_lengths_tr[8] = {190,190, 190,190, 0,0, 250,270}; | static const short stress_lengths_tr[8] = {190,190, 190,190, 0,0, 250,270}; | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_tr,stress_amps_tr); | SetupTranslator(tr,stress_lengths_tr,stress_amps_tr); | ||||
tr->charset_a0 = charsets[9]; // ISO-8859-9 - Latin5 | tr->charset_a0 = charsets[9]; // ISO-8859-9 - Latin5 | ||||
0x1b0, 0x1eeb, 0x1ee9, 0x1eed, 0x1eef, 0x1ef1, // ư | 0x1b0, 0x1eeb, 0x1ee9, 0x1eed, 0x1eef, 0x1ef1, // ư | ||||
0x79, 0x1ef3, 0xfd, 0x1ef7, 0x1ef9, 0x1e, 0 }; // y | 0x79, 0x1ef3, 0xfd, 0x1ef7, 0x1ef9, 0x1e, 0 }; // y | ||||
tr = new Translator(); | |||||
SetupTranslator(tr,stress_lengths_vi,stress_amps_vi); | SetupTranslator(tr,stress_lengths_vi,stress_amps_vi); | ||||
tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | tr->langopts.length_mods0 = tr->langopts.length_mods; // don't lengthen vowels in the last syllable | ||||
static const short stress_lengths_zh[8] = {230,150, 230,230, 230,0, 240,250}; // 1=tone5. end-of-sentence, 6=tone 1&4, 7=tone 2&3 | static const short stress_lengths_zh[8] = {230,150, 230,230, 230,0, 240,250}; // 1=tone5. end-of-sentence, 6=tone 1&4, 7=tone 2&3 | ||||
static const unsigned char stress_amps_zh[] = {22,16, 22,22, 22,22, 22,22 }; | static const unsigned char stress_amps_zh[] = {22,16, 22,22, 22,22, 22,22 }; | ||||
tr = new Translator; | |||||
SetupTranslator(tr,stress_lengths_zh,stress_amps_zh); | SetupTranslator(tr,stress_lengths_zh,stress_amps_zh); | ||||
tr->langopts.stress_rule = 3; // stress on final syllable of a "word" | tr->langopts.stress_rule = 3; // stress on final syllable of a "word" | ||||
break; | break; | ||||
default: | default: | ||||
tr = new Translator(); | |||||
break; | break; | ||||
} | } | ||||
Translator_Russian::Translator_Russian() : Translator() | |||||
{//=================================== | |||||
static void Translator_Russian(Translator *tr) | |||||
{//=========================================== | |||||
static const unsigned char stress_amps_ru[] = {16,16, 18,18, 20,24, 24,22 }; | static const unsigned char stress_amps_ru[] = {16,16, 18,18, 20,24, 24,22 }; | ||||
static const short stress_lengths_ru[8] = {150,140, 220,220, 0,0, 260,280}; | static const short stress_lengths_ru[8] = {150,140, 220,220, 0,0, 260,280}; | ||||
static const char ru_voiced[] = {0x11,0x12,0x13,0x14,0x16,0x17,0}; // letter group G (voiced obstruents) | static const char ru_voiced[] = {0x11,0x12,0x13,0x14,0x16,0x17,0}; // letter group G (voiced obstruents) | ||||
static const char ru_ivowels[] = {0x2c,0x15,0x31,0x18,0x2e,0x2f,0}; // letter group Y (iotated vowels & soft-sign) | static const char ru_ivowels[] = {0x2c,0x15,0x31,0x18,0x2e,0x2f,0}; // letter group Y (iotated vowels & soft-sign) | ||||
SetupTranslator(this,stress_lengths_ru,stress_amps_ru); | |||||
charset_a0 = charsets[18]; // KOI8-R | |||||
transpose_offset = 0x42f; // convert cyrillic from unicode into range 0x01 to 0x22 | |||||
transpose_min = 0x430; | |||||
transpose_max = 0x451; | |||||
letter_bits_offset = OFFSET_CYRILLIC; | |||||
memset(letter_bits,0,sizeof(letter_bits)); | |||||
SetLetterBits(this,0,ru_vowels); | |||||
SetLetterBits(this,1,ru_soft); | |||||
SetLetterBits(this,2,ru_consonants); | |||||
SetLetterBits(this,3,ru_hard); | |||||
SetLetterBits(this,4,ru_nothard); | |||||
SetLetterBits(this,5,ru_voiced); | |||||
SetLetterBits(this,6,ru_ivowels); | |||||
SetLetterBits(this,7,ru_vowels); | |||||
langopts.param[LOPT_UNPRONOUNCABLE] = 0x432; // [v] don't count this character at start of word | |||||
langopts.param[LOPT_REGRESSIVE_VOICING] = 1; | |||||
langopts.param[LOPT_REDUCE] = 2; | |||||
langopts.stress_rule = 5; | |||||
langopts.stress_flags = 0x0020; // waas 0x1010 | |||||
langopts.numbers = 0x0409; | |||||
langopts.numbers2 = 0xc2; // variant numbers before thousands | |||||
langopts.phoneme_change = 1; | |||||
langopts.testing = 2; | |||||
SetupTranslator(tr,stress_lengths_ru,stress_amps_ru); | |||||
tr->charset_a0 = charsets[18]; // KOI8-R | |||||
tr->transpose_offset = 0x42f; // convert cyrillic from unicode into range 0x01 to 0x22 | |||||
tr->transpose_min = 0x430; | |||||
tr->transpose_max = 0x451; | |||||
tr->letter_bits_offset = OFFSET_CYRILLIC; | |||||
memset(tr->letter_bits,0,sizeof(tr->letter_bits)); | |||||
SetLetterBits(tr,0,ru_vowels); | |||||
SetLetterBits(tr,1,ru_soft); | |||||
SetLetterBits(tr,2,ru_consonants); | |||||
SetLetterBits(tr,3,ru_hard); | |||||
SetLetterBits(tr,4,ru_nothard); | |||||
SetLetterBits(tr,5,ru_voiced); | |||||
SetLetterBits(tr,6,ru_ivowels); | |||||
SetLetterBits(tr,7,ru_vowels); | |||||
tr->langopts.param[LOPT_UNPRONOUNCABLE] = 0x432; // [v] don't count this character at start of word | |||||
tr->langopts.param[LOPT_REGRESSIVE_VOICING] = 1; | |||||
tr->langopts.param[LOPT_REDUCE] = 2; | |||||
tr->langopts.stress_rule = 5; | |||||
tr->langopts.stress_flags = 0x0020; // waas 0x1010 | |||||
tr->langopts.numbers = 0x0409; | |||||
tr->langopts.numbers2 = 0xc2; // variant numbers before thousands | |||||
tr->langopts.phoneme_change = 1; | |||||
tr->langopts.testing = 2; | |||||
} // end of Translator_Russian | } // end of Translator_Russian | ||||
#define PH(c1,c2) (c2<<8)+c1 // combine two characters into an integer for phoneme name | |||||
#define PY(c1,c2,c3) (c3<<16)+(c2<<8)+c1 | |||||
/* | /* | ||||
typedef struct { | typedef struct { | ||||
#define RUSSIAN2 | #define RUSSIAN2 | ||||
#ifdef RUSSIAN2 | #ifdef RUSSIAN2 | ||||
int Translator_Russian::ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//============================================================================================================== | |||||
int ChangePhonemes_ru(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//============================================================================================================= | |||||
// Called for each phoneme in the phoneme list, to allow a language to make changes | // Called for each phoneme in the phoneme list, to allow a language to make changes | ||||
// ph The current phoneme | // ph The current phoneme | ||||
#else | #else | ||||
int Translator_Russian::ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//=============================================================================================================== | |||||
int ChangePhonemes_ru(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch) | |||||
{//============================================================================================================= | |||||
// Called for each phoneme in the phoneme list, to allow a language to make changes | // Called for each phoneme in the phoneme list, to allow a language to make changes | ||||
// flags: bit 0=1 last phoneme in a word | // flags: bit 0=1 last phoneme in a word | ||||
// bit 1=1 this is the highest stressed vowel in the current word | // bit 1=1 this is the highest stressed vowel in the current word |
***************************************************************************/ | ***************************************************************************/ | ||||
class Translator_English: public Translator | |||||
{//======================================= | |||||
public: | |||||
Translator_English(); | |||||
int Unpronouncable(char *word); | |||||
}; // end of class Translator_English | |||||
class Translator_Russian: public Translator | |||||
{//======================================= | |||||
public: | |||||
Translator_Russian(); | |||||
private: | |||||
int ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch); | |||||
}; // end of class Translator_Russian | |||||
#define NUM_SEP_SPACE 0x1000 // allow space as thousands separator (in addition to langopts.thousands_sep) | #define NUM_SEP_SPACE 0x1000 // allow space as thousands separator (in addition to langopts.thousands_sep) | ||||
#define NUM_DEC_IT 0x2000 // (LANG=it) speak post-decimal-point digits as a combined number not as single digits | #define NUM_DEC_IT 0x2000 // (LANG=it) speak post-decimal-point digits as a combined number not as single digits | ||||
class Translator | |||||
struct Translator | |||||
{//============= | {//============= | ||||
public: | |||||
Translator(); | |||||
virtual ~Translator(); | |||||
void *TranslateClause(FILE *f_text, const void *vp_input, int *tone, char **voice_change); | |||||
int TranslateWord(char *word, int next_pause, WORD_TAB *wtab); | |||||
int LoadDictionary(const char *name, int no_error); | |||||
virtual void CalcLengths(); | |||||
virtual void CalcPitches(int clause_tone); | |||||
void GetTranslatedPhonemeString(char *phon_out, int n_phon_out); | |||||
LANGUAGE_OPTIONS langopts; | LANGUAGE_OPTIONS langopts; | ||||
int translator_name; | int translator_name; | ||||
int transpose_offset; | int transpose_offset; | ||||
int transpose_min; | int transpose_min; | ||||
char phon_out[300]; | char phon_out[300]; | ||||
char word_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | |||||
char phonemes_repeat[20]; | char phonemes_repeat[20]; | ||||
int phonemes_repeat_count; | int phonemes_repeat_count; | ||||
char *data_dictrules; // language_1 translation rules file | char *data_dictrules; // language_1 translation rules file | ||||
char *data_dictlist; // language_2 dictionary lookup file | char *data_dictlist; // language_2 dictionary lookup file | ||||
char *dict_hashtab[N_HASH_DICT]; // hash table to index dictionary lookup file | char *dict_hashtab[N_HASH_DICT]; // hash table to index dictionary lookup file | ||||
char *letterGroups[N_LETTER_GROUPS]; | |||||
private: | |||||
int TranslateWord2(char *word, WORD_TAB *wtab, int pre_pause, int next_pause); | |||||
int TranslateLetter(char *letter, char *phonemes, int control, int word_length); | |||||
void SetSpellingStress(char *phonemes, int control, int n_chars); | |||||
void WriteMnemonic(int *ix, int mnem); | |||||
void MakePhonemeList(int post_pause, int new_sentence); | |||||
int SubstitutePhonemes(PHONEME_LIST2 *plist_out); | |||||
int ReadClause(FILE *f_in, char *buf, short *charix, int n_buf, int *tone_type); | |||||
int AnnouncePunctuation(int c1, int c2, char *buf, int ix); | |||||
const char *LookupDict2(const char *word, const char *word2, char *phonetic, unsigned int *flags, int end_flags, WORD_TAB *wtab); | |||||
const char *LookupSpecial(const char *string, char *text_out); | |||||
const char *LookupCharName(int c); | |||||
void LookupLetter(unsigned int letter, int next_byte, char *ph_buf); | |||||
int LookupLetter2(unsigned int letter, char *ph_buf); | |||||
void LookupAccentedLetter(unsigned int letter, char *ph_buf); | |||||
int LookupNum2(int value, int control, char *ph_out); | |||||
int LookupNum3(int value, char *ph_out, int suppress_null, int thousandplex, int prev_thousands); | |||||
int LookupThousands(int value, int thousandplex, char *ph_out); | |||||
int TranslateNumber_1(char *word1, char *ph_out, unsigned int *flags, int wflags); | |||||
int TranslateRoman(char *word, char *ph_out); | |||||
int TranslateChar(char *ptr, int prev_in, unsigned int c, unsigned int next_in, int *insert); | |||||
void InitGroups(void); | |||||
void AppendPhonemes(char *string, int size, const char *ph); | |||||
char *DecodeRule(const char *group, char *rule); | |||||
void MatchRule(char *word[], const char *group, char *rule, MatchRecord *match_out, int end_flags, int dict_flags); | |||||
int TranslateRules(char *p, char *phonemes, int size, char *end_phonemes, int end_flags, unsigned int *dict_flags); | |||||
void ApplySpecialAttribute(char *phonemes, int dict_flags); | |||||
int IsLetter(int letter, int group); | |||||
int IsLetterGroup(char *word, int group, int pre); | |||||
void CalcPitches_Tone(int clause_tone); | |||||
protected: | |||||
virtual int Unpronouncable(char *word); | |||||
virtual void SetWordStress(char *output, unsigned int dictionary_flags, int tonic, int prev_stress); | |||||
virtual int RemoveEnding(char *word, int end_type, char *word_copy); | |||||
virtual int TranslateNumber(char *word1, char *ph_out, unsigned int *flags, int wflags); | |||||
virtual int ChangePhonemes(PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch); | |||||
int IsVowel(int letter); | |||||
int LookupDictList(char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab); | |||||
int Lookup(const char *word, char *ph_out); | |||||
// groups1 and groups2 are indexes into data_dictrules, set up by InitGroups() | // groups1 and groups2 are indexes into data_dictrules, set up by InitGroups() | ||||
// the two-letter rules for each letter must be consecutive in the language_rules source | // the two-letter rules for each letter must be consecutive in the language_rules source | ||||
unsigned char groups2_count[256]; // number of 2 letter groups for this initial letter | unsigned char groups2_count[256]; // number of 2 letter groups for this initial letter | ||||
unsigned char groups2_start[256]; // index into groups2 | unsigned char groups2_start[256]; // index into groups2 | ||||
char *letterGroups[N_LETTER_GROUPS]; | |||||
int n_ph_list2; | |||||
PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes | |||||
int expect_verb; | int expect_verb; | ||||
int expect_past; // expect past tense | int expect_past; // expect past tense | ||||
int expect_verb_s; | int expect_verb_s; | ||||
int expect_noun; | int expect_noun; | ||||
int word_flags; // word is all upper case | |||||
int prev_last_stress; | int prev_last_stress; | ||||
int prepause_timeout; | |||||
int end_stressed_vowel; // word ends with stressed vowel | |||||
int prev_dict_flags; // dictionary flags from previous word | |||||
char *clause_end; | char *clause_end; | ||||
int word_vowel_count; // number of vowels so far | int word_vowel_count; // number of vowels so far | ||||
int clause_upper_count; // number of upper case letters in the clause | int clause_upper_count; // number of upper case letters in the clause | ||||
int clause_lower_count; // number of lower case letters in the clause | int clause_lower_count; // number of lower case letters in the clause | ||||
int prepause_timeout; | |||||
int end_stressed_vowel; // word ends with stressed vowel | |||||
int prev_dict_flags; // dictionary flags from previous word | |||||
}; // end of class Translator | }; // end of class Translator | ||||
extern int option_tone1; | |||||
extern int option_tone2; | extern int option_tone2; | ||||
#define OPTION_EMPHASIZE_ALLCAPS 0x100 | #define OPTION_EMPHASIZE_ALLCAPS 0x100 | ||||
#define OPTION_EMPHASIZE_PENULTIMATE 0x200 | #define OPTION_EMPHASIZE_PENULTIMATE 0x200 | ||||
extern int option_phonemes; | extern int option_phonemes; | ||||
extern int option_phoneme_events; | extern int option_phoneme_events; | ||||
extern int option_linelength; // treat lines shorter than this as end-of-clause | extern int option_linelength; // treat lines shorter than this as end-of-clause | ||||
extern int option_harmonic1; | |||||
extern int option_multibyte; | extern int option_multibyte; | ||||
extern int option_capitals; | extern int option_capitals; | ||||
extern int option_punctuation; | extern int option_punctuation; | ||||
#define N_PUNCTLIST 60 | #define N_PUNCTLIST 60 | ||||
extern wchar_t option_punctlist[N_PUNCTLIST]; // which punctuation characters to announce | extern wchar_t option_punctlist[N_PUNCTLIST]; // which punctuation characters to announce | ||||
extern unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS]; | extern unsigned char punctuation_to_tone[INTONATION_TYPES][PUNCT_INTONATIONS]; | ||||
extern const unsigned short punct_chars[]; // punctuation chars fo end-of-clause | |||||
extern int speech_parameters[]; | |||||
extern Translator *translator; | extern Translator *translator; | ||||
extern Translator *translator2; | extern Translator *translator2; | ||||
extern char ctrl_embedded; // to allow an alternative CTRL for embedded commands | extern char ctrl_embedded; // to allow an alternative CTRL for embedded commands | ||||
extern char *p_textinput; | extern char *p_textinput; | ||||
extern wchar_t *p_wchar_input; | extern wchar_t *p_wchar_input; | ||||
extern int ungot_char; | |||||
extern int dictionary_skipwords; | extern int dictionary_skipwords; | ||||
extern int (* uri_callback)(int, const char *, const char *); | extern int (* uri_callback)(int, const char *, const char *); | ||||
extern int (* phoneme_callback)(const char *); | extern int (* phoneme_callback)(const char *); | ||||
extern void SetLengthMods(Translator *tr, int value); | extern void SetLengthMods(Translator *tr, int value); | ||||
Translator *SelectTranslator(const char *name); | |||||
int SetTranslator2(const char *name); | |||||
int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name,int flags); | int CompileDictionary(const char *dsource, const char *dict_name, FILE *log, char *err_name,int flags); | ||||
void LoadConfig(void); | void LoadConfig(void); | ||||
int PhonemeCode(unsigned int mnem); | |||||
void ChangeWordStress(Translator *tr, char *word, int new_stress); | |||||
int TransposeAlphabet(char *text, int offset, int min, int max); | int TransposeAlphabet(char *text, int offset, int min, int max); | ||||
int utf8_in(int *c, const char *buf, int backwards); | |||||
int utf8_in(int *c, const char *buf); | |||||
int utf8_in2(int *c, const char *buf, int backwards); | |||||
int utf8_out(unsigned int c, char *buf); | int utf8_out(unsigned int c, char *buf); | ||||
int utf8_nbytes(const char *buf); | int utf8_nbytes(const char *buf); | ||||
int lookupwchar(const unsigned short *list,int c); | int lookupwchar(const unsigned short *list,int c); | ||||
int Eof(void); | int Eof(void); | ||||
char *strchr_w(const char *s, int c); | char *strchr_w(const char *s, int c); | ||||
int IsBracket(int c); | int IsBracket(int c); | ||||
void ResetLetterBits(Translator *tr, int groups); | |||||
void SetLetterBits(Translator *tr, int group, const char *string); | |||||
void SetLetterBitsRange(Translator *tr, int group, int first, int last); | |||||
void SetLetterVowel(Translator *tr, int c); | |||||
void InitNamedata(void); | void InitNamedata(void); | ||||
void InitText(int flags); | void InitText(int flags); | ||||
void InitText2(void); | void InitText2(void); | ||||
int IsAlpha(unsigned int c); | int IsAlpha(unsigned int c); | ||||
int isspace2(unsigned int c); | int isspace2(unsigned int c); | ||||
int towlower2(unsigned int c); | int towlower2(unsigned int c); | ||||
void GetTranslatedPhonemeString(char *phon_out, int n_phon_out); | |||||
Translator *SelectTranslator(const char *name); | |||||
int SetTranslator2(const char *name); | |||||
void DeleteTranslator(Translator *tr); | |||||
int Lookup(Translator *tr, const char *word, char *ph_out); | |||||
int TranslateNumber(Translator *tr, char *word1, char *ph_out, unsigned int *flags, int wflags); | |||||
int TranslateRoman(Translator *tr, char *word, char *ph_out); | |||||
void ChangeWordStress(Translator *tr, char *word, int new_stress); | |||||
void SetSpellingStress(Translator *tr, char *phonemes, int control, int n_chars); | |||||
int TranslateLetter(Translator *tr, char *letter, char *phonemes, int control, int word_length); | |||||
void LookupLetter(Translator *tr, unsigned int letter, int next_byte, char *ph_buf); | |||||
void LookupAccentedLetter(Translator *tr, unsigned int letter, char *ph_buf); | |||||
int LoadDictionary(Translator *tr, const char *name, int no_error); | |||||
int LookupDictList(Translator *tr, char **wordptr, char *ph_out, unsigned int *flags, int end_flags, WORD_TAB *wtab); | |||||
void MakePhonemeList(Translator *tr, int post_pause, int new_sentence); | |||||
int ChangePhonemes_ru(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch); | |||||
void ApplySpecialAttribute(Translator *tr, char *phonemes, int dict_flags); | |||||
void AppendPhonemes(Translator *tr, char *string, int size, const char *ph); | |||||
void CalcLengths(Translator *tr); | |||||
void CalcPitches(Translator *tr, int clause_tone); | |||||
int RemoveEnding(Translator *tr, char *word, int end_type, char *word_copy); | |||||
int Unpronouncable(Translator *tr, char *word); | |||||
void SetWordStress(Translator *tr, char *output, unsigned int dictionary_flags, int tonic, int prev_stress); | |||||
int TranslateRules(Translator *tr, char *p, char *phonemes, int size, char *end_phonemes, int end_flags, unsigned int *dict_flags); | |||||
int TranslateWord(Translator *tr, char *word1, int next_pause, WORD_TAB *wtab); | |||||
void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *tone, char **voice_change); | |||||
int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int n_buf, int *tone_type); | |||||
void SetVoiceStack(espeak_VOICE *v); | void SetVoiceStack(espeak_VOICE *v); | ||||
extern FILE *f_trans; // for logging | extern FILE *f_trans; // for logging |
InitText(0); | InitText(0); | ||||
while((vp != NULL) && (n_ph_list < N_PH_LIST)) | while((vp != NULL) && (n_ph_list < N_PH_LIST)) | ||||
{ | { | ||||
vp = translator->TranslateClause(NULL,vp,&clause_tone,NULL); | |||||
translator->CalcPitches(clause_tone); | |||||
translator->CalcLengths(); | |||||
vp = TranslateClause(translator,NULL,vp,&clause_tone,NULL); | |||||
CalcPitches(translator,clause_tone); | |||||
CalcLengths(translator); | |||||
translator->GetTranslatedPhonemeString(translator->phon_out,sizeof(translator->phon_out)); | |||||
GetTranslatedPhonemeString(translator->phon_out,sizeof(translator->phon_out)); | |||||
if(clause_count++ > 0) | if(clause_count++ > 0) | ||||
strcat(phon_out," ||"); | strcat(phon_out," ||"); | ||||
strcat(phon_out,translator->phon_out); | strcat(phon_out,translator->phon_out); |
const char variants_female[N_VOICE_VARIANTS] = {11,12,13,14,0}; | const char variants_female[N_VOICE_VARIANTS] = {11,12,13,14,0}; | ||||
const char *variant_lists[3] = {variants_either, variants_male, variants_female}; | const char *variant_lists[3] = {variants_either, variants_male, variants_female}; | ||||
voice_t voicedata; | |||||
static voice_t voicedata; | |||||
voice_t *voice = &voicedata; | voice_t *voice = &voicedata; | ||||
char *fgets_strip(char *buf, int size, FILE *f_in) | |||||
{//=============================================== | |||||
static char *fgets_strip(char *buf, int size, FILE *f_in) | |||||
{//====================================================== | |||||
// strip trailing spaces, and truncate lines at // comment | // strip trailing spaces, and truncate lines at // comment | ||||
int len; | int len; | ||||
char *p; | char *p; | ||||
} | } | ||||
void SetToneAdjust(voice_t *voice, int *tone_pts) | |||||
{//============================================== | |||||
static void SetToneAdjust(voice_t *voice, int *tone_pts) | |||||
{//===================================================== | |||||
int ix; | int ix; | ||||
int pt; | int pt; | ||||
int y; | int y; | ||||
if(tone_only == 0) | if(tone_only == 0) | ||||
{ | { | ||||
n_replace_phonemes = 0; | n_replace_phonemes = 0; | ||||
option_tone1 = 0; | |||||
option_quiet = 0; | option_quiet = 0; | ||||
LoadMbrolaTable(NULL,NULL,0); | LoadMbrolaTable(NULL,NULL,0); | ||||
} | } | ||||
if((n < 2) || (n_replace_phonemes >= N_REPLACE_PHONEMES)) | if((n < 2) || (n_replace_phonemes >= N_REPLACE_PHONEMES)) | ||||
return; | return; | ||||
if((phon = LookupPh(phon_string1)) == 0) | |||||
if((phon = LookupPhonemeString(phon_string1)) == 0) | |||||
return; // not recognised | return; // not recognised | ||||
replace_phonemes[n_replace_phonemes].old_ph = phon; | replace_phonemes[n_replace_phonemes].old_ph = phon; | ||||
replace_phonemes[n_replace_phonemes].new_ph = LookupPh(phon_string2); | |||||
replace_phonemes[n_replace_phonemes].new_ph = LookupPhonemeString(phon_string2); | |||||
replace_phonemes[n_replace_phonemes++].type = flags; | replace_phonemes[n_replace_phonemes++].type = flags; | ||||
} // end of PhonemeReplacement | } // end of PhonemeReplacement | ||||
if(!tone_only && (translator != NULL)) | if(!tone_only && (translator != NULL)) | ||||
{ | { | ||||
delete translator; | |||||
DeleteTranslator(translator); | |||||
translator = NULL; | translator = NULL; | ||||
} | } | ||||
SelectPhonemeTableName(phonemes_name); | SelectPhonemeTableName(phonemes_name); | ||||
if(new_translator != NULL) | if(new_translator != NULL) | ||||
delete new_translator; | |||||
DeleteTranslator(new_translator); | |||||
new_translator = SelectTranslator(translator_name); | new_translator = SelectTranslator(translator_name); | ||||
langopts = &new_translator->langopts; | langopts = &new_translator->langopts; | ||||
sscanf(p,"%s",translator_name); | sscanf(p,"%s",translator_name); | ||||
if(new_translator != NULL) | if(new_translator != NULL) | ||||
delete new_translator; | |||||
DeleteTranslator(new_translator); | |||||
new_translator = SelectTranslator(translator_name); | new_translator = SelectTranslator(translator_name); | ||||
langopts = &new_translator->langopts; | langopts = &new_translator->langopts; | ||||
fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name); | fprintf(stderr,"Unknown phoneme table: '%s'\n",phonemes_name); | ||||
} | } | ||||
voice->phoneme_tab_ix = ix; | voice->phoneme_tab_ix = ix; | ||||
error = new_translator->LoadDictionary(new_dictionary, control & 4); | |||||
error = LoadDictionary(new_translator, new_dictionary, control & 4); | |||||
if(dictionary_name[0]==0) | if(dictionary_name[0]==0) | ||||
return(NULL); // no dictionary loaded | return(NULL); // no dictionary loaded | ||||
} // end of LoadVoice | } // end of LoadVoice | ||||
char *ExtractVoiceVariantName(char *vname, int variant_num) | |||||
{//======================================================== | |||||
static char *ExtractVoiceVariantName(char *vname, int variant_num) | |||||
{//=============================================================== | |||||
// Remove any voice variant suffix (name or number) from a voice name | // Remove any voice variant suffix (name or number) from a voice name | ||||
// Returns the voice variant name | // Returns the voice variant name | ||||
void GetVoices(const char *path) | |||||
{//============================= | |||||
static void GetVoices(const char *path) | |||||
{//==================================== | |||||
FILE *f_voice; | FILE *f_voice; | ||||
espeak_VOICE *voice_data; | espeak_VOICE *voice_data; | ||||
int ftype; | int ftype; |
extern char *spects_data; | extern char *spects_data; | ||||
extern int n_phoneme_tables; | extern int n_phoneme_tables; | ||||
extern PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS]; | |||||
// size of the vowelchart png | // size of the vowelchart png |
FILE *f_log = NULL; | FILE *f_log = NULL; | ||||
int option_waveout = 0; | int option_waveout = 0; | ||||
int option_harmonic1 = 10; // 10 | |||||
static int option_harmonic1 = 10; // 10 | |||||
int option_log_frames = 0; | int option_log_frames = 0; | ||||
static int flutter_amp = 64; | static int flutter_amp = 64; | ||||
static short echo_buf[N_ECHO_BUF]; | static short echo_buf[N_ECHO_BUF]; | ||||
static int voicing; | static int voicing; | ||||
RESONATOR rbreath[N_PEAKS]; | |||||
static RESONATOR rbreath[N_PEAKS]; | |||||
static int harm_sqrt_n = 0; | static int harm_sqrt_n = 0; | ||||
/* This is a fixed version of Pa_OpenDefaultStream() for use if the version in portaudio V19 | /* This is a fixed version of Pa_OpenDefaultStream() for use if the version in portaudio V19 | ||||
is broken */ | is broken */ | ||||
PaError Pa_OpenDefaultStream2( PaStream** stream, | |||||
static PaError Pa_OpenDefaultStream2( PaStream** stream, | |||||
int inputChannelCount, | int inputChannelCount, | ||||
int outputChannelCount, | int outputChannelCount, | ||||
PaSampleFormat sampleFormat, | PaSampleFormat sampleFormat, | ||||
void SetBreath() | |||||
{//============= | |||||
static void SetBreath() | |||||
{//==================== | |||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
int pk; | int pk; | ||||
} // end of SetBreath | } // end of SetBreath | ||||
int ApplyBreath(void) | |||||
{//================== | |||||
static int ApplyBreath(void) | |||||
{//========================= | |||||
int value = 0; | int value = 0; | ||||
#ifndef PLATFORM_RISCOS | #ifndef PLATFORM_RISCOS | ||||
int noise; | int noise; |