| @@ -40,6 +40,9 @@ | |||
| #include "translate.h" | |||
| #include "speech.h" | |||
| static void SetRegressiveVoicing(int regression, PHONEME_LIST2 *plist2, PHONEME_TAB *ph, Translator *tr); | |||
| static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata); | |||
| static const unsigned char pause_phonemes[8] = { | |||
| 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG | |||
| }; | |||
| @@ -122,20 +125,16 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| int j; | |||
| int insert_ph = 0; | |||
| PHONEME_LIST *phlist; | |||
| PHONEME_TAB *ph; | |||
| PHONEME_TAB *next, *next2; | |||
| PHONEME_TAB *ph = NULL; | |||
| PHONEME_TAB *next; | |||
| int unstress_count = 0; | |||
| int word_stress = 0; | |||
| int current_phoneme_tab; | |||
| int max_stress; | |||
| int voicing; | |||
| int regression; | |||
| int end_sourceix; | |||
| int alternative; | |||
| int delete_count; | |||
| int word_start; | |||
| bool inserted; | |||
| bool deleted; | |||
| PHONEME_DATA phdata; | |||
| bool start_of_clause = true; | |||
| @@ -212,83 +211,9 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| SelectPhonemeTable(current_phoneme_tab); | |||
| int regression; | |||
| if ((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0) { | |||
| // set consonant clusters to all voiced or all unvoiced | |||
| // Regressive | |||
| int type; | |||
| bool stop_propagation = false; | |||
| voicing = 0; | |||
| for (j = n_ph_list2-1; j >= 0; j--) { | |||
| if (plist2[j].phcode == phonSWITCH) { | |||
| /* Find previous phonSWITCH to determine language we're switching back to */ | |||
| int k; | |||
| for (k = j-1; k >= 0; k--) | |||
| if (plist2[k].phcode == phonSWITCH) | |||
| break; | |||
| if (k >= 0) | |||
| SelectPhonemeTable(plist2[k].tone_ph); | |||
| else | |||
| SelectPhonemeTable(tr->phoneme_tab_ix); | |||
| } | |||
| ph = phoneme_tab[plist2[j].phcode]; | |||
| if (ph == NULL) | |||
| continue; | |||
| if (plist2[j].synthflags & SFLAG_SWITCHED_LANG) { | |||
| stop_propagation = false; | |||
| voicing = 0; | |||
| if (regression & 0x100) | |||
| voicing = 1; // word-end devoicing | |||
| continue; | |||
| } | |||
| type = ph->type; | |||
| if (regression & 0x2) { | |||
| // [v] amd [v;] don't cause regression, or [R^] | |||
| if (((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff) == 'R')) { | |||
| stop_propagation = true; | |||
| if (regression & 0x10) | |||
| voicing = 0; | |||
| } | |||
| } | |||
| if ((type == phSTOP) || type == (phFRICATIVE)) { | |||
| if ((voicing == 0) && (regression & 0xf)) | |||
| voicing = 1; | |||
| else if ((voicing == 2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants | |||
| plist2[j].phcode = ph->end_type; // change to voiced equivalent | |||
| } else if ((type == phVSTOP) || type == (phVFRICATIVE)) { | |||
| if ((voicing == 0) && (regression & 0xf)) | |||
| voicing = 2; | |||
| else if ((voicing == 1) && (ph->end_type != 0)) | |||
| plist2[j].phcode = ph->end_type; // change to unvoiced equivalent | |||
| } else { | |||
| if (regression & 0x8) { | |||
| // LANG=Polish, propagate through liquids and nasals | |||
| if ((type == phPAUSE) || (type == phVOWEL)) | |||
| voicing = 0; | |||
| } else | |||
| voicing = 0; | |||
| } | |||
| if (stop_propagation) { | |||
| voicing = 0; | |||
| stop_propagation = false; | |||
| } | |||
| if (plist2[j].sourceix) { | |||
| if (regression & 0x04) { | |||
| // stop propagation at a word boundary | |||
| voicing = 0; | |||
| } | |||
| if (regression & 0x100) { | |||
| // devoice word-final consonants, unless propagating voiced | |||
| if (voicing == 0) | |||
| voicing = 1; | |||
| } | |||
| } | |||
| } | |||
| SetRegressiveVoicing(regression, plist2, ph, tr); | |||
| } | |||
| SelectPhonemeTable(tr->phoneme_tab_ix); | |||
| @@ -326,8 +251,8 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { | |||
| plist3 = &ph_list3[j]; | |||
| inserted = false; | |||
| deleted = false; | |||
| bool inserted = false; | |||
| bool deleted = false; | |||
| if (insert_ph != 0) { | |||
| // we have a (linking) phoneme which we need to insert here | |||
| next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert | |||
| @@ -390,16 +315,7 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| plist3->ph = ph; | |||
| plist3->phcode = alternative; | |||
| if (ph->type == phVOWEL) { | |||
| plist3->synthflags |= SFLAG_SYLLABLE; | |||
| if (ph2->type != phVOWEL) | |||
| plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed | |||
| } else | |||
| plist3->synthflags &= ~SFLAG_SYLLABLE; | |||
| // re-interpret the changed phoneme | |||
| // But it doesn't obey a second ChangePhoneme() | |||
| InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata); | |||
| ReInterpretPhoneme(ph, ph2, plist3, tr, &phdata, &worddata); | |||
| } | |||
| if ((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0) { | |||
| @@ -412,22 +328,11 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| if (alternative == 1) | |||
| deleted = true; // NULL phoneme, discard | |||
| else { | |||
| if (ph->type == phVOWEL) { | |||
| plist3->synthflags |= SFLAG_SYLLABLE; | |||
| if (ph2->type != phVOWEL) | |||
| plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed | |||
| } else | |||
| plist3->synthflags &= ~SFLAG_SYLLABLE; | |||
| // re-interpret the changed phoneme | |||
| // But it doesn't obey a second ChangePhoneme() | |||
| InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata); | |||
| ReInterpretPhoneme(ph, ph2, plist3, tr, &phdata, &worddata); | |||
| } | |||
| } | |||
| if ((ph->type == phVOWEL) && (deleted == false)) { | |||
| PHONEME_LIST *p; | |||
| // Check for consecutive unstressed syllables, even across word boundaries. | |||
| // Do this after changing phonemes according to stress level. | |||
| if (plist3->stresslevel <= 1) { | |||
| @@ -436,6 +341,7 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| if (tr->langopts.stress_flags & 0x08) { | |||
| // change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST) | |||
| PHONEME_LIST *p; | |||
| for (p = plist3+1; p->type != phPAUSE; p++) { | |||
| if (p->type == phVOWEL) { | |||
| if (p->stresslevel <= 1) { | |||
| @@ -518,8 +424,7 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| } | |||
| } | |||
| next2 = phoneme_tab[plist3[2].phcode]; | |||
| plist3[2].ph = next2; | |||
| plist3[2].ph = phoneme_tab[plist3[2].phcode]; | |||
| if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0)) | |||
| insert_ph = phdata.pd_param[pd_APPENDPHONEME]; | |||
| @@ -594,3 +499,95 @@ void MakePhonemeList(Translator *tr, int post_pause, bool start_sentence) | |||
| SelectPhonemeTable(tr->phoneme_tab_ix); | |||
| } | |||
| static void SetRegressiveVoicing(int regression, PHONEME_LIST2 *plist2, PHONEME_TAB *ph, Translator *tr) { | |||
| // set consonant clusters to all voiced or all unvoiced | |||
| // Regressive | |||
| int type; | |||
| bool stop_propagation = false; | |||
| int voicing = 0; | |||
| for (int j = n_ph_list2-1; j >= 0; j--) { | |||
| if (plist2[j].phcode == phonSWITCH) { | |||
| /* Find previous phonSWITCH to determine language we're switching back to */ | |||
| int k; | |||
| for (k = j-1; k >= 0; k--) | |||
| if (plist2[k].phcode == phonSWITCH) | |||
| break; | |||
| if (k >= 0) | |||
| SelectPhonemeTable(plist2[k].tone_ph); | |||
| else | |||
| SelectPhonemeTable(tr->phoneme_tab_ix); | |||
| } | |||
| ph = phoneme_tab[plist2[j].phcode]; | |||
| if (ph == NULL) | |||
| continue; | |||
| if (plist2[j].synthflags & SFLAG_SWITCHED_LANG) { | |||
| stop_propagation = false; | |||
| voicing = 0; | |||
| if (regression & 0x100) | |||
| voicing = 1; // word-end devoicing | |||
| continue; | |||
| } | |||
| type = ph->type; | |||
| if (regression & 0x2) { | |||
| // [v] amd [v;] don't cause regression, or [R^] | |||
| if (((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff) == 'R')) { | |||
| stop_propagation = true; | |||
| if (regression & 0x10) | |||
| voicing = 0; | |||
| } | |||
| } | |||
| if ((type == phSTOP) || type == (phFRICATIVE)) { | |||
| if ((voicing == 0) && (regression & 0xf)) | |||
| voicing = 1; | |||
| else if ((voicing == 2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants | |||
| plist2[j].phcode = ph->end_type; // change to voiced equivalent | |||
| } else if ((type == phVSTOP) || type == (phVFRICATIVE)) { | |||
| if ((voicing == 0) && (regression & 0xf)) | |||
| voicing = 2; | |||
| else if ((voicing == 1) && (ph->end_type != 0)) | |||
| plist2[j].phcode = ph->end_type; // change to unvoiced equivalent | |||
| } else { | |||
| if (regression & 0x8) { | |||
| // LANG=Polish, propagate through liquids and nasals | |||
| if ((type == phPAUSE) || (type == phVOWEL)) | |||
| voicing = 0; | |||
| } else | |||
| voicing = 0; | |||
| } | |||
| if (stop_propagation) { | |||
| voicing = 0; | |||
| stop_propagation = false; | |||
| } | |||
| if (plist2[j].sourceix) { | |||
| if (regression & 0x04) { | |||
| // stop propagation at a word boundary | |||
| voicing = 0; | |||
| } | |||
| if (regression & 0x100) { | |||
| // devoice word-final consonants, unless propagating voiced | |||
| if (voicing == 0) | |||
| voicing = 1; | |||
| } | |||
| } | |||
| } | |||
| } | |||
| static void ReInterpretPhoneme(PHONEME_TAB *ph, PHONEME_TAB *ph2, PHONEME_LIST *plist3, Translator *tr, PHONEME_DATA *phdata, WORD_PH_DATA *worddata) { | |||
| if (ph->type == phVOWEL) { | |||
| plist3->synthflags |= SFLAG_SYLLABLE; | |||
| if (ph2->type != phVOWEL) | |||
| plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed | |||
| } else | |||
| plist3->synthflags &= ~SFLAG_SYLLABLE; | |||
| // re-interpret the changed phoneme | |||
| // But it doesn't obey a second ChangePhoneme() | |||
| InterpretPhoneme(tr, 0x100, plist3, phdata, worddata); | |||
| } | |||