mirror of
https://github.com/rhasspy/espeak-ng.git
synced 2026-10-31 13:38:47 +00:00
[1.42.21]
New format for phoneme source files. Update phoneme data for Klatt synthesizer. git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@235 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
+588
-227
@@ -35,8 +35,8 @@
|
||||
#include "translate.h"
|
||||
#include "wave.h"
|
||||
|
||||
const char *version_string = "1.42.09 13.Dec.09";
|
||||
const int version_phdata = 0x014200;
|
||||
const char *version_string = "1.42.21 19.Dec.09";
|
||||
const int version_phdata = 0x014220;
|
||||
|
||||
int option_device_number = -1;
|
||||
FILE *f_logespeak = NULL;
|
||||
@@ -48,7 +48,7 @@ int current_phoneme_table;
|
||||
PHONEME_TAB *phoneme_tab[N_PHONEME_TAB];
|
||||
unsigned char phoneme_tab_flags[N_PHONEME_TAB]; // bit 0: not inherited
|
||||
|
||||
static unsigned int *phoneme_index=NULL;
|
||||
static USHORT *phoneme_index=NULL;
|
||||
char *spects_data=NULL;
|
||||
unsigned char *wavefile_data=NULL;
|
||||
static unsigned char *phoneme_tab_data = NULL;
|
||||
@@ -116,7 +116,7 @@ int LoadPhData()
|
||||
|
||||
if((phoneme_tab_data = (unsigned char *)ReadPhFile((void *)(phoneme_tab_data),"phontab")) == NULL)
|
||||
return(-1);
|
||||
if((phoneme_index = (unsigned int *)ReadPhFile((void *)(phoneme_index),"phonindex")) == NULL)
|
||||
if((phoneme_index = (USHORT *)ReadPhFile((void *)(phoneme_index),"phonindex")) == NULL)
|
||||
return(-1);
|
||||
if((spects_data = ReadPhFile((void *)(spects_data),"phondata")) == NULL)
|
||||
return(-1);
|
||||
@@ -204,172 +204,9 @@ int LookupPhonemeString(const char *string)
|
||||
|
||||
|
||||
|
||||
static unsigned int LookupSound2(int index, unsigned int other_phcode, int control)
|
||||
{//================================================================================
|
||||
// control=1 get formant transition data only
|
||||
|
||||
unsigned int code;
|
||||
unsigned int value, value2;
|
||||
|
||||
while((value = phoneme_index[index++]) != 0)
|
||||
{
|
||||
if((code = (value & 0xff)) == other_phcode)
|
||||
{
|
||||
while(((value2 = phoneme_index[index]) != 0) && ((value2 & 0xff) < 8))
|
||||
{
|
||||
switch(value2 & 0xff)
|
||||
{
|
||||
case 0:
|
||||
// next entry is a wavefile to be played along with the synthesis
|
||||
if(control==0)
|
||||
{
|
||||
wavefile_ix = value2 >> 8;
|
||||
}
|
||||
break;
|
||||
case 1:
|
||||
if(control==0)
|
||||
{
|
||||
seq_len_adjust = value2 >> 8;
|
||||
}
|
||||
break;
|
||||
case 2:
|
||||
if(control==0)
|
||||
{
|
||||
seq_len_adjust = value2 >> 8;
|
||||
seq_len_adjust = -seq_len_adjust;
|
||||
}
|
||||
break;
|
||||
case 3:
|
||||
if(control==0)
|
||||
{
|
||||
wavefile_amp = value2 >> 8;
|
||||
}
|
||||
break;
|
||||
case 4:
|
||||
// formant transition data, 2 words
|
||||
vowel_transition[0] = value2 >> 8;
|
||||
vowel_transition[1] = phoneme_index[index++ + 1];
|
||||
break;
|
||||
case 5:
|
||||
// formant transition data, 2 words
|
||||
vowel_transition[2] = value2 >> 8;
|
||||
vowel_transition[3] = phoneme_index[index++ + 1];
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
}
|
||||
return(value >> 8);
|
||||
}
|
||||
else
|
||||
if((code == 4) || (code == 5))
|
||||
{
|
||||
// formant transition data, ignore next word of data
|
||||
index++;
|
||||
}
|
||||
}
|
||||
return(3); // not found
|
||||
} // end of LookupSound2
|
||||
|
||||
|
||||
unsigned int LookupSound(PHONEME_TAB *this_ph, PHONEME_TAB *other_ph, int which, int *match_level, int control)
|
||||
{//============================================================================================================
|
||||
// follows, 1 other_ph preceeds this_ph, 2 other_ph follows this_ph
|
||||
// control: 1= get formant transition data only
|
||||
int spect_list;
|
||||
int spect_list2;
|
||||
int s_list;
|
||||
unsigned char virtual_ph;
|
||||
int result;
|
||||
int level=0;
|
||||
unsigned int other_code;
|
||||
unsigned int other_virtual;
|
||||
|
||||
if(control==0)
|
||||
{
|
||||
wavefile_ix = 0;
|
||||
wavefile_amp = 32;
|
||||
seq_len_adjust = 0;
|
||||
}
|
||||
memset(vowel_transition,0,sizeof(vowel_transition));
|
||||
|
||||
other_code = other_ph->code;
|
||||
if(phoneme_tab[other_code]->type == phPAUSE)
|
||||
other_code = phonPAUSE_SHORT; // use this version of Pause for matching
|
||||
|
||||
if(which==1)
|
||||
{
|
||||
spect_list = this_ph->after;
|
||||
virtual_ph = this_ph->start_type;
|
||||
spect_list2 = phoneme_tab[virtual_ph]->after;
|
||||
other_virtual = other_ph->end_type;
|
||||
}
|
||||
else
|
||||
{
|
||||
spect_list = this_ph->before;
|
||||
virtual_ph = this_ph->end_type;
|
||||
spect_list2 = phoneme_tab[virtual_ph]->before;
|
||||
other_virtual = other_ph->start_type;
|
||||
}
|
||||
|
||||
result = 3;
|
||||
// look for ph1-ph2 combination
|
||||
if((s_list = spect_list) != 0)
|
||||
{
|
||||
if((result = LookupSound2(s_list,other_code,control)) != 3)
|
||||
{
|
||||
level = 2;
|
||||
}
|
||||
else
|
||||
if(other_virtual != 0)
|
||||
{
|
||||
if((result = LookupSound2(spect_list,other_virtual,control)) != 3)
|
||||
{
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
// not found, look in a virtual phoneme if one is given for this phoneme
|
||||
if((result==3) && (virtual_ph != 0) && ((s_list = spect_list2) != 0))
|
||||
{
|
||||
if((result = LookupSound2(s_list,other_code,control)) != 3)
|
||||
{
|
||||
level = 1;
|
||||
}
|
||||
else
|
||||
if(other_virtual != 0)
|
||||
{
|
||||
if((result = LookupSound2(spect_list2,other_virtual,control)) != 3)
|
||||
{
|
||||
level = 1;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if(match_level != NULL)
|
||||
*match_level = level;
|
||||
|
||||
if(result==0)
|
||||
return(0); // NULL was given in the phoneme source
|
||||
|
||||
// note: values = 1 indicates use the default for this phoneme, even though we found a match
|
||||
// which set a secondary reference
|
||||
if(result >= 4)
|
||||
{
|
||||
// values 1-3 can be used for special codes
|
||||
// 1 = DFT from the phoneme source file
|
||||
return(result);
|
||||
}
|
||||
|
||||
// no match found for other_ph, return the default
|
||||
return(LookupSound2(this_ph->spect,phonPAUSE,control));
|
||||
|
||||
} // end of LookupSound
|
||||
|
||||
|
||||
|
||||
frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
|
||||
int which, int *match_level, int *n_frames, PHONEME_LIST *plist)
|
||||
{//=========================================================================================================
|
||||
frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist)
|
||||
{//===================================================================================================================
|
||||
int ix;
|
||||
int nf;
|
||||
int nf1;
|
||||
@@ -380,19 +217,10 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
int length_factor;
|
||||
SPECT_SEQ *seq, *seq2;
|
||||
SPECT_SEQK *seqk, *seqk2;
|
||||
PHONEME_TAB *next2_ph;
|
||||
frame_t *frame;
|
||||
static frameref_t frames_buf[N_SEQ_FRAMES];
|
||||
|
||||
PHONEME_TAB *other_ph;
|
||||
if(which == 1)
|
||||
other_ph = prev_ph;
|
||||
else
|
||||
other_ph = next_ph;
|
||||
|
||||
if((ix = LookupSound(this_ph,other_ph,which,match_level,0)) < 4)
|
||||
return(NULL);
|
||||
seq = (SPECT_SEQ *)(&spects_data[ix]);
|
||||
seq = (SPECT_SEQ *)(&spects_data[fmt_params->fmt_addr]);
|
||||
seqk = (SPECT_SEQK *)seq;
|
||||
nf = seq->n_frames;
|
||||
|
||||
@@ -400,8 +228,8 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
if(nf >= N_SEQ_FRAMES)
|
||||
nf = N_SEQ_FRAMES - 1;
|
||||
|
||||
seq_len_adjust = fmt_params->fmt2_lenadj + fmt_params->fmt_length;
|
||||
seq_break = 0;
|
||||
length1 = 0;
|
||||
|
||||
for(ix=0; ix<nf; ix++)
|
||||
{
|
||||
@@ -431,46 +259,21 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
}
|
||||
|
||||
// do we need to modify a frame for blending with a consonant?
|
||||
if(this_ph->type == phVOWEL)
|
||||
if((this_ph->type == phVOWEL) && (fmt_params->fmt2_addr == 0) && (fmt_params->use_vowelin))
|
||||
{
|
||||
if((which==2) && ((frames[nf-1].frflags & FRFLAG_BREAK) == 0))
|
||||
{
|
||||
// lookup formant transition for the following phoneme
|
||||
|
||||
if((*match_level == 0) || (next_ph->type == phNASAL))
|
||||
{
|
||||
LookupSound(next_ph,this_ph,1,NULL,1);
|
||||
seq_len_adjust += FormantTransition2(frames,nf,vowel_transition[2],vowel_transition[3],next_ph,which);
|
||||
}
|
||||
else
|
||||
if(next_ph->phflags == phVOWEL2)
|
||||
{
|
||||
// not really a consonant, rather a coloured vowel
|
||||
if(LookupSound(next_ph,this_ph,1,NULL,1) == 0)
|
||||
{
|
||||
next2_ph = plist[2].ph;
|
||||
LookupSound(next2_ph,next_ph,1,NULL,1);
|
||||
seq_len_adjust += FormantTransition2(frames,nf,vowel_transition[2],vowel_transition[3],next2_ph,which);
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
if(*match_level == 0)
|
||||
seq_len_adjust = FormantTransition2(frames,nf,vowel_transition0,vowel_transition1,prev_ph,which);
|
||||
}
|
||||
seq_len_adjust += FormantTransition2(frames,nf,fmt_params->transition0,fmt_params->transition1,NULL,which);
|
||||
}
|
||||
|
||||
length1 = 0;
|
||||
nf1 = nf - 1;
|
||||
for(ix=0; ix<nf1; ix++)
|
||||
length1 += frames[ix].length;
|
||||
|
||||
|
||||
if((wavefile_ix != 0) && ((wavefile_ix & 0x800000)==0))
|
||||
if(fmt_params->fmt2_addr != 0)
|
||||
{
|
||||
// a secondary reference has been returned, which is not a wavefile
|
||||
// add these spectra to the main sequence
|
||||
seq2 = (SPECT_SEQ *)(&spects_data[wavefile_ix]);
|
||||
seq2 = (SPECT_SEQ *)(&spects_data[fmt_params->fmt2_addr]);
|
||||
seqk2 = (SPECT_SEQK *)seq2;
|
||||
|
||||
// first frame of the addition just sets the length of the last frame of the main seq
|
||||
@@ -493,18 +296,18 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
wavefile_ix = 0;
|
||||
}
|
||||
|
||||
if((this_ph->type == phVOWEL) && (length1 > 0))
|
||||
if(length1 > 0)
|
||||
{
|
||||
if(which==2)
|
||||
{
|
||||
// adjust the length of the main part to match the standard length specified for the vowel
|
||||
// less the front part of the vowel and any added suffix
|
||||
|
||||
length_std = this_ph->std_length + seq_len_adjust - 45;
|
||||
|
||||
length_std = fmt_params->std_length + seq_len_adjust - 45;
|
||||
if(length_std < 10)
|
||||
length_std = 10;
|
||||
if(plist->synthflags & SFLAG_LENGTHEN)
|
||||
length_std += phoneme_tab[phonLENGTHEN]->std_length; // phoneme was followed by an extra : symbol
|
||||
length_std += (phoneme_tab[phonLENGTHEN]->std_length * 2); // phoneme was followed by an extra : symbol
|
||||
|
||||
// can adjust vowel length for stressed syllables here
|
||||
|
||||
@@ -518,22 +321,29 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
}
|
||||
else
|
||||
{
|
||||
// front of a vowel
|
||||
if(*match_level == 0)
|
||||
if(which == 1)
|
||||
{
|
||||
// allow very short vowels to have shorter front parts
|
||||
if(this_ph->std_length < 130)
|
||||
frames[0].length = (frames[0].length * this_ph->std_length)/130;
|
||||
// front of a vowel
|
||||
if(fmt_params->fmt_control == 1)
|
||||
{
|
||||
// This is the default start of a vowel.
|
||||
// Allow very short vowels to have shorter front parts
|
||||
if(fmt_params->std_length < 130)
|
||||
frames[0].length = (frames[0].length * fmt_params->std_length)/130;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
//not a vowel
|
||||
if(fmt_params->std_length > 0)
|
||||
{
|
||||
seq_len_adjust += (fmt_params->std_length - length1);
|
||||
}
|
||||
}
|
||||
|
||||
if(seq_len_adjust != 0)
|
||||
{
|
||||
length_std = 0;
|
||||
for(ix=0; ix<nf1; ix++)
|
||||
{
|
||||
length_std += frames[ix].length;
|
||||
}
|
||||
length_factor = ((length_std + seq_len_adjust) * 256)/length_std;
|
||||
length_factor = ((length1 + seq_len_adjust) * 256)/length1;
|
||||
for(ix=0; ix<nf1; ix++)
|
||||
{
|
||||
frames[ix].length = (frames[ix].length * length_factor)/256;
|
||||
@@ -547,11 +357,12 @@ frameref_t *LookupSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB
|
||||
} // end of LookupSpect
|
||||
|
||||
|
||||
|
||||
unsigned char *LookupEnvelope(int ix)
|
||||
{//================================
|
||||
if(ix==0)
|
||||
return(NULL);
|
||||
return((unsigned char *)&spects_data[phoneme_index[ix]]);
|
||||
return((unsigned char *)&spects_data[ix]);
|
||||
}
|
||||
|
||||
|
||||
@@ -689,6 +500,556 @@ void LoadConfig(void)
|
||||
}
|
||||
}
|
||||
}
|
||||
fclose(f);
|
||||
} // end of LoadConfig
|
||||
|
||||
|
||||
|
||||
|
||||
PHONEME_DATA this_ph_data;
|
||||
|
||||
|
||||
static void InvalidInstn(PHONEME_TAB *ph, int instn)
|
||||
{//====================================================
|
||||
fprintf(stderr,"Invalid instruction %.4x for phoneme '%s'\n", instn, WordToString(ph->mnemonic));
|
||||
}
|
||||
|
||||
|
||||
static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, int control)
|
||||
{//========================================================================================
|
||||
// condition:
|
||||
// 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress
|
||||
|
||||
int stress_level;
|
||||
PHONEME_LIST *pl;
|
||||
static int condition_level[4] = {1,2,4,15};
|
||||
|
||||
if(phoneme_tab[plist[0].phcode]->type == phVOWEL)
|
||||
{
|
||||
pl = plist;
|
||||
}
|
||||
else
|
||||
{
|
||||
// consonant, get stress from the following vowel
|
||||
if(phoneme_tab[plist[1].phcode]->type == phVOWEL)
|
||||
{
|
||||
pl = &plist[1];
|
||||
}
|
||||
else
|
||||
return(false); // no stress elevel for this consonant
|
||||
}
|
||||
|
||||
stress_level = pl->stresslevel & 0xf;
|
||||
|
||||
if(tr != NULL)
|
||||
{
|
||||
if((control & 1) && (plist->synthflags & SFLAG_DICTIONARY) && ((tr->langopts.param[LOPT_REDUCE] & 1)==0))
|
||||
{
|
||||
// change phoneme. Don't change phonemes which are given for the word in the dictionary.
|
||||
return(false);
|
||||
}
|
||||
|
||||
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;
|
||||
}
|
||||
}
|
||||
|
||||
if(condition == 4)
|
||||
{
|
||||
return(stress_level >= pl->wordstress);
|
||||
}
|
||||
|
||||
if(condition == 3)
|
||||
{
|
||||
// if stressed
|
||||
if(stress_level > 3)
|
||||
return(true);
|
||||
}
|
||||
else
|
||||
{
|
||||
if(stress_level < condition_level[condition])
|
||||
return(true);
|
||||
}
|
||||
return(false);
|
||||
|
||||
} // end of StressCondition
|
||||
|
||||
|
||||
static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, int instn)
|
||||
{//========================================================================================
|
||||
int which;
|
||||
unsigned int data;
|
||||
int instn2;
|
||||
PHONEME_TAB *ph;
|
||||
PHONEME_LIST *plist_this;
|
||||
static int ph_position[7] = {0, 1, 2, 3, 2, 0, 1};
|
||||
|
||||
data = instn & 0xff;
|
||||
instn2 = instn >> 8;
|
||||
|
||||
if(instn2 < 14)
|
||||
{
|
||||
which = (instn2) % 7;
|
||||
|
||||
if(which==4)
|
||||
{
|
||||
// nextPh not word boundary
|
||||
if(plist[1].sourceix)
|
||||
return(false);
|
||||
}
|
||||
if(which==5)
|
||||
{
|
||||
// prevPh, not word boundary
|
||||
if(plist[0].sourceix)
|
||||
return(false);
|
||||
}
|
||||
if(which==6)
|
||||
{
|
||||
// nextVowel, not word boundary
|
||||
for(which=2;;which++)
|
||||
{
|
||||
if(plist[which-1].sourceix)
|
||||
return(false);
|
||||
if(phoneme_tab[plist[which-1].phcode]->type == phVOWEL)
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
which = ph_position[which];
|
||||
}
|
||||
plist_this = plist;
|
||||
plist = &plist[which-1];
|
||||
|
||||
if(control & 0x100)
|
||||
{
|
||||
// change phonemes pass
|
||||
plist->ph = phoneme_tab[plist->phcode];
|
||||
}
|
||||
ph = plist->ph;
|
||||
|
||||
if(instn2 < 7)
|
||||
{
|
||||
// 'data' is a phoneme number
|
||||
if((phoneme_tab[data]->mnemonic == ph->mnemonic) == true)
|
||||
return(true);
|
||||
if((which == 0) && (ph->type == phVOWEL))
|
||||
return(data == ph->end_type); // prevPh() match on end_type
|
||||
return(data == ph->start_type); // thisPh() or nextPh(), match on start_type
|
||||
}
|
||||
|
||||
data = instn & 0x1f;
|
||||
|
||||
switch(instn & 0xe0)
|
||||
{
|
||||
case 0x00:
|
||||
// phoneme type, vowel, nasal, fricative, etc
|
||||
return(ph->type == data);
|
||||
break;
|
||||
|
||||
case 0x20:
|
||||
// place of articulation
|
||||
return(((ph->phflags >> 16) & 0xf) == data);
|
||||
break;
|
||||
|
||||
case 0x40:
|
||||
// is a bit set in phoneme flags
|
||||
return((ph->phflags & (1 << data)) != 0);
|
||||
break;
|
||||
|
||||
case 0x80:
|
||||
switch(data)
|
||||
{
|
||||
case 0:
|
||||
case 1:
|
||||
case 2:
|
||||
case 3:
|
||||
case 4:
|
||||
return(StressCondition(tr, plist, data, 0));
|
||||
|
||||
case 5: // isBreak, Either pause phoneme, or (stop/vstop/vfric not followed by vowel or (liquid in same word))
|
||||
return((ph->type == phPAUSE) || (plist_this->synthflags & SFLAG_NEXT_PAUSE));
|
||||
|
||||
case 6: // isWordStart
|
||||
return(plist->sourceix != 0);
|
||||
|
||||
case 7: // notWordStart
|
||||
return(plist->sourceix == 0);
|
||||
|
||||
case 8: // isWordEnd
|
||||
return(plist[1].sourceix || (plist[1].ph->type == phPAUSE));
|
||||
break;
|
||||
|
||||
case 9: // isAfterStress
|
||||
if(plist->sourceix != 0)
|
||||
return(false);
|
||||
do {
|
||||
plist--;
|
||||
if((plist->stresslevel & 0xf) >= 4)
|
||||
return(true);
|
||||
|
||||
} while (plist->sourceix == 0);
|
||||
break;
|
||||
|
||||
case 10: // isNotVowel
|
||||
return(ph->type != phVOWEL);
|
||||
|
||||
case 11: // isFinalVowel
|
||||
for(;;)
|
||||
{
|
||||
plist++;
|
||||
plist->ph = phoneme_tab[plist->phcode];
|
||||
if(plist->sourceix != 0)
|
||||
return(true); // start of next word, without finding another vowel
|
||||
if(plist->ph->type == phVOWEL)
|
||||
return(false);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
}
|
||||
return(false);
|
||||
}
|
||||
else
|
||||
if(instn2 == 0xf)
|
||||
{
|
||||
// Other conditions
|
||||
switch(data)
|
||||
{
|
||||
case 1: // PreVoicing
|
||||
return(control & 1);
|
||||
case 2: // KlattSynth
|
||||
return(voice->klattv[0] != 0);
|
||||
}
|
||||
}
|
||||
return(false);
|
||||
} // end of InterpretCondition
|
||||
|
||||
|
||||
static void SwitchVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT **p_prog, int instn_type)
|
||||
{//=====================================================================================================
|
||||
USHORT *prog;
|
||||
int voweltype;
|
||||
signed char x;
|
||||
|
||||
if(instn_type == 2)
|
||||
{
|
||||
phdata->pd_control |= pd_FORNEXTPH;
|
||||
voweltype = plist[1].ph->start_type; // SwitchNextVowelType
|
||||
}
|
||||
else
|
||||
{
|
||||
voweltype = plist[-1].ph->end_type; // SwitchPrevVowelType
|
||||
}
|
||||
|
||||
voweltype -= phonVOWELTYPES;
|
||||
if((voweltype >= 0) && (voweltype < 6))
|
||||
{
|
||||
prog = *p_prog + voweltype*2;
|
||||
phdata->sound_addr[instn_type] = (((prog[1] & 0xf) << 16) + prog[2]) * 4;
|
||||
x = (prog[1] >> 4) & 0xff;
|
||||
phdata->sound_param[instn_type] = x; // sign extend
|
||||
}
|
||||
|
||||
*p_prog += 12;
|
||||
} // end of SwitchVowelType
|
||||
|
||||
|
||||
static int NumInstnWords(USHORT *prog)
|
||||
{//===================================
|
||||
int instn;
|
||||
int instn2;
|
||||
int instn_type;
|
||||
static char n_words[11] = {1,1,1,1,1,1,1,1,1,2,4};
|
||||
|
||||
instn = *prog;
|
||||
instn_type = instn >> 12;
|
||||
if(instn_type < 11)
|
||||
return(n_words[instn_type]);
|
||||
|
||||
// 11 to 15, 2 words
|
||||
instn2 = prog[2];
|
||||
if((instn2 >> 12) == 0xf)
|
||||
{
|
||||
// addWav(), 2 more words
|
||||
return(4);
|
||||
}
|
||||
if(instn2 == i_CONTINUE)
|
||||
{
|
||||
return(3);
|
||||
}
|
||||
return(2);
|
||||
} // end of NumInstnWords
|
||||
|
||||
|
||||
|
||||
void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata)
|
||||
{//==========================================================================================
|
||||
// control:
|
||||
//bit 0: PreVoicing
|
||||
//bit 8: change phonemes
|
||||
PHONEME_TAB *ph;
|
||||
USHORT *prog;
|
||||
USHORT instn;
|
||||
int instn2;
|
||||
int or_flag;
|
||||
bool truth;
|
||||
int data;
|
||||
int end_flag;
|
||||
int ix;
|
||||
signed char param_sc;
|
||||
|
||||
#define N_RETURN 10
|
||||
int n_return=0;
|
||||
USHORT *return_addr[N_RETURN]; // return address stack
|
||||
|
||||
ph = plist->ph;
|
||||
|
||||
memset(phdata, 0, sizeof(PHONEME_DATA));
|
||||
phdata->pd_param[i_SET_LENGTH] = ph->std_length;
|
||||
phdata->pd_param[i_LENGTH_MOD] = ph->length_mod;
|
||||
|
||||
if(ph->program == 0)
|
||||
return;
|
||||
|
||||
end_flag = 0;
|
||||
|
||||
for(prog = &phoneme_index[ph->program]; end_flag != 1; prog++)
|
||||
{
|
||||
instn = *prog;
|
||||
instn2 = (instn >> 8) & 0xf;
|
||||
or_flag = 0;
|
||||
|
||||
switch(instn >> 12)
|
||||
{
|
||||
case 0:
|
||||
data = instn & 0xff;
|
||||
|
||||
if(instn2 == 0)
|
||||
{
|
||||
// instructions with no operand
|
||||
switch(data)
|
||||
{
|
||||
case i_RETURN:
|
||||
end_flag = 1;
|
||||
break;
|
||||
|
||||
case i_CONTINUE:
|
||||
break;
|
||||
|
||||
default:
|
||||
InvalidInstn(ph,instn);
|
||||
break;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(instn2 == i_APPEND_IFNEXTVOWEL)
|
||||
{
|
||||
if(phoneme_tab[plist[1].phcode]->type == phVOWEL)
|
||||
phdata->pd_param[i_APPEND_PHONEME] = data;
|
||||
}
|
||||
else
|
||||
if(instn2 < N_PHONEME_DATA_PARAM)
|
||||
{
|
||||
if(instn2 == i_CHANGE_PHONEME2)
|
||||
{
|
||||
phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme
|
||||
}
|
||||
phdata->pd_param[instn2] = data;
|
||||
if((instn2 == i_CHANGE_PHONEME) && (control & 0x100))
|
||||
{
|
||||
// found ChangePhoneme() in PhonemeList mode, exit
|
||||
end_flag = 1;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
InvalidInstn(ph,instn);
|
||||
}
|
||||
break;
|
||||
|
||||
case 1:
|
||||
if(tr == NULL)
|
||||
break; // ignore if in synthesis stage
|
||||
|
||||
if(instn2 < 8)
|
||||
{
|
||||
// ChangeIf
|
||||
if(StressCondition(tr, plist, instn2 & 7, 1))
|
||||
{
|
||||
phdata->pd_param[i_CHANGE_PHONEME] = instn & 0xff;
|
||||
end_flag = 1; // change phoneme, exit
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
case 3:
|
||||
// conditions
|
||||
or_flag = 0;
|
||||
truth = true;
|
||||
while((instn & 0xe000) == 0x2000)
|
||||
{
|
||||
// process a sequence of conditions, using boolean accumulator
|
||||
if(or_flag)
|
||||
truth = (truth || InterpretCondition(tr, control, plist, instn & 0xfff));
|
||||
else
|
||||
truth = (truth && InterpretCondition(tr, control, plist, instn & 0xfff));
|
||||
or_flag = instn & 0x1000;
|
||||
instn = *(++prog);
|
||||
}
|
||||
|
||||
if(truth == false)
|
||||
{
|
||||
if((instn & 0xf800) == i_JUMP_FALSE)
|
||||
{
|
||||
prog += instn & 0xff;
|
||||
}
|
||||
else
|
||||
{
|
||||
// instruction after a condition is not JUMP_FALSE, so skip the instruction.
|
||||
prog += NumInstnWords(prog);
|
||||
if((prog[0] & 0xfe00) == 0x6000)
|
||||
prog++; // and skip ELSE jump
|
||||
}
|
||||
}
|
||||
prog--;
|
||||
break;
|
||||
|
||||
case 6:
|
||||
// JUMP
|
||||
switch(instn2 >> 1)
|
||||
{
|
||||
case 0:
|
||||
prog += (instn & 0xff) - 1;
|
||||
break;
|
||||
|
||||
case 4:
|
||||
// conditional jumps should have been processed in the Condition section
|
||||
break;
|
||||
|
||||
case 5: // NexttVowelStarts
|
||||
SwitchVowelType(plist, phdata, &prog, 2);
|
||||
break;
|
||||
|
||||
case 6: // PrevVowelTypeEndings
|
||||
SwitchVowelType(plist, phdata, &prog, 3);
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 9:
|
||||
data = ((instn & 0xf) << 16) + prog[1];
|
||||
switch(instn2)
|
||||
{
|
||||
case 1:
|
||||
// call a procedure or another phoneme
|
||||
if(n_return < N_RETURN)
|
||||
{
|
||||
return_addr[n_return++] = prog+1;
|
||||
prog = &phoneme_index[data] - 1;
|
||||
}
|
||||
break;
|
||||
|
||||
case 2:
|
||||
// pitch envelope
|
||||
phdata->pitch_env = data;
|
||||
break;
|
||||
|
||||
case 3:
|
||||
// amplitude envelope
|
||||
phdata->amp_env = data;
|
||||
break;
|
||||
}
|
||||
break;
|
||||
|
||||
case 10: // Vowelin, Vowelout
|
||||
if(instn2 == 1)
|
||||
ix = 0;
|
||||
else
|
||||
ix = 2;
|
||||
|
||||
phdata->vowel_transition[ix] = ((prog[0] & 0xff) << 16) + prog[1];
|
||||
phdata->vowel_transition[ix+1] = (prog[2] << 16) + prog[3];
|
||||
prog += 3;
|
||||
break;
|
||||
|
||||
case 11: // FMT
|
||||
case 12: // WAV
|
||||
case 13: // VowelStart
|
||||
case 14: // VowelEnd
|
||||
case 15: // addWav
|
||||
instn2 = (instn >> 12) - 11;
|
||||
phdata->sound_addr[instn2] = ((instn & 0xf) << 18) + (prog[1] << 2);
|
||||
param_sc = phdata->sound_param[instn2] = (instn >> 4) & 0xff;
|
||||
prog++;
|
||||
|
||||
if(prog[1] != i_CONTINUE)
|
||||
{
|
||||
if(instn2 < 2)
|
||||
{
|
||||
// FMT() and WAV() imply Return
|
||||
end_flag = 1;
|
||||
if((prog[1] >> 12) == 0xf)
|
||||
{
|
||||
// Return after the following addWav()
|
||||
end_flag = 2;
|
||||
}
|
||||
}
|
||||
else
|
||||
if(instn2 == 4)
|
||||
{
|
||||
// addWav(), return if previous instruction was FMT() or WAV()
|
||||
end_flag--;
|
||||
}
|
||||
|
||||
if((instn2 != 1) && (instn2 != 4))
|
||||
{
|
||||
// FMT, VowelStart or VowelEnding.
|
||||
phdata->sound_param[instn2] = param_sc; // sign extend
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
default:
|
||||
InvalidInstn(ph,instn);
|
||||
break;
|
||||
}
|
||||
|
||||
if(ph->phflags & phSINGLE_INSTN)
|
||||
{
|
||||
end_flag = 1; // this phoneme has a one-instruction program, with an implicit Return
|
||||
}
|
||||
|
||||
if((end_flag == 1) && (n_return > 0))
|
||||
{
|
||||
// return from called procedure or phoneme
|
||||
end_flag = 0;
|
||||
prog = return_addr[--n_return];
|
||||
}
|
||||
}
|
||||
|
||||
} // end of InterpretPhoneme
|
||||
|
||||
|
||||
void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata)
|
||||
{//=====================================================
|
||||
// Examine the program of a single isolated phoneme
|
||||
int ix;
|
||||
PHONEME_LIST plist[4];
|
||||
memset(plist, 0, sizeof(plist));
|
||||
|
||||
for(ix=0; ix<4; ix++)
|
||||
{
|
||||
plist[ix].phcode = phonPAUSE;
|
||||
plist[ix].ph = phoneme_tab[phonPAUSE];
|
||||
}
|
||||
|
||||
plist[1].phcode = phcode;
|
||||
plist[1].ph = phoneme_tab[phcode];
|
||||
plist[2].sourceix = 1;
|
||||
|
||||
InterpretPhoneme(NULL, 0, &plist[1], phdata);
|
||||
} // end of InterpretPhoneme2
|
||||
|
||||
Reference in New Issue
Block a user