| 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; |