mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-10-31 13:38:47 +00:00
Language changes: da. Fixed crash bug (in lang=hi), affects prevVowel(), isFirstVowel, etc in phoneme definitions. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@317 d46cf337-b52f-0410-862d-fd96e6ae7743
651 lines
17 KiB
C++
651 lines
17 KiB
C++
/***************************************************************************
|
|
* Copyright (C) 2005 to 2013 by Jonathan Duddington *
|
|
* email: jonsd@users.sourceforge.net *
|
|
* *
|
|
* This program is free software; you can redistribute it and/or modify *
|
|
* it under the terms of the GNU General Public License as published by *
|
|
* the Free Software Foundation; either version 3 of the License, or *
|
|
* (at your option) any later version. *
|
|
* *
|
|
* This program is distributed in the hope that it will be useful, *
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
|
|
* GNU General Public License for more details. *
|
|
* *
|
|
* You should have received a copy of the GNU General Public License *
|
|
* along with this program; if not, see: *
|
|
* <http://www.gnu.org/licenses/>. *
|
|
***************************************************************************/
|
|
|
|
#include "StdAfx.h"
|
|
|
|
#include <stdio.h>
|
|
#include <stdlib.h>
|
|
#include <string.h>
|
|
|
|
#include "speak_lib.h"
|
|
#include "speech.h"
|
|
#include "phoneme.h"
|
|
#include "synthesize.h"
|
|
#include "translate.h"
|
|
|
|
|
|
const unsigned char pause_phonemes[8] = {0, phonPAUSE_VSHORT, phonPAUSE_SHORT, phonPAUSE, phonPAUSE_LONG, phonGLOTTALSTOP, phonPAUSE_LONG, phonPAUSE_LONG};
|
|
|
|
|
|
extern int n_ph_list2;
|
|
extern PHONEME_LIST2 ph_list2[N_PHONEME_LIST]; // first stage of text->phonemes
|
|
|
|
|
|
|
|
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;
|
|
int k;
|
|
int replace_flags;
|
|
int n_plist_out = 0;
|
|
int word_end;
|
|
PHONEME_LIST2 *plist2;
|
|
PHONEME_TAB *next=NULL;
|
|
|
|
for(ix=0; (ix < n_ph_list2) && (n_plist_out < N_PHONEME_LIST); ix++)
|
|
{
|
|
plist2 = &ph_list2[ix];
|
|
|
|
// don't do any substitution if the language has been temporarily changed
|
|
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
|
|
|
|
// 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->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->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
|
|
}
|
|
}
|
|
|
|
// copy phoneme into the output list
|
|
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
|
|
|
|
|
|
|
|
void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
|
|
{//=====================================================================
|
|
|
|
int ix=0;
|
|
int j;
|
|
int insert_ph = 0;
|
|
PHONEME_LIST *phlist;
|
|
PHONEME_TAB *ph;
|
|
PHONEME_TAB *next, *next2;
|
|
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;
|
|
PHONEME_DATA phdata;
|
|
|
|
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;
|
|
|
|
// is the last word of the clause unstressed ?
|
|
max_stress = 0;
|
|
for(j = n_ph_list2-3; j>=0; j--)
|
|
{
|
|
// 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;
|
|
}
|
|
if(max_stress < 4)
|
|
{
|
|
// the last word is unstressed, look for a previous word that can be stressed
|
|
while(--j >= 0)
|
|
{
|
|
if(plist2[j].synthflags & SFLAG_PROMOTE_STRESS) // dictionary flags indicated that this stress can be promoted
|
|
{
|
|
plist2[j].stresslevel = 4; // promote to stressed
|
|
break;
|
|
}
|
|
if(plist2[j].stresslevel >= 4)
|
|
{
|
|
// found a stressed syllable, so stop looking
|
|
break;
|
|
}
|
|
}
|
|
}
|
|
|
|
// 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--)
|
|
{
|
|
ph = phoneme_tab[plist2[j].phcode];
|
|
if(ph == NULL)
|
|
continue;
|
|
|
|
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)
|
|
{
|
|
// [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) && (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 = 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_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];
|
|
ph_list3[0].ph = ph;
|
|
word_start = 1;
|
|
|
|
for(j=0; insert_ph || ((j < n_ph_list3) && (ix < N_PHONEME_LIST-3)); j++)
|
|
{
|
|
plist3 = &ph_list3[j];
|
|
|
|
if(plist3->sourceix != 0)
|
|
word_start = j;
|
|
|
|
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
|
|
|
|
// re-use the previous entry for the inserted phoneme.
|
|
// That's OK because we don't look backwards from plist3 *** but CountVowelPosition() and isAfterStress does !!!
|
|
j--;
|
|
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;
|
|
}
|
|
else
|
|
{
|
|
// otherwise get the next phoneme from the list
|
|
ph = phoneme_tab[plist3->phcode];
|
|
plist3[0].ph = ph;
|
|
|
|
if(plist3->phcode == phonSWITCH)
|
|
{
|
|
// 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;
|
|
|
|
InterpretPhoneme(tr, 0x100, plist3, &phdata, &worddata);
|
|
|
|
if((alternative = phdata.pd_param[pd_INSERTPHONEME]) > 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)
|
|
{
|
|
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);
|
|
}
|
|
|
|
if((alternative = phdata.pd_param[pd_CHANGEPHONEME]) > 0)
|
|
{
|
|
PHONEME_TAB *ph2;
|
|
ph2 = ph;
|
|
ph = phoneme_tab[alternative];
|
|
plist3->ph = ph;
|
|
plist3->phcode = alternative;
|
|
|
|
if(alternative == 1)
|
|
continue; // NULL phoneme, discard
|
|
|
|
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);
|
|
}
|
|
|
|
if(ph->type == phVOWEL)
|
|
{
|
|
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)
|
|
{
|
|
// an unstressed vowel
|
|
unstress_count++;
|
|
|
|
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
|
|
{
|
|
unstress_count = 0;
|
|
}
|
|
}
|
|
|
|
if((plist3+1)->synthflags & SFLAG_LENGTHEN)
|
|
{
|
|
static char types_double[] = {phFRICATIVE,phVFRICATIVE,phNASAL,phLIQUID,0};
|
|
if(strchr(types_double,next->type))
|
|
{
|
|
// lengthen this consonant by doubling it
|
|
insert_ph = next->code;
|
|
(plist3+1)->synthflags ^= SFLAG_LENGTHEN;
|
|
}
|
|
}
|
|
|
|
if((plist3+1)->sourceix != 0)
|
|
{
|
|
int x;
|
|
|
|
if(tr->langopts.vowel_pause && (ph->type != phPAUSE))
|
|
{
|
|
|
|
if((ph->type != phVOWEL) && (tr->langopts.vowel_pause & 0x200))
|
|
{
|
|
// add a pause after a word which ends in a consonant
|
|
insert_ph = phonPAUSE_NOLINK;
|
|
}
|
|
|
|
if(next->type == phVOWEL)
|
|
{
|
|
if((x = tr->langopts.vowel_pause & 0x0c) != 0)
|
|
{
|
|
// break before a word which starts with a vowel
|
|
if(x == 0xc)
|
|
insert_ph = phonPAUSE_NOLINK;
|
|
else
|
|
insert_ph = phonPAUSE_VSHORT;
|
|
}
|
|
|
|
if((ph->type == phVOWEL) && ((x = tr->langopts.vowel_pause & 0x03) != 0))
|
|
{
|
|
// adjacent vowels over a word boundary
|
|
if(x == 2)
|
|
insert_ph = phonPAUSE_SHORT;
|
|
else
|
|
insert_ph = phonPAUSE_VSHORT;
|
|
}
|
|
|
|
if(((plist3+1)->stresslevel >= 4) && (tr->langopts.vowel_pause & 0x100))
|
|
{
|
|
// pause before a words which starts with a stressed vowel
|
|
insert_ph = phonPAUSE_SHORT;
|
|
}
|
|
}
|
|
}
|
|
|
|
if(plist3 != plist3_inserted)
|
|
{
|
|
if((x = (tr->langopts.word_gap & 0x7)) != 0)
|
|
{
|
|
if((x > 1) || ((insert_ph != phonPAUSE_SHORT) && (insert_ph != phonPAUSE_NOLINK)))
|
|
{
|
|
// don't reduce the pause
|
|
insert_ph = pause_phonemes[x];
|
|
}
|
|
}
|
|
if(option_wordgap > 0)
|
|
{
|
|
insert_ph = phonPAUSE_LONG;
|
|
}
|
|
}
|
|
}
|
|
|
|
next2 = phoneme_tab[plist3[2].phcode];
|
|
plist3[2].ph = next2;
|
|
|
|
if((insert_ph == 0) && (phdata.pd_param[pd_APPENDPHONEME] != 0))
|
|
{
|
|
insert_ph = phdata.pd_param[pd_APPENDPHONEME];
|
|
}
|
|
|
|
if(ph->phflags & phVOICED)
|
|
{
|
|
// check that a voiced consonant is preceded or followed by a vowel or liquid
|
|
// and if not, add a short schwa
|
|
|
|
// 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 = 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)
|
|
{
|
|
phlist[ix].newword = 5; // start of sentence + start of word
|
|
start_sentence = 0;
|
|
}
|
|
}
|
|
else
|
|
{
|
|
phlist[ix].newword = 0;
|
|
}
|
|
|
|
// phlist[ix].length = ph->std_length;
|
|
phlist[ix].length = phdata.pd_param[i_SET_LENGTH]*2;
|
|
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
|
|
}
|
|
|
|
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;
|
|
}
|
|
|
|
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].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].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];
|
|
|
|
n_phoneme_list = ix;
|
|
} // end of MakePhonemeList
|
|
|
|
|