From 3a8e234fa3bb50f2ac6356f96c406f197b328f3e Mon Sep 17 00:00:00 2001 From: Juho Hiltunen Date: Sun, 14 Jan 2018 14:39:42 +0200 Subject: [PATCH 1/4] fi: improve stress for numerals Source: http://scripta.kotus.fi/visk/sisallys.php?p=13 --- dictsource/fi_list | 26 +++++++++++++------------- 1 file changed, 13 insertions(+), 13 deletions(-) diff --git a/dictsource/fi_list b/dictsource/fi_list index 7c9e1b23..703f2fc0 100644 --- a/dictsource/fi_list +++ b/dictsource/fi_list @@ -109,23 +109,23 @@ _16 k'u:sitoista _17 s'eitsem&nt,oista _18 k'ahdeksant,oista _19 'yhdeks&nt,oista -_2X k'aksikymment& -_3X k'olmekymment& -_4X n'elj&kymment& -_5X v'i:sikymment& -_6X k'u:sikymment& -_7X s'eitsem&Nk,ymment& -_8X k'ahdeksaNk,ymment& -_9X 'yhdeks&Nk,ymment& -_0C s'ata:_ +_2X kaksik%ymm%ent%& +_3X kolmek%ymm%ent%& +_4X nelj&k%ymm%ent%& +_5X vi:sik%ymm%ent%& +_6X ku:sik%ymm%ent%& +_7X seitsem&Nk%ymm%ent%& +_8X kahdeksaNk%ymm%ent%& +_9X yhdeks&Nk%ymm%ent%& +_0C s,ata:_ _1C s'ata -_0M1 t'uhat:a +_0M1 t,uhat:a _1M1 t'uhat // no '1' before thousand -_0M2 m'iljo:na: +_0M2 m,iljo:na: _1M2 m'iljo:na -_0M3 m'iljardia +_0M3 m,iljardia _1M3 m'iljardi -_0M4 b'iljo:na: +_0M4 b,iljo:na: _1M4 b'iljo:na _dpt pilk:u // comma From afb4fe75e278ee9afd6a4a5aee4aab97cd4f0642 Mon Sep 17 00:00:00 2001 From: Juho Hiltunen Date: Sun, 14 Jan 2018 14:46:57 +0200 Subject: [PATCH 2/4] fi: fix behaviour of S_2_TO_HEAVY (adding secondary stress) Stress flag S_2_TO_HEAVY is currently only used by finnish. Current behaviour skips adding secondary stress if the following syllable is heavy. The behaviour should be to skip adding secondary stress if the rest of the word (excluding last syllable) contains a heavy syllable. Source of grammar rule and examples of expected behaviour: http://scripta.kotus.fi/visk/sisallys.php?p=13 --- src/libespeak-ng/dictionary.c | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/src/libespeak-ng/dictionary.c b/src/libespeak-ng/dictionary.c index 1b43acea..6ee34fb2 100644 --- a/src/libespeak-ng/dictionary.c +++ b/src/libespeak-ng/dictionary.c @@ -1373,6 +1373,19 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, if ((stress == 3) && (stressflags & S_NO_AUTO_2)) continue; // don't use secondary stress + // don't put secondary stress on a light syllable if the rest of the word (excluding last syllable) contains a heavy syllable + if ((v > 1) && (stressflags & S_2_TO_HEAVY) && (syllable_weight[v] == 0)) { + bool skip = false; + for (int i = v; i < vowel_count - 1; i++) { + if (syllable_weight[i] > 0) { + skip = true; + break; + } + } + if (skip == true) + continue; + } + if ((v > 1) && (stressflags & S_2_TO_HEAVY) && (syllable_weight[v] == 0) && (syllable_weight[v+1] > 0)) { // don't put secondary stress on a light syllable which is followed by a heavy syllable continue; From 88315250ff7f63d8f0be924a4b5ec96274474dae Mon Sep 17 00:00:00 2001 From: Juho Hiltunen Date: Sun, 14 Jan 2018 15:22:37 +0200 Subject: [PATCH 3/4] readability fix: use boolean instead of 0 and 1 for loop control --- src/libespeak-ng/dictionary.c | 35 +++++++++++++++++------------------ 1 file changed, 17 insertions(+), 18 deletions(-) diff --git a/src/libespeak-ng/dictionary.c b/src/libespeak-ng/dictionary.c index 1b43acea..bed81cde 100644 --- a/src/libespeak-ng/dictionary.c +++ b/src/libespeak-ng/dictionary.c @@ -1028,13 +1028,11 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, int v_stress; int stressed_syllable; // position of stressed syllable int max_stress_posn; - int unstressed_word = 0; char *max_output; int final_ph; int final_ph2; int mnem; int opt_length; - int done; int stressflags; int dflags = 0; int first_primary; @@ -1074,12 +1072,14 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, max_output = output + (N_WORD_PHONEMES-3); // check for overrun + // any stress position marked in the xx_list dictionary ? + bool unstressed_word = false; stressed_syllable = dflags & 0x7; if (dflags & 0x8) { // this indicates a word without a primary stress stressed_syllable = dflags & 0x3; - unstressed_word = 1; + unstressed_word = true; } max_stress = max_stress_input = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 1); @@ -1091,10 +1091,10 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, for (p = phonetic; *p != 0; p++) { if ((phoneme_tab[p[0]]->type == phVOWEL) && !(phoneme_tab[p[0]]->phflags & phNONSYLLABIC)) { int weight = 0; - int lengthened = 0; + bool lengthened = false; if (phoneme_tab[p[1]]->code == phonLENGTHEN) - lengthened = 1; + lengthened = true; if (lengthened || (phoneme_tab[p[0]]->phflags & phLONG)) { // long vowel, increase syllable weight @@ -1341,7 +1341,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, else stress = 3; - if (unstressed_word == 0) { + if (unstressed_word == false) { if ((stressflags & S_2_SYL_2) && (vowel_count == 3)) { // Two syllable word, if one syllable has primary stress, then give the other secondary stress if (vowel_stress[1] == 4) @@ -1357,15 +1357,15 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, } } - done = 0; + bool done = false; first_primary = 0; for (v = 1; v < vowel_count; v++) { if (vowel_stress[v] < 0) { if ((stressflags & S_FINAL_NO_2) && (stress < 4) && (v == vowel_count-1)) { // flag: don't give secondary stress to final vowel - } else if ((stressflags & 0x8000) && (done == 0)) { + } else if ((stressflags & 0x8000) && (done == false)) { vowel_stress[v] = (char)stress; - done = 1; + done = true; stress = 3; // use secondary stress for remaining syllables } else if ((vowel_stress[v-1] <= 1) && ((vowel_stress[v+1] <= 1) || ((stress == 4) && (vowel_stress[v+1] <= 2)))) { // trochaic: give stress to vowel surrounded by unstressed vowels @@ -1381,7 +1381,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // should start with secondary stress on the first syllable, or should it count back from // the primary stress and put secondary stress on alternate syllables? vowel_stress[v] = (char)stress; - done = 1; + done = true; stress = 3; // use secondary stress for remaining syllables } } @@ -1481,15 +1481,15 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, if ((*p == phonLENGTHEN) && ((opt_length = tr->langopts.param[LOPT_IT_LENGTHEN]) & 1)) { // remove lengthen indicator from non-stressed syllables - int shorten = 0; + bool shorten = false; if (opt_length & 0x10) { // only allow lengthen indicator on the highest stress syllable in the word if (v != max_stress_posn) - shorten = 1; + shorten = true; } else if (v_stress < 4) { // only allow lengthen indicator if stress >= 4. - shorten = 1; + shorten = true; } if (shorten) @@ -1515,7 +1515,6 @@ void AppendPhonemes(Translator *tr, char *string, int size, const char *ph) const char *p; unsigned char c; - int unstress_mark; int length; length = strlen(ph) + strlen(string); @@ -1523,21 +1522,21 @@ void AppendPhonemes(Translator *tr, char *string, int size, const char *ph) return; // any stressable vowel ? - unstress_mark = 0; + bool unstress_mark = false; p = ph; while ((c = *p++) != 0) { if (c >= n_phoneme_tab) continue; if (phoneme_tab[c]->type == phSTRESS) { if (phoneme_tab[c]->std_length < 4) - unstress_mark = 1; + unstress_mark = true; } else { if (phoneme_tab[c]->type == phVOWEL) { if (((phoneme_tab[c]->phflags & phUNSTRESSED) == 0) && - (unstress_mark == 0)) { + (unstress_mark == false)) { tr->word_stressed_count++; } - unstress_mark = 0; + unstress_mark = false; tr->word_vowel_count++; } } From da287fb8516fae0e4bb64ec8572f0f8cd2f44719 Mon Sep 17 00:00:00 2001 From: Juho Hiltunen Date: Sun, 14 Jan 2018 15:26:03 +0200 Subject: [PATCH 4/4] Unify terminology for stress synthesize.h now contains the definitions STRESS_IS_... that should be used with code related to syllable stress. Note that isBreak and other defines were renumbered so that stress definitions could have values 0-6. Possible TODOs: 1. Unify with terms used with phonemes, i.e. keywords like isDiminished in compiledata.c and stress_type in phsource/phonemes 2. Add functionality and documentation about STRESS_IS_PRIORITY and STRESS_IS_EMPHASIZED --- src/libespeak-ng/compiledata.c | 28 ++--- src/libespeak-ng/dictionary.c | 203 +++++++++++++++++---------------- src/libespeak-ng/synthdata.c | 18 +-- src/libespeak-ng/synthesize.h | 18 +-- 4 files changed, 136 insertions(+), 131 deletions(-) diff --git a/src/libespeak-ng/compiledata.c b/src/libespeak-ng/compiledata.c index b12d9705..9cd68d65 100644 --- a/src/libespeak-ng/compiledata.c +++ b/src/libespeak-ng/compiledata.c @@ -119,11 +119,11 @@ static keywtab_t k_properties[] = { { "isVelar", 0, CONDITION_IS_PLACE_OF_ARTICULATION | phPLACE_VELAR }, - { "isDiminished", 0, CONDITION_IS_OTHER | isDiminished }, - { "isUnstressed", 0, CONDITION_IS_OTHER | isUnstressed }, - { "isNotStressed", 0, CONDITION_IS_OTHER | isNotStressed }, - { "isStressed", 0, CONDITION_IS_OTHER | isStressed }, - { "isMaxStress", 0, CONDITION_IS_OTHER | isMaxStress }, + { "isDiminished", 0, CONDITION_IS_OTHER | STRESS_IS_DIMINISHED }, + { "isUnstressed", 0, CONDITION_IS_OTHER | STRESS_IS_UNSTRESSED }, + { "isNotStressed", 0, CONDITION_IS_OTHER | STRESS_IS_NOT_STRESSED }, + { "isStressed", 0, CONDITION_IS_OTHER | STRESS_IS_SECONDARY }, + { "isMaxStress", 0, CONDITION_IS_OTHER | STRESS_IS_PRIMARY }, { "isPause2", 0, CONDITION_IS_OTHER | isBreak }, { "isWordStart", 0, CONDITION_IS_OTHER | isWordStart }, @@ -260,10 +260,11 @@ static keywtab_t keywords[] = { { "InsertPhoneme", tINSTRN1, i_INSERT_PHONEME }, { "AppendPhoneme", tINSTRN1, i_APPEND_PHONEME }, { "IfNextVowelAppend", tINSTRN1, i_APPEND_IFNEXTVOWEL }, - { "ChangeIfDiminished", tINSTRN1, i_CHANGE_IF | isDiminished }, - { "ChangeIfUnstressed", tINSTRN1, i_CHANGE_IF | isUnstressed }, - { "ChangeIfNotStressed", tINSTRN1, i_CHANGE_IF | isNotStressed }, - { "ChangeIfStressed", tINSTRN1, i_CHANGE_IF | isStressed }, + { "ChangeIfDiminished", tINSTRN1, i_CHANGE_IF | STRESS_IS_DIMINISHED }, + { "ChangeIfUnstressed", tINSTRN1, i_CHANGE_IF | STRESS_IS_UNSTRESSED }, + { "ChangeIfNotStressed", tINSTRN1, i_CHANGE_IF | STRESS_IS_NOT_STRESSED }, + { "ChangeIfStressed", tINSTRN1, i_CHANGE_IF | STRESS_IS_SECONDARY }, + { "ChangeIfStressed", tINSTRN1, i_CHANGE_IF | STRESS_IS_PRIMARY }, { "PauseBefore", tINSTRN1, i_PAUSE_BEFORE }, { "PauseAfter", tINSTRN1, i_PAUSE_AFTER }, @@ -2045,10 +2046,11 @@ static int CompilePhoneme(int compile_phoneme) case i_INSERT_PHONEME: case i_REPLACE_NEXT_PHONEME: case i_VOICING_SWITCH: - case i_CHANGE_IF | isDiminished: - case i_CHANGE_IF | isUnstressed: - case i_CHANGE_IF | isNotStressed: - case i_CHANGE_IF | isStressed: + case i_CHANGE_IF | STRESS_IS_DIMINISHED: + case i_CHANGE_IF | STRESS_IS_UNSTRESSED: + case i_CHANGE_IF | STRESS_IS_NOT_STRESSED: + case i_CHANGE_IF | STRESS_IS_SECONDARY: + case i_CHANGE_IF | STRESS_IS_PRIMARY: value = NextItemBrackets(tPHONEMEMNEM, 0); *prog_out++ = (keyword << 8) + value; DecThenCount(); diff --git a/src/libespeak-ng/dictionary.c b/src/libespeak-ng/dictionary.c index bed81cde..2e23c598 100644 --- a/src/libespeak-ng/dictionary.c +++ b/src/libespeak-ng/dictionary.c @@ -584,11 +584,11 @@ const char *GetTranslatedPhonemeString(int phoneme_mode) if (plist->synthflags & SFLAG_SYLLABLE) { if ((stress = plist->stresslevel) > 1) { c = 0; - if (stress > 5) stress = 5; + if (stress > STRESS_IS_PRIORITY) stress = STRESS_IS_PRIORITY; if (use_ipa) { c = 0x2cc; // ipa, secondary stress - if (stress > 3) + if (stress > STRESS_IS_SECONDARY) c = 0x02c8; // ipa, primary stress } else c = stress_chars[stress]; @@ -853,7 +853,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char * int stress = -1; int primary_posn = 0; - vowel_stress[0] = 1; + vowel_stress[0] = STRESS_IS_UNSTRESSED; while (((phcode = *phonemes++) != 0) && (count < (N_WORD_PHONEMES/2)-1)) { if ((ph = phoneme_tab[phcode]) == NULL) continue; @@ -864,20 +864,20 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char * if (phcode == phonSTRESS_PREV) { // primary stress on preceeding vowel j = count - 1; - while ((j > 0) && (*stressed_syllable == 0) && (vowel_stress[j] < 4)) { - if ((vowel_stress[j] != 0) && (vowel_stress[j] != 1)) { + while ((j > 0) && (*stressed_syllable == 0) && (vowel_stress[j] < STRESS_IS_PRIMARY)) { + if ((vowel_stress[j] != STRESS_IS_DIMINISHED) && (vowel_stress[j] != STRESS_IS_UNSTRESSED)) { // don't promote a phoneme which must be unstressed - vowel_stress[j] = 4; + vowel_stress[j] = STRESS_IS_PRIMARY; - if (max_stress < 4) { - max_stress = 4; + if (max_stress < STRESS_IS_PRIMARY) { + max_stress = STRESS_IS_PRIMARY; primary_posn = j; } /* reduce any preceding primary stress markers */ for (ix = 1; ix < j; ix++) { - if (vowel_stress[ix] == 4) - vowel_stress[ix] = 3; + if (vowel_stress[ix] == STRESS_IS_PRIMARY) + vowel_stress[ix] = STRESS_IS_SECONDARY; } break; } @@ -896,13 +896,13 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char * if ((ph->type == phVOWEL) && !(ph->phflags & phNONSYLLABIC)) { vowel_stress[count] = (char)stress; - if ((stress >= 4) && (stress >= max_stress)) { + if ((stress >= STRESS_IS_PRIMARY) && (stress >= max_stress)) { primary_posn = count; max_stress = stress; } if ((stress < 0) && (control & 1) && (ph->phflags & phUNSTRESSED)) - vowel_stress[count] = 1; // weak vowel, must be unstressed + vowel_stress[count] = STRESS_IS_UNSTRESSED; // weak vowel, must be unstressed count++; stress = -1; @@ -910,12 +910,12 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char * // previous consonant phoneme is syllablic vowel_stress[count] = (char)stress; if ((stress == 0) && (control & 1)) - vowel_stress[count++] = 1; // syllabic consonant, usually unstressed + vowel_stress[count++] = STRESS_IS_UNSTRESSED; // syllabic consonant, usually unstressed } *ph_out++ = phcode; } - vowel_stress[count] = 1; + vowel_stress[count] = STRESS_IS_UNSTRESSED; *ph_out = 0; // has the position of the primary stress been specified by $1, $2, etc? @@ -923,27 +923,27 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char * if (*stressed_syllable >= count) *stressed_syllable = count-1; // the final syllable - vowel_stress[*stressed_syllable] = 4; - max_stress = 4; + vowel_stress[*stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; primary_posn = *stressed_syllable; } - if (max_stress == 5) { + if (max_stress == STRESS_IS_PRIORITY) { // priority stress, replaces any other primary stress marker for (ix = 1; ix < count; ix++) { - if (vowel_stress[ix] == 4) { + if (vowel_stress[ix] == STRESS_IS_PRIMARY) { if (tr->langopts.stress_flags & S_PRIORITY_STRESS) - vowel_stress[ix] = 1; + vowel_stress[ix] = STRESS_IS_UNSTRESSED; else - vowel_stress[ix] = 3; + vowel_stress[ix] = STRESS_IS_SECONDARY; } - if (vowel_stress[ix] == 5) { - vowel_stress[ix] = 4; + if (vowel_stress[ix] == STRESS_IS_PRIORITY) { + vowel_stress[ix] = STRESS_IS_PRIMARY; primary_posn = ix; } } - max_stress = 4; + max_stress = STRESS_IS_PRIMARY; } *stressed_syllable = primary_posn; @@ -969,7 +969,7 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress) strcpy((char *)phonetic, word); max_stress = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 0); - if (new_stress >= 4) { + if (new_stress >= STRESS_IS_PRIMARY) { // promote to primary stress for (ix = 1; ix < vowel_count; ix++) { if (vowel_stress[ix] >= max_stress) { @@ -990,7 +990,7 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress) p = phonetic; while (*p != 0) { if ((phoneme_tab[*p]->type == phVOWEL) && !(phoneme_tab[*p]->phflags & phNONSYLLABIC)) { - if ((vowel_stress[ix] == 0) || (vowel_stress[ix] > 1)) + if ((vowel_stress[ix] == STRESS_IS_DIMINISHED) || (vowel_stress[ix] > STRESS_IS_UNSTRESSED)) *word++ = stress_phonemes[(unsigned char)vowel_stress[ix]]; ix++; @@ -1045,13 +1045,6 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, static char consonant_types[16] = { 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0 }; - /* stress numbers STRESS_BASE + - 0 diminished, unstressed within a word - 1 unstressed, weak - 2 - 3 secondary stress - 4 main stress */ - stressflags = tr->langopts.stress_flags; if (dictionary_flags != NULL) @@ -1084,7 +1077,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, max_stress = max_stress_input = GetVowelStress(tr, phonetic, vowel_stress, &vowel_count, &stressed_syllable, 1); if ((max_stress < 0) && dictionary_flags) - max_stress = 0; + max_stress = STRESS_IS_DIMINISHED; // heavy or light syllables ix = 1; @@ -1124,16 +1117,16 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // stress on second syllable if ((stressed_syllable == 0) && (vowel_count > 2)) { stressed_syllable = 2; - if (max_stress == 0) - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + if (max_stress == STRESS_IS_DIMINISHED) + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; case 10: // penultimate, but final if only 1 or 2 syllables if (stressed_syllable == 0) { if (vowel_count < 4) { - vowel_stress[vowel_count - 1] = 4; - max_stress = 4; + vowel_stress[vowel_count - 1] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; break; } } @@ -1143,7 +1136,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, if (stressed_syllable == 0) { // no explicit stress - stress the penultimate vowel - max_stress = 4; + max_stress = STRESS_IS_PRIMARY; if (vowel_count > 2) { stressed_syllable = vowel_count - 2; @@ -1174,7 +1167,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, stressed_syllable = vowel_count - 1; } - if ((vowel_stress[stressed_syllable] == 0) || (vowel_stress[stressed_syllable] == 1)) { + if ((vowel_stress[stressed_syllable] == STRESS_IS_DIMINISHED) || (vowel_stress[stressed_syllable] == STRESS_IS_UNSTRESSED)) { // but this vowel is explicitly marked as unstressed if (stressed_syllable > 1) stressed_syllable--; @@ -1187,7 +1180,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // only set the stress if it's not already marked explicitly if (vowel_stress[stressed_syllable] < 0) { // don't stress if next and prev syllables are stressed - if ((vowel_stress[stressed_syllable-1] < 4) || (vowel_stress[stressed_syllable+1] < 4)) + if ((vowel_stress[stressed_syllable-1] < STRESS_IS_PRIMARY) || (vowel_stress[stressed_syllable+1] < STRESS_IS_PRIMARY)) vowel_stress[stressed_syllable] = max_stress; } } @@ -1200,13 +1193,13 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, while (stressed_syllable > 0) { // find the last vowel which is not unstressed - if (vowel_stress[stressed_syllable] < 0) { - vowel_stress[stressed_syllable] = 4; + if (vowel_stress[stressed_syllable] < STRESS_IS_DIMINISHED) { + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; break; } else stressed_syllable--; } - max_stress = 4; + max_stress = STRESS_IS_PRIMARY; } break; case 4: // stress on antipenultimate vowel @@ -1215,9 +1208,9 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, if (stressed_syllable < 1) stressed_syllable = 1; - if (max_stress == 0) - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + if (max_stress == STRESS_IS_DIMINISHED) + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; case 5: @@ -1237,8 +1230,8 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, else stressed_syllable = guess_ru[vowel_count]; } - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; case 6: // LANG=hi stress on the last heaviest syllable @@ -1248,7 +1241,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // find the heaviest syllable, excluding the final syllable for (ix = 1; ix < (vowel_count-1); ix++) { - if (vowel_stress[ix] < 0) { + if (vowel_stress[ix] < STRESS_IS_DIMINISHED) { if ((wt = syllable_weight[ix]) >= max_weight) { max_weight = wt; stressed_syllable = ix; @@ -1264,38 +1257,38 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, stressed_syllable = 1; } - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; case 7: // LANG=tr, the last syllable for any vowel marked explicitly as unstressed if (stressed_syllable == 0) { stressed_syllable = vowel_count - 1; for (ix = 1; ix < vowel_count; ix++) { - if (vowel_stress[ix] == 1) { + if (vowel_stress[ix] == STRESS_IS_UNSTRESSED) { stressed_syllable = ix-1; break; } } - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; case 9: // mark all as stressed for (ix = 1; ix < vowel_count; ix++) { - if (vowel_stress[ix] < 0) - vowel_stress[ix] = 4; + if (vowel_stress[ix] < STRESS_IS_DIMINISHED) + vowel_stress[ix] = STRESS_IS_PRIMARY; } break; case 12: // LANG=kl (Greenlandic) long_vowel = 0; for (ix = 1; ix < vowel_count; ix++) { - if (vowel_stress[ix] == 4) - vowel_stress[ix] = 3; // change marked stress (consonant clusters) to secondary (except the last) + if (vowel_stress[ix] == STRESS_IS_PRIMARY) + vowel_stress[ix] = STRESS_IS_SECONDARY; // change marked stress (consonant clusters) to secondary (except the last) if (vowel_length[ix] > 0) { long_vowel = ix; - vowel_stress[ix] = 3; // give secondary stress to all long vowels + vowel_stress[ix] = STRESS_IS_SECONDARY; // give secondary stress to all long vowels } } @@ -1312,86 +1305,94 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, stressed_syllable = vowel_count - 1; } } - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; break; case 13: // LANG=ml, 1st unless 1st vowel is short and 2nd is long if (stressed_syllable == 0) { stressed_syllable = 1; if ((vowel_length[1] == 0) && (vowel_count > 2) && (vowel_length[2] > 0)) stressed_syllable = 2; - vowel_stress[stressed_syllable] = 4; - max_stress = 4; + vowel_stress[stressed_syllable] = STRESS_IS_PRIMARY; + max_stress = STRESS_IS_PRIMARY; } break; } - if ((stressflags & S_FINAL_VOWEL_UNSTRESSED) && ((control & 2) == 0) && (vowel_count > 2) && (max_stress_input < 3) && (vowel_stress[vowel_count - 1] == 4)) { + if ((stressflags & S_FINAL_VOWEL_UNSTRESSED) && ((control & 2) == 0) && (vowel_count > 2) && (max_stress_input < STRESS_IS_SECONDARY) && (vowel_stress[vowel_count - 1] == STRESS_IS_PRIMARY)) { // Don't allow stress on a word-final vowel // Only do this if there is no suffix phonemes to be added, and if a stress position was not given explicitly if (phoneme_tab[final_ph]->type == phVOWEL) { - vowel_stress[vowel_count - 1] = 1; - vowel_stress[vowel_count - 2] = 4; + vowel_stress[vowel_count - 1] = STRESS_IS_UNSTRESSED; + vowel_stress[vowel_count - 2] = STRESS_IS_PRIMARY; } } // now guess the complete stress pattern - if (max_stress < 4) - stress = 4; // no primary stress marked, use for 1st syllable + if (max_stress < STRESS_IS_PRIMARY) + stress = STRESS_IS_PRIMARY; // no primary stress marked, use for 1st syllable else - stress = 3; + stress = STRESS_IS_SECONDARY; if (unstressed_word == false) { if ((stressflags & S_2_SYL_2) && (vowel_count == 3)) { // Two syllable word, if one syllable has primary stress, then give the other secondary stress - if (vowel_stress[1] == 4) - vowel_stress[2] = 3; - if (vowel_stress[2] == 4) - vowel_stress[1] = 3; + if (vowel_stress[1] == STRESS_IS_PRIMARY) + vowel_stress[2] = STRESS_IS_SECONDARY; + if (vowel_stress[2] == STRESS_IS_PRIMARY) + vowel_stress[1] = STRESS_IS_SECONDARY; } - if ((stressflags & S_INITIAL_2) && (vowel_stress[1] < 0)) { + if ((stressflags & S_INITIAL_2) && (vowel_stress[1] < STRESS_IS_DIMINISHED)) { // If there is only one syllable before the primary stress, give it a secondary stress - if ((vowel_count > 3) && (vowel_stress[2] >= 4)) - vowel_stress[1] = 3; + if ((vowel_count > 3) && (vowel_stress[2] >= STRESS_IS_PRIMARY)) + vowel_stress[1] = STRESS_IS_SECONDARY; } } bool done = false; first_primary = 0; for (v = 1; v < vowel_count; v++) { - if (vowel_stress[v] < 0) { - if ((stressflags & S_FINAL_NO_2) && (stress < 4) && (v == vowel_count-1)) { + if (vowel_stress[v] < STRESS_IS_DIMINISHED) { + if ((stressflags & S_FINAL_NO_2) && (stress < STRESS_IS_PRIMARY) && (v == vowel_count-1)) { // flag: don't give secondary stress to final vowel } else if ((stressflags & 0x8000) && (done == false)) { vowel_stress[v] = (char)stress; done = true; - stress = 3; // use secondary stress for remaining syllables - } else if ((vowel_stress[v-1] <= 1) && ((vowel_stress[v+1] <= 1) || ((stress == 4) && (vowel_stress[v+1] <= 2)))) { + stress = STRESS_IS_SECONDARY; // use secondary stress for remaining syllables + } else if ((vowel_stress[v-1] <= STRESS_IS_UNSTRESSED) && ((vowel_stress[v+1] <= STRESS_IS_UNSTRESSED) || ((stress == STRESS_IS_PRIMARY) && (vowel_stress[v+1] <= STRESS_IS_NOT_STRESSED)))) { // trochaic: give stress to vowel surrounded by unstressed vowels - if ((stress == 3) && (stressflags & S_NO_AUTO_2)) + if ((stress == STRESS_IS_SECONDARY) && (stressflags & S_NO_AUTO_2)) continue; // don't use secondary stress - if ((v > 1) && (stressflags & S_2_TO_HEAVY) && (syllable_weight[v] == 0) && (syllable_weight[v+1] > 0)) { - // don't put secondary stress on a light syllable which is followed by a heavy syllable - continue; + // don't put secondary stress on a light syllable if the rest of the word (excluding last syllable) contains a heavy syllable + if ((v > 1) && (stressflags & S_2_TO_HEAVY) && (syllable_weight[v] == 0)) { + bool skip = false; + for (int i = v; i < vowel_count - 1; i++) { + if (syllable_weight[i] > 0) { + skip = true; + break; + } + } + if (skip == true) + continue; } // should start with secondary stress on the first syllable, or should it count back from // the primary stress and put secondary stress on alternate syllables? vowel_stress[v] = (char)stress; done = true; - stress = 3; // use secondary stress for remaining syllables + stress = STRESS_IS_SECONDARY; // use secondary stress for remaining syllables } } - if (vowel_stress[v] >= 4) { + if (vowel_stress[v] >= STRESS_IS_PRIMARY) { if (first_primary == 0) first_primary = v; else if (stressflags & S_FIRST_PRIMARY) { // reduce primary stresses after the first to secondary - vowel_stress[v] = 3; + vowel_stress[v] = STRESS_IS_SECONDARY; } } } @@ -1403,7 +1404,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, tonic = tr->langopts.unstressed_wd2; // more than one syllable, used secondary stress as the main stress } - max_stress = 0; + max_stress = STRESS_IS_DIMINISHED; max_stress_posn = 0; for (v = 1; v < vowel_count; v++) { if (vowel_stress[v] >= max_stress) { @@ -1416,7 +1417,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // find position of highest stress, and replace it by 'tonic' // don't disturb an explicitly set stress by 'unstress-at-end' flag - if ((tonic > max_stress) || (max_stress <= 4)) + if ((tonic > max_stress) || (max_stress <= STRESS_IS_PRIMARY)) vowel_stress[max_stress_posn] = (char)tonic; max_stress = tonic; } @@ -1434,7 +1435,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, if ((tr->langopts.vowel_pause & 0x30) && (ph->type == phVOWEL)) { // word starts with a vowel - if ((tr->langopts.vowel_pause & 0x20) && (vowel_stress[1] >= 4)) + if ((tr->langopts.vowel_pause & 0x20) && (vowel_stress[1] >= STRESS_IS_PRIMARY)) *output++ = phonPAUSE_NOLINK; // not to be replaced by link else *output++ = phonPAUSE_VSHORT; // break, but no pause @@ -1454,26 +1455,26 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, v_stress = vowel_stress[v]; tr->prev_last_stress = v_stress; - if (v_stress <= 1) { + if (v_stress <= STRESS_IS_UNSTRESSED) { if ((v > 1) && (max_stress >= 2) && (stressflags & S_FINAL_DIM) && (v == (vowel_count-1))) { // option: mark unstressed final syllable as diminished - v_stress = 0; + v_stress = STRESS_IS_DIMINISHED; } else if ((stressflags & S_NO_DIM) || (v == 1) || (v == (vowel_count-1))) { // first or last syllable, or option 'don't set diminished stress' - v_stress = 1; - } else if ((v == (vowel_count-2)) && (vowel_stress[vowel_count-1] <= 1)) { + v_stress = STRESS_IS_UNSTRESSED; + } else if ((v == (vowel_count-2)) && (vowel_stress[vowel_count-1] <= STRESS_IS_UNSTRESSED)) { // penultimate syllable, followed by an unstressed final syllable - v_stress = 1; + v_stress = STRESS_IS_UNSTRESSED; } else { // unstressed syllable within a word - if ((vowel_stress[v-1] < 0) || ((stressflags & S_MID_DIM) == 0)) { - v_stress = 0; // change to 0 (diminished stress) + if ((vowel_stress[v-1] < STRESS_IS_DIMINISHED) || ((stressflags & S_MID_DIM) == 0)) { + v_stress = STRESS_IS_DIMINISHED; vowel_stress[v] = v_stress; } } } - if ((v_stress == 0) || (v_stress > 1)) + if ((v_stress == STRESS_IS_DIMINISHED) || (v_stress > STRESS_IS_UNSTRESSED)) *output++ = stress_phonemes[v_stress]; // mark stress of all vowels except 1 (unstressed) if (vowel_stress[v] > max_stress) @@ -1487,8 +1488,8 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags, // only allow lengthen indicator on the highest stress syllable in the word if (v != max_stress_posn) shorten = true; - } else if (v_stress < 4) { - // only allow lengthen indicator if stress >= 4. + } else if (v_stress < STRESS_IS_PRIMARY) { + // only allow lengthen indicator if stress >= STRESS_IS_PRIMARY. shorten = true; } diff --git a/src/libespeak-ng/synthdata.c b/src/libespeak-ng/synthdata.c index a6b2a785..dc6943ca 100644 --- a/src/libespeak-ng/synthdata.c +++ b/src/libespeak-ng/synthdata.c @@ -466,15 +466,15 @@ static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, if ((tr->langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= pl->wordstress)) { // treat the most stressed syllable in an unstressed word as stressed - stress_level = 4; + stress_level = STRESS_IS_PRIMARY; } } - if (condition == isMaxStress) + if (condition == STRESS_IS_PRIMARY) return stress_level >= pl->wordstress; - if (condition == isStressed) { - if (stress_level > 3) + if (condition == STRESS_IS_SECONDARY) { + if (stress_level > STRESS_IS_SECONDARY) return true; } else { if (stress_level < condition_level[condition]) @@ -633,11 +633,11 @@ static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, case CONDITION_IS_OTHER: switch (data) { - case isDiminished: - case isUnstressed: - case isNotStressed: - case isStressed: - case isMaxStress: + case STRESS_IS_DIMINISHED: + case STRESS_IS_UNSTRESSED: + case STRESS_IS_NOT_STRESSED: + case STRESS_IS_SECONDARY: + case STRESS_IS_PRIMARY: return StressCondition(tr, plist, data, 0); case isBreak: return (ph->type == phPAUSE) || (plist_this->synthflags & SFLAG_NEXT_PAUSE); diff --git a/src/libespeak-ng/synthesize.h b/src/libespeak-ng/synthesize.h index 62ead06a..826b237f 100644 --- a/src/libespeak-ng/synthesize.h +++ b/src/libespeak-ng/synthesize.h @@ -319,16 +319,15 @@ typedef struct { #define CONDITION_IS_OTHER 0x80 // other conditions (stress) -#define isDiminished 0 -#define isUnstressed 1 -#define isNotStressed 2 -#define isStressed 3 -#define isMaxStress 4 +#define STRESS_IS_DIMINISHED 0 // diminished, unstressed within a word +#define STRESS_IS_UNSTRESSED 1 // unstressed, weak +#define STRESS_IS_NOT_STRESSED 2 // default, not stressed +#define STRESS_IS_SECONDARY 3 // secondary stress +#define STRESS_IS_PRIMARY 4 // primary (main) stress +#define STRESS_IS_PRIORITY 5 // replaces primary markers +#define STRESS_IS_EMPHASIZED 6 // emphasized // other conditions -#define isBreak 5 // pause phoneme or (stop/vstop/vfric not followed by vowel or (liquid in same word)) -#define isWordStart 6 -#define isWordEnd 8 #define isAfterStress 9 #define isNotVowel 10 #define isFinalVowel 11 @@ -336,6 +335,9 @@ typedef struct { #define isFirstVowel 13 #define isSecondVowel 14 #define isTranslationGiven 16 // phoneme translation given in **_list or as [[...]] +#define isBreak 17 // pause phoneme or (stop/vstop/vfric not followed by vowel or (liquid in same word)) +#define isWordStart 18 +#define isWordEnd 19 #define i_StressLevel 0x800