TranslateWord2 passes translator2 as tr to TranslateWord which may call TranslateWord3, SpeakIndividualLetters, TranslateLetter, which was calling SetTranslator2 again, thus freeing the very tr being used. Make that latter use another translator.master
if (tr->translator_name == L('e', 'n')) | if (tr->translator_name == L('e', 'n')) | ||||
return; // we are already using English | return; // we are already using English | ||||
SetTranslator2(ESPEAKNG_DEFAULT_VOICE); | |||||
if (Lookup(translator2, &single_letter[2], ph_buf3) != 0) { | |||||
SetTranslator3(ESPEAKNG_DEFAULT_VOICE); | |||||
if (Lookup(translator3, &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); | ||||
} | } | ||||
// don't say "superscript" during normal text reading | // don't say "superscript" during normal text reading | ||||
Lookup(tr, modifier, capital); | Lookup(tr, modifier, capital); | ||||
if (capital[0] == 0) { | if (capital[0] == 0) { | ||||
capital[2] = SetTranslator2(ESPEAKNG_DEFAULT_VOICE); // overwrites previous contents of translator2 | |||||
Lookup(translator2, modifier, &capital[3]); | |||||
capital[2] = SetTranslator3(ESPEAKNG_DEFAULT_VOICE); // overwrites previous contents of translator3 | |||||
Lookup(translator3, modifier, &capital[3]); | |||||
if (capital[3] != 0) { | if (capital[3] != 0) { | ||||
capital[0] = phonPAUSE; | capital[0] = phonPAUSE; | ||||
capital[1] = phonSWITCH; | capital[1] = phonSWITCH; | ||||
ph_buf2[0] = 0; | ph_buf2[0] = 0; | ||||
if (Lookup(translator, alphabet->name, ph_alphabet) == 0) { // the original language for the current voice | if (Lookup(translator, alphabet->name, ph_alphabet) == 0) { // the original language for the current voice | ||||
// Can't find the local name for this alphabet, use the English name | // Can't find the local name for this alphabet, use the English name | ||||
ph_alphabet[2] = SetTranslator2(ESPEAKNG_DEFAULT_VOICE); // overwrites previous contents of translator2 | |||||
Lookup(translator2, alphabet->name, ph_buf2); | |||||
ph_alphabet[2] = SetTranslator3(ESPEAKNG_DEFAULT_VOICE); // overwrites previous contents of translator3 | |||||
Lookup(translator3, alphabet->name, ph_buf2); | |||||
} else if (translator != tr) { | } else if (translator != tr) { | ||||
phontab_1 = tr->phoneme_tab_ix; | phontab_1 = tr->phoneme_tab_ix; | ||||
strcpy(ph_buf2, ph_alphabet); | strcpy(ph_buf2, ph_alphabet); | ||||
char hangul_buf[12]; | char hangul_buf[12]; | ||||
// speak in the language for this alphabet (or English) | // speak in the language for this alphabet (or English) | ||||
ph_buf[2] = SetTranslator2(WordToString2(language)); | |||||
ph_buf[2] = SetTranslator3(WordToString2(language)); | |||||
if (translator2 != NULL) { | |||||
if (translator3 != NULL) { | |||||
if (((code = letter - 0xac00) >= 0) && (letter <= 0xd7af)) { | if (((code = letter - 0xac00) >= 0) && (letter <= 0xd7af)) { | ||||
// Special case for Korean letters. | // Special case for Korean letters. | ||||
// break a syllable hangul into 2 or 3 individual jamo | // break a syllable hangul into 2 or 3 individual jamo | ||||
p3[6] = ' '; | p3[6] = ' '; | ||||
p3[7] = 0; | p3[7] = 0; | ||||
ph_buf[3] = 0; | ph_buf[3] = 0; | ||||
TranslateRules(translator2, &hangul_buf[1], &ph_buf[3], sizeof(ph_buf)-3, NULL, 0, NULL); | |||||
SetWordStress(translator2, &ph_buf[3], NULL, -1, 0); | |||||
TranslateRules(translator3, &hangul_buf[1], &ph_buf[3], sizeof(ph_buf)-3, NULL, 0, NULL); | |||||
SetWordStress(translator3, &ph_buf[3], NULL, -1, 0); | |||||
} else | } else | ||||
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1); | |||||
LookupLetter(translator3, letter, word[n_bytes], &ph_buf[3], control & 1); | |||||
if (ph_buf[3] == phonSWITCH) { | if (ph_buf[3] == phonSWITCH) { | ||||
// another level of language change | // another level of language change | ||||
ph_buf[2] = SetTranslator2(&ph_buf[4]); | |||||
LookupLetter(translator2, letter, word[n_bytes], &ph_buf[3], control & 1); | |||||
ph_buf[2] = SetTranslator3(&ph_buf[4]); | |||||
LookupLetter(translator3, letter, word[n_bytes], &ph_buf[3], control & 1); | |||||
} | } | ||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table |
Translator *translator = NULL; // the main translator | Translator *translator = NULL; // the main translator | ||||
Translator *translator2 = NULL; // secondary translator for certain words | Translator *translator2 = NULL; // secondary translator for certain words | ||||
static char translator2_language[20] = { 0 }; | static char translator2_language[20] = { 0 }; | ||||
Translator *translator3 = NULL; // tertiary translator for certain words | |||||
static char translator3_language[20] = { 0 }; | |||||
FILE *f_trans = NULL; // phoneme output text | FILE *f_trans = NULL; // phoneme output text | ||||
int option_tone_flags = 0; // bit 8=emphasize allcaps, bit 9=emphasize penultimate stress | int option_tone_flags = 0; // bit 8=emphasize allcaps, bit 9=emphasize penultimate stress | ||||
} while (((embedded_cmd & 0x80) == 0) && (embedded_read < embedded_ix)); | } while (((embedded_cmd & 0x80) == 0) && (embedded_read < embedded_ix)); | ||||
} | } | ||||
int SetTranslator2(const char *new_language) | |||||
static int SetAlternateTranslator(const char *new_language, Translator **translator, char translator_language[20]) | |||||
{ | { | ||||
// Set translator2 to a second language | |||||
// Set alternate translator to a second language | |||||
int new_phoneme_tab; | int new_phoneme_tab; | ||||
if ((new_phoneme_tab = SelectPhonemeTableName(new_language)) >= 0) { | if ((new_phoneme_tab = SelectPhonemeTableName(new_language)) >= 0) { | ||||
if ((translator2 != NULL) && (strcmp(new_language, translator2_language) != 0)) { | |||||
if ((*translator != NULL) && (strcmp(new_language, translator_language) != 0)) { | |||||
// we already have an alternative translator, but not for the required language, delete it | // we already have an alternative translator, but not for the required language, delete it | ||||
DeleteTranslator(translator2); | |||||
translator2 = NULL; | |||||
DeleteTranslator(*translator); | |||||
*translator = NULL; | |||||
} | } | ||||
if (translator2 == NULL) { | |||||
translator2 = SelectTranslator(new_language); | |||||
strcpy(translator2_language, new_language); | |||||
if (*translator == NULL) { | |||||
*translator = SelectTranslator(new_language); | |||||
strcpy(translator_language, new_language); | |||||
if (LoadDictionary(translator2, translator2->dictionary_name, 0) != 0) { | |||||
if (LoadDictionary(*translator, (*translator)->dictionary_name, 0) != 0) { | |||||
SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | SelectPhonemeTable(voice->phoneme_tab_ix); // revert to original phoneme table | ||||
new_phoneme_tab = -1; | new_phoneme_tab = -1; | ||||
translator2_language[0] = 0; | |||||
translator_language[0] = 0; | |||||
} | } | ||||
translator2->phoneme_tab_ix = new_phoneme_tab; | |||||
(*translator)->phoneme_tab_ix = new_phoneme_tab; | |||||
} | } | ||||
} | } | ||||
if (translator2 != NULL) | |||||
translator2->phonemes_repeat[0] = 0; | |||||
if (*translator != NULL) | |||||
(*translator)->phonemes_repeat[0] = 0; | |||||
return new_phoneme_tab; | return new_phoneme_tab; | ||||
} | } | ||||
int SetTranslator2(const char *new_language) | |||||
{ | |||||
return SetAlternateTranslator(new_language, &translator2, translator2_language); | |||||
} | |||||
int SetTranslator3(const char *new_language) | |||||
{ | |||||
return SetAlternateTranslator(new_language, &translator3, translator3_language); | |||||
} | |||||
static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pause) | static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pause) | ||||
{ | { | ||||
int flags = 0; | int flags = 0; |
extern Translator *translator; | extern Translator *translator; | ||||
extern Translator *translator2; | extern Translator *translator2; | ||||
extern Translator *translator3; | |||||
extern char dictionary_name[40]; | extern char dictionary_name[40]; | ||||
extern espeak_ng_TEXT_DECODER *p_decoder; | extern espeak_ng_TEXT_DECODER *p_decoder; | ||||
extern int dictionary_skipwords; | extern int dictionary_skipwords; | ||||
Translator *SelectTranslator(const char *name); | Translator *SelectTranslator(const char *name); | ||||
int SetTranslator2(const char *name); | int SetTranslator2(const char *name); | ||||
int SetTranslator3(const char *name); | |||||
void DeleteTranslator(Translator *tr); | void DeleteTranslator(Translator *tr); | ||||
void ProcessLanguageOptions(LANGUAGE_OPTIONS *langopts); | void ProcessLanguageOptions(LANGUAGE_OPTIONS *langopts); | ||||