summaryrefslogtreecommitdiff
path: root/navit/support/espeak/phonemelist.c
diff options
context:
space:
mode:
Diffstat (limited to 'navit/support/espeak/phonemelist.c')
-rw-r--r--[-rwxr-xr-x]navit/support/espeak/phonemelist.c677
1 files changed, 331 insertions, 346 deletions
diff --git a/navit/support/espeak/phonemelist.c b/navit/support/espeak/phonemelist.c
index d663e2e94..07d6fd3d7 100755..100644
--- a/navit/support/espeak/phonemelist.c
+++ b/navit/support/espeak/phonemelist.c
@@ -1,5 +1,5 @@
/***************************************************************************
- * Copyright (C) 2005 to 2007 by Jonathan Duddington *
+ * Copyright (C) 2005 to 2014 by Jonathan Duddington *
* email: jonsd@users.sourceforge.net *
* *
* This program is free software; you can redistribute it and/or modify *
@@ -38,20 +38,8 @@ extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes
-static int ChangePhonemes(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch)
-{//=================================================================================================================
-// Called for each phoneme in the phoneme list, to allow a language to make changes
-// ph The current phoneme
-
- if(tr->translator_name == L('r','u'))
- return(ChangePhonemes_ru(tr, phlist, n_ph, index, ph, ch));
-
- return(0);
-}
-
-
-static int SubstitutePhonemes(Translator *tr, PHONEME_LIST2 *plist_out)
-{//====================================================================
+static int SubstitutePhonemes(Translator *tr, PHONEME_LIST *plist_out)
+{//===================================================================
// Copy the phonemes list and perform any substitutions that are required for the
// current voice
int ix;
@@ -59,113 +47,47 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST2 *plist_out)
int replace_flags;
int n_plist_out = 0;
int word_end;
- int max_stress = -1;
- int switched_language = 0;
- int max_stress_posn=0;
- int n_syllables = 0;
- int syllable = 0;
- int syllable_stressed = 0;
PHONEME_LIST2 *plist2;
- PHONEME_LIST2 *pl;
PHONEME_TAB *next=NULL;
for(ix=0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++)
{
plist2 = &ph_list2[ix];
- if(plist2->phcode == phonSWITCH)
- switched_language ^= 1;
-
// don't do any substitution if the language has been temporarily changed
- if(switched_language == 0)
+ if(!(plist2->synthflags & SFLAG_SWITCHED_LANG))
{
if(ix < (n_ph_list2 -1))
next = phoneme_tab[ph_list2[ix+1].phcode];
-
+
word_end = 0;
if((plist2+1)->sourceix || ((next != 0) && (next->type == phPAUSE)))
word_end = 1; // this phoneme is the end of a word
-
- if(tr->langopts.phoneme_change != 0)
- {
- // this language does changes to phonemes after translation
- int flags;
- CHANGEPH ch;
- if(plist2->sourceix)
- {
- // start of a word, find the stressed vowel
- syllable = 0;
- syllable_stressed = 0;
- n_syllables = 0;
-
- max_stress = -1;
- max_stress_posn = ix;
- for(k=ix; k < n_ph_list2; k++)
- {
- if(((pl = &ph_list2[k])->sourceix != 0) && (k > ix))
- break;
-
- pl->stress &= 0xf;
-
- if(phoneme_tab[pl->phcode]->type == phVOWEL)
- {
- n_syllables++;
-
- if(pl->stress > max_stress)
- {
- syllable_stressed = n_syllables;
- max_stress = pl->stress;
- max_stress_posn = k;
- }
- }
- }
- }
- if(phoneme_tab[plist2->phcode]->type == phVOWEL)
- {
- syllable++;
- }
-
- // make any language specific changes
- flags = 0;
- if(ix == max_stress_posn)
- flags |= 2;
- if(ix > max_stress_posn)
- flags |= 4;
- if(ph_list2[ix].synthflags & SFLAG_DICTIONARY)
- flags |= 8;
- ch.flags = flags | word_end;
-
- ch.stress = plist2->stress;
- ch.stress_highest = max_stress;
- ch.n_vowels = n_syllables;
- ch.vowel_this = syllable;
- ch.vowel_stressed = syllable_stressed;
-
- ChangePhonemes(tr, ph_list2, n_ph_list2, ix, phoneme_tab[ph_list2[ix].phcode], &ch);
- }
-
// check whether a Voice has specified that we should replace this phoneme
for(k=0; k<n_replace_phonemes; k++)
{
if(plist2->phcode == replace_phonemes[k].old_ph)
{
replace_flags = replace_phonemes[k].type;
-
+
if((replace_flags & 1) && (word_end == 0))
continue; // this replacement only occurs at the end of a word
-
- if((replace_flags & 2) && ((plist2->stress & 0x7) > 3))
+
+ if((replace_flags & 2) && ((plist2->stresslevel & 0x7) > 3))
continue; // this replacement doesn't occur in stressed syllables
-
+
+ if((replace_flags & 4) && (plist2->sourceix == 0))
+ continue; // this replacement only occurs at the start of a word
+
// substitute the replacement phoneme
plist2->phcode = replace_phonemes[k].new_ph;
- if((plist2->stress > 1) && (phoneme_tab[plist2->phcode]->phflags & phUNSTRESSED))
- plist2->stress = 0; // the replacement must be unstressed
+ if((plist2->stresslevel > 1) && (phoneme_tab[plist2->phcode]->phflags & phUNSTRESSED))
+ plist2->stresslevel = 0; // the replacement must be unstressed
break;
}
}
-
+
if(plist2->phcode == 0)
{
continue; // phoneme has been replaced by NULL, so don't copy it
@@ -173,7 +95,10 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST2 *plist_out)
}
// copy phoneme into the output list
- memcpy(&plist_out[n_plist_out++],plist2,sizeof(PHONEME_LIST2));
+ memcpy(&plist_out[n_plist_out],plist2,sizeof(PHONEME_LIST2));
+ plist_out[n_plist_out].ph = phoneme_tab[plist2->phcode];
+ plist_out[n_plist_out].type = plist_out[n_plist_out].ph->type;
+ n_plist_out++;
}
return(n_plist_out);
} // end of SubstitutePhonemes
@@ -188,22 +113,30 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
int insert_ph = 0;
PHONEME_LIST *phlist;
PHONEME_TAB *ph;
- PHONEME_TAB *prev, *next, *next2;
+ PHONEME_TAB *next, *next2;
int unstress_count = 0;
int word_stress = 0;
- int switched_language = 0;
+ int current_phoneme_tab;
int max_stress;
int voicing;
int regression;
int end_sourceix;
int alternative;
- int first_vowel=0; // first vowel in a word
- PHONEME_LIST2 ph_list3[N_PHONEME_LIST];
+ int delete_count;
+ int word_start;
+ int inserted;
+ int deleted;
+ PHONEME_DATA phdata;
- static PHONEME_LIST2 ph_list2_null = {0,0,0,0,0};
- PHONEME_LIST2 *plist2 = &ph_list2_null;
- PHONEME_LIST2 *plist2_inserted = NULL;
+ int n_ph_list3;
+ PHONEME_LIST *plist3;
+ PHONEME_LIST *plist3_inserted = NULL;
+ PHONEME_LIST ph_list3[N_PHONEME_LIST];
+ PHONEME_LIST2 *plist2;
+ WORD_PH_DATA worddata;
+
+ memset(&worddata, 0, sizeof(worddata));
plist2 = ph_list2;
phlist = phoneme_list;
end_sourceix = plist2[n_ph_list2-1].sourceix;
@@ -212,9 +145,9 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
max_stress = 0;
for(j = n_ph_list2-3; j>=0; j--)
{
- // start with the last phoneme (before the terminating pauses) and move forwards
- if((plist2[j].stress & 0x7f) > max_stress)
- max_stress = plist2[j].stress & 0x7f;
+ // start with the last phoneme (before the terminating pauses) and move backwards
+ if((plist2[j].stresslevel & 0x7f) > max_stress)
+ max_stress = plist2[j].stresslevel & 0x7f;
if(plist2[j].sourceix != 0)
break;
}
@@ -225,10 +158,10 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
{
if(plist2[j].synthflags & SFLAG_PROMOTE_STRESS) // dictionary flags indicated that this stress can be promoted
{
- plist2[j].stress = 4; // promote to stressed
+ plist2[j].stresslevel = 4; // promote to stressed
break;
}
- if(plist2[j].stress >= 4)
+ if(plist2[j].stresslevel >= 4)
{
// found a stressed syllable, so stop looking
break;
@@ -236,11 +169,48 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
+ // look for switch of phoneme tables
+ delete_count = 0;
+ current_phoneme_tab = tr->phoneme_tab_ix;
+ for(j = 0; j < n_ph_list2; j++)
+ {
+ if(current_phoneme_tab != tr->phoneme_tab_ix)
+ {
+ plist2[j].synthflags |= SFLAG_SWITCHED_LANG;
+ }
+
+ if(delete_count > 0)
+ {
+ memcpy(&plist2[j-delete_count], &plist2[j], sizeof(plist2[0]));
+ }
+
+ if(plist2[j].phcode == phonSWITCH)
+ {
+ if((!(plist2[j].synthflags & SFLAG_EMBEDDED)) && (
+ (plist2[j].tone_ph == current_phoneme_tab) ||
+ (plist2[j+1].phcode == phonSWITCH) ||
+ ((plist2[j+1].phcode == phonPAUSE) && (plist2[j+2].phcode == phonSWITCH))
+ ))
+ {
+ // delete this phonSWITCH if it's switching to the current phoneme table, or
+ // delete this phonSWITCH if its followed by another phonSWITCH
+ delete_count++;
+ }
+ else
+ {
+ current_phoneme_tab = plist2[j].tone_ph;
+ }
+ }
+
+ }
+ n_ph_list2 -= delete_count;
+
if((regression = tr->langopts.param[LOPT_REGRESSIVE_VOICING]) != 0)
{
// set consonant clusters to all voiced or all unvoiced
// Regressive
int type;
+ int stop_propagation = 0;
voicing = 0;
for(j=n_ph_list2-1; j>=0; j--)
@@ -249,43 +219,48 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if(ph == NULL)
continue;
- if(ph->code == phonSWITCH)
- switched_language ^= 1;
- if(switched_language)
+ if(plist2[j].synthflags & SFLAG_SWITCHED_LANG)
+ {
+ stop_propagation = 0;
+ voicing = 0;
+ if(regression & 0x100)
+ voicing = 1; // word-end devoicing
continue;
+ }
type = ph->type;
if(regression & 0x2)
{
- // LANG=Russian, [v] amd [v;] don't cause regression, or [R^]
- if((ph->mnemonic == 'v') || (ph->mnemonic == ((';'<<8)+'v')) || ((ph->mnemonic & 0xff)== 'R'))
- type = phLIQUID;
+ // [v] amd [v;] don't cause regression, or [R^]
+ if(((ph->mnemonic & 0xff) == 'v') || ((ph->mnemonic & 0xff)== 'R'))
+ {
+ stop_propagation = 1;
+ if(regression & 0x10)
+ voicing = 0;
+ }
}
if((type==phSTOP) || type==(phFRICATIVE))
{
- if(voicing==0)
+ if((voicing==0) && (regression & 0xf))
{
voicing = 1;
}
- else
- if((voicing==2) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING))
+ else if((voicing==2) && (ph->end_type != 0)) // use end_type field for voicing_switch for consonants
{
- plist2[j].phcode = ph->alternative_ph; // change to voiced equivalent
+ plist2[j].phcode = ph->end_type; // change to voiced equivalent
}
}
- else
- if((type==phVSTOP) || type==(phVFRICATIVE))
+ else if((type==phVSTOP) || type==(phVFRICATIVE))
{
- if(voicing==0)
+ if((voicing==0) && (regression & 0xf))
{
voicing = 2;
}
- else
- if((voicing==1) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING))
+ else if((voicing==1) && (ph->end_type != 0))
{
- plist2[j].phcode = ph->alternative_ph; // change to unvoiced equivalent
+ plist2[j].phcode = ph->end_type; // change to unvoiced equivalent
}
}
else
@@ -301,234 +276,257 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
voicing = 0;
}
}
- if((regression & 0x4) && (plist2[j].sourceix))
+ if(stop_propagation)
{
- // stop propagation at a word boundary
voicing = 0;
+ stop_propagation = 0;
+ }
+
+ 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;
+ }
+ }
}
}
}
- n_ph_list2 = SubstitutePhonemes(tr,ph_list3) - 2;
+ n_ph_list3 = SubstitutePhonemes(tr,ph_list3) - 2;
+
+ for(j=0; (j < n_ph_list3) && (ix < N_PHONEME_LIST-3);)
+ {
+ if(ph_list3[j].sourceix)
+ {
+ // start of a word
+ int k;
+ int nextw;
+ word_stress = 0;
+
+ // find the highest stress level in this word
+ for(nextw=j; nextw < n_ph_list3;)
+ {
+ if(ph_list3[nextw].stresslevel > word_stress)
+ word_stress = ph_list3[nextw].stresslevel;
+
+ nextw++;
+ if(ph_list3[nextw].sourceix)
+ break; // start of the next word
+ }
+ for(k=j; k<nextw; k++)
+ {
+ ph_list3[k].wordstress = word_stress;
+ }
+ j = nextw;
+ }
+ else
+ {
+ j++;
+ }
+ }
// transfer all the phonemes of the clause into phoneme_list
ph = phoneme_tab[phonPAUSE];
- switched_language = 0;
+ ph_list3[0].ph = ph;
+ word_start = 1;
- for(j=0; insert_ph || ((j < n_ph_list2) && (ix < N_PHONEME_LIST-3)); j++)
+ for(j=0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++)
{
- prev = ph;
-
- plist2 = &ph_list3[j];
+ plist3 = &ph_list3[j];
+ inserted = 0;
+ deleted = 0;
if(insert_ph != 0)
{
// we have a (linking) phoneme which we need to insert here
- next = phoneme_tab[plist2->phcode]; // this phoneme, i.e. after the insert
+ next = phoneme_tab[plist3->phcode]; // this phoneme, i.e. after the insert
// re-use the previous entry for the inserted phoneme.
- // That's OK because we don't look backwards from plist2
+ // That's OK because we don't look backwards from plist3 *** but CountVowelPosition() and isAfterStress does !!!
j--;
- plist2 = plist2_inserted = &ph_list3[j];
- memset(plist2, 0, sizeof(*plist2));
- plist2->phcode = insert_ph;
+ plist3 = plist3_inserted = &ph_list3[j];
+ if(j > 0)
+ {
+ // move all previous phonemes in the word back one place
+ int k;
+ if(word_start > 0)
+ {
+ k = word_start;
+ word_start--;
+ }
+ else
+ {
+ k = 2; // No more space, don't loose the start of word mark at ph_list2[word_start]
+ }
+ for(; k<=j; k++)
+ memcpy(&ph_list3[k-1], &ph_list3[k], sizeof(*plist3));
+ }
+ memset(&plist3[0], 0, sizeof(*plist3));
+ plist3->phcode = insert_ph;
ph = phoneme_tab[insert_ph];
+ plist3->ph = ph;
insert_ph = 0;
+ inserted = 1; // don't insert the same phoneme repeatedly
}
else
{
// otherwise get the next phoneme from the list
- ph = phoneme_tab[plist2->phcode];
+ if(plist3->sourceix != 0)
+ word_start = j;
- if(plist2->phcode == phonSWITCH)
- {
- // change phoneme table
- SelectPhonemeTable(plist2->tone_number);
- switched_language ^= SFLAG_SWITCHED_LANG;
- }
- next = phoneme_tab[(plist2+1)->phcode]; // the phoneme after this one
- }
+ ph = phoneme_tab[plist3->phcode];
+ plist3[0].ph = ph;
- if(plist2->sourceix)
- {
- // start of a word
- int k;
- word_stress = 0;
- first_vowel = 1;
-
- // find the highest stress level in this word
- for(k=j+1; k < n_ph_list2; k++)
+ if(plist3->phcode == phonSWITCH)
{
- if(ph_list3[k].sourceix)
- break; // start of the next word
-
- if(ph_list3[k].stress > word_stress)
- word_stress = ph_list3[k].stress;
+ // change phoneme table
+ SelectPhonemeTable(plist3->tone_ph);
}
+ next = phoneme_tab[plist3[1].phcode]; // the phoneme after this one
+ plist3[1].ph = next;
}
if(ph == NULL) continue;
- if(ph->type == phVOWEL)
- {
- // check for consecutive unstressed syllables
- if(plist2->stress == 0)
- {
- // an unstressed vowel
- unstress_count++;
- if((unstress_count > 1) && ((unstress_count & 1)==0))
- {
- // in a sequence of unstressed syllables, reduce alternate syllables to 'diminished'
- // stress. But not for the last phoneme of a stressed word
- if((tr->langopts.stress_flags & 0x2) || ((word_stress > 3) && ((plist2+1)->sourceix!=0)))
- {
- // An unstressed final vowel of a stressed word
- unstress_count=1; // try again for next syllable
- }
- else
- {
- plist2->stress = 1; // change stress to 'diminished'
- }
- }
- }
- else
- {
- unstress_count = 0;
- }
- }
-
- alternative = 0;
-
- if(ph->alternative_ph > 0)
- {
- switch(ph->phflags & phALTERNATIVE)
- {
- // This phoneme changes if vowel follows, or doesn't follow, depending on its phNOTFOLLOWS flag
- case phBEFORENOTVOWEL:
- if(next->type != phVOWEL)
- alternative = ph->alternative_ph;
- break;
-
- case phBEFORENOTVOWEL2: // LANG=tr
- if(((plist2+1)->sourceix != 0) ||
- ((next->type != phVOWEL) && ((phoneme_tab[(plist2+2)->phcode]->type != phVOWEL) || ((plist2+2)->sourceix != 0))))
- {
- alternative = ph->alternative_ph;
- }
- break;
-
- case phBEFOREVOWELPAUSE:
- if((next->type == phVOWEL) || (next->type == phPAUSE))
- alternative = ph->alternative_ph;
- break;
-
- case phBEFOREVOWEL:
- if(next->type == phVOWEL)
- alternative = ph->alternative_ph;
- break;
+ InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
- case phBEFORE_R:
- if(next->phflags & phRHOTIC)
- {
- alternative = ph->alternative_ph;
- }
- break;
- }
- }
- if(ph->phflags & phBEFOREPAUSE)
+ if((alternative = phdata.pd_param[pd_CHANGE_NEXTPHONEME]) > 0)
{
- if(next->type == phPAUSE)
- alternative = ph->link_out; // replace with the link_out phoneme
+ ph_list3[j+1].ph = phoneme_tab[alternative];
+ ph_list3[j+1].phcode = alternative;
+ ph_list3[j+1].type = phoneme_tab[alternative]->type;
+ next = phoneme_tab[alternative];
}
- if(alternative == 1)
- continue; // NULL phoneme, discard
-
- if(alternative > 1)
+ if(((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 0) && (inserted == 0))
{
+ // PROBLEM: if we insert a phoneme before a vowel then we loose the stress.
PHONEME_TAB *ph2;
ph2 = ph;
+
+ insert_ph = plist3->phcode;
ph = phoneme_tab[alternative];
+ plist3->ph = ph;
+ plist3->phcode = alternative;
if(ph->type == phVOWEL)
{
- plist2->synthflags |= SFLAG_SYLLABLE;
+ plist3->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
- plist2->stress = 0; // change from non-vowel to vowel, make sure it's unstressed
+ plist3->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
}
else
- plist2->synthflags &= ~SFLAG_SYLLABLE;
- }
+ plist3->synthflags &= ~SFLAG_SYLLABLE;
- if(tr->langopts.param[LOPT_REDUCE_T])
- {
- if((ph->mnemonic == 't') && (plist2->sourceix == 0) && ((prev->type == phVOWEL) || (prev->mnemonic == 'n')))
- {
- if(((plist2+1)->sourceix == 0) && ((plist2+1)->stress < 3) && (next->type == phVOWEL))
- {
- ph = phoneme_tab[phonT_REDUCED];
- }
- }
+ // re-interpret the changed phoneme
+ // But it doesn't obey a second ChangePhoneme()
+ InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
}
-
- while((ph->reduce_to != 0) && (!(plist2->synthflags & SFLAG_DICTIONARY) || (tr->langopts.param[LOPT_REDUCE] & 1)))
+ if((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0)
{
- int reduce_level;
- int stress_level;
- int reduce = 0;
-
- reduce_level = (ph->phflags >> 28) & 7;
+ PHONEME_TAB *ph2;
+ ph2 = ph;
+ ph = phoneme_tab[alternative];
+ plist3->ph = ph;
+ plist3->phcode = alternative;
- if(ph->type == phVOWEL)
+ if(alternative == 1)
{
- stress_level = plist2->stress;
+ deleted = 1; // NULL phoneme, discard
}
else
{
- // consonant, get stress from the following vowel
- if(next->type == phVOWEL)
- stress_level = (plist2+1)->stress;
+ 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
- break;
- }
+ plist3->synthflags &= ~SFLAG_SYLLABLE;
- if((stress_level == 1) && (first_vowel))
- stress_level = 0; // ignore 'dimished' stress on first syllable
-
- if(stress_level == 1)
- reduce = 1; // stress = 'reduced'
+ // re-interpret the changed phoneme
+ // But it doesn't obey a second ChangePhoneme()
+ InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
+ }
+ }
- if(stress_level < reduce_level)
- reduce =1;
+ if((ph->type == phVOWEL) && (deleted == 0))
+ {
+ PHONEME_LIST *p;
- if((word_stress < 4) && (tr->langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= word_stress))
+ // Check for consecutive unstressed syllables, even across word boundaries.
+ // Do this after changing phonemes according to stress level.
+ if(plist3->stresslevel <= 1)
{
- // don't reduce the most stressed syllable in an unstressed word
- reduce = 0;
- }
+ // an unstressed vowel
+ unstress_count++;
- if(reduce)
- ph = phoneme_tab[ph->reduce_to];
+ if(tr->langopts.stress_flags & 0x08)
+ {
+ // change sequences of consecutive unstressed vowels in unstressed words to diminished stress (TEST)
+ for(p=plist3+1; p->type != phPAUSE; p++)
+ {
+ if(p->type == phVOWEL)
+ {
+ if(p->stresslevel <= 1)
+ {
+ if(plist3->wordstress < 4)
+ plist3->stresslevel = 0;
+ if(p->wordstress < 4)
+ p->stresslevel = 0;
+ }
+ break;
+ }
+ }
+ }
+ else
+ {
+ if((unstress_count > 1) && ((unstress_count & 1)==0))
+ {
+ // in a sequence of unstressed syllables, reduce alternate syllables to 'diminished'
+ // stress. But not for the last phoneme of a stressed word
+ if((tr->langopts.stress_flags & S_NO_DIM) || ((word_stress > 3) && ((plist3+1)->sourceix!=0)))
+ {
+ // An unstressed final vowel of a stressed word
+ unstress_count=1; // try again for next syllable
+ }
+ else
+ {
+ plist3->stresslevel = 0; // change stress to 'diminished'
+ }
+ }
+ }
+ }
else
- break;
+ {
+ unstress_count = 0;
+ }
}
- if(ph->type == phVOWEL)
- first_vowel = 0;
-
- if((plist2+1)->synthflags & SFLAG_LENGTHEN)
+ if((plist3+1)->synthflags & SFLAG_LENGTHEN)
{
static char types_double[] = {phFRICATIVE,phVFRICATIVE,phNASAL,phLIQUID,0};
- if(strchr(types_double,next->type))
+ if((j > 0) && (strchr(types_double,next->type)))
{
// lengthen this consonant by doubling it
+ // BUT, can't insert a phoneme at position plist3[0] because it crashes PrevPh()
insert_ph = next->code;
- (plist2+1)->synthflags ^= SFLAG_LENGTHEN;
+ (plist3+1)->synthflags ^= SFLAG_LENGTHEN;
}
}
- if((plist2+1)->sourceix != 0)
+ if((plist3+1)->sourceix != 0)
{
int x;
@@ -551,7 +549,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
else
insert_ph = phonPAUSE_VSHORT;
}
-
+
if((ph->type == phVOWEL) && ((x = tr->langopts.vowel_pause & 0x03) != 0))
{
// adjacent vowels over a word boundary
@@ -560,8 +558,8 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
else
insert_ph = phonPAUSE_VSHORT;
}
-
- if(((plist2+1)->stress >= 4) && (tr->langopts.vowel_pause & 0x100))
+
+ if(((plist3+1)->stresslevel >= 4) && (tr->langopts.vowel_pause & 0x100))
{
// pause before a words which starts with a stressed vowel
insert_ph = phonPAUSE_SHORT;
@@ -569,7 +567,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
- if(plist2 != plist2_inserted)
+ if((plist3 != plist3_inserted) && (ix > 0))
{
if((x = (tr->langopts.word_gap & 0x7)) != 0)
{
@@ -586,33 +584,12 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
- next2 = phoneme_tab[(plist2+2)->phcode];
+ next2 = phoneme_tab[plist3[2].phcode];
+ plist3[2].ph = next2;
- if((insert_ph == 0) && (ph->link_out != 0) && !(ph->phflags & phBEFOREPAUSE) && (((plist2+1)->synthflags & SFLAG_EMBEDDED)==0))
+ if((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0))
{
- if(ph->phflags & phAPPENDPH)
- {
- // always append the specified phoneme, unless it already is the next phoneme
- if((ph->link_out != (plist2+1)->phcode) && (next->type == phVOWEL))
-// if(ph->link_out != (plist2+1)->phcode)
- {
- insert_ph = ph->link_out;
- }
- }
- else
- if(((tr->langopts.word_gap & 8)==0) || ((plist2+1)->sourceix == 0))
- {
- // This phoneme can be linked to a following vowel by inserting a linking phoneme
- if(next->type == phVOWEL)
- insert_ph = ph->link_out;
- else
- if(next->code == phonPAUSE_SHORT)
- {
- // Pause followed by Vowel, replace the Short Pause with the linking phoneme,
- if(next2->type == phVOWEL)
- (plist2+1)->phcode = ph->link_out; // replace pause by linking phoneme
- }
- }
+ insert_ph = phdata.pd_param[pd_APPENDPHONEME];
}
if(ph->phflags & phVOICED)
@@ -623,62 +600,70 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
// not yet implemented
}
- phlist[ix].ph = ph;
- phlist[ix].type = ph->type;
- phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
- phlist[ix].synthflags = plist2->synthflags | switched_language;
- phlist[ix].stresslevel = plist2->stress & 0xf;
- phlist[ix].tone_ph = plist2->tone_number;
- phlist[ix].sourceix = 0;
-
- if(plist2->sourceix != 0)
+ if(deleted == 0)
{
- phlist[ix].sourceix = plist2->sourceix;
- phlist[ix].newword = 1; // this phoneme is the start of a word
+ phlist[ix].ph = ph;
+ phlist[ix].type = ph->type;
+ phlist[ix].env = PITCHfall; // default, can be changed in the "intonation" module
+ phlist[ix].synthflags = plist3->synthflags;
+ phlist[ix].stresslevel = plist3->stresslevel & 0xf;
+ phlist[ix].wordstress = plist3->wordstress;
+ phlist[ix].tone_ph = plist3->tone_ph;
+ phlist[ix].sourceix = 0;
+ phlist[ix].phcode = ph->code;
+
+ if(plist3->sourceix != 0)
+ {
+ phlist[ix].sourceix = plist3->sourceix;
+ phlist[ix].newword = 1; // this phoneme is the start of a word
- if(start_sentence)
+ if(start_sentence)
+ {
+ phlist[ix].newword = 5; // start of sentence + start of word
+ start_sentence = 0;
+ }
+ }
+ else
{
- phlist[ix].newword = 5; // start of sentence + start of word
- start_sentence = 0;
+ phlist[ix].newword = 0;
}
- }
- else
- {
- phlist[ix].newword = 0;
- }
- phlist[ix].length = ph->std_length;
- if((ph->code == phonPAUSE_LONG) && (option_wordgap > 0))
- {
- phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
- phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
- }
+ // phlist[ix].length = ph->std_length;
+ phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
+ if((ph->code == phonPAUSE_LONG) && (option_wordgap > 0) && (plist3[1].sourceix != 0))
+ {
+ phlist[ix].ph = phoneme_tab[phonPAUSE_SHORT];
+ phlist[ix].length = option_wordgap*14; // 10mS per unit at the default speed
+ }
- if(ph->type==phVOWEL || ph->type==phLIQUID || ph->type==phNASAL || ph->type==phVSTOP || ph->type==phVFRICATIVE)
- {
- phlist[ix].length = 128; // length_mod
- phlist[ix].env = PITCHfall;
- }
+ if(ph->type==phVOWEL || ph->type==phLIQUID || ph->type==phNASAL || ph->type==phVSTOP || ph->type==phVFRICATIVE || (ph->phflags & phPREVOICE))
+ {
+ phlist[ix].length = 128; // length_mod
+ phlist[ix].env = PITCHfall;
+ }
- phlist[ix].prepause = 0;
- phlist[ix].amp = 20; // default, will be changed later
- phlist[ix].pitch1 = 0x400;
- phlist[ix].pitch2 = 0x400;
- ix++;
+ phlist[ix].prepause = 0;
+ phlist[ix].amp = 20; // default, will be changed later
+ phlist[ix].pitch1 = 255;
+ phlist[ix].pitch2 = 255;
+ ix++;
+ }
}
phlist[ix].newword = 2; // end of clause
- phlist[ix].type = phPAUSE; // terminate with 2 Pause phonemes
+ phlist[ix].phcode = phonPAUSE;
+ phlist[ix].type = phPAUSE; // terminate with 2 Pause phonemes
phlist[ix].length = post_pause; // length of the pause, depends on the punctuation
phlist[ix].sourceix = end_sourceix;
phlist[ix].synthflags = 0;
+ phlist[ix++].ph = phoneme_tab[phonPAUSE];
- phlist[ix++].ph = phoneme_tab[phonPAUSE];
- phlist[ix].type = phPAUSE;
+ phlist[ix].phcode = phonPAUSE;
+ phlist[ix].type = phPAUSE;
phlist[ix].length = 0;
phlist[ix].sourceix=0;
phlist[ix].synthflags = 0;
- phlist[ix++].ph = phoneme_tab[phonPAUSE_SHORT];
+ phlist[ix++].ph = phoneme_tab[phonPAUSE_SHORT];
n_phoneme_list = ix;
} // end of MakePhonemeList