[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:
jonsd
2009-12-20 07:48:33 +00:00
parent dd1623232f
commit 20f52f0301
231 changed files with 10132 additions and 8946 deletions
+2305 -1513
View File
File diff suppressed because it is too large Load Diff
+71 -70
View File
@@ -36,7 +36,6 @@
#include "translate.h"
int dictionary_skipwords;
char dictionary_name[40];
@@ -482,7 +481,7 @@ void DecodePhonemes(const char *inptr, char *outptr)
if((ph = phoneme_tab[phcode]) == NULL)
continue;
if((ph->type == phSTRESS) && (ph->std_length <= 4) && (ph->spect == 0))
if((ph->type == phSTRESS) && (ph->std_length <= 4) && (ph->program == 0))
{
if(ph->std_length > 1)
*outptr++ = stress_chars[ph->std_length];
@@ -847,26 +846,26 @@ return(0);
static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char *vowel_stress, int &vowel_count, int &stressed_syllable, int control)
{//====================================================================================================================================================
static int GetVowelStress(Translator *tr, unsigned char *phonemes, signed char *vowel_stress, int &vowel_count, int &stressed_syllable, int control)
{//=================================================================================================================================================
// control = 1, set stress to 1 for forced unstressed vowels
unsigned char phcode;
PHONEME_TAB *ph;
unsigned char *ph_out = phonemes;
int count = 1;
int max_stress = 0;
int max_stress = -1;
int ix;
int j;
int stress = 0;
int stress = -1;
int primary_posn = 0;
vowel_stress[0] = 0;
vowel_stress[0] = 1;
while(((phcode = *phonemes++) != 0) && (count < (N_WORD_PHONEMES/2)-1))
{
if((ph = phoneme_tab[phcode]) == NULL)
continue;
if((ph->type == phSTRESS) && (ph->spect == 0))
if((ph->type == phSTRESS) && (ph->program == 0))
{
/* stress marker, use this for the following vowel */
@@ -876,7 +875,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char
j = count - 1;
while((j > 0) && (stressed_syllable == 0) && (vowel_stress[j] < 4))
{
if(vowel_stress[j] != 1)
if((vowel_stress[j] != 0) && (vowel_stress[j] != 1))
{
// don't promote a phoneme which must be unstressed
vowel_stress[j] = 4;
@@ -920,11 +919,11 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char
max_stress = stress;
}
if((stress == 0) && (control & 1) && (ph->phflags & phUNSTRESSED))
if((stress < 0) && (control & 1) && (ph->phflags & phUNSTRESSED))
vowel_stress[count] = 1; /* weak vowel, must be unstressed */
count++;
stress = 0;
stress = -1;
}
else
if(phcode == phonSYLLABIC)
@@ -937,7 +936,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char
*ph_out++ = phcode;
}
vowel_stress[count] = 0;
vowel_stress[count] = 1;
*ph_out = 0;
/* has the position of the primary stress been specified by $1, $2, etc? */
@@ -959,7 +958,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char
if(vowel_stress[ix] == 4)
{
if(tr->langopts.stress_flags & 0x20000)
vowel_stress[ix] = 0;
vowel_stress[ix] = 1;
else
vowel_stress[ix] = 3;
}
@@ -980,7 +979,7 @@ static int GetVowelStress(Translator *tr, unsigned char *phonemes, unsigned char
static char stress_phonemes[] = {phonSTRESS_U, phonSTRESS_D, phonSTRESS_2, phonSTRESS_3,
static char stress_phonemes[] = {phonSTRESS_D, phonSTRESS_U, phonSTRESS_2, phonSTRESS_3,
phonSTRESS_P, phonSTRESS_P2, phonSTRESS_TONIC};
@@ -992,7 +991,7 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress)
int vowel_count; // num of vowels + 1
int stressed_syllable=0; // position of stressed syllable
unsigned char phonetic[N_WORD_PHONEMES];
unsigned char vowel_stress[N_WORD_PHONEMES/2];
signed char vowel_stress[N_WORD_PHONEMES/2];
strcpy((char *)phonetic,word);
max_stress = GetVowelStress(tr, phonetic, vowel_stress, vowel_count, stressed_syllable, 0);
@@ -1026,8 +1025,8 @@ void ChangeWordStress(Translator *tr, char *word, int new_stress)
{
if((phoneme_tab[*p]->type == phVOWEL) && !(phoneme_tab[*p]->phflags & phNONSYLLABIC))
{
if(vowel_stress[ix] != 0)
*word++ = stress_phonemes[vowel_stress[ix]];
if((vowel_stress[ix] == 0) || (vowel_stress[ix] > 1))
*word++ = stress_phonemes[(unsigned char)vowel_stress[ix]];
ix++;
}
@@ -1073,7 +1072,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
int done;
int stressflags;
unsigned char vowel_stress[N_WORD_PHONEMES/2];
signed char vowel_stress[N_WORD_PHONEMES/2];
char syllable_weight[N_WORD_PHONEMES/2];
char vowel_length[N_WORD_PHONEMES/2];
unsigned char phonetic[N_WORD_PHONEMES];
@@ -1116,12 +1115,15 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
}
max_stress = GetVowelStress(tr, phonetic, vowel_stress, vowel_count, stressed_syllable, 1);
if((max_stress == 0) && (tr->langopts.stress_flags & 1) && (vowel_count == 2))
if(max_stress < 0)
{
// option: don't stress monosyllables except at end-of-clause
vowel_stress[1] = 1;
dictionary_flags[0] |= FLAG_STRESS_END2;
if((tr->langopts.stress_flags & 1) && (vowel_count == 2))
{
// lang=fr: don't stress monosyllables except at end-of-clause
vowel_stress[1] = 0;
dictionary_flags[0] |= FLAG_STRESS_END2;
}
max_stress = 0;
}
// heavy or light syllables
@@ -1233,7 +1235,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
}
}
if(vowel_stress[stressed_syllable] == 1)
if((vowel_stress[stressed_syllable] == 0) || (vowel_stress[stressed_syllable] == 1))
{
// but this vowel is explicitly marked as unstressed
if(stressed_syllable > 1)
@@ -1248,7 +1250,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
}
// only set the stress if it's not already marked explicitly
if(vowel_stress[stressed_syllable] == 0)
if(vowel_stress[stressed_syllable] < 0)
{
// don't stress if next and prev syllables are stressed
if((vowel_stress[stressed_syllable-1] < 4) || (vowel_stress[stressed_syllable+1] < 4))
@@ -1267,7 +1269,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
while(stressed_syllable > 0)
{
// find the last vowel which is not unstressed
if(vowel_stress[stressed_syllable] == 0)
if(vowel_stress[stressed_syllable] < 0)
{
vowel_stress[stressed_syllable] = 4;
break;
@@ -1329,7 +1331,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
// find the heaviest syllable, excluding the final syllable
for(ix = 1; ix < (vowel_count-1); ix++)
{
if(vowel_stress[ix] == 0)
if(vowel_stress[ix] < 0)
{
if((wt = syllable_weight[ix]) >= max_weight)
{
@@ -1377,7 +1379,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
case 9: // mark all as stressed
for(ix=1; ix<vowel_count; ix++)
{
if(vowel_stress[ix] == 0)
if(vowel_stress[ix] < 0)
vowel_stress[ix] = 4;
}
break;
@@ -1399,7 +1401,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
vowel_stress[1] = 3;
}
if((stressflags & 0x2000) && (vowel_stress[1] == 0))
if((stressflags & 0x2000) && (vowel_stress[1] < 0))
{
// If there is only one syllable before the primary stress, give it a secondary stress
if((vowel_count > 2) && (vowel_stress[2] >= 4))
@@ -1411,7 +1413,7 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
done = 0;
for(v=1; v<vowel_count; v++)
{
if(vowel_stress[v] == 0)
if(vowel_stress[v] < 0)
{
if((stressflags & 0x10) && (stress < 4) && (v == vowel_count-1))
{
@@ -1541,33 +1543,33 @@ void SetWordStress(Translator *tr, char *output, unsigned int *dictionary_flags,
if((v > 1) && (max_stress >= 4) && (stressflags & 4) && (v == (vowel_count-1)))
{
// option: mark unstressed final syllable as diminished
v_stress = 1;
v_stress = 0;
}
else
if((stressflags & 2) || (v == 1) || (v == (vowel_count-1)))
{
// first or last syllable, or option 'don't set diminished stress'
v_stress = 0;
v_stress = 1;
}
else
if((v == (vowel_count-2)) && (vowel_stress[vowel_count-1] <= 1))
{
// penultimate syllable, followed by an unstressed final syllable
v_stress = 0;
v_stress = 1;
}
else
{
// unstressed syllable within a word
if((vowel_stress[v-1] != 1) || ((stressflags & 0x10000) == 0))
if((vowel_stress[v-1] < 0) || ((stressflags & 0x10000) == 0))
{
v_stress = 1; /* change from 0 (unstressed) to 1 (diminished stress) */
v_stress = 0; /* change to 0 (diminished stress) */
vowel_stress[v] = v_stress;
}
}
}
if(v_stress > 0)
*output++ = stress_phonemes[v_stress]; // mark stress of all vowels except 0 (unstressed)
if((v_stress == 0) || (v_stress > 1))
*output++ = stress_phonemes[v_stress]; // mark stress of all vowels except 1 (unstressed)
if(vowel_stress[v] > max_stress)
@@ -2830,39 +2832,39 @@ void ApplySpecialAttribute(Translator *tr, char *phonemes, int dict_flags)
// common letter pairs, encode these as a single byte
static const short pairs_ru[] = {
0x010c, // ла 21052 0x23
0x010e, // на 18400
0x0113, // та 14254
0x0301, // ав 31083
0x030f, // ов 13420
0x060e, // не 21798
0x0611, // ре 19458
0x0903, // ви 16226
0x0b01, // ак 14456
0x0b0f, // ок 17836
0x0c01, // ал 13324
0x0c09, // ил 16877
0x0e01, // ан 15359
0x0e06, // ен 13543 0x30
0x0e09, // ин 17168
0x0e0e, // нн 15973
0x0e0f, // он 22373
0x0e1c, // ын 15052
0x0f03, // во 24947
0x0f11, // ро 13552
0x0f12, // со 16368
0x100f, // оп 19054
0x1011, // рп 17067
0x1101, // ар 23967
0x1106, // ер 18795
0x1109, // ир 13797
0x110f, // ор 21737
0x1213, // тс 25076
0x1220, // яс 14310
0x010c, // ла 21052 0x23
0x010e, // на 18400
0x0113, // та 14254
0x0301, // ав 31083
0x030f, // ов 13420
0x060e, // не 21798
0x0611, // ре 19458
0x0903, // ви 16226
0x0b01, // ак 14456
0x0b0f, // ок 17836
0x0c01, // ал 13324
0x0c09, // ил 16877
0x0e01, // ан 15359
0x0e06, // ен 13543 0x30
0x0e09, // ин 17168
0x0e0e, // нн 15973
0x0e0f, // он 22373
0x0e1c, // ын 15052
0x0f03, // во 24947
0x0f11, // ро 13552
0x0f12, // со 16368
0x100f, // оп 19054
0x1011, // рп 17067
0x1101, // ар 23967
0x1106, // ер 18795
0x1109, // ир 13797
0x110f, // ор 21737
0x1213, // тс 25076
0x1220, // яс 14310
0x7fff};
//0x040f ог 12976
//0x1306 ет 12826
//0x0f0d мо 12688
//0x040f ог 12976
//0x1306 ет 12826
//0x0f0d мо 12688
int TransposeAlphabet(char *text, int offset, int min, int max)
@@ -2985,7 +2987,6 @@ static const char *LookupDict2(Translator *tr, const char *word, const char *wor
wlen = strlen(word);
}
hash = HashDictionary(word);
p = tr->dict_hashtab[hash];
+5 -5
View File
@@ -37,8 +37,8 @@ static const char *help_text =
"\nspeak [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, <words> are spoken, or if none then text is\n"
"spoken from stdin, each line separately.\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
@@ -63,11 +63,11 @@ static const char *help_text =
"--stdout Write speech output to stdout\n"
"--compile=<voice name>\n"
"\t Compile the pronunciation rules and dictionary in the current\n"
"\t directory. =<voice name> is optional and specifies which language\n"
"\t directory. <voice name> specifies the language\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--phonout=\"<filename>\"\n"
"\t Write output from -x -X commands and mbrola phoneme data to this file\n"
"\t Write output from -x -X commands, and mbrola phoneme data, to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
@@ -78,7 +78,7 @@ static const char *help_text =
"\t If <language> is omitted, then list all voices.\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values = a pitch increase (try -k20).\n";
"\t higher values indicate a pitch increase (try -k20).\n";
+3 -3
View File
@@ -62,7 +62,7 @@ extern void ConvertToUtf8();
extern void FormatDictionary(const char *dictname);
extern void init_z();
extern void CompileInit(void);
extern void CompilePhonemeData(void);
extern void CompileMbrola();
extern void InitSpectrumDisplay();
extern void InitProsodyDisplay();
@@ -146,7 +146,7 @@ extern void VoiceReset(int control);
if(strcmp(param,"--compile")==0)
{
CompileInit();
CompilePhonemeData();
exit(0);
}
}
@@ -558,7 +558,7 @@ void MyFrame::OnTools(wxCommandEvent& event)
break;
case MENU_COMPILE_PH:
CompileInit();
CompilePhonemeData();
break;
case MENU_COMPILE_MBROLA:
+7 -8
View File
@@ -232,7 +232,7 @@ static void DecodePhonemes2(const char *inptr, char *outptr)
if((ph = phoneme_tab[phcode]) == NULL)
continue;
if((ph->type == phSTRESS) && (ph->std_length <= 4) && (ph->spect == 0))
if((ph->type == phSTRESS) && (ph->std_length <= 4) && (ph->program == 0))
{
if(ph->std_length > 2)
*outptr++ = stress_chars[ph->std_length];
@@ -305,7 +305,7 @@ void Lexicon_It(int pass)
FILE *f_in;
FILE *f_out;
FILE *f_listx;
FILE *f_list_in;
FILE *f_list_in = NULL;
long int displ;
const char *alt_string;
char buf[200];
@@ -1322,8 +1322,8 @@ void FormatDictionary(const char *dictname)
char *p_start;
unsigned short *pw;
unsigned short *pw_match;
unsigned short *pw_post;
unsigned short *pw_phonemes;
unsigned short *pw_post = NULL;
unsigned short *pw_phonemes = NULL;
int c;
int ix;
int n_pre;
@@ -1733,6 +1733,7 @@ void Test2()
const char* text1 = "Hello world. Testing.";
extern void TestCompile2(void);
void TestTest(int control)
{//=======================
@@ -1747,8 +1748,6 @@ void TestTest(int control)
//CharsetToUnicode("ISO-8859-4");
//CharsetToUnicode("ISCII");
return;
if(control==2)
{
return;
@@ -1778,8 +1777,8 @@ if(control==2)
espeak_SetSynthCallback(TestSynthCallback);
espeak_SetUriCallback(TestUriCallback);
espeak_Synth(text1, strlen(text1)+1, 0, POS_CHARACTER, 0, espeakSSML|espeakCHARS_UTF8, &unique_identifier, (void *)user_data);
espeak_Synth(text1, strlen(text1)+1, 0, POS_CHARACTER, 0, espeakSSML|espeakCHARS_UTF8, &unique_identifier, (void *)(user_data+1));
espeak_Synth(textbuf, strlen(textbuf)+1, 0, POS_CHARACTER, 0, espeakSSML|espeakCHARS_UTF8, &unique_identifier, (void *)user_data);
// espeak_Synth(text1, strlen(text1)+1, 0, POS_CHARACTER, 0, espeakSSML|espeakCHARS_UTF8, &unique_identifier, (void *)(user_data+1));
espeak_SetParameter(espeakPUNCTUATION, 1, 0);
espeak_Synchronize();
+2 -2
View File
@@ -840,7 +840,7 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
p->tone_ph = PhonemeCode2('4','4');
// tone 5 is unstressed (shorter)
p->stresslevel = 1; // diminished stress
p->stresslevel = 0; // diminished stress
}
}
@@ -859,7 +859,7 @@ static void CalcPitches_Tone(Translator *tr, int clause_tone)
{
tone_ph = p->tone_ph;
if(p->stresslevel != 1) // TEST, consider all syllables as stressed
if(p->stresslevel != 0) // TEST, consider all syllables as stressed
{
if(ix == final_stressed)
{
+67 -70
View File
@@ -241,8 +241,6 @@ static int parwave(klatt_frame_ptr frame)
static double sourc;
int ix;
frame_init(frame); /* get parameters for next frame of speech */
flutter(frame); /* add f0 flutter */
#ifdef LOG_FRAMES
@@ -468,7 +466,7 @@ if(option_log_frames)
{
temp = 32767.0;
}
*out_ptr++ = int(temp);
*out_ptr++ = int(temp) >> 8;
sample_count++;
@@ -483,28 +481,36 @@ if(option_log_frames)
/*
function PARWAVE_INIT
Initialises all parameters used in parwave, sets resonator internal memory
to zero.
*/
static void reset_resonators()
void KlattReset(int control)
{
int r_ix;
#ifdef LOG_FRAMES
if(option_log_frames)
{
FILE *f_log;
f_log=fopen("log-klatt","a");
if(f_log != NULL)
if(control == 2)
{
fprintf(f_log,"Reset\n");
fclose(f_log);
//Full reset
kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000;
kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000;
kt_globals.minus_pi_t = -PI / kt_globals.samrate;
kt_globals.two_pi_t = -2.0 * kt_globals.minus_pi_t;
setabc(kt_globals.FLPhz,kt_globals.BLPhz,&(kt_globals.rsn[RLP]));
}
if(control > 0)
{
kt_globals.nper = 0;
kt_globals.T0 = 0;
kt_globals.nopen = 0;
kt_globals.nmod = 0;
for(r_ix=RGL; r_ix < N_RSN; r_ix++)
{
kt_globals.rsn[r_ix].p1 = 0;
kt_globals.rsn[r_ix].p2 = 0;
}
}
}
#endif
for(r_ix=0; r_ix <= R6p; r_ix++)
{
@@ -514,22 +520,6 @@ if(option_log_frames)
}
void KlattReset()
{
kt_globals.FLPhz = (950 * kt_globals.samrate) / 10000;
kt_globals.BLPhz = (630 * kt_globals.samrate) / 10000;
kt_globals.minus_pi_t = -PI / kt_globals.samrate;
kt_globals.two_pi_t = -2.0 * kt_globals.minus_pi_t;
setabc(kt_globals.FLPhz,kt_globals.BLPhz,&(kt_globals.rsn[RLP]));
kt_globals.nper = 0;
kt_globals.T0 = 0;
kt_globals.nopen = 0;
kt_globals.nmod = 0;
reset_resonators();
}
/*
function FRAME_INIT
@@ -996,6 +986,7 @@ int Wavegen_Klatt(int resume)
int pk;
int x;
int ix;
int fade;
if(resume==0)
{
@@ -1071,22 +1062,37 @@ int Wavegen_Klatt(int resume)
if(kt_globals.nspfr > STEPSIZE)
kt_globals.nspfr = STEPSIZE;
frame_init(&kt_frame); /* get parameters for next frame of speech */
if(parwave(&kt_frame) == 1)
{
return(1);
return(1); // output buffer is full
}
}
if(end_wave == 1)
if(end_wave > 0)
{
#ifdef deleted
if(end_wave == 2)
{
fade = (kt_globals.T0 - kt_globals.nper)/4; // samples until end of current cycle
if(fade < 64)
fade = 64;
}
else
#endif
{
fade = 64; // not followd by formant synthesis
}
// fade out to avoid a click
kt_globals.fadeout = 64;
kt_globals.fadeout = fade;
end_wave = 0;
sample_count -= 64;
kt_globals.nspfr = 64;
sample_count -= fade;
kt_globals.nspfr = fade;
if(parwave(&kt_frame) == 1)
{
return(1);
return(1); // output buffer is full
}
}
@@ -1100,6 +1106,7 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v
DOUBLEX next;
int qix;
int cmd;
frame_t *fr3;
static frame_t prev_fr;
if(wvoice != NULL)
@@ -1129,6 +1136,17 @@ void SetSynth_Klatt(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v
if(cmd==WCMD_KLATT)
{
end_wave = 0; // next wave generation is from another spectrum
fr3 = (frame_t *)wcmdq[qix][2];
for(ix=1; ix<6; ix++)
{
if(fr3->ffreq[ix] != fr2->ffreq[ix])
{
// there is a discontinuity in formants
end_wave = 2;
break;
}
}
break;
}
if((cmd==WCMD_WAVE) || (cmd==WCMD_PAUSE))
@@ -1162,39 +1180,18 @@ if(option_log_frames)
if(control & 1)
{
if(wdata.prev_was_synth == 0)
for(ix=1; ix<6; ix++)
{
// A break, not following on from another synthesized sound.
// Reset the synthesizer
KlattReset();
}
else
{
for(ix=1; ix<6; ix++)
if(prev_fr.ffreq[ix] != fr1->ffreq[ix])
{
if(prev_fr.ffreq[ix] != fr1->ffreq[ix])
{
// Discontinuity in formants.
// fade out to avoid a click, but only up to the end of output buffer
ix = (out_end - out_ptr)/2;
if(ix > 64)
ix = 64;
kt_globals.fadeout = ix;
kt_globals.nspfr = ix;
parwave(&kt_frame);
reset_resonators();
break;
}
// Discontinuity in formants.
// end_wave was set in SetSynth_Klatt() to fade out the previous frame
KlattReset(0);
break;
}
}
wdata.prev_was_synth = 1;
memcpy(&prev_fr,fr2,sizeof(prev_fr));
}
if(fr2->frflags & FRFLAG_BREAK)
{
// fr2 = fr1;
// reset_resonators(&kt_globals);
}
for(ix=0; ix<N_KLATTP; ix++)
{
@@ -1313,7 +1310,7 @@ void KlattInit()
kt_globals.outsl = 0;
kt_globals.f0_flutter = 20;
KlattReset();
KlattReset(2);
// set default values for frame parameters
for(ix=0; ix<=9; ix++)
+12 -17
View File
@@ -48,6 +48,7 @@
#define phAPPENDPH 0x2000 // always insert another phoneme (link_out) after this one
#define phBRKAFTER 0x4000 // [*] add a post-pause
#define phBEFOREPAUSE 0x8000 // replace with the link_out phoneme if the next phoneme is a pause
#define phSINGLE_INSTN 0x1000 // this phoneme has a single instruction program, with an implicit Return
#define phALTERNATIVE 0x1c00 // bits 10,11,12 specifying use of alternative_ph
#define phBEFOREVOWEL 0x0000
@@ -61,6 +62,7 @@
#define phLONG 0x200000
#define phLENGTHENSTOP 0x400000 // make the pre-pause slightly longer
#define phRHOTIC 0x800000
#define phLOCAL 0x80000000 // used during compilation
// fixed phoneme code numbers, these can be used from the program code
#define phonCONTROL 1
@@ -78,7 +80,6 @@
#define phonSCHWA 13
#define phonSCHWA_SHORT 14
#define phonEND_WORD 15
#define phonSONORANT 16
#define phonDEFAULTTONE 17
#define phonCAPITAL 18
#define phonGLOTTALSTOP 19
@@ -90,6 +91,7 @@
#define phonT_REDUCED 25
#define phonSTRESS_TONIC 26
#define phonPAUSE_CLAUSE 27
#define phonVOWELTYPES 28 // 28 to 33
extern const unsigned char pause_phonemes[8]; // 0, vshort, short, pause, long, glottalstop
@@ -103,29 +105,22 @@ extern const unsigned char pause_phonemes[8]; // 0, vshort, short, pause, long,
#define N_PHONEME_TAB_NAME 32 // must be multiple of 4
// main table of phonemes, index by phoneme number (1-254)
typedef struct {
unsigned int mnemonic; // 1st char is in the l.s.byte
unsigned int phflags; // bits 28-30 reduce_to level, bits 16-19 place of articulation
// bits 10-11 alternative ph control
unsigned short std_length; // for vowels, in mS; for phSTRESS, the stress/tone type
unsigned short spect;
unsigned short before;
unsigned short after;
unsigned char code; // the phoneme number
unsigned char type; // phVOWEL, phPAUSE, phSTOP etc
unsigned int mnemonic; // 1st char is in the l.s.byte
unsigned int phflags; // bits 16-19 place of articulation
unsigned short program;
unsigned char code; // the phoneme number
unsigned char type; // phVOWEL, phPAUSE, phSTOP etc
unsigned char start_type;
unsigned char end_type;
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab
unsigned char reduce_to; // change to this phoneme if unstressed
unsigned char alternative_ph; // change to this phoneme if a vowel follows/doesn't follow
unsigned char link_out; // insert linking phoneme if a vowel follows
unsigned char std_length; // for vowels, in mS/2; for phSTRESS, the stress/tone type
unsigned char length_mod; // a length_mod group number, used to access length_mod_tab
} PHONEME_TAB;
// Several phoneme tables may be loaded into memory. phoneme_tab points to
// one for the current voice
extern int n_phoneme_tab;
+103 -211
View File
@@ -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,14 +47,8 @@ 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++)
@@ -86,66 +68,6 @@ static int SubstitutePhonemes(Translator *tr, PHONEME_LIST2 *plist_out)
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
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->stresslevel &= 0xf;
if(phoneme_tab[pl->phcode]->type == phVOWEL)
{
n_syllables++;
if(pl->stresslevel > max_stress)
{
syllable_stressed = n_syllables;
max_stress = pl->stresslevel;
max_stress_posn = k;
}
}
}
}
if(phoneme_tab[plist2->phcode]->type == phVOWEL)
{
syllable++;
}
// make any language specific changes
int flags;
CHANGEPH ch;
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->stresslevel;
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++)
{
@@ -174,7 +96,8 @@ 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));
n_plist_out++;
}
return(n_plist_out);
} // end of SubstitutePhonemes
@@ -199,11 +122,15 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
int end_sourceix;
int alternative;
int first_vowel=0; // first vowel in a word
PHONEME_LIST2 ph_list3[N_PHONEME_LIST];
PHONEME_DATA phdata;
int n_ph_list3;
PHONEME_LIST *plist3;
PHONEME_LIST *plist3_inserted = NULL;
PHONEME_LIST ph_list3[N_PHONEME_LIST];
static PHONEME_LIST2 ph_list2_null = {0,0,0,0,0};
PHONEME_LIST2 *plist2 = &ph_list2_null;
PHONEME_LIST2 *plist2_inserted = NULL;
plist2 = ph_list2;
phlist = phoneme_list;
@@ -271,9 +198,9 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
voicing = 1;
}
else
if((voicing==2) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING))
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
@@ -284,9 +211,9 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
voicing = 2;
}
else
if((voicing==1) && ((ph->phflags & phALTERNATIVE)==phSWITCHVOICING))
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
@@ -310,47 +237,56 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
n_ph_list2 = SubstitutePhonemes(tr,ph_list3) - 2;
n_ph_list3 = SubstitutePhonemes(tr,ph_list3) - 2;
// transfer all the phonemes of the clause into phoneme_list
ph = phoneme_tab[phonPAUSE];
ph_list3[0].ph = ph;
switched_language = 0;
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];
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
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)
{
memcpy(&plist3[-1], &plist3[0], 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[plist2->phcode];
ph = phoneme_tab[plist3->phcode];
plist3[0].ph = ph;
if(plist2->phcode == phonSWITCH)
if(plist3->phcode == phonSWITCH)
{
// change phoneme table
SelectPhonemeTable(plist2->tone_ph);
SelectPhonemeTable(plist3->tone_ph);
switched_language ^= SFLAG_SWITCHED_LANG;
}
next = phoneme_tab[(plist2+1)->phcode]; // the phoneme after this one
next = phoneme_tab[plist3[1].phcode]; // the phoneme after this one
plist3[1].ph = next;
}
if(plist2->sourceix)
if(plist3->sourceix)
{
// start of a word
int k;
@@ -358,7 +294,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
first_vowel = 1;
// find the highest stress level in this word
for(k=j+1; k < n_ph_list2; k++)
for(k=j+1; k < n_ph_list3; k++)
{
if(ph_list3[k].sourceix)
break; // start of the next word
@@ -366,14 +302,46 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if(ph_list3[k].stresslevel > word_stress)
word_stress = ph_list3[k].stresslevel;
}
while(--k >= j)
{
ph_list3[k].wordstress = word_stress;
}
}
if(ph == NULL) continue;
InterpretPhoneme(tr, 0x100, plist3, &phdata);
if((alternative = phdata.pd_param[pd_CHANGEPHONEME]) == 1)
continue; // NULL phoneme, discard
if(alternative > 1)
{
PHONEME_TAB *ph2;
ph2 = ph;
ph = phoneme_tab[alternative];
plist3->phcode = alternative;
plist3->ph = ph;
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);
}
if(ph->type == phVOWEL)
{
// check for consecutive unstressed syllables
if(plist2->stresslevel == 0)
// 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++;
@@ -381,14 +349,14 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
{
// 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)))
if((tr->langopts.stress_flags & 0x2) || ((word_stress > 3) && ((plist3+1)->sourceix!=0)))
{
// An unstressed final vowel of a stressed word
unstress_count=1; // try again for next syllable
}
else
{
plist2->stresslevel = 1; // change stress to 'diminished'
plist3->stresslevel = 0; // change stress to 'diminished'
}
}
}
@@ -398,82 +366,21 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
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;
case phBEFORE_R:
if(next->phflags & phRHOTIC)
{
alternative = ph->alternative_ph;
}
break;
}
}
if(ph->phflags & phBEFOREPAUSE)
{
if(next->type == phPAUSE)
alternative = ph->link_out; // replace with the link_out phoneme
}
if(alternative == 1)
continue; // NULL phoneme, discard
if(alternative > 1)
{
PHONEME_TAB *ph2;
ph2 = ph;
ph = phoneme_tab[alternative];
if(ph->type == phVOWEL)
{
plist2->synthflags |= SFLAG_SYLLABLE;
if(ph2->type != phVOWEL)
plist2->stresslevel = 0; // change from non-vowel to vowel, make sure it's unstressed
}
else
plist2->synthflags &= ~SFLAG_SYLLABLE;
}
#ifdef deleted
if(tr->langopts.param[LOPT_REDUCE_T])
{
if((ph->mnemonic == 't') && (plist2->sourceix == 0) && ((prev->type == phVOWEL) || (prev->mnemonic == 'n')))
if((ph->mnemonic == 't') && (plist3->sourceix == 0) && ((prev->type == phVOWEL) || (prev->mnemonic == 'n')))
{
if(((plist2+1)->sourceix == 0) && ((plist2+1)->stresslevel < 3) && (next->type == phVOWEL))
if(((plist3+1)->sourceix == 0) && ((plist3+1)->stress < 3) && (next->type == phVOWEL))
{
ph = phoneme_tab[phonT_REDUCED];
}
}
}
#endif
while((ph->reduce_to != 0) && (!(plist2->synthflags & SFLAG_DICTIONARY) || (tr->langopts.param[LOPT_REDUCE] & 1)))
#ifdef deleted
while((ph->reduce_to != 0) && (!(plist3->synthflags & SFLAG_DICTIONARY) || (tr->langopts.param[LOPT_REDUCE] & 1)))
{
int reduce_level;
int stress_level;
@@ -483,13 +390,13 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
if(ph->type == phVOWEL)
{
stress_level = plist2->stresslevel;
stress_level = plist3->stress;
}
else
{
// consonant, get stress from the following vowel
if(next->type == phVOWEL)
stress_level = (plist2+1)->stresslevel;
stress_level = (plist3+1)->stress;
else
break;
}
@@ -514,22 +421,23 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
else
break;
}
#endif
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))
{
// lengthen this consonant by doubling it
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;
@@ -562,7 +470,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
insert_ph = phonPAUSE_VSHORT;
}
if(((plist2+1)->stresslevel >= 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;
@@ -570,7 +478,7 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
}
if(plist2 != plist2_inserted)
if(plist3 != plist3_inserted)
{
if((x = (tr->langopts.word_gap & 0x7)) != 0)
{
@@ -587,33 +495,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)
@@ -627,14 +514,16 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
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->stresslevel & 0xf;
phlist[ix].tone_ph = plist2->tone_ph;
phlist[ix].synthflags = plist3->synthflags | switched_language;
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(plist2->sourceix != 0)
if(plist3->sourceix != 0)
{
phlist[ix].sourceix = plist2->sourceix;
phlist[ix].sourceix = plist3->sourceix;
phlist[ix].newword = 1; // this phoneme is the start of a word
if(start_sentence)
@@ -648,7 +537,8 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
phlist[ix].newword = 0;
}
phlist[ix].length = ph->std_length;
// 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];
@@ -669,12 +559,14 @@ void MakePhonemeList(Translator *tr, int post_pause, int start_sentence)
}
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;
+5 -2
View File
@@ -28,6 +28,7 @@
#include "phoneme.h"
#include "synthesize.h"
#include "prosodydisplay.h"
#include "translate.h"
extern MyFrame *myframe;
extern ChildFrProsody *prosodyframe;
@@ -113,7 +114,7 @@ int ProsodyDisplay::GetWidth(PHONEME_LIST *p)
if(p->ph == NULL)
return(0);
w = p->ph->std_length;
w = (p->ph->std_length * 2);
if(w == 0) w = 60;
if(p->length != 0)
@@ -334,6 +335,7 @@ void ProsodyDisplay::DrawEnv(wxDC& dc, int x1, int y1, int width, PHONEME_LIST *
int x,y;
int y2=0;
unsigned char *env;
PHONEME_DATA phdata_tone;
if(width <= 0) return;
@@ -354,7 +356,8 @@ void ProsodyDisplay::DrawEnv(wxDC& dc, int x1, int y1, int width, PHONEME_LIST *
if((ph->type == phVOWEL) && (ph->tone_ph != 0))
{
// the envelope is given by a Tone phoneme acting on this vowel
env = LookupEnvelope(phoneme_tab[ph->tone_ph]->spect);
InterpretPhoneme2(ph->tone_ph, &phdata_tone);
env = LookupEnvelope(phdata_tone.pitch_env);
}
for(ix=0; ix<=width; ix+=4)
+10 -4
View File
@@ -298,6 +298,7 @@ void CalcLengths(Translator *tr)
int emphasized;
int tone_mod;
unsigned char *pitch_env=NULL;
PHONEME_DATA phdata_tone;
for(ix=1; ix<n_phoneme_list; ix++)
{
@@ -408,7 +409,7 @@ void CalcLengths(Translator *tr)
case phLIQUID:
case phNASAL:
p->amp = tr->stress_amps[1]; // unless changed later
p->amp = tr->stress_amps[0]; // unless changed later
p->length = 256; // TEMPORARY
min_drop = 0;
@@ -474,6 +475,10 @@ void CalcLengths(Translator *tr)
if(stress > 7) stress = 7;
if(stress <= 1)
{
stress = stress ^ 1; // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
}
if(pre_sonorant)
p->amp = tr->stress_amps[stress]-1;
else
@@ -562,7 +567,7 @@ void CalcLengths(Translator *tr)
{
length_mod += 20;
}
if((len = tr->stress_lengths[stress]) == 0)
len = tr->stress_lengths[6];
@@ -580,7 +585,7 @@ void CalcLengths(Translator *tr)
if(end_of_clause == 2)
{
// this is the last syllable in the clause, lengthen it - more for short vowels
len = p->ph->std_length;
len = (p->ph->std_length * 2);
if(tr->langopts.stress_flags & 0x40000)
len=200; // don't lengthen short vowels more than long vowels at end-of-clause
length_mod = length_mod * (256 + (280 - len)/3)/256;
@@ -608,7 +613,8 @@ if(p->type != phVOWEL)
if(p->tone_ph != 0)
{
pitch_env = LookupEnvelope(phoneme_tab[p->tone_ph]->spect);
InterpretPhoneme2(p->tone_ph, &phdata_tone);
pitch_env = LookupEnvelope(phdata_tone.pitch_env);
}
else
{
+5 -5
View File
@@ -69,8 +69,8 @@ static const char *help_text =
"\nspeak [options] [\"<words>\"]\n\n"
"-f <text file> Text file to speak\n"
"--stdin Read text input from stdin instead of a file\n\n"
"If neither -f nor --stdin, <words> are spoken, or if none then text is\n"
"spoken from stdin, each line separately.\n\n"
"If neither -f nor --stdin, then <words> are spoken, or if none then text\n"
"is spoken from stdin, each line separately.\n\n"
"-a <integer>\n"
"\t Amplitude, 0 to 200, default is 100\n"
"-g <integer>\n"
@@ -95,11 +95,11 @@ static const char *help_text =
"--stdout Write speech output to stdout\n"
"--compile=<voice name>\n"
"\t Compile the pronunciation rules and dictionary in the current\n"
"\t directory. =<voice name> is optional and specifies which language\n"
"\t directory. <voice name> specifies the language\n"
"--path=\"<path>\"\n"
"\t Specifies the directory containing the espeak-data directory\n"
"--phonout=\"<filename>\"\n"
"\t Write output from -x -X commands and mbrola phoneme data to this file\n"
"\t Write output from -x -X commands, and mbrola phoneme data, to this file\n"
"--punct=\"<characters>\"\n"
"\t Speak the names of punctuation characters during speaking. If\n"
"\t =<characters> is omitted, all punctuation is spoken.\n"
@@ -110,7 +110,7 @@ static const char *help_text =
"\t If <language> is omitted, then list all voices.\n"
"-k <integer>\n"
"\t Indicate capital letters with: 1=sound, 2=the word \"capitals\",\n"
"\t higher values = a pitch increase (try -k20).\n";
"\t higher values indicate a pitch increase (try -k20).\n";
void DisplayVoices(FILE *f_out, char *language);
+1
View File
@@ -171,6 +171,7 @@ void SpectDisplay::OnActivate(int active)
}
else
{
formantdlg->GetValues(spectseq, sframe);
ReadDialogValues();
}
}
+3 -3
View File
@@ -41,7 +41,7 @@ extern int Wavegen_Klatt(int resume);
extern void SetSynth(int length, int modn, frame_t *fr1, frame_t *fr2, voice_t *v);
extern int Wavegen();
extern void CloseWaveFile2();
extern void KlattReset();
extern void KlattReset(int control);
extern FILE *f_wave;
static int frame_width;
@@ -1006,7 +1006,7 @@ void SpectSeq::MakeWave(int start, int end, PitchEnvelope &pitch)
if(voice->klattv[0])
{
synthesizer_type = 1;
KlattReset();
KlattReset(2);
}
SpeakNextClause(NULL,NULL,2); // stop speaking file
@@ -1125,7 +1125,7 @@ void SpectFrame::MakeWaveF(int control, PitchEnvelope &pitche, int amplitude, in
if(voice->klattv[0])
{
synthesizer_type = 1;
KlattReset();
KlattReset(2);
}
SpeakNextClause(NULL,NULL,2); // stop speaking file
+16 -7
View File
@@ -540,6 +540,8 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
PHONEME_LIST *p;
PHONEME_LIST *next;
PHONEME_LIST *prev;
PHONEME_DATA phdata;
FMT_PARAMS fmtp;
int pause = 0;
int released;
int name2;
@@ -655,10 +657,11 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
if(next->type==phVOWEL) released = 1;
if(next->type==phLIQUID && !next->newword) released = 1;
if(released)
len = DoSample(p->ph,next->ph,2,0,-1);
else
len = DoSample(p->ph,phoneme_tab[phonPAUSE],2,0,-1);
if(released == 0)
p->synthflags |= SFLAG_NEXT_PAUSE;
InterpretPhoneme(NULL, 0, p, &phdata);
len = DoSample3(&phdata, 0, -1);
len = (len * 1000)/samplerate; // convert to mS
len += PauseLength(p->prepause,1);
break;
@@ -669,9 +672,10 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
case phFRICATIVE:
len = 0;
InterpretPhoneme(NULL, 0, p, &phdata);
if(p->synthflags & SFLAG_LENGTHEN)
len = DoSample(ph,ph_next,2,p->length,-1); // play it twice for [s:] etc.
len += DoSample(ph,ph_next,2,p->length,-1);
len = DoSample3(&phdata, p->length, -1); // play it twice for [s:] etc.
len += DoSample3(&phdata, p->length, -1);
len = (len * 1000)/samplerate; // convert to mS
break;
@@ -679,7 +683,12 @@ void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola)
case phNASAL:
if(next->type != phVOWEL)
{
len = DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,-1);
memset(&fmtp, 0, sizeof(fmtp));
InterpretPhoneme(NULL, 0, p, &phdata);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
len = DoSpect2(p->ph, 0, &fmtp, p, -1);
// len = DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,-1);
len = (len * 1000)/samplerate;
if(next->type == phPAUSE)
len += 50;
+588 -227
View File
@@ -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
+308 -136
View File
@@ -219,72 +219,153 @@ static void DoPause(int length, int control)
extern int seq_len_adjust; // temporary fix to advance the start point for playing the wav sample
static int DoSample2(int index, int which, int length_mod, int amp)
{//================================================================
static int DoSample2(int index, int which, int std_length, int control, int length_mod, int amp)
{//=============================================================================================
int length;
int length1;
int wav_length;
int format;
int min_length;
int start=0;
int x;
int len4;
long *q;
unsigned char *p;
index = index & 0x7fffff;
p = &wavefile_data[index];
format = p[2];
length1 = (p[1] * 256);
length1 += p[0]; // length in bytes
wav_length = (p[1] * 256);
wav_length += p[0]; // length in bytes
if(seq_len_adjust > 0)
{
start = (seq_len_adjust * samplerate)/1000;
if(format == 0)
start *= 2;
length1 -= start;
index += start;
}
if(length_mod > 0)
length = (length1 * length_mod) / 256;
else
length = length1;
length = (length * speed.speed_factor2)/256;
min_length = speed.min_sample_len;
if(format==0)
min_length *= 2;
if(std_length > 0)
{
std_length = (std_length * samplerate)/1000;
if(format == 0)
std_length *= 2;
x = (min_length * std_length)/wav_length;
if(x > min_length)
min_length = x;
}
else
{
// no length specified, use the length of the stored sound
std_length = wav_length;
}
if(length_mod > 0)
{
std_length = (std_length * length_mod)/256;
}
length = (std_length * speed.speed_factor2)/256;
if(control & pd_DONTLENGTHEN)
{
// this option is used for Stops, with short noise bursts.
// Don't change their length much.
if(length > std_length)
{
// don't let length exceed std_length
length = std_length;
}
else
{
// reduce the reduction in length
// length = (length + std_length)/2;
}
}
if(length < min_length)
length = min_length;
if(length > length1)
length = length1; // don't exceed wavefile length
if(format==0)
length /= 2; // 2 byte samples
if(format == 0)
{
// 16 bit samples
length /= 2;
wav_length /= 2;
}
if(amp < 0)
return(length);
len4 = wav_length / 4;
index += 4;
if(amp >= 0)
if(which & 0x100)
{
// mix this with synthesised wave
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
if(which & 0x100)
q[0] = WCMD_WAVE2; // mix this with synthesised wave
else
q[0] = WCMD_WAVE;
q[1] = length; // length in samples
q[0] = WCMD_WAVE2;
q[1] = length | (wav_length << 16); // length in samples
q[2] = long(&wavefile_data[index]);
q[3] = format + (amp << 8);
WcmdqInc();
return(length);
}
if(length > wav_length)
{
x = len4*3;
length -= x;
}
else
{
x = length;
length = 0;
}
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = x; // length in samples
q[2] = long(&wavefile_data[index]);
q[3] = format + (amp << 8);
WcmdqInc();
while(length > len4*3)
{
x = len4;
if(format == 0)
x *= 2;
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = len4*2; // length in samples
q[2] = long(&wavefile_data[index+x]);
q[3] = format + (amp << 8);
WcmdqInc();
length -= len4*2;
}
if(length > 0)
{
x = wav_length - length;
if(format == 0)
x *= 2;
last_wcmdq = wcmdq_tail;
q = wcmdq[wcmdq_tail];
q[0] = WCMD_WAVE;
q[1] = length; // length in samples
q[2] = long(&wavefile_data[index+x]);
q[3] = format + (amp << 8);
WcmdqInc();
}
return(length);
} // end of Synthesize::DoSample2
} // end of DoSample2
#ifdef deleted
int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp)
{//====================== ==========================================================
int index;
@@ -304,10 +385,37 @@ int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int
if(amp == -1)
amp2 = amp;
result = DoSample2(index,which,length_mod,amp2);
result = DoSample2(index,which,length_mod,0,amp2);
last_frame = NULL;
return(result);
} // end of Synthesize::DoSample
} // end of DoSample
#endif
int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp)
{//=========================================================
int amp2;
int len;
EndPitch(1);
if(amp == -1)
{
// just get the length, don't produce sound
amp2 = amp;
}
else
{
amp2 = phdata->sound_param[pd_WAV];
if(amp2 == 0)
amp2 = 100;
amp2 = (amp2 * 32)/100;
}
seq_len_adjust=0;
len = DoSample2(phdata->sound_addr[pd_WAV], 2, phdata->pd_param[pd_LENGTHMOD]*2, phdata->pd_control, length_mod, amp2);
last_frame = NULL;
return(len);
} // end of DoSample3
@@ -554,7 +662,7 @@ static short vcolouring[N_VCOLOUR][5] = {
if(voice->klattv[0])
{
// fr->klattp[KLATT_AV] = 53; // reduce the amplituide of the start of a vowel
fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 6;
fr->klattp[KLATT_AV] = seq[1].frame->klattp[KLATT_AV] - 4;
}
if(f2 != 0)
{
@@ -861,10 +969,10 @@ static void StartSyllable(void)
}
int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
int which, PHONEME_LIST *plist, int modulation)
{//===================================================================================
// which 1 start of phoneme, 2 body and end
int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation)
{//========================================================================================================
// which 0 not a vowel, 1 start of vowel, 2 body and end of vowel
// length_mod: 256 = 100%
// modulation: -1 = don't write to wcmdq
@@ -877,70 +985,47 @@ int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
int ix;
long *q;
int len;
int min;
int match_level;
int frame_length;
int frame1_length;
int frame2_length;
int length_factor;
int length_mod;
int length_mod2; // reduced effect length_mod
int total_len = 0;
int len_adjust_factor = 256;
static int wave_flag = 0;
int wcmd_spect = WCMD_SPECT;
if(fmt_params->fmt_addr == 0)
return(0);
length_mod = plist->length;
if(length_mod==0) length_mod=256;
length_mod2 = (length_mod*(256-speed.speed_factor3) + 256*speed.speed_factor3)/256;
if(which==1)
if(which==1)
{
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (plist[-1].type==phLIQUID) || (plist[-1].type==phNASAL))
{
// limit the shortening of sonorants before shortened (eg. unstressed vowels)
if((this_ph->type==phLIQUID) || (prev_ph->type==phLIQUID) || (prev_ph->type==phNASAL))
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
{
if(length_mod < (len = translator->langopts.param[LOPT_SONORANT_MIN]))
{
length_mod = len;
}
length_mod = len;
}
}
}
modn_flags = 0;
frames = LookupSpect(this_ph,prev_ph,next_ph,which,&match_level,&n_frames, plist);
frames = LookupSpect(this_ph, which, fmt_params, &n_frames, plist);
if(frames == NULL)
return(0); // not found
// if((which==2) && (this_ph->phflags & phLONG))
if((which==2) && (this_ph->std_length >= 200))
{
// apply a minimum length for long vowels at fast speeds, to keep the distinction with short vowels
total_len = 0;
for(frameix=0; frameix<(n_frames-1); frameix++)
{
length_factor = length_mod;
if(frames[frameix].frflags & FRFLAG_LEN_MOD) // reduce effect of length mod
{
length_factor = length_mod2;
}
len = (frames[frameix].length * samplerate)/1000;
len = (len * length_factor)/256;
total_len += len;
}
min = translator->langopts.param[LOPT_MIN_LONG_VOWEL] * (samplerate)/1000;
min = (min * length_mod2)/256;
if(total_len < min)
{
len_adjust_factor = (min*256)/total_len;
}
}
frame1 = frames[0].frame;
frame1_length = frames[0].length;
if(voice->klattv[0])
wcmd_spect = WCMD_KLATT;
wavefile_ix = fmt_params->wav_addr;
wavefile_amp = (fmt_params->wav_amp * 32)/100;
if(wavefile_amp == 0)
wavefile_amp = 32;
if(wavefile_ix == 0)
{
if(wave_flag)
@@ -990,30 +1075,29 @@ int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
syllable_centre = wcmdq_tail;
}
total_len = 0;
frame_length = frame1_length;
for(frameix=1; frameix<n_frames; frameix++)
{
frame2 = frames[frameix].frame;
frame2_length = frames[frameix].length;
if((wavefile_ix != 0) && ((frame1->frflags & FRFLAG_DEFER_WAV)==0))
if((fmt_params->wav_addr != 0) && ((frame1->frflags & FRFLAG_DEFER_WAV)==0))
{
// there is a wave file to play along with this synthesis
seq_len_adjust = 0;
DoSample2(wavefile_ix,which+0x100,0,wavefile_amp);
DoSample2(fmt_params->wav_addr, which+0x100, 0, fmt_params->fmt_control, 0, wavefile_amp);
wave_flag = 1;
wavefile_ix = 0;
fmt_params->wav_addr = 0;
}
length_factor = length_mod;
if(frame1->frflags & FRFLAG_LEN_MOD) // reduce effect of length mod
{
length_factor = length_mod2;
length_factor = (length_mod*(256-speed.speed_factor3) + 256*speed.speed_factor3)/256;
}
len = (frame_length * samplerate)/1000;
len = (len * length_factor)/256;
len = (len * len_adjust_factor)/256;
if(modulation >= 0)
{
@@ -1054,7 +1138,9 @@ int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
}
}
return(total_len);
} // end of Synthesize::DoSpect
} // end of DoSpect
static void DoMarker(int type, int char_posn, int length, int value)
@@ -1158,6 +1244,12 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
PHONEME_TAB *prev_ph;
static int sourceix=0;
PHONEME_DATA phdata;
PHONEME_DATA phdata_prev;
PHONEME_DATA phdata_next;
PHONEME_DATA phdata_tone;
FMT_PARAMS fmtp;
#ifdef TEST_MBROLA
if(mbrola_name[0] != 0)
return(MbrolaGenerate(phoneme_list,n_ph,resume));
@@ -1252,20 +1344,29 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
if(next->type==phLIQUID) released = 1;
// if(((p->ph->phflags & phPLACE) == phPLACE_blb) && (next->ph->phflags & phSIBILANT)) released = 1;
}
if(released == 0)
p->synthflags |= SFLAG_NEXT_PAUSE;
if(released)
DoSample(p->ph,next->ph,2,0,0);
else
DoSample(p->ph,phoneme_tab[phonPAUSE],2,0,0);
InterpretPhoneme(NULL, 0, p, &phdata);
phdata.pd_control |= pd_DONTLENGTHEN;
DoSample3(&phdata, 0, 0);
break;
case phFRICATIVE:
InterpretPhoneme(NULL, 0, p, &phdata);
if(p->synthflags & SFLAG_LENGTHEN)
DoSample(p->ph,next->ph,2,p->length,0); // play it twice for [s:] etc.
DoSample(p->ph,next->ph,2,p->length,0);
{
DoSample3(&phdata, p->length, 0); // play it twice for [s:] etc.
}
DoSample3(&phdata, p->length, 0);
break;
case phVSTOP:
ph = p->ph;
memset(&fmtp, 0, sizeof(fmtp));
fmtp.fmt_control = pd_DONTLENGTHEN;
pre_voiced = 0;
if(next->type==phVOWEL)
{
@@ -1292,11 +1393,15 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
if((prev->type==phVOWEL) || (prev->ph->phflags & phVOWEL2))
{
// a period of voicing before the release
DoSpect(p->ph,phoneme_tab[phonSCHWA],next->ph,1,p,0);
InterpretPhoneme(NULL, 0x01, p, &phdata);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
DoSpect2(ph, 0, &fmtp, p, 0);
if(p->synthflags & SFLAG_LENGTHEN)
{
DoPause(20,0);
DoSpect(p->ph,phoneme_tab[phonSCHWA],next->ph,1,p,0);
DoSpect2(ph, 0, &fmtp, p, 0);
}
}
else
@@ -1311,18 +1416,24 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
{
// followed by a vowel, or liquid + vowel
StartSyllable();
DoSpect(p->ph,prev->ph,next->ph,2,p,0);
}
else
{
DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,0);
if((p->newword == 0) && (next2->newword == 0))
{
if((next->type == phVFRICATIVE) && (p->ph->mnemonic !='d'))
DoPause(20,0);
if((next->type == phFRICATIVE) || (next->type == phNASAL))
DoPause(12,0);
}
p->synthflags |= SFLAG_NEXT_PAUSE;
}
InterpretPhoneme(NULL,0, p, &phdata);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV];
fmtp.wav_amp = phdata.sound_param[pd_ADDWAV];
DoSpect2(ph, 0, &fmtp, p, 0);
if((p->newword == 0) && (next2->newword == 0))
{
if(next->type == phVFRICATIVE)
DoPause(20,0);
if(next->type == phFRICATIVE)
DoPause(12,0);
}
break;
@@ -1347,22 +1458,29 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
}
}
if((next->type==phVOWEL) || ((next->type==phLIQUID) && (next->newword==0))) // ?? test 14.Aug.2007
if((next->type==phVOWEL) || ((next->type==phLIQUID)) && (next->newword==0)) // ?? test 14.Aug.2007
{
StartSyllable();
if(p->synthflags & SFLAG_LENGTHEN)
DoSpect(p->ph,prev->ph,next->ph,2,p,0);
DoSpect(p->ph,prev->ph,next->ph,2,p,0);
}
else
{
if(p->synthflags & SFLAG_LENGTHEN)
DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,0);
DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,0);
p->synthflags |= SFLAG_NEXT_PAUSE;
}
InterpretPhoneme(NULL,0, p, &phdata);
memset(&fmtp, 0, sizeof(fmtp));
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV];
fmtp.wav_amp = phdata.sound_param[pd_ADDWAV];
if(p->synthflags & SFLAG_LENGTHEN)
DoSpect2(p->ph, 0, &fmtp, p, 0);
DoSpect2(p->ph, 0, &fmtp, p, 0);
break;
case phNASAL:
memset(&fmtp, 0, sizeof(fmtp));
if(!(p->synthflags & SFLAG_SEQCONTINUE))
{
DoAmplitude(p->amp,NULL);
@@ -1374,29 +1492,32 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
last_frame = NULL;
}
InterpretPhoneme(NULL,0, p, &phdata);
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
if(next->type==phVOWEL)
{
StartSyllable();
DoSpect(p->ph,prev->ph,next->ph,1,p,0);
DoSpect2(p->ph, 0, &fmtp, p, 0);
}
else
if(prev->type==phVOWEL && (p->synthflags & SFLAG_SEQCONTINUE))
{
DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,0);
DoSpect2(p->ph, 0, &fmtp, p, 0);
}
else
{
last_frame = NULL; // only for nasal ?
if(next->type == phLIQUID)
DoSpect(p->ph,prev->ph,phoneme_tab[phonSONORANT],2,p,0);
else
DoSpect(p->ph,prev->ph,phoneme_tab[phonPAUSE],2,p,0);
DoSpect2(p->ph, 0, &fmtp, p, 0);
last_frame = NULL;
}
break;
case phLIQUID:
memset(&fmtp, 0, sizeof(fmtp));
modulation = 0;
if(p->ph->phflags & phTRILL)
modulation = 5;
@@ -1419,17 +1540,14 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
if(next->type==phVOWEL)
{
StartSyllable();
DoSpect(p->ph,prev_ph,next->ph,1,p,modulation); // (,)r
}
else
if(prev->type==phVOWEL && (p->synthflags & SFLAG_SEQCONTINUE))
{
DoSpect(p->ph,prev_ph,next->ph,1,p,modulation);
}
else
{
DoSpect(p->ph,prev_ph,next->ph,1,p,modulation);
}
InterpretPhoneme(NULL, 0, p, &phdata);
fmtp.std_length = phdata.pd_param[i_SET_LENGTH]*2;
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
fmtp.wav_addr = phdata.sound_addr[pd_ADDWAV];
fmtp.wav_amp = phdata.sound_param[pd_ADDWAV];
DoSpect2(p->ph, 0, &fmtp, p, modulation);
break;
@@ -1437,16 +1555,46 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
ph = p->ph;
stress = p->stresslevel & 0xf;
// vowel transition from the preceding phoneme
vowel_transition0 = vowel_transition[0];
vowel_transition1 = vowel_transition[1];
memset(&fmtp, 0, sizeof(fmtp));
InterpretPhoneme(NULL, 0, p, &phdata);
fmtp.std_length = phdata.pd_param[i_SET_LENGTH] * 2;
if(((fmtp.fmt_addr = phdata.sound_addr[pd_VWLSTART]) != 0) && ((phdata.pd_control & pd_FORNEXTPH) == 0))
{
// a vowel start has been specified by the Vowel program
fmtp.fmt_length = phdata.sound_param[pd_VWLSTART];
}
else
if(prev->type != phPAUSE)
{
// check the previous phoneme
InterpretPhoneme(NULL, 0, prev, &phdata_prev);
if((fmtp.fmt_addr = phdata_prev.sound_addr[pd_VWLSTART]) != 0)
{
// a vowel start has been specified by the Vowel program
fmtp.fmt2_lenadj = phdata_prev.sound_param[pd_VWLSTART];
}
fmtp.transition0 = phdata_prev.vowel_transition[0];
fmtp.transition1 = phdata_prev.vowel_transition[1];
}
if(fmtp.fmt_addr == 0)
{
// use the default start for this vowel
fmtp.use_vowelin = 1;
fmtp.fmt_control = 1;
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
// fmtp.fmt_length = phdata.sound_param[pd_FMT];
}
pitch_env = envelope_data[p->env];
amp_env = NULL;
if(p->tone_ph != 0)
{
pitch_env = LookupEnvelope(phoneme_tab[p->tone_ph]->spect);
amp_env = LookupEnvelope(phoneme_tab[p->tone_ph]->after);
InterpretPhoneme2(p->tone_ph, &phdata_tone);
pitch_env = LookupEnvelope(phdata_tone.pitch_env);
amp_env = LookupEnvelope(phdata_tone.amp_env);
}
StartSyllable();
@@ -1462,13 +1610,13 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
{
DoAmplitude(p->amp,amp_env);
DoPitch(pitch_env,p->pitch1,p->pitch2); // don't use prevocalic rising tone
DoSpect(ph,prev->ph,next->ph,1,p,modulation);
DoSpect2(ph, 1, &fmtp, p, modulation);
}
else
if(prev->type==phLIQUID || prev->type==phNASAL)
{
DoAmplitude(p->amp,amp_env);
DoSpect(ph,prev->ph,next->ph,1,p,modulation); // continue with pre-vocalic rising tone
DoSpect2(ph, 1, &fmtp, p, modulation); // continue with pre-vocalic rising tone
DoPitch(pitch_env,p->pitch1,p->pitch2);
}
else
@@ -1479,7 +1627,7 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
DoPitch(pitch_env,p->pitch1,p->pitch2);
}
DoSpect(ph,prev->ph,next->ph,1,p,modulation);
DoSpect2(ph, 1, &fmtp, p, modulation);
}
if(option_phoneme_events)
@@ -1487,9 +1635,33 @@ int Generate(PHONEME_LIST *phoneme_list, int *n_ph, int resume)
DoMarker(espeakEVENT_PHONEME, sourceix, 0, p->ph->mnemonic);
}
DoSpect(p->ph,prev->ph,next->ph,2,p,modulation);
fmtp.fmt_addr = phdata.sound_addr[pd_FMT];
fmtp.fmt_length = phdata.sound_param[pd_FMT];
fmtp.transition0 = 0;
fmtp.transition1 = 0;
if((fmtp.fmt2_addr = phdata.sound_addr[pd_VWLEND]) != 0)
{
fmtp.fmt2_lenadj = phdata.sound_param[pd_VWLEND];
}
else
if(next->type != phPAUSE)
{
fmtp.fmt2_lenadj = 0;
InterpretPhoneme(NULL, 0, next, &phdata_next);
fmtp.use_vowelin = 1;
fmtp.transition0 = phdata_next.vowel_transition[2]; // always do vowel_transition, even if ph_VWLEND ?? consider [N]
fmtp.transition1 = phdata_next.vowel_transition[3];
if((fmtp.fmt2_addr = phdata_next.sound_addr[pd_VWLEND]) != 0)
{
fmtp.fmt2_lenadj = phdata_next.sound_param[pd_VWLEND];
}
}
DoSpect2(ph, 2, &fmtp, p, modulation);
memset(vowel_transition,0,sizeof(vowel_transition));
break;
}
ix++;
+138 -9
View File
@@ -47,6 +47,9 @@
#define SFLAG_SWITCHED_LANG 0x20 // this word uses phonemes from a different language
#define SFLAG_PROMOTE_STRESS 0x40 // this unstressed word can be promoted to stressed
#define SFLAG_PREV_PAUSE 0x1000 // consider previous phoneme as pause
#define SFLAG_NEXT_PAUSE 0x2000 // consider next phoneme as pause
// embedded command numbers
#define EMBED_P 1 // pitch
#define EMBED_S 2 // speed (used in setlengths)
@@ -170,10 +173,11 @@ int n_mix_wavefile; // length in bytes
int mix_wave_scale; // 0=2 byte samples
int mix_wave_amp;
int mix_wavefile_ix;
int mix_wavefile_max; // length of available WAV data (in bytes)
int mix_wavefile_offset;
int amplitude;
int amplitude_v;
int prev_was_synth; // previous sound was synthesized (not a played wave or pause)
} WGEN_DATA;
@@ -207,24 +211,147 @@ typedef struct {
frame_t *frame;
} frameref_t;
// a clause translated into phoneme codes (first stage)
typedef struct {
unsigned char phcode;
unsigned char stresslevel;
unsigned char wordstress;
unsigned char tone_ph; // tone phoneme to use with this vowel
unsigned short synthflags;
unsigned short sourceix; // ix into the original source text string, only set at the start of a word
} PHONEME_LIST2;
typedef struct {
// The first section is a copy of PHONEME_LIST2
unsigned char phcode;
unsigned char stresslevel;
unsigned char wordstress;
unsigned char tone_ph; // tone phoneme to use with this vowel
unsigned short synthflags;
unsigned short sourceix; // ix into the original source text string, only set at the start of a word
PHONEME_TAB *ph;
unsigned char env; // pitch envelope number
unsigned char stresslevel;
unsigned char type;
unsigned char prepause;
unsigned char postpause;
unsigned char amp;
unsigned char tone_ph; // tone phoneme to use with this vowel
unsigned char newword; // bit 0=start of word, bit 1=end of clause, bit 2=start of sentence
unsigned char synthflags;
short length; // length_mod
short pitch1; // pitch, 0-4095 within the Voice's pitch range
short pitch2;
unsigned short sourceix; // ix into the original source text string, only set at the start of a word
} PHONEME_LIST;
#define pd_FMT 0
#define pd_WAV 1
#define pd_VWLSTART 2
#define pd_VWLEND 3
#define pd_ADDWAV 4
#define N_PHONEME_DATA_PARAM 16
#define pd_APPENDPHONEME i_APPEND_PHONEME
#define pd_CHANGEPHONEME i_CHANGE_PHONEME
#define pd_LENGTHMOD i_SET_LENGTH
#define pd_FORNEXTPH 0x2
#define pd_DONTLENGTHEN 0x4
#define pd_REDUCELENGTHCHANGE 0x8
typedef struct {
int pd_control;
int pd_param[N_PHONEME_DATA_PARAM]; // set from group 0 instructions
int sound_addr[5];
int sound_param[5];
int vowel_transition[4];
int pitch_env;
int amp_env;
} PHONEME_DATA;
typedef struct {
int fmt_control;
int use_vowelin;
int fmt_addr;
int fmt_length;
int fmt2_addr;
int fmt2_lenadj;
int wav_addr;
int wav_amp;
int transition0;
int transition1;
int std_length;
} FMT_PARAMS;
// instructions
#define i_RETURN 0x0001
#define i_CONTINUE 0x0002
// Group 0 instrcutions with 8 bit operand. These value go into bits 8-15 if the instruction
#define i_CHANGE_PHONEME 0x01
#define i_REPLACE_NEXT_PHONEME 0x02
#define i_INSERT_PHONEME 0x03
#define i_APPEND_PHONEME 0x04
#define i_APPEND_IFNEXTVOWEL 0x05
#define i_VOICING_SWITCH 0x06
#define i_PAUSE_BEFORE 0x07
#define i_PAUSE_AFTER 0x08
#define i_LENGTH_MOD 0x09
#define i_SET_LENGTH 0x0a
#define i_LONG_LENGTH 0x0b
#define i_CHANGE_PHONEME2 0x0c // not yet used
#define i_CHANGE_IF 0x10 // 0x10 to 0x14
#define i_ADD_LENGTH 0x0c
// conditions and jumps
#define i_CONDITION 0x2000
#define i_OR 0x1000 // added to i_CONDITION
#define i_JUMP 0x6000
#define i_JUMP_FALSE 0x6800
#define i_SWITCH_NEXTVOWEL 0x6a00
#define i_SWITCH_PREVVOWEL 0x6c00
#define MAX_JUMP 255 // max jump distance
// multi-word instructions
#define i_CALLPH 0x9100
#define i_PITCHENV 0x9200
#define i_AMPENV 0x9300
#define i_VOWELIN 0xa100
#define i_VOWELOUT 0xa200
#define i_FMT 0xb000
#define i_WAV 0xc000
#define i_VWLSTART 0xd000
#define i_VWLENDING 0xe000
#define i_WAVADD 0xf000
// conditions
#define i_isDiminished 0x80
#define i_isUnstressed 0x81
#define i_isNotStressed 0x82
#define i_isStressed 0x83
#define i_isMaxStress 0x84
#define i_isBreak 0x85
#define i_isWordStart 0x86
#define i_notWordStart 0x87
#define i_isWordEnd 0x88
#define i_isAfterStress 0x89
#define i_isNotVowel 0x8a
#define i_isFinalVowel 0x8b
#define i_isPalatal 0x49 // bit 9 in phflags
#define i_isRhotic 0x56 // bit 22 in phflags
#define i_StressLevel 0x800
typedef struct {
int name;
int length;
@@ -317,7 +444,7 @@ extern char mbrola_name[20];
// from synthdata file
unsigned int LookupSound(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int *match_level, int control);
frameref_t *LookupSpect(PHONEME_TAB *ph1, 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);
unsigned char *LookupEnvelope(int ix);
int LoadPhData();
@@ -365,13 +492,15 @@ espeak_ERROR LoadMbrolaTable(const char *mbrola_voice, const char *phtrans, int
void SetParameter(int parameter, int value, int relative);
void MbrolaTranslate(PHONEME_LIST *plist, int n_phonemes, FILE *f_mbrola);
//int MbrolaSynth(char *p_mbrola);
int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp);
int DoSpect(PHONEME_TAB *this_ph, PHONEME_TAB *prev_ph, PHONEME_TAB *next_ph,
int which, PHONEME_LIST *plist, int modulation);
//int DoSample(PHONEME_TAB *ph1, PHONEME_TAB *ph2, int which, int length_mod, int amp);
int DoSample3(PHONEME_DATA *phdata, int length_mod, int amp);
int DoSpect2(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, PHONEME_LIST *plist, int modulation);
int PauseLength(int pause, int control);
int LookupPhonemeTable(const char *name);
void InitBreath(void);
void KlattInit();
void KlattReset(int control);
int Wavegen_Klatt2(int length, int modulation, int resume, frame_t *fr1, frame_t *fr2);
+2 -91
View File
@@ -1183,8 +1183,9 @@ typedef struct {
*/
#define RUSSIAN2
#ifdef RUSSIAN2
// This is now done in the phoneme data, ph_russian
int ChangePhonemes_ru(Translator *tr, PHONEME_LIST2 *phlist, int n_ph, int index, PHONEME_TAB *ph, CHANGEPH *ch)
{//=============================================================================================================
@@ -1276,96 +1277,6 @@ PH('V','#'),PH('I','3'),PH('I','2'),PH('E','3')};
return(0);
}
#else
int ChangePhonemes_ru(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
// flags: bit 0=1 last phoneme in a word
// bit 1=1 this is the highest stressed vowel in the current word
// bit 2=1 after the highest stressed vowel in the current word
// bit 3=1 the phonemes were specified explicitly, or found from an entry in the xx_list dictionary
// ph The current phoneme
int variant;
int vowelix;
PHONEME_TAB *prev, *next;
if(ch->flags & 8)
return(0); // full phoneme translation has already been given
// Russian vowel softening and reduction rules
if(ph->type == phVOWEL)
{
#define N_VOWELS_RU 7
static unsigned char vowels_ru[N_VOWELS_RU] = {'a','A','o','E','i','u','y'};
// each line gives: soft, reduced, soft-reduced, post-tonic
static unsigned short vowel_replace[N_VOWELS_RU][4] = {
{'&', 'V', 'I', 'V'}, // a
{'&', 'V', 'I', 'V'}, // A
{'8', 'V', 'I', 'V'}, // o
{'e', 'I', 'I', 'I'}, // E
{'i', 'I', 'I', 'I'}, // i
{'u'+('"'<<8), 'U', 'U', 'U'}, // u
{'y', 'Y', 'Y', 'Y'}}; // y
prev = phoneme_tab[phlist[index-1].phcode];
next = phoneme_tab[phlist[index+1].phcode];
if(prev->mnemonic == 'j')
return(0);
// lookup the vowel name to get an index into the vowel_replace[] table
for(vowelix=0; vowelix<N_VOWELS_RU; vowelix++)
{
if(vowels_ru[vowelix] == ph->mnemonic)
break;
}
if(vowelix == N_VOWELS_RU)
return(0);
// do we need a variant of this vowel, depending on the stress and adjacent phonemes ?
variant = -1;
if(ch->flags & 2)
{
// a stressed vowel
if((prev->phflags & phPALATAL) && ((next->phflags & phPALATAL) || phoneme_tab[phlist[index+2].phcode]->mnemonic == ';'))
{
// between two palatal consonants, use the soft variant
variant = 0;
}
}
else
{
// an unstressed vowel
if(prev->phflags & phPALATAL)
{
variant = 2; // unstressed soft
}
else
if((ph->mnemonic == 'o') && ((prev->phflags & phPLACE) == phPLACE_pla))
{
variant = 2; // unstressed soft ([o] vowel following: ш ж
}
else
if(ch->flags & 4)
{
variant = 3; // post tonic
}
else
{
variant = 1; // unstressed
}
}
if(variant >= 0)
{
phlist[index].phcode = PhonemeCode(vowel_replace[vowelix][variant]);
}
}
return(0);
}
#endif
+5 -5
View File
@@ -962,7 +962,7 @@ if((wmark > 0) && (wmark < 8))
if(prefix_type & SUFX_B)
{
// SUFX_B is used for Turkish, tr_rules contains "(Pb£
// SUFX_B is used for Turkish, tr_rules contains "(Pb£
// retranslate the prefix part
char *wordpf;
char prefix_phonemes2[12];
@@ -1593,7 +1593,7 @@ static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pa
plist2 = &ph_list2[n_ph_list2];
stress = 0;
next_stress = 0;
next_stress = 1;
srcix = 0;
max_stress = -1;
@@ -1663,7 +1663,7 @@ static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pa
// don't add stress phonemes codes to the list, but give their stress
// value to the next vowel phoneme
// std_length is used to hold stress number or (if >10) a tone number for a tone language
if(ph->spect == 0)
if(ph->program == 0)
next_stress = ph->std_length;
else
{
@@ -1720,7 +1720,7 @@ static int TranslateWord2(Translator *tr, char *word, WORD_TAB *wtab, int pre_pa
if(ph->type == phVOWEL)
{
stress = next_stress;
next_stress = 0;
next_stress = 1; // default is 'unstressed'
if(stress >= 4)
{
@@ -2272,7 +2272,7 @@ if((c == '/') && (tr->langopts.testing & 2) && IsDigit09(next_in) && IsAlpha(pre
if((c == 0x92) || (c == 0xb4) || (c == 0x2019) || (c == 0x2032))
c = '\''; // 'microsoft' quote or sexed closing single quote, or prime - possibly used as apostrophe
if((c == '?') && IsAlpha(prev_out) && IsAlpha(next_in))
if(((c == 0x2018) || (c == '?')) && IsAlpha(prev_out) && IsAlpha(next_in))
{
// ? between two letters may be a smart-quote replaced by ?
c = '\'';
+2 -9
View File
@@ -229,15 +229,6 @@ typedef struct{
unsigned char length;
} WORD_TAB;
// a clause translated into phoneme codes (first stage)
typedef struct {
unsigned char phcode;
unsigned char stresslevel;
unsigned char tone_ph;
unsigned char synthflags;
unsigned short sourceix;
} PHONEME_LIST2;
typedef struct {
int type;
@@ -642,5 +633,7 @@ void *TranslateClause(Translator *tr, FILE *f_text, const void *vp_input, int *t
int ReadClause(Translator *tr, FILE *f_in, char *buf, short *charix, int *charix_top, int n_buf, int *tone_type);
void SetVoiceStack(espeak_VOICE *v);
void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata);
void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata);
extern FILE *f_trans; // for logging
+10 -6
View File
@@ -511,7 +511,7 @@ void MakeVowelLists(void)
SPECT_SEQ *seq;
SPECT_SEQK *seqk;
frame_t *frame;
int match_level;
PHONEME_DATA phdata;
char dirname[sizeof(path_source)+20];
char fname[sizeof(dirname)+40];
@@ -540,10 +540,12 @@ void MakeVowelLists(void)
ph = phoneme_tab[phcode];
if(ph->type != phVOWEL)
if((ph==NULL) || (ph->type != phVOWEL))
continue;
if((ix = LookupSound(ph, phoneme_tab[phonPAUSE], 1, &match_level, 0)) == 0)
InterpretPhoneme2(phcode, &phdata);
if((ix = phdata.sound_addr[pd_FMT]) == 0)
continue;
seq = (SPECT_SEQ *)(&spects_data[ix]);
@@ -572,9 +574,11 @@ void MakeVowelLists(void)
}
extern int n_envelopes;
extern char envelope_paths[][80];
extern unsigned char envelope_dat[][128];
#define N_ENVELOPES 30
#define ENV_LEN 128
int n_envelopes = 0;
char envelope_paths[N_ENVELOPES][80];
unsigned char envelope_dat[N_ENVELOPES][ENV_LEN];
#define HT_ENV 140
#define WD_ENV 128*2
+15 -9
View File
@@ -720,7 +720,6 @@ void WavegenInit(int rate, int wavemult_fact)
max_hval = 0;
wdata.amplitude = 32;
wdata.prev_was_synth = 0;
for(ix=0; ix<N_EMBEDDED_VALUES; ix++)
embedded_value[ix] = embedded_default[ix];
@@ -1355,17 +1354,20 @@ int Wavegen()
if(wdata.mix_wave_scale == 0)
{
// a 16 bit sample
c = wdata.mix_wavefile[wdata.mix_wavefile_ix+1];
sample = wdata.mix_wavefile[wdata.mix_wavefile_ix] + (c * 256);
c = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset+1];
sample = wdata.mix_wavefile[wdata.mix_wavefile_ix+wdata.mix_wavefile_offset] + (c * 256);
wdata.mix_wavefile_ix += 2;
}
else
{
// a 8 bit sample, scaled
sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_ix++] * wdata.mix_wave_scale;
sample = (signed char)wdata.mix_wavefile[wdata.mix_wavefile_offset+wdata.mix_wavefile_ix++] * wdata.mix_wave_scale;
}
z2 = (sample * wdata.amplitude_v) >> 10;
z2 = (z2 * wdata.mix_wave_amp)/32;
if((wdata.mix_wavefile_ix + wdata.mix_wavefile_offset) >= wdata.mix_wavefile_max) // reached the end of available WAV data
wdata.mix_wavefile_offset -= (wdata.mix_wavefile_max*3)/4;
}
z1 = z2 + (((total>>8) * amplitude2) >> 13);
@@ -1864,14 +1866,14 @@ int WavegenFill(int fill_zeros)
echo_complete -= length;
}
wdata.n_mix_wavefile = 0;
wdata.prev_was_synth = 0;
KlattReset(1);
result = PlaySilence(length,resume);
break;
case WCMD_WAVE:
echo_complete = echo_length;
wdata.n_mix_wavefile = 0;
wdata.prev_was_synth = 0;
KlattReset(1);
result = PlayWave(length,resume,(unsigned char*)q[2], q[3] & 0xff, q[3] >> 8);
break;
@@ -1879,11 +1881,15 @@ int WavegenFill(int fill_zeros)
// wave file to be played at the same time as synthesis
wdata.mix_wave_amp = q[3] >> 8;
wdata.mix_wave_scale = q[3] & 0xff;
wdata.n_mix_wavefile = (length & 0xffff);
wdata.mix_wavefile_max = (length >> 16) & 0xffff;
if(wdata.mix_wave_scale == 0)
wdata.n_mix_wavefile = length*2;
else
wdata.n_mix_wavefile = length;
{
wdata.n_mix_wavefile *= 2;
wdata.mix_wavefile_max *= 2;
}
wdata.mix_wavefile_ix = 0;
wdata.mix_wavefile_offset = 0;
wdata.mix_wavefile = (unsigned char *)q[2];
break;