Browse Source

MerGe branch 'phonemelist_cleanup'

master
Juho Hiltunen 2 years ago
parent
commit
b368302170
1 changed files with 105 additions and 108 deletions
  1. 105
    108
      src/libespeak-ng/phonemelist.c

+ 105
- 108
src/libespeak-ng/phonemelist.c View File

#include "translate.h" #include "translate.h"
#include "speech.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] = { static const unsigned char pause_phonemes[8] = {
0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG 0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG
}; };
int j; int j;
int insert_ph = 0; int insert_ph = 0;
PHONEME_LIST *phlist; PHONEME_LIST *phlist;
PHONEME_TAB *ph;
PHONEME_TAB *next, *next2;
PHONEME_TAB *ph = NULL;
PHONEME_TAB *next;
int unstress_count = 0; int unstress_count = 0;
int word_stress = 0; int word_stress = 0;
int current_phoneme_tab; int current_phoneme_tab;
int max_stress; int max_stress;
int voicing;
int regression;
int end_sourceix; int end_sourceix;
int alternative; int alternative;
int delete_count; int delete_count;
int word_start; int word_start;
bool inserted;
bool deleted;
PHONEME_DATA phdata; PHONEME_DATA phdata;
bool start_of_clause = true; bool start_of_clause = true;




SelectPhonemeTable(current_phoneme_tab); SelectPhonemeTable(current_phoneme_tab);


int regression;
if ((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0) { 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); SelectPhonemeTable(tr->phoneme_tab_ix);
for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) { for (j = 0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++) {
plist3 = &ph_list3[j]; plist3 = &ph_list3[j];


inserted = false;
deleted = false;
bool inserted = false;
bool deleted = false;
if (insert_ph != 0) { if (insert_ph != 0) {
// we have a (linking) phoneme which we need to insert here // we have a (linking) phoneme which we need to insert here
next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert
plist3->ph = ph; plist3->ph = ph;
plist3->phcode = alternative; 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) { if ((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0) {
if (alternative == 1) if (alternative == 1)
deleted = true; // NULL phoneme, discard deleted = true; // NULL phoneme, discard
else { 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)) { if ((ph->type == phVOWEL) && (deleted == false)) {
PHONEME_LIST *p;

// Check for consecutive unstressed syllables, even across word boundaries. // Check for consecutive unstressed syllables, even across word boundaries.
// Do this after changing phonemes according to stress level. // Do this after changing phonemes according to stress level.
if (plist3->stresslevel <= 1) { if (plist3->stresslevel <= 1) {


if (tr->langopts.stress_flags & 0x08) { if (tr->langopts.stress_flags & 0x08) {
// change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST) // change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST)
PHONEME_LIST *p;
for (p = plist3+1; p->type != phPAUSE; p++) { for (p = plist3+1; p->type != phPAUSE; p++) {
if (p->type == phVOWEL) { if (p->type == phVOWEL) {
if (p->stresslevel <= 1) { if (p->stresslevel <= 1) {
} }
} }


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)) if ((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0))
insert_ph = phdata.pd_param[pd_APPENDPHONEME]; insert_ph = phdata.pd_param[pd_APPENDPHONEME];


SelectPhonemeTable(tr->phoneme_tab_ix); 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);
}

Loading…
Cancel
Save