[1.29.25] <emphasis> tag now changes the intonation to emphasize the specified word.

option_emphasize_allcaps in translate.cpp, if set will emphasize words which are all-capitals.
Changed intonation.cpp.
Added an intonation for sentences which end in an exclamation mark.


git-svn-id: https://espeak.svn.sourceforge.net/svnroot/espeak/trunk@111 d46cf337-b52f-0410-862d-fd96e6ae7743
This commit is contained in:
jonsd
2007-12-14 10:43:52 +00:00
parent 363753f388
commit 22756f15a6
15 changed files with 345 additions and 392 deletions
+222 -299
View File
@@ -35,13 +35,20 @@
provide a more flexible intonation system.
*/
typedef struct {
char stress;
char env;
char flags; //bit 0=pitch rising, bit1=emnphasized
short pitch1;
short pitch2;
} SYLLABLE;
SYLLABLE syllable_tab[N_PHONEME_LIST];
static int tone_pitch_env; /* used to return pitch envelope */
static int vowel_ix;
static int vowel_ix_top;
static int *vowel_tab;
/* Pitch data for tone types */
/*****************************/
@@ -241,9 +248,6 @@ typedef struct {
unsigned char tonic_max1;
unsigned char tonic_min1;
unsigned char emph_level;
unsigned char emph_next;
unsigned char pre_start;
unsigned char pre_end;
@@ -262,17 +266,17 @@ typedef struct {
#define N_TONE_TABLE 15
static TONE_TABLE tone_table[N_TONE_TABLE] = {
{PITCHfall, 30, 5, PITCHfall, 30, 7, // statement
12, 10,
20, 25, 34, 22, drops_0, 3, 3, 12, 8, 0},
{PITCHfall, 30, 5, PITCHfall, 30, 8, // statement
20, 25, 34, 22, drops_0, 3, 3, 12, 7, 0},
{PITCHfrise, 38,10, PITCHfrise2, 36,10, // comma, or question
30, 20,
20, 25, 34, 20, drops_0, 3, 3, 15, 25, 0},
{PITCHfrise, 37,10, PITCHfrise2, 35,10, // comma
20, 25, 34, 20, drops_0, 3, 3, 15, 24, 0},
{PITCHdrop, 38, 1, PITCHdrop, 42,25, // exclamation
30, 20,
20, 25, 34, 22, drops_0, 3, 3, 12, 8, 0},
{PITCHfrise, 39,10, PITCHfrise2, 36,10, // question
20, 25, 34, 20, drops_0, 3, 3, 15, 29, 0},
{PITCHfall, 36, 0, PITCHfall, 40, 30, // statement, emphatic
20, 25, 34, 22, drops_0, 3, 3, 20, 4, 0},
#ifdef deleted
@@ -314,15 +318,14 @@ static TONE_TABLE tone_table[N_TONE_TABLE] = {
/* indexed by stress */
static int min_drop[] = {0x300,0x300,0x400,0x400,0x900,0x900,0x900,0x900};
static int min_drop[] = {0x300,0x300,0x400,0x400,0x900,0x900,0x900,0xb00};
#define SECONDARY 3
#define PRIMARY 4
#define PRIMARY_STRESSED 5
#define PRIMARY_MARKED 6
#define PRIMARY_STRESSED 6
#define PRIMARY_LAST 7
@@ -330,37 +333,48 @@ static int number_pre;
static int number_body;
static int number_tail;
static int last_primary;
static int tone_type;
static int tone_posn;
static int annotation;
static int tone_posn2;
static int no_tonic;
static void count_pitch_vowels()
/******************************/
static void count_pitch_vowels(int start, int end, int clause_end)
/****************************************************************/
{
int ix;
int stress;
int max_stress = 0;
int max_stress_posn = 0;
int max_stress_posn = 0; // last syllable ot the highest stress
int max_stress_posn2 = 0; // penuntimate syllable of the highest stress
int last2_primary;
number_pre = -1; /* number of vowels before 1st primary stress */
number_body = 0;
number_tail = 0; /* number between tonic syllable and next primary */
last_primary = 0;
last2_primary = 0;
for(ix=vowel_ix; ix<vowel_ix_top; ix++)
for(ix=start; ix<end; ix++)
{
stress = vowel_tab[ix] & 0x3f; /* marked stress level */
stress = syllable_tab[ix].stress; /* marked stress level */
if(stress >= max_stress)
{
max_stress = stress;
if(stress > max_stress)
{
max_stress_posn2 = ix;
}
else
{
max_stress_posn2 = max_stress_posn;
}
max_stress_posn = ix;
max_stress = stress;
}
if(stress >= PRIMARY)
{
if(number_pre < 0)
number_pre = ix;
number_pre = ix - start;
last_primary = ix;
}
@@ -370,19 +384,18 @@ static void count_pitch_vowels()
if(number_pre < 0)
number_pre = 0;
number_tail = vowel_ix_top - max_stress_posn - 1;
number_tail = end - max_stress_posn - 1;
tone_posn = max_stress_posn;
tone_posn = last_primary;
tone_posn2 = max_stress_posn2;
if(no_tonic)
{
tone_posn = vowel_ix_top;
tone_posn = tone_posn2 = end-1;
}
else
// if((last_primary - max_stress_posn) > 2)
if(end == clause_end)
{
if(vowel_tab[last_primary] < PRIMARY_MARKED)
vowel_tab[last_primary] = PRIMARY_LAST;
syllable_tab[last_primary].stress = PRIMARY_LAST;
}
} /* end of count_pitch_vowels */
@@ -398,7 +411,7 @@ static int count_increments(int ix, int end_ix, int min_stress)
while(ix < end_ix)
{
stress = vowel_tab[ix++] & 0x3f;
stress = syllable_tab[ix++].stress;
// if(stress >= PRIMARY_MARKED)
// break;
@@ -410,9 +423,9 @@ static int count_increments(int ix, int end_ix, int min_stress)
static void set_pitch(int ix, int base, int drop)
/***********************************************/
// Set the pitch of a vowel in vowel_tab. Base & drop are Hz * 256
static void set_pitch(SYLLABLE *syl, int base, int drop)
/******************************************************/
// Set the pitch of a vowel in syllable_tab. Base & drop are Hz * 256
{
int pitch1, pitch2;
int flags = 0;
@@ -421,39 +434,30 @@ static void set_pitch(int ix, int base, int drop)
int pitch_range2 = 148;
int pitch_base2 = 72;
// fprintf(f_log,"base=%3d,drop=%3d ",base>>8,drop>>8);
// pitch_range2 = pitch_range + 20;
// pitch_base2 = pitch_base - (128-72);
if(base < 0) base = 0;
pitch2 = ((base * pitch_range2 ) >> 15) + pitch_base2;
if(drop < 0)
{
flags = 0x80;
flags = 1;
drop = -drop;
}
pitch1 = pitch2 + ((drop * pitch_range2) >> 15);
//x = (pitch1 - pitch2) / 4; // TEST
//pitch1 -= x;
//pitch2 += x;
if(pitch1 > 511) pitch1 = 511;
if(pitch2 > 511) pitch2 = 511;
// fprintf(f_log," %d p1=%3d p2=%3d %x\n",vowel_tab[ix] & 0x3f,pitch1,pitch2,flags);
vowel_tab[ix] = (vowel_tab[ix] & 0x3f) + flags
+ (pitch1 << 8) + (pitch2 << 17);
syl->pitch1 = pitch1;
syl->pitch2 = pitch2;
syl->flags |= flags;
} /* end of set_pitch */
static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress)
/******************************************************************************/
static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress, int continuing)
/**********************************************************************************************/
/* Calculate pitches until next RESET or tonic syllable, or end.
Increment pitch if stress is >= min_stress.
Used for tonic segment */
@@ -464,17 +468,33 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress)
int n_primary=0;
int initial;
int overflow=0;
int marking=0;
int *drops;
short *overflow_tab;
SYLLABLE *syl;
static char overflow_tab[5] = {0, 20, 12, 4, 0};
static short overflow_tab1[5] = {0, 20, 12, 4, 0};
static short continue_tab[5] = {-14, 16, 10, 4, 0};
drops = t->body_drops;
initial = 1;
if(continuing)
{
initial =0;
overflow = 0;
overflow_tab = continue_tab;
increment = (t->body_end - t->body_start) << 8;
increment = increment / (t->body_max_steps -1);
}
else
{
overflow_tab = overflow_tab1;
initial = 1;
}
while(ix < end_ix)
{
stress = vowel_tab[ix] & 0x3f;
syl = &syllable_tab[ix];
stress = syl->stress;
// if(stress == PRIMARY_MARKED)
// initial = 1; // reset the intonation pattern
@@ -509,50 +529,34 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress)
else
{
pitch = (t->body_end << 8) - (increment * overflow_tab[overflow++])/16;
if(overflow > 4) overflow = 0;
if(overflow > 4)
{
overflow = 0;
overflow_tab = overflow_tab1;
}
}
}
if(stress == PRIMARY_MARKED)
{
pitch = (t->emph_level << 8);
marking = 2;
n_primary = marking+1; // move into overflow region
}
else
if(marking > 0)
{
marking--;
pitch = (t->emph_next << 8);
}
n_primary--;
}
if((annotation==0) && (stress >= PRIMARY))
if(stress >= PRIMARY)
{
vowel_tab[ix] = PRIMARY_STRESSED;
set_pitch(ix,pitch,drops[stress]);
}
if(stress >= PRIMARY_MARKED)
{
vowel_tab[ix] = PRIMARY_MARKED;
set_pitch(ix,pitch,drops[stress]);
syl->stress = PRIMARY_STRESSED;
set_pitch(syl,pitch,drops[stress]);
}
else
if(stress >= SECONDARY)
{
/* use secondary stress for unmarked word stress, if no annotation */
set_pitch(ix,pitch,drops[stress]);
set_pitch(syl,pitch,drops[stress]);
}
else
{
/* unstressed, drop pitch if preceded by PRIMARY */
if((vowel_tab[ix-1] & 0x3f) >= SECONDARY)
set_pitch(ix,pitch - (t->body_lower_u << 8), drops[stress]);
if((syllable_tab[ix-1].stress & 0x3f) >= SECONDARY)
set_pitch(syl,pitch - (t->body_lower_u << 8), drops[stress]);
else
set_pitch(ix,pitch,drops[stress]);
set_pitch(syl,pitch,drops[stress]);
}
ix++;
@@ -562,6 +566,8 @@ static int calc_pitch_segment(int ix, int end_ix, TONE_TABLE *t, int min_stress)
static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int min_stress)
/****************************************************************************************/
/* Linear pitch rise/fall, change pitch at min_stress or stronger
@@ -572,6 +578,7 @@ static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int m
int increment;
int n_increments;
int drop;
SYLLABLE *syl;
if(ix >= end_ix)
return(ix);
@@ -588,11 +595,12 @@ static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int m
pitch = start_p << 8;
while(ix < end_ix)
{
stress = vowel_tab[ix] & 0x3f;
syl = &syllable_tab[ix];
stress = syl->stress;
if(increment > 0)
{
set_pitch(ix,pitch,-increment);
set_pitch(syl,pitch,-increment);
pitch += increment;
}
else
@@ -602,7 +610,7 @@ static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int m
drop = min_drop[stress];
pitch += increment;
set_pitch(ix,pitch,drop);
set_pitch(syl,pitch,drop);
}
ix++;
@@ -615,32 +623,40 @@ static int calc_pitch_segment2(int ix, int end_ix, int start_p, int end_p, int m
static int calc_pitches(int *syllable_tab, int num, int sentence_tone)
/********************************************************************/
static int calc_pitches(int start, int end, int group_tone)
/**********************************************************/
/* Calculate pitch values for the vowels in this tone group */
{
int ix;
TONE_TABLE *t;
int drop;
int continuing = 0;
t = &tone_table[tone_type];
ix = vowel_ix;
if(start > 0)
continuing = 1;
t = &tone_table[group_tone];
ix = start;
/* vowels before the first primary stress */
/******************************************/
if(number_pre > 0)
{
ix = calc_pitch_segment2(ix,ix+number_pre,t->pre_start,t->pre_end, 0);
ix = calc_pitch_segment2(ix, ix+number_pre, t->pre_start, t->pre_end, 0);
}
/* body of tonic segment */
/*************************/
if(annotation)
ix = calc_pitch_segment(ix,tone_posn, t, PRIMARY_MARKED);
else
ix = calc_pitch_segment(ix,tone_posn, t, PRIMARY);
if(option_tone2 & 1)
{
static int count=0;
count++;
//if(count & 1)
tone_posn = tone_posn2; // TEST put tone on the penultimate stressed word
}
ix = calc_pitch_segment(ix,tone_posn, t, PRIMARY, continuing);
if(no_tonic)
return(0);
@@ -652,20 +668,23 @@ static int calc_pitches(int *syllable_tab, int num, int sentence_tone)
{
tone_pitch_env = t->pitch_env0;
drop = t->tonic_max0 - t->tonic_min0;
set_pitch(ix++,t->tonic_min0 << 8,drop << 8);
set_pitch(&syllable_tab[ix++],t->tonic_min0 << 8,drop << 8);
}
else
{
tone_pitch_env = t->pitch_env1;
drop = t->tonic_max1 - t->tonic_min1;
set_pitch(ix++,t->tonic_min1 << 8,drop << 8);
set_pitch(&syllable_tab[ix++],t->tonic_min1 << 8,drop << 8);
}
syllable_tab[tone_posn].env = tone_pitch_env;
if(syllable_tab[tone_posn].stress == PRIMARY)
syllable_tab[tone_posn].stress = PRIMARY_STRESSED;
/* tail, after the tonic syllable */
/**********************************/
calc_pitch_segment2(ix,vowel_ix_top,t->tail_start,t->tail_end,0);
calc_pitch_segment2(ix, end, t->tail_start, t->tail_end, 0);
return(tone_pitch_env);
} /* end of calc_pitches */
@@ -674,129 +693,6 @@ static int calc_pitches(int *syllable_tab, int num, int sentence_tone)
static int calc_pitch_segmentX(int ix, int end_ix, TONE_TABLE *t, int min_stress)
/******************************************************************************/
/* Calculate pitches until next RESET or tonic syllable, or end.
Increment pitch if stress is >= min_stress.
Used for tonic segment */
// EXPERIMENTAL VERSION
{
int stress;
int pitch=0;
int n_primary;
int initial;
int *drops;
int prev_stress=0;
int n_unstressed;
int j;
drops = t->body_drops; // pitch fall or raise for each stress value
n_primary = count_increments(ix,end_ix,min_stress)-1; // number if primary stress in the clause -1
initial = 1;
while(ix < end_ix) // for each syllable
{
for(j=ix; j<end_ix; j++)
{
// how many unstressed syllables before the next primary stress ?
if((vowel_tab[j] & 0x3f) > SECONDARY)
break;
}
n_unstressed = (j - ix - 1);
stress = vowel_tab[ix] & 0x3f; // stress value of this syllable
pitch = 0x1000; // set a base pitch
pitch += ((n_primary % 3) * 0x0500); // some variety. add an offset that changes after each primary stress
if(stress >= PRIMARY)
{
vowel_tab[ix] = PRIMARY_MARKED;
set_pitch(ix,pitch+0x100, -0x0900);
n_primary--;
}
// else
// if(stress >= SECONDARY)
// {
// set_pitch(ix,pitch,drops[stress]);
// }
else
{
if(ix > 0)
prev_stress = vowel_tab[ix-1] & 0x3f; // stress level of previous syllable
if(prev_stress >= PRIMARY)
{
// an unstressed syllable which follows a primary stress syllable
set_pitch(ix,pitch+0x0200, 0x0800);
}
else
{
stress = 0; // treat secondary stress the same as unstressed ??
set_pitch(ix,pitch + n_unstressed*0x300, drops[stress]);
}
n_unstressed--;
}
ix++;
}
return(ix);
} /* end of calc_pitch_segmentX */
static int calc_pitchesX(int *syllable_tab, int num, int sentence_tone)
/********************************************************************/
/* Calculate pitch values for the vowels in this tone group */
// EXPERMENTAL VERSION of calc_pitches()
{
int ix;
TONE_TABLE *t;
int drop;
t = &tone_table[tone_type];
ix = vowel_ix;
/* body of tonic segment */
/*************************/
if(annotation)
ix = calc_pitch_segmentX(ix,tone_posn, t, PRIMARY_MARKED);
else
ix = calc_pitch_segmentX(ix,tone_posn, t, PRIMARY);
if(no_tonic)
return(0);
/* tonic syllable */
/******************/
if(number_tail == 0)
{
tone_pitch_env = t->pitch_env0;
drop = t->tonic_max0 - t->tonic_min0;
set_pitch(ix++,t->tonic_min0 << 8,drop << 8);
}
else
{
tone_pitch_env = t->pitch_env1;
drop = t->tonic_max1 - t->tonic_min1;
set_pitch(ix++,t->tonic_min1 << 8,drop << 8);
}
/* tail, after the tonic syllable */
/**********************************/
calc_pitch_segment2(ix,vowel_ix_top,t->tail_start,t->tail_end,0);
return(tone_pitch_env);
} /* end of calc_pitchesX */
void Translator::CalcPitches_Tone(int clause_tone)
{//===============================================
@@ -958,124 +854,143 @@ void Translator::CalcPitches_Tone(int clause_tone)
p->pitch2 = pitch_adjust + phoneme_tab[tone_ph]->end_type;
}
}
} // end of Translator::CalcPitches_Tone
void Translator::CalcPitches(int clause_tone)
void Translator::CalcPitches(int clause_type)
{//==========================================
// clause_tone: 0=. 1=, 2=?, 3=! 4=none
// clause_type: 0=. 1=, 2=?, 3=! 4=none
PHONEME_LIST *p;
SYLLABLE *syl;
int ix;
int x;
int st_ix;
int tonic_ix=0;
int tonic_env;
int max_stress=0;
int n_st;
int option;
int st_ix_changed = -1;
int syllable_tab[N_PHONEME_LIST];
int group_tone;
int group_tone_emph;
int ph_start=0;
int st_start;
int count;
int n_primary;
int count_primary;
int ph_end=n_phoneme_list;
if(langopts.intonation == 1)
{
CalcPitches_Tone(clause_tone);
CalcPitches_Tone(clause_type);
return;
}
st_ix=0;
p = &phoneme_list[0];
for(ix=0; ix<n_phoneme_list; ix++, p++)
{
if(p->synthflags & SFLAG_SYLLABLE)
{
syllable_tab[st_ix] = p->tone;
if(option_tone2 == 1)
{
// reduce number of full-stress words
if((p->tone == 4) && ((st_ix % 2) != 1))
{
syllable_tab[st_ix] = 3;
st_ix_changed = st_ix;
}
}
if(option_tone2 == 2)
{
// reduce all full-stress words, except last
if(p->tone == 4)
{
syllable_tab[st_ix] = 3;
st_ix_changed = st_ix;
}
}
st_ix++;
if(p->tone >= max_stress)
{
max_stress = p->tone;
tonic_ix = ix;
}
}
}
if(st_ix_changed >= 0)
syllable_tab[st_ix_changed] = 4;
if(st_ix == 0)
return; // no vowels, nothing to do
option = option_tone1 & 0xf;
if(option > 4)
option = 0;
tone_type = punct_to_tone[option][clause_tone]; /* unless changed by count_pitch_vowels */
group_tone_emph = group_tone = punct_to_tone[option][clause_type];
group_tone_emph = punct_to_tone[option][3]; // emphatic form of statement
if(clause_tone == 4)
if(clause_type == 4)
no_tonic = 1; /* incomplete clause, used for abbreviations such as Mr. Dr. Mrs. */
else
no_tonic = 0;
/* transfer vowel data from ph_list to syllable_tab */
vowel_tab = syllable_tab;
vowel_ix_top = st_ix;
n_st = 0;
n_primary = 0;
for(ix=0; ix<n_phoneme_list; ix++)
{
p = &phoneme_list[ix];
if(p->synthflags & SFLAG_SYLLABLE)
{
syllable_tab[n_st].flags = 0;
syllable_tab[n_st++].stress = p->tone; // stress level
count_pitch_vowels();
if(p->tone >= 4)
n_primary++;
}
}
syllable_tab[n_st].stress = 0; // extra 0 entry at the end
if((option_tone1 & 0xf0)== 0x10)
tonic_env = calc_pitchesX(syllable_tab,st_ix,clause_tone);
else
tonic_env = calc_pitches(syllable_tab,st_ix,clause_tone);
if(n_st == 0)
return; // nothing to do
st_start = 0;
count_primary=0;
for(st_ix=0; st_ix<n_st; st_ix++)
{
syl = &syllable_tab[st_ix];
if(syl->stress >= 4)
count_primary++;
if((syl->stress == 6) && (syllable_tab[st_ix+1].stress == 6))
{
syllable_tab[st_ix].flags = 2;
syl->stress = 4;
}
if(syl->stress == 6)
{
// an emphasized syllable, end the tone group after the next primary stress
syllable_tab[st_ix].flags = 2;
count = 0;
if((n_primary - count_primary) > 1)
count =1;
for(ix=st_ix+1; ix<n_st; ix++)
{
if(syllable_tab[ix].stress > 4)
break;
if(syllable_tab[ix].stress == 4)
{
count++;
if(count > 1)
break;
}
}
count_pitch_vowels(st_start, ix, n_st);
if((ix < n_st) || (clause_type == 0))
calc_pitches(st_start, ix, group_tone_emph); // split into > 1 tone groups, use emphatic tone
else
calc_pitches(st_start, ix, group_tone);
st_start = ix;
}
}
if(st_start < st_ix)
{
count_pitch_vowels(st_start, st_ix, n_st);
calc_pitches(st_start, st_ix, group_tone);
}
// unpack pitch data
st_ix=0;
p = &phoneme_list[0];
for(ix=0; ix<n_phoneme_list; ix++, p++)
for(ix=ph_start; ix < ph_end; ix++)
{
p->tone = syllable_tab[st_ix] & 0x3f;
p = &phoneme_list[ix];
p->tone = syllable_tab[st_ix].stress;
if(p->synthflags & SFLAG_SYLLABLE)
{
x = ((syllable_tab[st_ix] >> 8) & 0x1ff) - 72;
syl = &syllable_tab[st_ix];
x = syl->pitch1 - 72;
if(x < 0) x = 0;
p->pitch1 = x;
x = ((syllable_tab[st_ix] >> 17) & 0x1ff) - 72;
x = syl->pitch2 - 72;
if(x < 0) x = 0;
p->pitch2 = x;
p->env = PITCHfall;
if(syllable_tab[st_ix] & 0x80)
if(syl->flags & 1)
{
// if(p->pitch1 > p->pitch2)
// p->env = PITCHfall;
// else
p->env = PITCHrise;
p->env = PITCHrise;
}
if(p->pitch1 > p->pitch2)
{
// swap so that pitch2 is the higher
@@ -1083,10 +998,18 @@ void Translator::CalcPitches(int clause_tone)
p->pitch1 = p->pitch2;
p->pitch2 = x;
}
if(ix==tonic_ix) p->env = tonic_env;
if(p->tone > 5)
p->env = syl->env;
if(syl->flags & 2)
{
p->tone |= 8; // emphasized
}
st_ix++;
}
}
} // end of Translator::CalcPitches