static int resample_count = 0; | static int resample_count = 0; | ||||
static int resample_fails = 0; | static int resample_fails = 0; | ||||
static int then_count = 0; | static int then_count = 0; | ||||
static int after_if = 0; | |||||
static bool after_if = false; | |||||
static char current_fname[80]; | static char current_fname[80]; | ||||
typedef struct { | typedef struct { | ||||
USHORT *p_then; | USHORT *p_then; | ||||
USHORT *p_else; | USHORT *p_else; | ||||
int returned; | |||||
bool returned; | |||||
} IF_STACK; | } IF_STACK; | ||||
IF_STACK if_stack[N_IF_STACK]; | IF_STACK if_stack[N_IF_STACK]; | ||||
int max = 0; | int max = 0; | ||||
int length; | int length; | ||||
int sr1, sr2; | int sr1, sr2; | ||||
int failed; | |||||
bool failed; | |||||
int len; | int len; | ||||
int resample_wav = 0; | |||||
bool resample_wav = false; | |||||
const char *fname2; | const char *fname2; | ||||
char fname_temp[100]; | char fname_temp[100]; | ||||
char msg[120]; | char msg[120]; | ||||
int fd_temp; | int fd_temp; | ||||
char command[sizeof(path_home)+250]; | char command[sizeof(path_home)+250]; | ||||
failed = 0; | |||||
failed = false; | |||||
#ifdef HAVE_MKSTEMP | #ifdef HAVE_MKSTEMP | ||||
strcpy(fname_temp, "/tmp/espeakXXXXXX"); | strcpy(fname_temp, "/tmp/espeakXXXXXX"); | ||||
sprintf(command, "sox \"%s/%s.wav\" -r %d -c1 -t wav %s\n", phsrc, fname2, samplerate_native, fname_temp); | sprintf(command, "sox \"%s/%s.wav\" -r %d -c1 -t wav %s\n", phsrc, fname2, samplerate_native, fname_temp); | ||||
if (system(command) != 0) | if (system(command) != 0) | ||||
failed = 1; | |||||
failed = true; | |||||
if (failed || (GetFileLength(fname_temp) <= 0)) { | if (failed || (GetFileLength(fname_temp) <= 0)) { | ||||
if (resample_fails < 2) | if (resample_fails < 2) | ||||
if (f_report != NULL) | if (f_report != NULL) | ||||
fprintf(f_report, "resampled %s\n", fname); | fprintf(f_report, "resampled %s\n", fname); | ||||
resample_count++; | resample_count++; | ||||
resample_wav = 1; | |||||
resample_wav = true; | |||||
fseek(f, 40, SEEK_SET); // skip past the WAV header, up to before "data length" | fseek(f, 40, SEEK_SET); // skip past the WAV header, up to before "data length" | ||||
} | } | ||||
length++; | length++; | ||||
} | } | ||||
if (resample_wav != 0) { | |||||
if (resample_wav == true) { | |||||
fclose(f); | fclose(f); | ||||
remove(fname_temp); | remove(fname_temp); | ||||
} | } | ||||
static int CompileIf(int elif) | static int CompileIf(int elif) | ||||
{ | { | ||||
int key; | int key; | ||||
int finish = 0; | |||||
bool finish = false; | |||||
int word = 0; | int word = 0; | ||||
int word2; | int word2; | ||||
int data; | int data; | ||||
int bitmap; | int bitmap; | ||||
int brackets; | int brackets; | ||||
int not_flag; | |||||
bool not_flag; | |||||
USHORT *prog_last_if = NULL; | USHORT *prog_last_if = NULL; | ||||
then_count = 2; | then_count = 2; | ||||
after_if = 1; | |||||
after_if = true; | |||||
while (!finish) { | while (!finish) { | ||||
not_flag = 0; | |||||
not_flag = false; | |||||
word2 = 0; | word2 = 0; | ||||
if (prog_out >= prog_out_max) { | if (prog_out >= prog_out_max) { | ||||
error("Phoneme program too large"); | error("Phoneme program too large"); | ||||
error("Expected a condition, not '%s'", item_string); | error("Expected a condition, not '%s'", item_string); | ||||
if ((item_type == 0) && (key == k_NOT)) { | if ((item_type == 0) && (key == k_NOT)) { | ||||
not_flag = 1; | |||||
not_flag = true; | |||||
if ((key = NextItem(tCONDITION)) < 0) | if ((key = NextItem(tCONDITION)) < 0) | ||||
error("Expected a condition, not '%s'", item_string); | error("Expected a condition, not '%s'", item_string); | ||||
} | } | ||||
*prog_last_if |= i_OR; | *prog_last_if |= i_OR; | ||||
break; | break; | ||||
case k_THEN: | case k_THEN: | ||||
finish = 1; | |||||
finish = true; | |||||
break; | break; | ||||
default: | default: | ||||
error("Expected AND, OR, THEN"); | error("Expected AND, OR, THEN"); | ||||
if_stack[if_level].p_else = NULL; | if_stack[if_level].p_else = NULL; | ||||
} | } | ||||
if_stack[if_level].returned = 0; | |||||
if_stack[if_level].returned = false; | |||||
if_stack[if_level].p_then = prog_out; | if_stack[if_level].p_then = prog_out; | ||||
*prog_out++ = i_JUMP_FALSE; | *prog_out++ = i_JUMP_FALSE; | ||||
return 0; | return 0; | ||||
} | } | ||||
if (if_stack[if_level].returned == 0) | |||||
if (if_stack[if_level].returned == false) | |||||
FillThen(1); | FillThen(1); | ||||
else | else | ||||
FillThen(0); | FillThen(0); | ||||
if (if_stack[if_level].returned == 0) { | |||||
if (if_stack[if_level].returned == false) { | |||||
ref = prog_out; | ref = prog_out; | ||||
*prog_out++ = 0; | *prog_out++ = 0; | ||||
prog_out = prog_buf; | prog_out = prog_buf; | ||||
prog_out_max = &prog_buf[MAX_PROG_BUF-1]; | prog_out_max = &prog_buf[MAX_PROG_BUF-1]; | ||||
if_level = 0; | if_level = 0; | ||||
if_stack[0].returned = 0; | |||||
after_if = 0; | |||||
if_stack[0].returned = false; | |||||
after_if = false; | |||||
phoneme_flags = 0; | phoneme_flags = 0; | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
if (phoneme_out->type == phVOWEL) | if (phoneme_out->type == phVOWEL) | ||||
value = (value * vowel_length_factor)/100; | value = (value * vowel_length_factor)/100; | ||||
if (after_if == 0) | |||||
if (after_if == false) | |||||
phoneme_out->std_length = value/2; | phoneme_out->std_length = value/2; | ||||
else { | else { | ||||
*prog_out++ = (i_SET_LENGTH << 8) + value/2; | *prog_out++ = (i_SET_LENGTH << 8) + value/2; | ||||
DecThenCount(); | DecThenCount(); | ||||
break; | break; | ||||
case kFMT: | case kFMT: | ||||
if_stack[if_level].returned = 1; | |||||
if_stack[if_level].returned = true; | |||||
DecThenCount(); | DecThenCount(); | ||||
if (phoneme_out->type == phVOWEL) | if (phoneme_out->type == phVOWEL) | ||||
CompileSound(keyword, 1); | CompileSound(keyword, 1); | ||||
CompileSound(keyword, 0); | CompileSound(keyword, 0); | ||||
break; | break; | ||||
case kWAV: | case kWAV: | ||||
if_stack[if_level].returned = 1; | |||||
if_stack[if_level].returned = true; | |||||
// fallthrough: | // fallthrough: | ||||
case kVOWELSTART: | case kVOWELSTART: | ||||
case kVOWELENDING: | case kVOWELENDING: | ||||
endphoneme = 1; | endphoneme = 1; | ||||
if (if_level > 0) | if (if_level > 0) | ||||
error("Missing ENDIF"); | error("Missing ENDIF"); | ||||
if ((prog_out > prog_buf) && (if_stack[0].returned == 0)) | |||||
if ((prog_out > prog_buf) && (if_stack[0].returned == false)) | |||||
*prog_out++ = INSTN_RETURN; | *prog_out++ = INSTN_RETURN; | ||||
break; | break; | ||||
} | } | ||||
char c; | char c; | ||||
int keyword; | int keyword; | ||||
int n_tune_names = 0; | int n_tune_names = 0; | ||||
int done_split = 0; | |||||
int done_onset = 0; | |||||
int done_last = 0; | |||||
bool done_split = false; | |||||
bool done_onset = false; | |||||
bool done_last = false; | |||||
int n_preset_tunes = 0; | int n_preset_tunes = 0; | ||||
int found = 0; | int found = 0; | ||||
int tune_number = 0; | int tune_number = 0; | ||||
switch (keyword) | switch (keyword) | ||||
{ | { | ||||
case kTUNE: | case kTUNE: | ||||
done_split = 0; | |||||
done_split = false; | |||||
memcpy(&new_tune, &default_tune, sizeof(TUNE)); | memcpy(&new_tune, &default_tune, sizeof(TUNE)); | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
break; | break; | ||||
case kENDTUNE: | case kENDTUNE: | ||||
if (!found) continue; | if (!found) continue; | ||||
if (done_onset == 0) { | |||||
if (done_onset == false) { | |||||
new_tune.unstr_start[0] = new_tune.unstr_start[1]; | new_tune.unstr_start[0] = new_tune.unstr_start[1]; | ||||
new_tune.unstr_end[0] = new_tune.unstr_end[1]; | new_tune.unstr_end[0] = new_tune.unstr_end[1]; | ||||
} | } | ||||
if (done_last == 0) { | |||||
if (done_last == false) { | |||||
new_tune.unstr_start[2] = new_tune.unstr_start[1]; | new_tune.unstr_start[2] = new_tune.unstr_start[1]; | ||||
new_tune.unstr_end[2] = new_tune.unstr_end[1]; | new_tune.unstr_end[2] = new_tune.unstr_end[1]; | ||||
} | } | ||||
new_tune.onset = NextItem(tNUMBER); | new_tune.onset = NextItem(tNUMBER); | ||||
new_tune.unstr_start[0] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_start[0] = NextItem(tSIGNEDNUMBER); | ||||
new_tune.unstr_end[0] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_end[0] = NextItem(tSIGNEDNUMBER); | ||||
done_onset = 1; | |||||
done_onset = true; | |||||
break; | break; | ||||
case kTUNE_HEADLAST: | case kTUNE_HEADLAST: | ||||
new_tune.head_last = NextItem(tNUMBER); | new_tune.head_last = NextItem(tNUMBER); | ||||
new_tune.unstr_start[2] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_start[2] = NextItem(tSIGNEDNUMBER); | ||||
new_tune.unstr_end[2] = NextItem(tSIGNEDNUMBER); | new_tune.unstr_end[2] = NextItem(tSIGNEDNUMBER); | ||||
done_last = 1; | |||||
done_last = true; | |||||
break; | break; | ||||
case kTUNE_HEADENV: | case kTUNE_HEADENV: | ||||
NextItem(tSTRING); | NextItem(tSTRING); | ||||
error("Bad envelope name: '%s'", item_string); | error("Bad envelope name: '%s'", item_string); | ||||
break; | break; | ||||
} | } | ||||
done_split = 1; | |||||
done_split = true; | |||||
new_tune.split_nucleus_env = ix; | new_tune.split_nucleus_env = ix; | ||||
new_tune.split_nucleus_max = NextItem(tNUMBER); | new_tune.split_nucleus_max = NextItem(tNUMBER); | ||||
new_tune.split_nucleus_min = NextItem(tNUMBER); | new_tune.split_nucleus_min = NextItem(tNUMBER); |
static int linenum; | static int linenum; | ||||
static int error_count; | static int error_count; | ||||
static int text_mode = 0; | |||||
static bool text_mode = false; | |||||
static int debug_flag = 0; | static int debug_flag = 0; | ||||
static int error_need_dictionary = 0; | static int error_need_dictionary = 0; | ||||
char *p_end; | char *p_end; | ||||
int ix; | int ix; | ||||
int match_type; | int match_type; | ||||
int finished = 0; | |||||
bool finished = false; | |||||
int value; | int value; | ||||
int linenum = 0; | int linenum = 0; | ||||
int flags; | int flags; | ||||
int suffix_char; | int suffix_char; | ||||
int condition_num = 0; | int condition_num = 0; | ||||
int at_start = 0; | |||||
bool at_start = false; | |||||
const char *name; | const char *name; | ||||
char buf[200]; | char buf[200]; | ||||
char buf_pre[200]; | char buf_pre[200]; | ||||
{ | { | ||||
case 0: | case 0: | ||||
case RULE_PHONEMES: | case RULE_PHONEMES: | ||||
finished = 1; | |||||
finished = true; | |||||
break; | break; | ||||
case RULE_PRE_ATSTART: | case RULE_PRE_ATSTART: | ||||
at_start = 1; | |||||
at_start = true; | |||||
// fallthrough: | // fallthrough: | ||||
case RULE_PRE: | case RULE_PRE: | ||||
match_type = RULE_PRE; | match_type = RULE_PRE; | ||||
int flag_offset; | int flag_offset; | ||||
int length; | int length; | ||||
int multiple_words = 0; | int multiple_words = 0; | ||||
int multiple_numeric_hyphen = 0; | |||||
bool multiple_numeric_hyphen = false; | |||||
char *multiple_string = NULL; | char *multiple_string = NULL; | ||||
char *multiple_string_end = NULL; | char *multiple_string_end = NULL; | ||||
int len_word; | int len_word; | ||||
int len_phonetic; | int len_phonetic; | ||||
int text_not_phonemes; // this word specifies replacement text, not phonemes | |||||
bool text_not_phonemes = false; // this word specifies replacement text, not phonemes | |||||
unsigned int wc; | unsigned int wc; | ||||
int all_upper_case; | |||||
bool all_upper_case; | |||||
char *mnemptr; | char *mnemptr; | ||||
unsigned char flag_codes[100]; | unsigned char flag_codes[100]; | ||||
int bad_phoneme; | int bad_phoneme; | ||||
static char nullstring[] = { 0 }; | static char nullstring[] = { 0 }; | ||||
text_not_phonemes = 0; | |||||
phonetic = word = nullstring; | phonetic = word = nullstring; | ||||
p = linebuf; | p = linebuf; | ||||
flagnum = LookupMnem(mnem_flags, mnemptr); | flagnum = LookupMnem(mnem_flags, mnemptr); | ||||
if (flagnum > 0) { | if (flagnum > 0) { | ||||
if (flagnum == 200) | if (flagnum == 200) | ||||
text_mode = 1; | |||||
text_mode = true; | |||||
else if (flagnum == 201) | else if (flagnum == 201) | ||||
text_mode = 0; | |||||
text_mode = false; | |||||
else if (flagnum == BITNUM_FLAG_TEXTMODE) | else if (flagnum == BITNUM_FLAG_TEXTMODE) | ||||
text_not_phonemes = 1; | |||||
text_not_phonemes = true; | |||||
else | else | ||||
flag_codes[n_flag_codes++] = flagnum; | flag_codes[n_flag_codes++] = flagnum; | ||||
} else { | } else { | ||||
case LINE_PARSER_END_OF_WORD: | case LINE_PARSER_END_OF_WORD: | ||||
if ((c == '-') && multiple_words) { | if ((c == '-') && multiple_words) { | ||||
if (IsDigit09(word[0])) | if (IsDigit09(word[0])) | ||||
multiple_numeric_hyphen = 1; | |||||
multiple_numeric_hyphen = true; | |||||
flag_codes[n_flag_codes++] = BITNUM_FLAG_HYPHENATED; | flag_codes[n_flag_codes++] = BITNUM_FLAG_HYPHENATED; | ||||
c = ' '; | c = ' '; | ||||
} | } | ||||
return 0; // blank line | return 0; // blank line | ||||
if (text_mode) | if (text_mode) | ||||
text_not_phonemes = 1; | |||||
text_not_phonemes = true; | |||||
if (text_not_phonemes) { | if (text_not_phonemes) { | ||||
if (word[0] == '_') { | if (word[0] == '_') { | ||||
// PROBLEM vowel reductions are not applied to the translated phonemes | // PROBLEM vowel reductions are not applied to the translated phonemes | ||||
// condition rules are not applied | // condition rules are not applied | ||||
TranslateWord(translator, phonetic, NULL, NULL); | TranslateWord(translator, phonetic, NULL, NULL); | ||||
text_not_phonemes = 0; | |||||
text_not_phonemes = false; | |||||
strncpy0(encoded_ph, word_phonemes, N_WORD_BYTES-4); | strncpy0(encoded_ph, word_phonemes, N_WORD_BYTES-4); | ||||
if ((word_phonemes[0] == 0) && (error_need_dictionary < 3)) { | if ((word_phonemes[0] == 0) && (error_need_dictionary < 3)) { | ||||
// convert to lower case, and note if the word is all-capitals | // convert to lower case, and note if the word is all-capitals | ||||
int c2; | int c2; | ||||
all_upper_case = 1; | |||||
all_upper_case = true; | |||||
for (p = word;;) { | for (p = word;;) { | ||||
// 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() | ||||
if (iswupper(c2)) | if (iswupper(c2)) | ||||
utf8_out(towlower2(c2), p); | utf8_out(towlower2(c2), p); | ||||
else | else | ||||
all_upper_case = 0; | |||||
all_upper_case = false; | |||||
p += ix; | p += ix; | ||||
} | } | ||||
if (all_upper_case) | if (all_upper_case) | ||||
char fname[sizeof(path_home)+45]; | char fname[sizeof(path_home)+45]; | ||||
char dict_line[256]; // length is uint8_t, so an entry can't take up more than 256 bytes | char dict_line[256]; // length is uint8_t, so an entry can't take up more than 256 bytes | ||||
text_mode = 0; | |||||
text_mode = false; | |||||
// try with and without '.txt' extension | // try with and without '.txt' extension | ||||
sprintf(fname, "%s%s.txt", path, filename); | sprintf(fname, "%s%s.txt", path, filename); | ||||
int c2, c3; | int c2, c3; | ||||
int sxflags; | int sxflags; | ||||
int value; | int value; | ||||
int literal; | |||||
int hexdigit_input = 0; | |||||
bool literal; | |||||
bool hexdigit_input = false; | |||||
int state = *state_out; | int state = *state_out; | ||||
MNEM_TAB *mr; | MNEM_TAB *mr; | ||||
sxflags = 0x808000; // to ensure non-zero bytes | sxflags = 0x808000; // to ensure non-zero bytes | ||||
for (p = string, ix = 0;;) { | for (p = string, ix = 0;;) { | ||||
literal = 0; | |||||
literal = false; | |||||
c = *p++; | c = *p++; | ||||
if ((c == '0') && (p[0] == 'x') && (isHexDigit(p[1]) >= 0) && (isHexDigit(p[2]) >= 0)) { | if ((c == '0') && (p[0] == 'x') && (isHexDigit(p[1]) >= 0) && (isHexDigit(p[2]) >= 0)) { | ||||
hexdigit_input = 1; | |||||
hexdigit_input = true; | |||||
c = p[1]; | c = p[1]; | ||||
p += 2; | p += 2; | ||||
} | } | ||||
c = (c-'0')*64 + (p[0]-'0')*8 + (p[1]-'0'); | c = (c-'0')*64 + (p[0]-'0')*8 + (p[1]-'0'); | ||||
p += 2; | p += 2; | ||||
} | } | ||||
literal = 1; | |||||
literal = true; | |||||
} | } | ||||
if (hexdigit_input) { | if (hexdigit_input) { | ||||
if (((c2 = isHexDigit(c)) >= 0) && ((c3 = isHexDigit(p[0])) >= 0)) { | if (((c2 = isHexDigit(c)) >= 0) && ((c3 = isHexDigit(p[0])) >= 0)) { | ||||
c = c2 * 16 + c3; | c = c2 * 16 + c3; | ||||
literal = 1; | |||||
literal = true; | |||||
p++; | p++; | ||||
} else | } else | ||||
hexdigit_input = 0; | |||||
hexdigit_input = false; | |||||
} | } | ||||
if ((state == 1) || (state == 3)) { | if ((state == 1) || (state == 3)) { | ||||
// replace special characters (note: 'E' is reserved for a replaced silent 'e') | // replace special characters (note: 'E' is reserved for a replaced silent 'e') | ||||
if (literal == 0) { | |||||
if (literal == false) { | |||||
static const char lettergp_letters[9] = { LETTERGP_A, LETTERGP_B, LETTERGP_C, 0, 0, LETTERGP_F, LETTERGP_G, LETTERGP_H, LETTERGP_Y }; | static const char lettergp_letters[9] = { LETTERGP_A, LETTERGP_B, LETTERGP_C, 0, 0, LETTERGP_F, LETTERGP_G, LETTERGP_H, LETTERGP_Y }; | ||||
switch (c) | switch (c) | ||||
{ | { | ||||
int len_name; | int len_name; | ||||
int start; | int start; | ||||
int state = 2; | int state = 2; | ||||
int finish = 0; | |||||
bool finish = false; | |||||
char buf[80]; | char buf[80]; | ||||
char output[150]; | char output[150]; | ||||
int bad_phoneme; | int bad_phoneme; | ||||
p = buf; | p = buf; | ||||
for (ix = 0; finish == 0; ix++) { | |||||
for (ix = 0; finish == false; ix++) { | |||||
switch (c = input[ix]) | switch (c = input[ix]) | ||||
{ | { | ||||
case ')': // end of prefix section | case ')': // end of prefix section | ||||
case 0: // end of line | case 0: // end of line | ||||
*p = 0; | *p = 0; | ||||
copy_rule_string(buf, &state); | copy_rule_string(buf, &state); | ||||
finish = 1; | |||||
finish = true; | |||||
break; | break; | ||||
case '\t': // end of section section | case '\t': // end of section section | ||||
case ' ': | case ' ': |
int c; | int c; | ||||
int mnem; | int mnem; | ||||
int len; | int len; | ||||
int first; | |||||
bool first; | |||||
int ix = 0; | int ix = 0; | ||||
char *p; | char *p; | ||||
PHONEME_DATA phdata; | PHONEME_DATA phdata; | ||||
} | } | ||||
} | } | ||||
first = 1; | |||||
first = true; | |||||
for (mnem = ph->mnemonic; (c = mnem & 0xff) != 0; mnem = mnem >> 8) { | for (mnem = ph->mnemonic; (c = mnem & 0xff) != 0; mnem = mnem >> 8) { | ||||
if ((c == '/') && (option_phoneme_variants == 0)) | if ((c == '/') && (option_phoneme_variants == 0)) | ||||
break; // discard phoneme variant indicator | break; // discard phoneme variant indicator | ||||
ix += utf8_out(c, &phon_out[ix]); | ix += utf8_out(c, &phon_out[ix]); | ||||
} else | } else | ||||
phon_out[ix++] = c; | phon_out[ix++] = c; | ||||
first = 0; | |||||
first = false; | |||||
} | } | ||||
phon_out = &phon_out[ix]; | phon_out = &phon_out[ix]; | ||||
int n_bytes; | int n_bytes; | ||||
int add_points; | int add_points; | ||||
int command; | int command; | ||||
int check_atstart; | |||||
bool check_atstart; | |||||
unsigned int *flags; | unsigned int *flags; | ||||
MatchRecord match; | MatchRecord match; | ||||
letter_w = 0; | letter_w = 0; | ||||
distance_right = -6; // used to reduce points for matches further away the current letter | distance_right = -6; // used to reduce points for matches further away the current letter | ||||
distance_left = -2; | distance_left = -2; | ||||
check_atstart = 0; | |||||
check_atstart = false; | |||||
match.points = 1; | match.points = 1; | ||||
match.end_type = 0; | match.end_type = 0; | ||||
failed = 2; // matched OK | failed = 2; // matched OK | ||||
break; | break; | ||||
case RULE_PRE_ATSTART: // pre rule with implied 'start of word' | case RULE_PRE_ATSTART: // pre rule with implied 'start of word' | ||||
check_atstart = 1; | |||||
check_atstart = true; | |||||
unpron_ignore = 0; | unpron_ignore = 0; | ||||
match_type = RULE_PRE; | match_type = RULE_PRE; | ||||
break; | break; | ||||
if ((failed == 2) && (unpron_ignore == 0)) { | if ((failed == 2) && (unpron_ignore == 0)) { | ||||
// do we also need to check for 'start of word' ? | // do we also need to check for 'start of word' ? | ||||
if ((check_atstart == 0) || (pre_ptr[-1] == ' ')) { | |||||
if ((check_atstart == false) || (pre_ptr[-1] == ' ')) { | |||||
if (check_atstart) | if (check_atstart) | ||||
match.points += 4; | match.points += 4; | ||||
const char *map; | const char *map; | ||||
char *p = text; | char *p = text; | ||||
char *p2; | char *p2; | ||||
int all_alpha = 1; | |||||
bool all_alpha = true; | |||||
int bits; | int bits; | ||||
int acc; | int acc; | ||||
int pairs_start; | int pairs_start; | ||||
if (map[c - min] > 0) | if (map[c - min] > 0) | ||||
buf[bufix++] = map[c - min]; | buf[bufix++] = map[c - min]; | ||||
else { | else { | ||||
all_alpha = 0; | |||||
all_alpha = false; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
} else { | } else { | ||||
all_alpha = 0; | |||||
all_alpha = false; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
if (option_phonemes & espeakPHONEMES_TRACE) { | if (option_phonemes & espeakPHONEMES_TRACE) { | ||||
char ph_decoded[N_WORD_PHONEMES]; | char ph_decoded[N_WORD_PHONEMES]; | ||||
int textmode; | |||||
bool textmode; | |||||
DecodePhonemes(phonetic, ph_decoded); | DecodePhonemes(phonetic, ph_decoded); | ||||
if ((dictionary_flags & FLAG_TEXTMODE) == 0) | if ((dictionary_flags & FLAG_TEXTMODE) == 0) | ||||
textmode = 0; | |||||
textmode = false; | |||||
else | else | ||||
textmode = 1; | |||||
textmode = true; | |||||
if (textmode == translator->langopts.textmode) { | if (textmode == translator->langopts.textmode) { | ||||
// only show this line if the word translates to phonemes, not replacement text | // only show this line if the word translates to phonemes, not replacement text |
int increment = 0; | int increment = 0; | ||||
int n_steps = 0; | int n_steps = 0; | ||||
int stage; // onset, head, last | int stage; // onset, head, last | ||||
int initial; | |||||
bool initial; | |||||
int overflow_ix = 0; | int overflow_ix = 0; | ||||
int pitch_range; | int pitch_range; | ||||
int pitch_range_abs; | int pitch_range_abs; | ||||
int n_unstressed = 0; | int n_unstressed = 0; | ||||
int unstressed_ix = 0; | int unstressed_ix = 0; | ||||
int unstressed_inc; | int unstressed_inc; | ||||
int used_onset = 0; | |||||
bool used_onset = false; | |||||
int head_final = end_ix; | int head_final = end_ix; | ||||
int secondary = 2; | int secondary = 2; | ||||
pitch_range = (tune->head_end - tune->head_start) << 8; | pitch_range = (tune->head_end - tune->head_start) << 8; | ||||
pitch_range_abs = abs(pitch_range); | pitch_range_abs = abs(pitch_range); | ||||
drops = drops_0; // this should be controled by tune->head_drops | drops = drops_0; // this should be controled by tune->head_drops | ||||
initial = 1; | |||||
initial = true; | |||||
stage = 0; | stage = 0; | ||||
if (tune->onset == 255) | if (tune->onset == 255) | ||||
// a primary stress | // a primary stress | ||||
if ((initial) || (stress == 5)) { | if ((initial) || (stress == 5)) { | ||||
initial = 0; | |||||
initial = false; | |||||
overflow_ix = 0; | overflow_ix = 0; | ||||
if (tune->onset == 255) { | if (tune->onset == 255) { | ||||
// a pitch has been specified for the onset syllable, don't include it in the pitch incrementing | // a pitch has been specified for the onset syllable, don't include it in the pitch incrementing | ||||
n_steps = count_increments(syllable_tab, syl_ix+1, head_final, 4); | n_steps = count_increments(syllable_tab, syl_ix+1, head_final, 4); | ||||
pitch = tune->onset << 8; | pitch = tune->onset << 8; | ||||
used_onset = 1; | |||||
used_onset = true; | |||||
} | } | ||||
if (n_steps > tune->head_max_steps) | if (n_steps > tune->head_max_steps) | ||||
} else { | } else { | ||||
if (used_onset) { | if (used_onset) { | ||||
stage = 1; | stage = 1; | ||||
used_onset = 0; | |||||
used_onset = false; | |||||
pitch = tune->head_start << 8; | pitch = tune->head_start << 8; | ||||
n_steps++; | n_steps++; | ||||
} else if (n_steps > 0) | } else if (n_steps > 0) | ||||
/* Calculate pitches until next RESET or tonic syllable, or end. | /* Calculate pitches until next RESET or tonic syllable, or end. | ||||
Increment pitch if stress is >= min_stress. | Increment pitch if stress is >= min_stress. | ||||
Used for tonic segment */ | Used for tonic segment */ | ||||
static int calc_pitch_segment(SYLLABLE *syllable_tab, int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, int continuing) | |||||
static int calc_pitch_segment(SYLLABLE *syllable_tab, int ix, int end_ix, TONE_HEAD *th, TONE_NUCLEUS *tn, int min_stress, bool continuing) | |||||
{ | { | ||||
int stress; | int stress; | ||||
int pitch = 0; | int pitch = 0; | ||||
int increment = 0; | int increment = 0; | ||||
int n_primary = 0; | int n_primary = 0; | ||||
int n_steps = 0; | int n_steps = 0; | ||||
int initial; | |||||
bool initial; | |||||
int overflow = 0; | int overflow = 0; | ||||
int n_overflow; | int n_overflow; | ||||
int pitch_range; | int pitch_range; | ||||
pitch_range_abs = abs(pitch_range); | pitch_range_abs = abs(pitch_range); | ||||
if (continuing) { | if (continuing) { | ||||
initial = 0; | |||||
initial = false; | |||||
overflow = 0; | overflow = 0; | ||||
n_overflow = 5; | n_overflow = 5; | ||||
overflow_tab = continue_tab; | overflow_tab = continue_tab; | ||||
} else { | } else { | ||||
n_overflow = th->n_overflow; | n_overflow = th->n_overflow; | ||||
overflow_tab = th->overflow; | overflow_tab = th->overflow; | ||||
initial = 1; | |||||
initial = true; | |||||
} | } | ||||
while (ix < end_ix) { | while (ix < end_ix) { | ||||
// a primary stress | // a primary stress | ||||
if ((initial) || (stress == 5)) { | if ((initial) || (stress == 5)) { | ||||
initial = 0; | |||||
initial = false; | |||||
overflow = 0; | overflow = 0; | ||||
n_steps = n_primary = count_increments(syllable_tab, ix, end_ix, min_stress); | n_steps = n_primary = count_increments(syllable_tab, ix, end_ix, min_stress); | ||||
TONE_HEAD *th; | TONE_HEAD *th; | ||||
TONE_NUCLEUS *tn; | TONE_NUCLEUS *tn; | ||||
int drop; | int drop; | ||||
int continuing = 0; | |||||
bool continuing = false; | |||||
if (control == 0) | if (control == 0) | ||||
return calc_pitches2(syllable_tab, start, end, tune_number); | return calc_pitches2(syllable_tab, start, end, tune_number); | ||||
if (start > 0) | if (start > 0) | ||||
continuing = 1; | |||||
continuing = true; | |||||
th = &tone_head_table[tune_number]; | th = &tone_head_table[tune_number]; | ||||
tn = &tone_nucleus_table[tune_number]; | tn = &tone_nucleus_table[tune_number]; | ||||
int final_stressed = 0; | int final_stressed = 0; | ||||
int tone_ph; | int tone_ph; | ||||
int pause; | |||||
int tone_promoted; | |||||
bool pause; | |||||
bool tone_promoted; | |||||
PHONEME_TAB *tph; | PHONEME_TAB *tph; | ||||
PHONEME_TAB *prev_tph; // forget across word boundary | PHONEME_TAB *prev_tph; // forget across word boundary | ||||
PHONEME_TAB *prevw_tph; // remember across word boundary | PHONEME_TAB *prevw_tph; // remember across word boundary | ||||
p->tone_ph = PhonemeCode('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 | ||||
} | } | ||||
pause = 1; | |||||
tone_promoted = 0; | |||||
pause = true; | |||||
tone_promoted = false; | |||||
prev_p = p = &phoneme_list[0]; | prev_p = p = &phoneme_list[0]; | ||||
prev_tph = prevw_tph = phoneme_tab[phonPAUSE]; | prev_tph = prevw_tph = phoneme_tab[phonPAUSE]; | ||||
// perform tone sandhi | // perform tone sandhi | ||||
for (ix = 0; ix < n_phoneme_list; ix++, p++) { | for (ix = 0; ix < n_phoneme_list; ix++, p++) { | ||||
if ((p->type == phPAUSE) && (p->ph->std_length > 50)) { | if ((p->type == phPAUSE) && (p->ph->std_length > 50)) { | ||||
pause = 1; // there is a pause since the previous vowel | |||||
pause = true; // there is a pause since the previous vowel | |||||
prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone | prevw_tph = phoneme_tab[phonPAUSE]; // forget previous tone | ||||
} | } | ||||
if (tone_ph == 0) { | if (tone_ph == 0) { | ||||
if (pause || tone_promoted) { | if (pause || tone_promoted) { | ||||
tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1 | tone_ph = PhonemeCode2('5', '5'); // no previous vowel, use tone 1 | ||||
tone_promoted = 1; | |||||
tone_promoted = true; | |||||
} else | } else | ||||
tone_ph = PhonemeCode2('1', '1'); // default tone 5 | tone_ph = PhonemeCode2('1', '1'); // default tone 5 | ||||
p->tone_ph = tone_ph; | p->tone_ph = tone_ph; | ||||
tph = phoneme_tab[tone_ph]; | tph = phoneme_tab[tone_ph]; | ||||
} else | } else | ||||
tone_promoted = 0; | |||||
tone_promoted = false; | |||||
if (ix == final_stressed) { | if (ix == final_stressed) { | ||||
if ((tph->mnemonic == 0x3535 ) || (tph->mnemonic == 0x3135)) { | if ((tph->mnemonic == 0x3535 ) || (tph->mnemonic == 0x3135)) { | ||||
prev_p = p; | prev_p = p; | ||||
prevw_tph = prev_tph = tph; | prevw_tph = prev_tph = tph; | ||||
pause = 0; | |||||
pause = false; | |||||
} | } | ||||
} | } | ||||
{ | { | ||||
// returns M, or perhaps MA or MB for some cases | // returns M, or perhaps MA or MB for some cases | ||||
int teens = 0; | |||||
bool teens = false; | |||||
if (((value % 100) > 10) && ((value % 100) < 20)) | if (((value % 100) > 10) && ((value % 100) < 20)) | ||||
teens = 1; | |||||
teens = true; | |||||
switch ((translator->langopts.numbers2 >> 6) & 0x7) | switch ((translator->langopts.numbers2 >> 6) & 0x7) | ||||
{ | { | ||||
case 1: // lang=ru use singular for xx1 except for x11 | case 1: // lang=ru use singular for xx1 except for x11 | ||||
if ((teens == 0) && ((value % 10) == 1)) | |||||
if ((teens == false) && ((value % 10) == 1)) | |||||
return "1M"; | return "1M"; | ||||
break; | break; | ||||
case 2: // lang=cs,sk | case 2: // lang=cs,sk | ||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 3: // lang=pl | case 3: // lang=pl | ||||
if ((teens == 0) && (((value % 10) >= 2) && ((value % 10) <= 4))) | |||||
if ((teens == false) && (((value % 10) >= 2) && ((value % 10) <= 4))) | |||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 4: // lang=lt | case 4: // lang=lt | ||||
if ((teens == 1) || ((value % 10) == 0)) | |||||
if ((teens == true) || ((value % 10) == 0)) | |||||
return "0MB"; | return "0MB"; | ||||
if ((value % 10) == 1) | if ((value % 10) == 1) | ||||
return "0MA"; | return "0MA"; | ||||
break; | break; | ||||
case 5: // lang=bs,hr,sr | case 5: // lang=bs,hr,sr | ||||
if (teens == 0) { | |||||
if (teens == false) { | |||||
if ((value % 10) == 1) | if ((value % 10) == 1) | ||||
return "1M"; | return "1M"; | ||||
if (((value % 10) >= 2) && ((value % 10) <= 4)) | if (((value % 10) >= 2) && ((value % 10) <= 4)) | ||||
return used_and; | return used_and; | ||||
} | } | ||||
static int LookupNum3(Translator *tr, int value, char *ph_out, int suppress_null, int thousandplex, int control) | |||||
static int LookupNum3(Translator *tr, int value, char *ph_out, bool suppress_null, int thousandplex, int control) | |||||
{ | { | ||||
// Translate a 3 digit number | // Translate a 3 digit number | ||||
// control bit 0, previous thousands | // control bit 0, previous thousands | ||||
int exact; | int exact; | ||||
int ordinal; | int ordinal; | ||||
int tplex; | int tplex; | ||||
int say_zero_hundred = 0; | |||||
int say_one_hundred; | |||||
bool say_zero_hundred = false; | |||||
bool say_one_hundred; | |||||
char string[12]; // for looking up entries in **_list | char string[12]; // for looking up entries in **_list | ||||
char buf1[100]; | char buf1[100]; | ||||
char buf2[100]; | char buf2[100]; | ||||
ph_thousand_and[0] = 0; | ph_thousand_and[0] = 0; | ||||
if ((tr->langopts.numbers & NUM_ZERO_HUNDRED) && ((control & 1) || (hundreds >= 10))) | if ((tr->langopts.numbers & NUM_ZERO_HUNDRED) && ((control & 1) || (hundreds >= 10))) | ||||
say_zero_hundred = 1; // lang=vi | |||||
say_zero_hundred = true; // lang=vi | |||||
if ((hundreds > 0) || say_zero_hundred) { | if ((hundreds > 0) || say_zero_hundred) { | ||||
found = 0; | found = 0; | ||||
sprintf(ph_thousands, "%s%c%s%c", ph_digits, phonEND_WORD, ph_10T, phonEND_WORD); | sprintf(ph_thousands, "%s%c%s%c", ph_digits, phonEND_WORD, ph_10T, phonEND_WORD); | ||||
hundreds %= 10; | hundreds %= 10; | ||||
if ((hundreds == 0) && (say_zero_hundred == 0)) | |||||
if ((hundreds == 0) && (say_zero_hundred == false)) | |||||
ph_100[0] = 0; | ph_100[0] = 0; | ||||
suppress_null = 1; | |||||
suppress_null = true; | |||||
control |= 1; | control |= 1; | ||||
} | } | ||||
if ((tr->langopts.numbers & NUM_AND_HUNDRED) && ((control & 1) || (ph_thousands[0] != 0))) | if ((tr->langopts.numbers & NUM_AND_HUNDRED) && ((control & 1) || (ph_thousands[0] != 0))) | ||||
Lookup(tr, "_0and", ph_thousand_and); | Lookup(tr, "_0and", ph_thousand_and); | ||||
suppress_null = 1; | |||||
suppress_null = true; | |||||
found = 0; | found = 0; | ||||
if ((ordinal) | if ((ordinal) | ||||
if (found) | if (found) | ||||
ph_100[0] = 0; | ph_100[0] = 0; | ||||
else { | else { | ||||
say_one_hundred = 1; | |||||
say_one_hundred = true; | |||||
if (hundreds == 1) { | if (hundreds == 1) { | ||||
if ((tr->langopts.numbers & NUM_OMIT_1_HUNDRED) != 0) | if ((tr->langopts.numbers & NUM_OMIT_1_HUNDRED) != 0) | ||||
say_one_hundred = 0; | |||||
say_one_hundred = false; | |||||
} | } | ||||
if (say_one_hundred != 0) | |||||
if (say_one_hundred == true) | |||||
LookupNum2(tr, hundreds, thousandplex, 0, ph_digits); | LookupNum2(tr, hundreds, thousandplex, 0, ph_digits); | ||||
} | } | ||||
} | } | ||||
buf2[0] = 0; | buf2[0] = 0; | ||||
if ((tensunits != 0) || (suppress_null == 0)) { | |||||
if ((tensunits != 0) || (suppress_null == false)) { | |||||
x = 0; | x = 0; | ||||
if (thousandplex == 0) { | if (thousandplex == 0) { | ||||
x = 2; // allow "eins" for 1 rather than "ein" | x = 2; // allow "eins" for 1 rather than "ein" | ||||
int ix; | int ix; | ||||
int digix; | int digix; | ||||
unsigned char c; | unsigned char c; | ||||
int suppress_null = 0; | |||||
bool suppress_null = false; | |||||
int decimal_point = 0; | int decimal_point = 0; | ||||
int thousandplex = 0; | int thousandplex = 0; | ||||
int thousands_exact = 1; | int thousands_exact = 1; | ||||
} | } | ||||
if ((value == 0) && prev_thousands) | if ((value == 0) && prev_thousands) | ||||
suppress_null = 1; | |||||
suppress_null = true; | |||||
if (tr->translator_name == L('h', 'u')) { | if (tr->translator_name == L('h', 'u')) { | ||||
// variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt | // variant form of numbers when followed by hyphen and a suffix starting with 'a' or 'e' (but not a, e, az, ez, azt, ezt | ||||
// this "word" ends with a decimal point | // this "word" ends with a decimal point | ||||
Lookup(tr, "_dpt", ph_append); | Lookup(tr, "_dpt", ph_append); | ||||
decimal_point = 0x100; | decimal_point = 0x100; | ||||
} else if (suppress_null == 0) { | |||||
} else if (suppress_null == false) { | |||||
if (thousands_inc > 0) { | if (thousands_inc > 0) { | ||||
if (thousandplex > 0) { | if (thousandplex > 0) { | ||||
if ((suppress_null == 0) && (LookupThousands(tr, value, thousandplex, thousands_exact, ph_append))) { | |||||
if ((suppress_null == false) && (LookupThousands(tr, value, thousandplex, thousands_exact, ph_append))) { | |||||
// found an exact match for N thousand | // found an exact match for N thousand | ||||
value = 0; | value = 0; | ||||
suppress_null = 1; | |||||
suppress_null = true; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
n_digits++; | n_digits++; | ||||
} | } | ||||
if ((decimal_count <= max_decimal_count) && IsDigit09(word[n_digits])) { | if ((decimal_count <= max_decimal_count) && IsDigit09(word[n_digits])) { | ||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0, 0, 0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, false, 0, 0); | |||||
strcat(ph_out, buf1); | strcat(ph_out, buf1); | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } | ||||
case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero | case NUM_DFRACTION_1: // italian, say "hundredths" if leading zero | ||||
case NUM_DFRACTION_5: // hungarian, always say "tenths" etc. | case NUM_DFRACTION_5: // hungarian, always say "tenths" etc. | ||||
case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction | case NUM_DFRACTION_6: // kazakh, always say "tenths" etc, before the decimal fraction | ||||
LookupNum3(tr, atoi(&word[n_digits]), ph_buf, 0, 0, 0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), ph_buf, false, 0, 0); | |||||
if ((word[n_digits] == '0') || (decimal_mode != NUM_DFRACTION_1)) { | if ((word[n_digits] == '0') || (decimal_mode != NUM_DFRACTION_1)) { | ||||
// 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); | ||||
case NUM_DFRACTION_3: | case NUM_DFRACTION_3: | ||||
// Romanian decimal fractions | // Romanian decimal fractions | ||||
if ((decimal_count <= 4) && (word[n_digits] != '0')) { | if ((decimal_count <= 4) && (word[n_digits] != '0')) { | ||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, 0, 0, 0); | |||||
LookupNum3(tr, atoi(&word[n_digits]), buf1, false, 0, 0); | |||||
strcat(ph_out, buf1); | strcat(ph_out, buf1); | ||||
n_digits += decimal_count; | n_digits += decimal_count; | ||||
} | } |
int k; | int k; | ||||
int replace_flags; | int replace_flags; | ||||
int n_plist_out = 0; | int n_plist_out = 0; | ||||
int word_end; | |||||
bool word_end; | |||||
PHONEME_LIST2 *plist2; | PHONEME_LIST2 *plist2; | ||||
PHONEME_TAB *next = NULL; | PHONEME_TAB *next = NULL; | ||||
if (ix < (n_ph_list2 -1)) | if (ix < (n_ph_list2 -1)) | ||||
next = phoneme_tab[ph_list2[ix+1].phcode]; | next = phoneme_tab[ph_list2[ix+1].phcode]; | ||||
word_end = 0; | |||||
word_end = false; | |||||
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 = true; // this phoneme is the end of a word | |||||
// check whether a Voice has specified that we should replace this phoneme | // check whether a Voice has specified that we should replace this phoneme | ||||
for (k = 0; k < n_replace_phonemes; k++) { | for (k = 0; k < n_replace_phonemes; k++) { | ||||
if (plist2->phcode == replace_phonemes[k].old_ph) { | if (plist2->phcode == replace_phonemes[k].old_ph) { | ||||
replace_flags = replace_phonemes[k].type; | replace_flags = replace_phonemes[k].type; | ||||
if ((replace_flags & 1) && (word_end == 0)) | |||||
if ((replace_flags & 1) && (word_end == false)) | |||||
continue; // this replacement only occurs at the end of a word | continue; // this replacement only occurs at the end of a word | ||||
if ((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3)) | if ((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3)) | ||||
return n_plist_out; | return n_plist_out; | ||||
} | } | ||||
void MakePhonemeList(Translator *tr, int post_pause, int start_sentence) | |||||
void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||||
{ | { | ||||
int ix = 0; | int ix = 0; | ||||
int j; | int j; | ||||
// set consonant clusters to all voiced or all unvoiced | // set consonant clusters to all voiced or all unvoiced | ||||
// Regressive | // Regressive | ||||
int type; | int type; | ||||
int stop_propagation = 0; | |||||
bool stop_propagation = false; | |||||
voicing = 0; | voicing = 0; | ||||
for (j = n_ph_list2-1; j >= 0; j--) { | for (j = n_ph_list2-1; j >= 0; j--) { | ||||
continue; | continue; | ||||
if (plist2[j].synthflags & SFLAG_SWITCHED_LANG) { | if (plist2[j].synthflags & SFLAG_SWITCHED_LANG) { | ||||
stop_propagation = 0; | |||||
stop_propagation = false; | |||||
voicing = 0; | voicing = 0; | ||||
if (regression & 0x100) | if (regression & 0x100) | ||||
voicing = 1; // word-end devoicing | voicing = 1; // word-end devoicing | ||||
if (regression & 0x2) { | if (regression & 0x2) { | ||||
// [v] amd [v;] don't cause regression, or [R^] | // [v] amd [v;] don't cause regression, or [R^] | ||||
if (((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff) == 'R')) { | if (((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff) == 'R')) { | ||||
stop_propagation = 1; | |||||
stop_propagation = true; | |||||
if (regression & 0x10) | if (regression & 0x10) | ||||
voicing = 0; | voicing = 0; | ||||
} | } | ||||
} | } | ||||
if (stop_propagation) { | if (stop_propagation) { | ||||
voicing = 0; | voicing = 0; | ||||
stop_propagation = 0; | |||||
stop_propagation = false; | |||||
} | } | ||||
if (plist2[j].sourceix) { | if (plist2[j].sourceix) { | ||||
if (start_sentence) { | if (start_sentence) { | ||||
phlist[ix].newword = 5; // start of sentence + start of word | phlist[ix].newword = 5; // start of sentence + start of word | ||||
start_sentence = 0; | |||||
start_sentence = false; | |||||
} | } | ||||
} else | } else | ||||
phlist[ix].newword = 0; | phlist[ix].newword = 0; |
static int ungot_char; | static int ungot_char; | ||||
static const char *ungot_word = NULL; | static const char *ungot_word = NULL; | ||||
static int ignore_text = 0; // set during <sub> ... </sub> to ignore text which has been replaced by an alias | |||||
static int audio_text = 0; // set during <audio> ... </audio> | |||||
static int clear_skipping_text = 0; // next clause should clear the skipping_text flag | |||||
static bool ignore_text = false; // set during <sub> ... </sub> to ignore text which has been replaced by an alias | |||||
static bool audio_text = false; // set during <audio> ... </audio> | |||||
static bool clear_skipping_text = false; // next clause should clear the skipping_text flag | |||||
int count_characters = 0; | int count_characters = 0; | ||||
static int sayas_mode; | static int sayas_mode; | ||||
static int sayas_start; | static int sayas_start; | ||||
return 0; | return 0; | ||||
} | } | ||||
static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int *outix, int n_outbuf, int self_closing) | |||||
static int ProcessSsmlTag(wchar_t *xml_buf, char *outbuf, int *outix, int n_outbuf, bool self_closing) | |||||
{ | { | ||||
// xml_buf is the tag and attributes with a zero terminator in place of the original '>' | // xml_buf is the tag and attributes with a zero terminator in place of the original '>' | ||||
// returns a clause terminator value. | // returns a clause terminator value. | ||||
case SSML_SUB: | case SSML_SUB: | ||||
if ((attr1 = GetSsmlAttribute(px, "alias")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "alias")) != NULL) { | ||||
// use the alias rather than the text | // use the alias rather than the text | ||||
ignore_text = 1; | |||||
ignore_text = true; | |||||
*outix += attrcopy_utf8(&outbuf[*outix], attr1, n_outbuf-*outix); | *outix += attrcopy_utf8(&outbuf[*outix], attr1, n_outbuf-*outix); | ||||
} | } | ||||
break; | break; | ||||
case SSML_IGNORE_TEXT: | case SSML_IGNORE_TEXT: | ||||
ignore_text = 1; | |||||
ignore_text = true; | |||||
break; | break; | ||||
case SSML_SUB + SSML_CLOSE: | case SSML_SUB + SSML_CLOSE: | ||||
case SSML_IGNORE_TEXT + SSML_CLOSE: | case SSML_IGNORE_TEXT + SSML_CLOSE: | ||||
ignore_text = 0; | |||||
ignore_text = false; | |||||
break; | break; | ||||
case SSML_MARK: | case SSML_MARK: | ||||
if ((attr1 = GetSsmlAttribute(px, "name")) != NULL) { | if ((attr1 = GetSsmlAttribute(px, "name")) != NULL) { | ||||
if (strcmp(skip_marker, buf) == 0) { | if (strcmp(skip_marker, buf) == 0) { | ||||
// This is the marker we are waiting for before starting to speak | // This is the marker we are waiting for before starting to speak | ||||
clear_skipping_text = 1; | |||||
clear_skipping_text = true; | |||||
skip_marker[0] = 0; | skip_marker[0] = 0; | ||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
} | } | ||||
if (self_closing) | if (self_closing) | ||||
PopParamStack(tag_type, outbuf, outix); | PopParamStack(tag_type, outbuf, outix); | ||||
else | else | ||||
audio_text = 1; | |||||
audio_text = true; | |||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
case SSML_AUDIO + SSML_CLOSE: | case SSML_AUDIO + SSML_CLOSE: | ||||
PopParamStack(tag_type, outbuf, outix); | PopParamStack(tag_type, outbuf, outix); | ||||
audio_text = 0; | |||||
audio_text = false; | |||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
case SSML_BREAK: | case SSML_BREAK: | ||||
value = 21; | value = 21; | ||||
int n_xml_buf; | int n_xml_buf; | ||||
int terminator; | int terminator; | ||||
int found; | int found; | ||||
int any_alnum = 0; | |||||
int self_closing; | |||||
bool any_alnum = false; | |||||
bool self_closing; | |||||
int punct_data = 0; | int punct_data = 0; | ||||
int is_end_clause; | |||||
bool is_end_clause; | |||||
int announced_punctuation = 0; | int announced_punctuation = 0; | ||||
int stressed_word = 0; | |||||
bool stressed_word = false; | |||||
int end_clause_after_tag = 0; | int end_clause_after_tag = 0; | ||||
int end_clause_index = 0; | int end_clause_index = 0; | ||||
wchar_t xml_buf[N_XML_BUF+1]; | wchar_t xml_buf[N_XML_BUF+1]; | ||||
static int ungot_string_ix = -1; | static int ungot_string_ix = -1; | ||||
if (clear_skipping_text) { | if (clear_skipping_text) { | ||||
skipping_text = 0; | |||||
clear_skipping_text = 0; | |||||
skipping_text = false; | |||||
clear_skipping_text = false; | |||||
} | } | ||||
tr->phonemes_repeat_count = 0; | tr->phonemes_repeat_count = 0; | ||||
if ((skip_characters > 0) && (count_characters >= skip_characters)) { | if ((skip_characters > 0) && (count_characters >= skip_characters)) { | ||||
// reached the specified start position | // reached the specified start position | ||||
// don't break a word | // don't break a word | ||||
clear_skipping_text = 1; | |||||
clear_skipping_text = true; | |||||
skip_characters = 0; | skip_characters = 0; | ||||
UngetC(c2); | UngetC(c2); | ||||
return CLAUSE_NONE; | return CLAUSE_NONE; | ||||
xml_buf[n_xml_buf] = 0; | xml_buf[n_xml_buf] = 0; | ||||
c2 = ' '; | c2 = ' '; | ||||
self_closing = 0; | |||||
self_closing = false; | |||||
if (xml_buf[n_xml_buf-1] == '/') { | if (xml_buf[n_xml_buf-1] == '/') { | ||||
// a self-closing tag | // a self-closing tag | ||||
xml_buf[n_xml_buf-1] = ' '; | xml_buf[n_xml_buf-1] = ' '; | ||||
self_closing = 1; | |||||
self_closing = true; | |||||
} | } | ||||
terminator = ProcessSsmlTag(xml_buf, buf, &ix, n_buf, self_closing); | terminator = ProcessSsmlTag(xml_buf, buf, &ix, n_buf, self_closing); | ||||
} | } | ||||
if (iswalnum(c1)) | if (iswalnum(c1)) | ||||
any_alnum = 1; | |||||
any_alnum = true; | |||||
else { | else { | ||||
if (stressed_word) { | if (stressed_word) { | ||||
stressed_word = 0; | |||||
stressed_word = false; | |||||
c1 = CHAR_EMPHASIS; // indicate this word is stressed | c1 = CHAR_EMPHASIS; // indicate this word is stressed | ||||
UngetC(c2); | UngetC(c2); | ||||
c2 = ' '; | c2 = ' '; | ||||
announced_punctuation = 0; | announced_punctuation = 0; | ||||
if ((phoneme_mode == 0) && (sayas_mode == 0)) { | if ((phoneme_mode == 0) && (sayas_mode == 0)) { | ||||
is_end_clause = 0; | |||||
is_end_clause = false; | |||||
if (end_clause_after_tag) { | if (end_clause_after_tag) { | ||||
// Because of an xml tag, we are waiting for the | // Because of an xml tag, we are waiting for the | ||||
if ((punct_data = clause_type_from_codepoint(c1)) != CLAUSE_NONE) { | if ((punct_data = clause_type_from_codepoint(c1)) != CLAUSE_NONE) { | ||||
if (punct_data & CLAUSE_PUNCTUATION_IN_WORD) { | if (punct_data & CLAUSE_PUNCTUATION_IN_WORD) { | ||||
// Armenian punctuation inside a word | // Armenian punctuation inside a word | ||||
stressed_word = 1; | |||||
stressed_word = true; | |||||
*tone_type = punct_data >> 12 & 0xf; // override the end-of-sentence type | *tone_type = punct_data >> 12 & 0xf; // override the end-of-sentence type | ||||
continue; | continue; | ||||
} | } | ||||
if ((iswspace(c2) || (punct_data & CLAUSE_OPTIONAL_SPACE_AFTER) || IsBracket(c2) || (c2 == '?') || Eof() || (c2 == ctrl_embedded))) { // don't check for '-' because it prevents recognizing ':-)' | if ((iswspace(c2) || (punct_data & CLAUSE_OPTIONAL_SPACE_AFTER) || IsBracket(c2) || (c2 == '?') || Eof() || (c2 == ctrl_embedded))) { // don't check for '-' because it prevents recognizing ':-)' | ||||
// note: (c2='?') is for when a smart-quote has been replaced by '?' | // note: (c2='?') is for when a smart-quote has been replaced by '?' | ||||
is_end_clause = 1; | |||||
is_end_clause = true; | |||||
} | } | ||||
} | } | ||||
// don't announce punctuation for the alternative text inside inside <audio> ... </audio> | // don't announce punctuation for the alternative text inside inside <audio> ... </audio> | ||||
if (c1 == 0xe000+'<') c1 = '<'; | if (c1 == 0xe000+'<') c1 = '<'; | ||||
if (option_punctuation && iswpunct(c1) && (audio_text == 0)) { | |||||
if (option_punctuation && iswpunct(c1) && (audio_text == false)) { | |||||
// option is set to explicitly speak punctuation characters | // option is set to explicitly speak punctuation characters | ||||
// 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 ((c1 == ',') && (cprev == '.') && (tr->translator_name == L('h', 'u')) && iswdigit(cprev2) && (iswdigit(c_next) || (iswlower(c_next)))) { | if ((c1 == ',') && (cprev == '.') && (tr->translator_name == L('h', 'u')) && iswdigit(cprev2) && (iswdigit(c_next) || (iswlower(c_next)))) { | ||||
// lang=hu, fix for ordinal numbers, eg: "december 2., szerda", ignore ',' after ordinal number | // lang=hu, fix for ordinal numbers, eg: "december 2., szerda", ignore ',' after ordinal number | ||||
c1 = CHAR_COMMA_BREAK; | c1 = CHAR_COMMA_BREAK; | ||||
is_end_clause = 0; | |||||
is_end_clause = false; | |||||
} | } | ||||
if (c1 == '.') { | if (c1 == '.') { | ||||
(iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) { // lang=hu | (iswdigit(cprev) || (IsRomanU(cprev) && (IsRomanU(cprev2) || iswspace(cprev2))))) { // lang=hu | ||||
// dot after a number indicates an ordinal number | // dot after a number indicates an ordinal number | ||||
if (!iswdigit(cprev)) | if (!iswdigit(cprev)) | ||||
is_end_clause = 0; // Roman number followed by dot | |||||
is_end_clause = false; // Roman number followed by dot | |||||
else if (iswlower(c_next) || (c_next == '-')) // hyphen is needed for lang-hu (eg. 2.-kal) | else if (iswlower(c_next) || (c_next == '-')) // hyphen is needed for lang-hu (eg. 2.-kal) | ||||
is_end_clause = 0; // only if followed by lower-case, (or if there is a XML tag) | |||||
is_end_clause = false; // only if followed by lower-case, (or if there is a XML tag) | |||||
} else if (c_next == '\'') | } else if (c_next == '\'') | ||||
is_end_clause = 0; // eg. u.s.a.'s | |||||
is_end_clause = false; // eg. u.s.a.'s | |||||
if (iswlower(c_next)) { | if (iswlower(c_next)) { | ||||
// next word has no capital letter, this dot is probably from an abbreviation | // next word has no capital letter, this dot is probably from an abbreviation | ||||
is_end_clause = 0; | is_end_clause = 0; | ||||
} | } | ||||
if (any_alnum == 0) { | |||||
if (any_alnum == false) { | |||||
// no letters or digits yet, so probably not a sentence terminator | // no letters or digits yet, so probably not a sentence terminator | ||||
// Here, dot is followed by space or bracket | // Here, dot is followed by space or bracket | ||||
c1 = ' '; | c1 = ' '; | ||||
is_end_clause = 0; | |||||
is_end_clause = false; | |||||
} | } | ||||
} else { | } else { | ||||
if (any_alnum == 0) { | |||||
if (any_alnum == false) { | |||||
// no letters or digits yet, so probably not a sentence terminator | // no letters or digits yet, so probably not a sentence terminator | ||||
is_end_clause = 0; | |||||
is_end_clause = false; | |||||
} | } | ||||
} | } | ||||
if (is_end_clause && (c1 == '.') && (c_next == '<') && option_ssml) { | if (is_end_clause && (c1 == '.') && (c_next == '<') && option_ssml) { | ||||
// wait until after the end of the xml tag, then look for upper-case letter | // wait until after the end of the xml tag, then look for upper-case letter | ||||
is_end_clause = 0; | |||||
is_end_clause = false; | |||||
end_clause_index = ix; | end_clause_index = ix; | ||||
end_clause_after_tag = punct_data; | end_clause_after_tag = punct_data; | ||||
} | } | ||||
current_voice_id[0] = 0; | current_voice_id[0] = 0; | ||||
ignore_text = 0; | |||||
audio_text = 0; | |||||
clear_skipping_text = 0; | |||||
ignore_text = false; | |||||
audio_text = false; | |||||
clear_skipping_text = false; | |||||
count_characters = -1; | count_characters = -1; | ||||
sayas_mode = 0; | sayas_mode = 0; | ||||
int stress; | int stress; | ||||
int type; | int type; | ||||
static int more_syllables = 0; | static int more_syllables = 0; | ||||
int pre_sonorant = 0; | |||||
int pre_voiced = 0; | |||||
bool pre_sonorant = false; | |||||
bool pre_voiced = false; | |||||
int last_pitch = 0; | int last_pitch = 0; | ||||
int pitch_start; | int pitch_start; | ||||
int length_mod; | int length_mod; | ||||
if (type == phVFRICATIVE) { | if (type == phVFRICATIVE) { | ||||
if (next->type == phVOWEL) | if (next->type == phVOWEL) | ||||
pre_voiced = 1; | |||||
pre_voiced = true; | |||||
if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) | if ((prev->type == phVOWEL) || (prev->type == phLIQUID)) | ||||
p->length = (255 + prev->length)/2; | p->length = (255 + prev->length)/2; | ||||
} | } | ||||
if (next->type == phVOWEL || next->type == phLIQUID) { | if (next->type == phVOWEL || next->type == phLIQUID) { | ||||
if ((next->type == phVOWEL) || !next->newword) | if ((next->type == phVOWEL) || !next->newword) | ||||
pre_voiced = 1; | |||||
pre_voiced = true; | |||||
p->prepause = 40; | p->prepause = 40; | ||||
} | } | ||||
if (next->type == phVOWEL) | if (next->type == phVOWEL) | ||||
pre_sonorant = 1; | |||||
pre_sonorant = true; | |||||
else { | else { | ||||
p->pitch2 = last_pitch; | p->pitch2 = last_pitch; | ||||
if (p->pitch2 < 16) | if (p->pitch2 < 16) | ||||
p->pitch1 = 0; | p->pitch1 = 0; | ||||
p->env = PITCHfall; | p->env = PITCHfall; | ||||
pre_voiced = 0; | |||||
pre_voiced = false; | |||||
} | } | ||||
break; | break; | ||||
case phVOWEL: | case phVOWEL: | ||||
} | } | ||||
last_pitch = p->pitch1 + ((p->pitch2-p->pitch1)*envelope_data[p->env][127])/256; | last_pitch = p->pitch1 + ((p->pitch2-p->pitch1)*envelope_data[p->env][127])/256; | ||||
pre_sonorant = 0; | |||||
pre_voiced = 0; | |||||
pre_sonorant = false; | |||||
pre_voiced = false; | |||||
break; | break; | ||||
} | } | ||||
} | } |
} | } | ||||
if (skip_characters || skip_words || skip_sentences) | if (skip_characters || skip_words || skip_sentences) | ||||
skipping_text = 1; | |||||
skipping_text = true; | |||||
end_character_position = end_position; | end_character_position = end_position; | ||||
if (index_mark != NULL) { | if (index_mark != NULL) { | ||||
strncpy0(skip_marker, index_mark, sizeof(skip_marker)); | strncpy0(skip_marker, index_mark, sizeof(skip_marker)); | ||||
skipping_text = 1; | |||||
skipping_text = true; | |||||
} | } | ||||
end_character_position = end_position; | end_character_position = end_position; |
MBROLA_TAB *pr; | MBROLA_TAB *pr; | ||||
PHONEME_TAB *other_ph; | PHONEME_TAB *other_ph; | ||||
int found = 0; | |||||
bool found = false; | |||||
static int mnem; | static int mnem; | ||||
// control | // control | ||||
while (pr->name != 0) { | while (pr->name != 0) { | ||||
if (mnem == pr->name) { | if (mnem == pr->name) { | ||||
if (pr->next_phoneme == 0) | if (pr->next_phoneme == 0) | ||||
found = 1; | |||||
found = true; | |||||
else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN)) | else if ((pr->next_phoneme == ':') && (plist->synthflags & SFLAG_LENGTHEN)) | ||||
found = 1; | |||||
found = true; | |||||
else { | else { | ||||
if (pr->control & 2) | if (pr->control & 2) | ||||
other_ph = ph_prev; | other_ph = ph_prev; | ||||
if ((pr->next_phoneme == other_ph->mnemonic) || | if ((pr->next_phoneme == other_ph->mnemonic) || | ||||
((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) || | ((pr->next_phoneme == 2) && (other_ph->type == phVOWEL)) || | ||||
((pr->next_phoneme == '_') && (other_ph->type == phPAUSE))) | ((pr->next_phoneme == '_') && (other_ph->type == phPAUSE))) | ||||
found = 1; | |||||
found = true; | |||||
} | } | ||||
if ((pr->control & 4) && (plist->newword == 0)) // only at start of word | if ((pr->control & 4) && (plist->newword == 0)) // only at start of word | ||||
found = 0; | |||||
found = false; | |||||
if ((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word | if ((pr->control & 0x40) && (plist[1].newword == 0)) // only at the end of a word | ||||
found = 0; | |||||
found = false; | |||||
if ((pr->control & 0x20) && (plist->stresslevel < plist->wordstress)) | if ((pr->control & 0x20) && (plist->stresslevel < plist->wordstress)) | ||||
found = 0; // only in stressed syllables | |||||
found = false; // only in stressed syllables | |||||
if (found) { | if (found) { | ||||
*name2 = pr->mbr_name2; | *name2 = pr->mbr_name2; | ||||
bool released; | bool released; | ||||
int name2; | int name2; | ||||
int control; | int control; | ||||
int done; | |||||
bool done; | |||||
int len_percent; | int len_percent; | ||||
const char *final_pitch; | const char *final_pitch; | ||||
char *ptr; | char *ptr; | ||||
name2 = 0; | name2 = 0; | ||||
} | } | ||||
done = 0; | |||||
done = false; | |||||
final_pitch = ""; | final_pitch = ""; | ||||
switch (ph->type) | switch (ph->type) | ||||
pitch = WritePitch(p->env, p->pitch1, p->pitch2, -len_percent, 0); | pitch = WritePitch(p->env, p->pitch1, p->pitch2, -len_percent, 0); | ||||
ptr += sprintf(ptr, "%s\t%d\t%s", WordToString(name2), len-len1, pitch); | ptr += sprintf(ptr, "%s\t%d\t%s", WordToString(name2), len-len1, pitch); | ||||
} | } | ||||
done = 1; | |||||
done = true; | |||||
break; | break; | ||||
case phSTOP: | case phSTOP: | ||||
released = false; | released = false; |
unsigned int data; | unsigned int data; | ||||
int instn; | int instn; | ||||
int instn2; | int instn2; | ||||
int check_endtype = 0; | |||||
bool check_endtype = false; | |||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
PHONEME_LIST *plist_this; | PHONEME_LIST *plist_this; | ||||
case 0: // prevPh | case 0: // prevPh | ||||
case 5: // prevPhW | case 5: // prevPhW | ||||
plist--; | plist--; | ||||
check_endtype = 1; | |||||
check_endtype = true; | |||||
break; | break; | ||||
case 1: // thisPh | case 1: // thisPh | ||||
break; | break; | ||||
if ((worddata == NULL) || (worddata->prev_vowel.ph == NULL)) | if ((worddata == NULL) || (worddata->prev_vowel.ph == NULL)) | ||||
return false; // no previous vowel | return false; // no previous vowel | ||||
plist = &(worddata->prev_vowel); | plist = &(worddata->prev_vowel); | ||||
check_endtype = 1; | |||||
check_endtype = true; | |||||
break; | break; | ||||
case 9: // next3PhW | case 9: // next3PhW | ||||
for (ix = 1; ix <= 3; ix++) { | for (ix = 1; ix <= 3; ix++) { | ||||
if ((plist[0].sourceix) || (plist[-1].sourceix)) | if ((plist[0].sourceix) || (plist[-1].sourceix)) | ||||
return false; | return false; | ||||
plist -= 2; | plist -= 2; | ||||
check_endtype = 1; | |||||
check_endtype = true; | |||||
break; | break; | ||||
} | } | ||||
int ix; | int ix; | ||||
int len; | int len; | ||||
int pk; | int pk; | ||||
int modified; | |||||
bool modified; | |||||
int allowed; | int allowed; | ||||
int diff; | int diff; | ||||
break; // doesn't follow on from previous frame | break; // doesn't follow on from previous frame | ||||
frame = frame2 = (frame_t *)q[2]; | frame = frame2 = (frame_t *)q[2]; | ||||
modified = 0; | |||||
modified = false; | |||||
if (frame->frflags & FRFLAG_BREAK) | if (frame->frflags & FRFLAG_BREAK) | ||||
break; | break; | ||||
allowed = (allowed * len)/256; | allowed = (allowed * len)/256; | ||||
if (diff > allowed) { | if (diff > allowed) { | ||||
if (modified == 0) { | |||||
if (modified == false) { | |||||
frame2 = CopyFrame(frame, 0); | frame2 = CopyFrame(frame, 0); | ||||
modified = 1; | |||||
modified = true; | |||||
} | } | ||||
frame2->ffreq[pk] = frame1->ffreq[pk] + allowed; | frame2->ffreq[pk] = frame1->ffreq[pk] + allowed; | ||||
q[2] = (intptr_t)frame2; | q[2] = (intptr_t)frame2; | ||||
} else if (diff < -allowed) { | } else if (diff < -allowed) { | ||||
if (modified == 0) { | |||||
if (modified == false) { | |||||
frame2 = CopyFrame(frame, 0); | frame2 = CopyFrame(frame, 0); | ||||
modified = 1; | |||||
modified = true; | |||||
} | } | ||||
frame2->ffreq[pk] = frame1->ffreq[pk] - allowed; | frame2->ffreq[pk] = frame1->ffreq[pk] - allowed; | ||||
q[2] = (intptr_t)frame2; | q[2] = (intptr_t)frame2; | ||||
} | } | ||||
frame = frame2 = (frame_t *)q[3]; | frame = frame2 = (frame_t *)q[3]; | ||||
modified = 0; | |||||
modified = false; | |||||
if (frame1->frflags & FRFLAG_BREAK) | if (frame1->frflags & FRFLAG_BREAK) | ||||
break; | break; | ||||
allowed = (allowed * len)/256; | allowed = (allowed * len)/256; | ||||
if (diff > allowed) { | if (diff > allowed) { | ||||
if (modified == 0) { | |||||
if (modified == false) { | |||||
frame2 = CopyFrame(frame, 0); | frame2 = CopyFrame(frame, 0); | ||||
modified = 1; | |||||
modified = true; | |||||
} | } | ||||
frame2->ffreq[pk] = frame1->ffreq[pk] + allowed; | frame2->ffreq[pk] = frame1->ffreq[pk] + allowed; | ||||
q[3] = (intptr_t)frame2; | q[3] = (intptr_t)frame2; | ||||
} else if (diff < -allowed) { | } else if (diff < -allowed) { | ||||
if (modified == 0) { | |||||
if (modified == false) { | |||||
frame2 = CopyFrame(frame, 0); | frame2 = CopyFrame(frame, 0); | ||||
modified = 1; | |||||
modified = true; | |||||
} | } | ||||
frame2->ffreq[pk] = frame1->ffreq[pk] - allowed; | frame2->ffreq[pk] = frame1->ffreq[pk] - allowed; | ||||
q[3] = (intptr_t)frame2; | q[3] = (intptr_t)frame2; | ||||
unsigned char *amp_env; | unsigned char *amp_env; | ||||
PHONEME_TAB *ph; | PHONEME_TAB *ph; | ||||
int use_ipa = 0; | int use_ipa = 0; | ||||
int done_phoneme_marker; | |||||
bool done_phoneme_marker; | |||||
int vowelstart_prev; | int vowelstart_prev; | ||||
char phoneme_name[16]; | char phoneme_name[16]; | ||||
static int sourceix = 0; | static int sourceix = 0; | ||||
if ((p->prepause > 0) && !(p->ph->phflags & phPREVOICE)) | if ((p->prepause > 0) && !(p->ph->phflags & phPREVOICE)) | ||||
DoPause(p->prepause, 1); | DoPause(p->prepause, 1); | ||||
done_phoneme_marker = 0; | |||||
done_phoneme_marker = false; | |||||
if (option_phoneme_events && (p->ph->code != phonEND_WORD)) { | if (option_phoneme_events && (p->ph->code != phonEND_WORD)) { | ||||
if ((p->type == phVOWEL) && (prev->type == phLIQUID || prev->type == phNASAL)) { | if ((p->type == phVOWEL) && (prev->type == phLIQUID || prev->type == phNASAL)) { | ||||
// For vowels following a liquid or nasal, do the phoneme event after the vowel-start | // For vowels following a liquid or nasal, do the phoneme event after the vowel-start | ||||
} else { | } else { | ||||
WritePhMnemonic(phoneme_name, p->ph, p, use_ipa, NULL); | WritePhMnemonic(phoneme_name, p->ph, p, use_ipa, NULL); | ||||
DoPhonemeMarker(espeakEVENT_PHONEME, sourceix, 0, phoneme_name); | DoPhonemeMarker(espeakEVENT_PHONEME, sourceix, 0, phoneme_name); | ||||
done_phoneme_marker = 1; | |||||
done_phoneme_marker = true; | |||||
} | } | ||||
} | } | ||||
DoSpect2(ph, 1, &fmtp, p, modulation); | DoSpect2(ph, 1, &fmtp, p, modulation); | ||||
} | } | ||||
if ((option_phoneme_events) && (done_phoneme_marker == 0)) { | |||||
if ((option_phoneme_events) && (done_phoneme_marker == false)) { | |||||
WritePhMnemonic(phoneme_name, p->ph, p, use_ipa, NULL); | WritePhMnemonic(phoneme_name, p->ph, p, use_ipa, NULL); | ||||
DoPhonemeMarker(espeakEVENT_PHONEME, sourceix, 0, phoneme_name); | DoPhonemeMarker(espeakEVENT_PHONEME, sourceix, 0, phoneme_name); | ||||
} | } | ||||
} | } | ||||
if (text_decoder_eof(p_decoder)) { | if (text_decoder_eof(p_decoder)) { | ||||
skipping_text = 0; | |||||
skipping_text = false; | |||||
return 0; | return 0; | ||||
} | } | ||||
tr->langopts.our_alphabet = 0x3100; | tr->langopts.our_alphabet = 0x3100; | ||||
tr->langopts.word_gap = 0x21; // length of a final vowel is less dependent on the next consonant, don't merge consonant with next word | tr->langopts.word_gap = 0x21; // length of a final vowel is less dependent on the next consonant, don't merge consonant with next word | ||||
if (name2 == L3('z', 'h', 'y')) { | if (name2 == L3('z', 'h', 'y')) { | ||||
tr->langopts.textmode = 1; | |||||
tr->langopts.textmode = true; | |||||
tr->langopts.listx = 1; // compile zh_listx after zh_list | tr->langopts.listx = 1; // compile zh_listx after zh_list | ||||
tr->langopts.numbers = 1; | tr->langopts.numbers = 1; | ||||
tr->langopts.numbers2 = NUM2_ZERO_TENS; | tr->langopts.numbers2 = NUM2_ZERO_TENS; |
int skip_words; | int skip_words; | ||||
int skip_characters; | int skip_characters; | ||||
char skip_marker[N_MARKER_LENGTH]; | char skip_marker[N_MARKER_LENGTH]; | ||||
int skipping_text; // waiting until word count, sentence count, or named marker is reached | |||||
bool skipping_text; // waiting until word count, sentence count, or named marker is reached | |||||
int end_character_position; | int end_character_position; | ||||
int count_sentences; | int count_sentences; | ||||
int count_words; | int count_words; | ||||
int clause_start_char; | int clause_start_char; | ||||
int clause_start_word; | int clause_start_word; | ||||
int new_sentence; | |||||
bool new_sentence; | |||||
static int word_emphasis = 0; // set if emphasis level 3 or 4 | static int word_emphasis = 0; // set if emphasis level 3 or 4 | ||||
static int embedded_flag = 0; // there are embedded commands to be applied to the next phoneme, used in TranslateWord2() | static int embedded_flag = 0; // there are embedded commands to be applied to the next phoneme, used in TranslateWord2() | ||||
static int prev_clause_pause = 0; | static int prev_clause_pause = 0; | ||||
static int max_clause_pause = 0; | static int max_clause_pause = 0; | ||||
static int any_stressed_words; | |||||
static bool any_stressed_words; | |||||
int pre_pause; | int pre_pause; | ||||
ALPHABET *current_alphabet; | ALPHABET *current_alphabet; | ||||
{ | { | ||||
int posn = 0; | int posn = 0; | ||||
int capitals = 0; | int capitals = 0; | ||||
int non_initial = 0; | |||||
bool non_initial = false; | |||||
if (spell_word > 2) | if (spell_word > 2) | ||||
capitals = 2; // speak 'capital' | capitals = 2; // speak 'capital' | ||||
while ((*word != ' ') && (*word != 0)) { | while ((*word != ' ') && (*word != 0)) { | ||||
word += TranslateLetter(tr, word, phonemes, capitals | non_initial); | word += TranslateLetter(tr, word, phonemes, capitals | non_initial); | ||||
posn++; | posn++; | ||||
non_initial = 1; | |||||
non_initial = true; | |||||
if (phonemes[0] == phonSWITCH) { | if (phonemes[0] == phonSWITCH) { | ||||
// change to another language in order to translate this word | // change to another language in order to translate this word | ||||
strcpy(word_phonemes, phonemes); | strcpy(word_phonemes, phonemes); | ||||
int first_char; | int first_char; | ||||
int last_char = 0; | int last_char = 0; | ||||
int prefix_flags = 0; | int prefix_flags = 0; | ||||
int more_suffixes; | |||||
int confirm_prefix; | |||||
bool more_suffixes; | |||||
bool confirm_prefix; | |||||
int spell_word; | int spell_word; | ||||
int emphasize_allcaps = 0; | int emphasize_allcaps = 0; | ||||
int wflags; | int wflags; | ||||
// dictionary_flags may have ben set there | // dictionary_flags may have ben set there | ||||
int posn; | int posn; | ||||
int non_initial; | |||||
bool non_initial = false; | |||||
int length; | int length; | ||||
posn = 0; | posn = 0; | ||||
non_initial = 0; | |||||
length = 999; | length = 999; | ||||
wordx = word1; | wordx = word1; | ||||
break; | break; | ||||
if (posn > 0) | if (posn > 0) | ||||
non_initial = 1; | |||||
non_initial = true; | |||||
wordx += TranslateLetter(tr, wordx, unpron_phonemes, non_initial); | wordx += TranslateLetter(tr, wordx, unpron_phonemes, non_initial); | ||||
posn++; | posn++; | ||||
c_temp = wordx[-1]; | c_temp = wordx[-1]; | ||||
found = false; | found = false; | ||||
confirm_prefix = 1; | |||||
confirm_prefix = true; | |||||
for (loopcount = 0; (loopcount < 50) && (end_type & SUFX_P); loopcount++) { | for (loopcount = 0; (loopcount < 50) && (end_type & SUFX_P); loopcount++) { | ||||
// Found a standard prefix, remove it and retranslate | // Found a standard prefix, remove it and retranslate | ||||
// loopcount guards against an endless loop | // loopcount guards against an endless loop | ||||
fprintf(f_trans, " suffix [%s]\n\n", end_phonemes2); | fprintf(f_trans, " suffix [%s]\n\n", end_phonemes2); | ||||
} | } | ||||
} | } | ||||
confirm_prefix = 0; | |||||
confirm_prefix = false; | |||||
continue; | continue; | ||||
} | } | ||||
} | } | ||||
} | } | ||||
c_temp = wordx[-1]; | c_temp = wordx[-1]; | ||||
wordx[-1] = ' '; | wordx[-1] = ' '; | ||||
confirm_prefix = 1; | |||||
confirm_prefix = true; | |||||
wflags |= FLAG_PREFIX_REMOVED; | wflags |= FLAG_PREFIX_REMOVED; | ||||
if (prefix_type & SUFX_B) { | if (prefix_type & SUFX_B) { | ||||
// The word has a standard ending, re-translate without this ending | // The word has a standard ending, re-translate without this ending | ||||
end_flags = RemoveEnding(tr, wordx, end_type, word_copy); | end_flags = RemoveEnding(tr, wordx, end_type, word_copy); | ||||
more_suffixes = 1; | |||||
more_suffixes = true; | |||||
while (more_suffixes) { | while (more_suffixes) { | ||||
more_suffixes = 0; | |||||
more_suffixes = false; | |||||
phonemes[0] = 0; | phonemes[0] = 0; | ||||
if (prefix_phonemes[0] != 0) { | if (prefix_phonemes[0] != 0) { | ||||
if ((end_type != 0) && !(end_type & SUFX_P)) { | if ((end_type != 0) && !(end_type & SUFX_P)) { | ||||
// there is another suffix | // there is another suffix | ||||
end_flags = RemoveEnding(tr, wordx, end_type, NULL); | end_flags = RemoveEnding(tr, wordx, end_type, NULL); | ||||
more_suffixes = 1; | |||||
more_suffixes = true; | |||||
} | } | ||||
} else { | } else { | ||||
// don't remove any previous suffix | // don't remove any previous suffix | ||||
char words_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | char words_phonemes[N_WORD_PHONEMES]; // a word translated into phoneme codes | ||||
char *phonemes = words_phonemes; | char *phonemes = words_phonemes; | ||||
int available = N_WORD_PHONEMES; | int available = N_WORD_PHONEMES; | ||||
int first_word = 1; | |||||
bool first_word = true; | |||||
int flags = TranslateWord3(tr, word_start, wtab, word_out); | int flags = TranslateWord3(tr, word_start, wtab, word_out); | ||||
if (flags & FLAG_TEXTMODE && word_out) { | if (flags & FLAG_TEXTMODE && word_out) { | ||||
int n; | int n; | ||||
if (first_word) { | if (first_word) { | ||||
n = snprintf(phonemes, available, "%s", word_phonemes); | n = snprintf(phonemes, available, "%s", word_phonemes); | ||||
first_word = 0; | |||||
first_word = false; | |||||
} else { | } else { | ||||
n = snprintf(phonemes, available, "%c%s", phonEND_WORD, word_phonemes); | n = snprintf(phonemes, available, "%c%s", phonEND_WORD, word_phonemes); | ||||
} | } | ||||
int prev_vowel = -1; | int prev_vowel = -1; | ||||
int pitch_raised = 0; | int pitch_raised = 0; | ||||
int switch_phonemes = -1; | int switch_phonemes = -1; | ||||
int first_phoneme = 1; | |||||
bool first_phoneme = true; | |||||
int source_ix; | int source_ix; | ||||
int len; | int len; | ||||
int ix; | int ix; | ||||
if ((flags & FLAG_COMBINE) && !(wtab[1].flags & FLAG_PHONEMES)) { | if ((flags & FLAG_COMBINE) && !(wtab[1].flags & FLAG_PHONEMES)) { | ||||
char *p2; | char *p2; | ||||
int ok = 1; | |||||
bool ok = true; | |||||
unsigned int flags2[2]; | unsigned int flags2[2]; | ||||
int c_word2; | int c_word2; | ||||
char ph_buf[N_WORD_PHONEMES]; | char ph_buf[N_WORD_PHONEMES]; | ||||
utf8_in(&c_word2, p2+1); // first character of the next word; | utf8_in(&c_word2, p2+1); // first character of the next word; | ||||
if (!iswalpha(c_word2)) | if (!iswalpha(c_word2)) | ||||
ok = 0; | |||||
ok = false; | |||||
if (ok != 0) { | |||||
if (ok == true) { | |||||
strcpy(ph_buf, word_phonemes); | strcpy(ph_buf, word_phonemes); | ||||
flags2[0] = TranslateWord(translator, p2+1, wtab+1, NULL); | flags2[0] = TranslateWord(translator, p2+1, wtab+1, NULL); | ||||
if ((flags2[0] & FLAG_WAS_UNPRONOUNCABLE) || (word_phonemes[0] == phonSWITCH)) | if ((flags2[0] & FLAG_WAS_UNPRONOUNCABLE) || (word_phonemes[0] == phonSWITCH)) | ||||
ok = 0; | |||||
ok = false; | |||||
if (sylimit & 0x100) { | if (sylimit & 0x100) { | ||||
// only if the second word has $alt attribute | // only if the second word has $alt attribute | ||||
if ((flags2[0] & FLAG_ALT_TRANS) == 0) | if ((flags2[0] & FLAG_ALT_TRANS) == 0) | ||||
ok = 0; | |||||
ok = false; | |||||
} | } | ||||
if ((sylimit & 0x200) && ((wtab+1)->flags & FLAG_LAST_WORD)) { | if ((sylimit & 0x200) && ((wtab+1)->flags & FLAG_LAST_WORD)) { | ||||
// not if the next word is end-of-sentence | // not if the next word is end-of-sentence | ||||
ok = 0; | |||||
ok = false; | |||||
} | } | ||||
if (ok == 0) | |||||
if (ok == false) | |||||
strcpy(word_phonemes, ph_buf); | strcpy(word_phonemes, ph_buf); | ||||
} | } | ||||
next_stress = 1; // default is 'unstressed' | next_stress = 1; // default is 'unstressed' | ||||
if (stress >= 4) | if (stress >= 4) | ||||
any_stressed_words = 1; | |||||
any_stressed_words = true; | |||||
if ((prev_vowel >= 0) && (n_ph_list2-1) != prev_vowel) | if ((prev_vowel >= 0) && (n_ph_list2-1) != prev_vowel) | ||||
ph_list2[n_ph_list2-1].stresslevel = stress; // set stress for previous consonant | ph_list2[n_ph_list2-1].stresslevel = stress; // set stress for previous consonant | ||||
ph_list2[n_ph_list2].stresslevel = stress; | ph_list2[n_ph_list2].stresslevel = stress; | ||||
n_ph_list2++; | n_ph_list2++; | ||||
first_phoneme = 0; | |||||
first_phoneme = false; | |||||
} | } | ||||
} | } | ||||
unsigned int word; | unsigned int word; | ||||
unsigned int new_c, c2, c_lower; | unsigned int new_c, c2, c_lower; | ||||
int upper_case = 0; | int upper_case = 0; | ||||
static int ignore_next = 0; | |||||
static bool ignore_next = false; | |||||
const unsigned int *replace_chars; | const unsigned int *replace_chars; | ||||
if (ignore_next) { | if (ignore_next) { | ||||
ignore_next = 0; | |||||
ignore_next = false; | |||||
return 8; | return 8; | ||||
} | } | ||||
if (c == 0) return 0; | if (c == 0) return 0; | ||||
} | } | ||||
if ((word >> 16) == (unsigned int)towlower2(next_in)) { | if ((word >> 16) == (unsigned int)towlower2(next_in)) { | ||||
new_c = replace_chars[ix+1]; | new_c = replace_chars[ix+1]; | ||||
ignore_next = 1; | |||||
ignore_next = true; | |||||
break; | break; | ||||
} | } | ||||
} | } | ||||
int pre_pause_add = 0; | int pre_pause_add = 0; | ||||
int word_mark = 0; | int word_mark = 0; | ||||
int all_upper_case = FLAG_ALL_UPPER; | int all_upper_case = FLAG_ALL_UPPER; | ||||
int finished; | |||||
int single_quoted; | |||||
int phoneme_mode = 0; | |||||
bool finished = false; | |||||
bool single_quoted = false; | |||||
bool phoneme_mode = false; | |||||
int dict_flags = 0; // returned from dictionary lookup | int dict_flags = 0; // returned from dictionary lookup | ||||
int word_flags; // set here | int word_flags; // set here | ||||
int next_word_flags; | int next_word_flags; | ||||
int new_sentence2; | |||||
bool new_sentence2; | |||||
int embedded_count = 0; | int embedded_count = 0; | ||||
int letter_count = 0; | int letter_count = 0; | ||||
int space_inserted = 0; | |||||
int syllable_marked = 0; | |||||
int decimal_sep_count = 0; | |||||
bool space_inserted = false; | |||||
bool syllable_marked = false; | |||||
bool decimal_sep_count = false; | |||||
char *word; | char *word; | ||||
char *p; | char *p; | ||||
int j, k; | int j, k; | ||||
embedded_ix = 0; | embedded_ix = 0; | ||||
embedded_read = 0; | embedded_read = 0; | ||||
pre_pause = 0; | pre_pause = 0; | ||||
any_stressed_words = 0; | |||||
any_stressed_words = false; | |||||
if ((clause_start_char = count_characters) < 0) | if ((clause_start_char = count_characters) < 0) | ||||
clause_start_char = 0; | clause_start_char = 0; | ||||
if (new_sentence) | if (new_sentence) | ||||
terminator |= CLAUSE_TYPE_SENTENCE; // carry forward an end-of-sentence indicator | terminator |= CLAUSE_TYPE_SENTENCE; // carry forward an end-of-sentence indicator | ||||
max_clause_pause += clause_pause; | max_clause_pause += clause_pause; | ||||
new_sentence2 = 0; | |||||
new_sentence2 = false; | |||||
} else { | } else { | ||||
max_clause_pause = clause_pause; | max_clause_pause = clause_pause; | ||||
new_sentence2 = new_sentence; | new_sentence2 = new_sentence; | ||||
if (skip_sentences > 0) { | if (skip_sentences > 0) { | ||||
skip_sentences--; | skip_sentences--; | ||||
if (skip_sentences == 0) | if (skip_sentences == 0) | ||||
skipping_text = 0; | |||||
skipping_text = false; | |||||
} | } | ||||
} | } | ||||
tr->prev_dict_flags[1] = 0; | tr->prev_dict_flags[1] = 0; | ||||
word_count = 0; | word_count = 0; | ||||
single_quoted = 0; | |||||
word_flags = 0; | word_flags = 0; | ||||
next_word_flags = 0; | next_word_flags = 0; | ||||
words[0].start = ix; | words[0].start = ix; | ||||
words[0].flags = 0; | words[0].flags = 0; | ||||
finished = 0; | |||||
for (j = 0; charix[j] <= 0; j++) ; | for (j = 0; charix[j] <= 0; j++) ; | ||||
words[0].sourceix = charix[j]; | words[0].sourceix = charix[j]; | ||||
next_in_nbytes = utf8_in(&next_in, &source[source_index]); | next_in_nbytes = utf8_in(&next_in, &source[source_index]); | ||||
if (c == 0) { | if (c == 0) { | ||||
finished = 1; | |||||
finished = true; | |||||
c = ' '; | c = ' '; | ||||
} | } | ||||
all_upper_case = FLAG_PHONEMES; | all_upper_case = FLAG_PHONEMES; | ||||
if ((c == ']') && (next_in == ']')) { | if ((c == ']') && (next_in == ']')) { | ||||
phoneme_mode = 0; | |||||
phoneme_mode = false; | |||||
source_index++; | source_index++; | ||||
c = ' '; | c = ' '; | ||||
} | } | ||||
if (count_sayas_digits > (option_sayas2 & 0xf)) { | if (count_sayas_digits > (option_sayas2 & 0xf)) { | ||||
// break after the specified number of digits | // break after the specified number of digits | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
count_sayas_digits = 0; | count_sayas_digits = 0; | ||||
} | } | ||||
} else { | } else { | ||||
count_sayas_digits = 0; | count_sayas_digits = 0; | ||||
if (iswdigit(prev_out)) { | if (iswdigit(prev_out)) { | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} | } | ||||
} | } | ||||
} else if ((option_sayas2 & 0x10) == 0) { | } else if ((option_sayas2 & 0x10) == 0) { | ||||
// allow a tone number as part of the word | // allow a tone number as part of the word | ||||
} else { | } else { | ||||
c = ' '; // ensure we have an end-of-word terminator | c = ' '; // ensure we have an end-of-word terminator | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} | } | ||||
} | } | ||||
} | } | ||||
if (iswdigit(prev_out)) { | if (iswdigit(prev_out)) { | ||||
if (!iswdigit(c) && (c != '.') && (c != ',') && (c != ' ')) { | if (!iswdigit(c) && (c != '.') && (c != ',') && (c != ' ')) { | ||||
c = ' '; // terminate digit string with a space | c = ' '; // terminate digit string with a space | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} | } | ||||
} else { // Prev output is not digit | } else { // Prev output is not digit | ||||
if (prev_in == ',') { | if (prev_in == ',') { | ||||
if (c == ',') | if (c == ',') | ||||
c = ' '; | c = ' '; | ||||
} else { | } else { | ||||
decimal_sep_count = 0; | |||||
decimal_sep_count = false; | |||||
} | } | ||||
} | } | ||||
if (c == '[') { | if (c == '[') { | ||||
if ((next_in == '\002') || ((next_in == '[') && option_phoneme_input)) { | if ((next_in == '\002') || ((next_in == '[') && option_phoneme_input)) { | ||||
// "[\002" is used internally to start phoneme mode | // "[\002" is used internally to start phoneme mode | ||||
phoneme_mode = FLAG_PHONEMES; | |||||
phoneme_mode = true; | |||||
source_index++; | source_index++; | ||||
continue; | continue; | ||||
} | } | ||||
if ((prev_out != ' ') && (wcschr(tr->punct_within_word, prev_out) == 0)) { | if ((prev_out != ' ') && (wcschr(tr->punct_within_word, prev_out) == 0)) { | ||||
// start of word, insert space if not one there already | // start of word, insert space if not one there already | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
if (!IsBracket(prev_out)) // ?? perhaps only set FLAG_NOSPACE for . - / (hyphenated words, URLs, etc) | if (!IsBracket(prev_out)) // ?? perhaps only set FLAG_NOSPACE for . - / (hyphenated words, URLs, etc) | ||||
next_word_flags |= FLAG_NOSPACE; | next_word_flags |= FLAG_NOSPACE; | ||||
// Break into separate words | // Break into separate words | ||||
if (IsAlpha(prev_out)) { | if (IsAlpha(prev_out)) { | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
word_flags |= FLAG_HYPHEN_AFTER; | word_flags |= FLAG_HYPHEN_AFTER; | ||||
next_word_flags |= FLAG_HYPHEN; | next_word_flags |= FLAG_HYPHEN; | ||||
} | } | ||||
c = towlower2(c); | c = towlower2(c); | ||||
if ((j = tr->langopts.param[LOPT_CAPS_IN_WORD]) > 0) { | if ((j = tr->langopts.param[LOPT_CAPS_IN_WORD]) > 0) { | ||||
if ((j == 2) && (syllable_marked == 0)) { | |||||
if ((j == 2) && (syllable_marked == false)) { | |||||
char_inserted = c; | char_inserted = c; | ||||
c = 0x2c8; // stress marker | c = 0x2c8; // stress marker | ||||
syllable_marked = 1; | |||||
syllable_marked = true; | |||||
} | } | ||||
} else { | } else { | ||||
if (iswlower(prev_in)) { | if (iswlower(prev_in)) { | ||||
c = towlower2(c); | c = towlower2(c); | ||||
} else { | } else { | ||||
c = ' '; // lower case followed by upper case, treat as new word | c = ' '; // lower case followed by upper case, treat as new word | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
prev_in_save = c; | prev_in_save = c; | ||||
} | } | ||||
} else if ((c != ' ') && iswupper(prev_in) && iswlower(next_in)) { | } else if ((c != ' ') && iswupper(prev_in) && iswlower(next_in)) { | ||||
} else if (IsAlpha(next2_in)) { | } else if (IsAlpha(next2_in)) { | ||||
// changing from upper to lower case, start new word at the last uppercase, if 3 or more letters | // changing from upper to lower case, start new word at the last uppercase, if 3 or more letters | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
prev_in_save = c; | prev_in_save = c; | ||||
next_word_flags |= FLAG_NOSPACE; | next_word_flags |= FLAG_NOSPACE; | ||||
} | } | ||||
if (prev_out != ' ') { | if (prev_out != ' ') { | ||||
// previous 'word' not yet ended (not alpha or numeric), start new word now. | // previous 'word' not yet ended (not alpha or numeric), start new word now. | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} else { | } else { | ||||
// '-' between two letters is a hyphen, treat as a space | // '-' between two letters is a hyphen, treat as a space | ||||
word_flags |= FLAG_HYPHEN; | word_flags |= FLAG_HYPHEN; | ||||
if (prev_out == '.') { | if (prev_out == '.') { | ||||
// multiple dots, separate by spaces. Note >3 dots has been replaced by elipsis | // multiple dots, separate by spaces. Note >3 dots has been replaced by elipsis | ||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} else if ((word_count > 0) && !(words[word_count-1].flags & FLAG_NOSPACE) && IsAlpha(prev_in)) { | } else if ((word_count > 0) && !(words[word_count-1].flags & FLAG_NOSPACE) && IsAlpha(prev_in)) { | ||||
// dot after a word, with space following, probably an abbreviation | // dot after a word, with space following, probably an abbreviation | ||||
words[word_count-1].flags |= FLAG_HAS_DOT; | words[word_count-1].flags |= FLAG_HAS_DOT; | ||||
} else if (c == '\'') { | } else if (c == '\'') { | ||||
if (((prev_in == '.') || iswalnum(prev_in)) && IsAlpha(next_in)) { | if (((prev_in == '.') || iswalnum(prev_in)) && IsAlpha(next_in)) { | ||||
// between two letters, or in an abbreviation (eg. u.s.a.'s). Consider the apostrophe as part of the word | // between two letters, or in an abbreviation (eg. u.s.a.'s). Consider the apostrophe as part of the word | ||||
single_quoted = 0; | |||||
single_quoted = false; | |||||
} else if ((tr->langopts.param[LOPT_APOSTROPHE] & 1) && IsAlpha(next_in)) | } else if ((tr->langopts.param[LOPT_APOSTROPHE] & 1) && IsAlpha(next_in)) | ||||
single_quoted = 0; // apostrophe at start of word is part of the word | |||||
single_quoted = false; // apostrophe at start of word is part of the word | |||||
else if ((tr->langopts.param[LOPT_APOSTROPHE] & 2) && IsAlpha(prev_in)) | else if ((tr->langopts.param[LOPT_APOSTROPHE] & 2) && IsAlpha(prev_in)) | ||||
single_quoted = 0; // apostrophe at end of word is part of the word | |||||
single_quoted = false; // apostrophe at end of word is part of the word | |||||
else if ((wcschr(tr->char_plus_apostrophe, prev_in) != 0) && (prev_out2 == ' ')) { | else if ((wcschr(tr->char_plus_apostrophe, prev_in) != 0) && (prev_out2 == ' ')) { | ||||
// consider single character plus apostrophe as a word | // consider single character plus apostrophe as a word | ||||
single_quoted = 0; | |||||
single_quoted = false; | |||||
if (next_in == ' ') | if (next_in == ' ') | ||||
source_index++; // skip following space | source_index++; // skip following space | ||||
} else { | } else { | ||||
if ((prev_out == 's') && (single_quoted == 0)) { | |||||
if ((prev_out == 's') && (single_quoted == false)) { | |||||
// looks like apostrophe after an 's' | // looks like apostrophe after an 's' | ||||
c = ' '; | c = ' '; | ||||
} else { | } else { | ||||
if (IsSpace(prev_out)) | if (IsSpace(prev_out)) | ||||
single_quoted = 1; | |||||
single_quoted = true; | |||||
else | else | ||||
single_quoted = 0; | |||||
single_quoted = false; | |||||
pre_pause_add = 4; // single quote | pre_pause_add = 4; // single quote | ||||
c = ' '; | c = ' '; | ||||
else if (iswdigit(c)) { | else if (iswdigit(c)) { | ||||
if (tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in)) { | if (tr->langopts.tone_numbers && IsAlpha(prev_out) && !IsDigit(next_in)) { | ||||
} else if ((prev_out != ' ') && !iswdigit(prev_out)) { | } else if ((prev_out != ' ') && !iswdigit(prev_out)) { | ||||
if ((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count > 0) && (tr->langopts.decimal_sep == ','))) { | |||||
if ((prev_out != tr->langopts.decimal_sep) || ((decimal_sep_count == true) && (tr->langopts.decimal_sep == ','))) { | |||||
c = ' '; | c = ' '; | ||||
space_inserted = 1; | |||||
space_inserted = true; | |||||
} else | } else | ||||
decimal_sep_count = 1; | |||||
decimal_sep_count = true; | |||||
} else if ((prev_out == ' ') && IsAlpha(prev_out2) && !IsAlpha(prev_in)) { | } else if ((prev_out == ' ') && IsAlpha(prev_out2) && !IsAlpha(prev_in)) { | ||||
// insert extra space between a word and a number, to distinguish 'a 2' from 'a2' | // insert extra space between a word and a number, to distinguish 'a 2' from 'a2' | ||||
sbuf[ix++] = ' '; | sbuf[ix++] = ' '; | ||||
pre_pause = 0; | pre_pause = 0; | ||||
word_mark = 0; | word_mark = 0; | ||||
all_upper_case = FLAG_ALL_UPPER; | all_upper_case = FLAG_ALL_UPPER; | ||||
syllable_marked = 0; | |||||
syllable_marked = false; | |||||
} | } | ||||
if (space_inserted) { | if (space_inserted) { | ||||
source_index = prev_source_index; // rewind to the previous character | source_index = prev_source_index; // rewind to the previous character | ||||
char_inserted = 0; | char_inserted = 0; | ||||
space_inserted = 0; | |||||
space_inserted = false; | |||||
} | } | ||||
} else { | } else { | ||||
if ((ix < (N_TR_SOURCE - 4))) | if ((ix < (N_TR_SOURCE - 4))) | ||||
if (skip_words > 0) { | if (skip_words > 0) { | ||||
skip_words--; | skip_words--; | ||||
if (skip_words == 0) | if (skip_words == 0) | ||||
skipping_text = 0; | |||||
skipping_text = false; | |||||
} | } | ||||
if (skipping_text) | if (skipping_text) | ||||
continue; | continue; | ||||
if (tone_out != NULL) | if (tone_out != NULL) | ||||
*tone_out = tone; | *tone_out = tone; | ||||
new_sentence = 0; | |||||
new_sentence = false; | |||||
if (terminator & CLAUSE_TYPE_SENTENCE) | if (terminator & CLAUSE_TYPE_SENTENCE) | ||||
new_sentence = 1; // next clause is a new sentence | |||||
new_sentence = true; // next clause is a new sentence | |||||
if (voice_change != NULL) { | if (voice_change != NULL) { | ||||
// return new voice name if an embedded voice change command terminated the clause | // return new voice name if an embedded voice change command terminated the clause | ||||
skip_marker[0] = 0; | skip_marker[0] = 0; | ||||
skip_words = 0; | skip_words = 0; | ||||
skip_characters = 0; | skip_characters = 0; | ||||
skipping_text = 0; | |||||
new_sentence = 1; | |||||
skipping_text = false; | |||||
new_sentence = true; | |||||
prev_clause_pause = 0; | prev_clause_pause = 0; | ||||
char spelling_stress; // 0=default, 1=stress first letter | char spelling_stress; // 0=default, 1=stress first letter | ||||
char tone_numbers; | char tone_numbers; | ||||
char ideographs; // treat as separate words | char ideographs; // treat as separate words | ||||
char textmode; // the meaning of FLAG_TEXTMODE is reversed (to save data when *_list file is compiled) | |||||
bool textmode; // the meaning of FLAG_TEXTMODE is reversed (to save data when *_list file is compiled) | |||||
char dotless_i; // uses letter U+0131 | char dotless_i; // uses letter U+0131 | ||||
int testing; // testing options: bit 1= specify stressed syllable in the form: "outdoor/2" | int testing; // testing options: bit 1= specify stressed syllable in the form: "outdoor/2" | ||||
int listx; // compile *_listx after *list | int listx; // compile *_listx after *list | ||||
extern int skip_characters; | extern int skip_characters; | ||||
extern int skip_words; | extern int skip_words; | ||||
extern int skip_sentences; | extern int skip_sentences; | ||||
extern int skipping_text; | |||||
extern bool skipping_text; | |||||
extern int end_character_position; | extern int end_character_position; | ||||
extern int clause_start_char; | extern int clause_start_char; | ||||
extern int clause_start_word; | extern int clause_start_word; | ||||
void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len); | void print_dictionary_flags(unsigned int *flags, char *buf, int buf_len); | ||||
char *DecodeRule(const char *group_chars, int group_length, char *rule, int control); | char *DecodeRule(const char *group_chars, int group_length, char *rule, int control); | ||||
void MakePhonemeList(Translator *tr, int post_pause, int new_sentence); | |||||
void MakePhonemeList(Translator *tr, int post_pause, bool new_sentence); | |||||
int ChangePhonemes_ru(Translator *tr, 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); | ||||
void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags); | void ApplySpecialAttribute2(Translator *tr, char *phonemes, int dict_flags); | ||||
void AppendPhonemes(Translator *tr, char *string, int size, const char *ph); | void AppendPhonemes(Translator *tr, char *string, int size, const char *ph); |
int value2; | int value2; | ||||
int langix = 0; | int langix = 0; | ||||
int tone_only = control & 2; | int tone_only = control & 2; | ||||
int language_set = 0; | |||||
int phonemes_set = 0; | |||||
bool language_set = false; | |||||
bool phonemes_set = false; | |||||
int stress_amps_set = 0; | int stress_amps_set = 0; | ||||
int stress_lengths_set = 0; | int stress_lengths_set = 0; | ||||
int stress_add_set = 0; | int stress_add_set = 0; | ||||
} | } | ||||
// only act on the first language line | // only act on the first language line | ||||
if (language_set == 0) { | |||||
if (language_set == false) { | |||||
language_type = strtok(language_name, "-"); | language_type = strtok(language_name, "-"); | ||||
language_set = 1; | |||||
language_set = true; | |||||
strcpy(translator_name, language_type); | strcpy(translator_name, language_type); | ||||
strcpy(new_dictionary, language_type); | strcpy(new_dictionary, language_type); | ||||
strcpy(phonemes_name, language_type); | strcpy(phonemes_name, language_type); | ||||
fprintf(stderr, "Cannot set stressopt: language not set, or is invalid.\n"); | fprintf(stderr, "Cannot set stressopt: language not set, or is invalid.\n"); | ||||
break; | break; | ||||
case V_REPLACE: | case V_REPLACE: | ||||
if (phonemes_set == 0) { | |||||
if (phonemes_set == false) { | |||||
// must set up a phoneme table before we can lookup phoneme mnemonics | // must set up a phoneme table before we can lookup phoneme mnemonics | ||||
SelectPhonemeTableName(phonemes_name); | SelectPhonemeTableName(phonemes_name); | ||||
phonemes_set = 1; | |||||
phonemes_set = true; | |||||
} | } | ||||
PhonemeReplacement(p); | PhonemeReplacement(p); | ||||
break; | break; |