Esempio n. 1
0
void ProsodyDisplay::DrawEnv(wxDC& dc, int x1, int y1, int width, PHONEME_LIST *ph)
{//==============================================================================
	int  pitchr;
	int  pitch;
	int  p1;
	int  ix;
	int  x,y;
	int  y2=0;
	unsigned char *env;
	PHONEME_DATA phdata_tone;

	if(width <= 0) return;

	if((pitchr = ph->pitch2 - ph->pitch1) < 0)
	{
		pitchr = -pitchr;
		p1 = ph->pitch2;
	}
	else
	{
		p1 = ph->pitch1;
	}

	if(p1 == 255) return;

	dc.SetPen(PEN_PITCHENV);

	env = envelope_data[ph->env];
	if((ph->type == phVOWEL) && (ph->tone_ph != 0))
	{
		// the envelope is given by a Tone phoneme acting on this vowel
		InterpretPhoneme2(ph->tone_ph, &phdata_tone);
		env = GetEnvelope(phdata_tone.pitch_env);
	}

	if(env == NULL)
		return;

	for(ix=0; ix<=width; ix+=4)
	{
		x = int((ix * 127.9)/width);
		pitch = p1 + (pitchr * env[x])/256;
		y = y1-int(pitch * scaley);
		if(ix > 0)
			dc.DrawLine(x1+ix-4,y2,x1+ix,y);
		y2 = y;
	}
}  // end of DrawEnv
Esempio n. 2
0
void CalcLengths(Translator *tr)
{//==============================
	int ix;
	int ix2;
	PHONEME_LIST *prev;
	PHONEME_LIST *next;
	PHONEME_LIST *next2;
	PHONEME_LIST *next3;
	PHONEME_LIST *p;
	PHONEME_LIST *p2;

	int  stress;
	int  type;
	static int  more_syllables=0;
	int  pre_sonorant=0;
	int  pre_voiced=0;
	int  last_pitch = 0;
	int  pitch_start;
	int  length_mod;
	int  len;
	int  env2;
	int  end_of_clause;
	int  embedded_ix = 0;
	int  min_drop;
	int  pitch1;
	int emphasized;
	int  tone_mod;
	unsigned char *pitch_env=NULL;
	PHONEME_DATA phdata_tone;

	for(ix=1; ix<n_phoneme_list; ix++)
	{
		prev = &phoneme_list[ix-1];
		p = &phoneme_list[ix];
		stress = p->stresslevel & 0x7;
		emphasized = p->stresslevel & 0x8;

		next = &phoneme_list[ix+1];

		if(p->synthflags & SFLAG_EMBEDDED)
		{
			DoEmbedded2(&embedded_ix);
		}

		type = p->type;
		if(p->synthflags & SFLAG_SYLLABLE)
			type = phVOWEL;

		switch(type)
		{
		case phPAUSE:
			last_pitch = 0;
			break;
			
		case phSTOP:
			last_pitch = 0;
			if(prev->type == phFRICATIVE)
				p->prepause = 25;
			else
			if((more_syllables > 0) || (stress < 4))
				p->prepause = 48;
			else
				p->prepause = 60;

			if(prev->type == phSTOP)
				p->prepause = 60;

			if((tr->langopts.word_gap & 0x10) && (p->newword))
				p->prepause = 60;

			if(p->ph->phflags & phLENGTHENSTOP)
				p->prepause += 30;

			if(p->synthflags & SFLAG_LENGTHEN)
				p->prepause += tr->langopts.long_stop;
			break;

		case phVFRICATIVE:
		case phFRICATIVE:
			if(p->newword)
			{
				if((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE))
				{
				}
				else
				{
					p->prepause = 15;
				}
			}

			if(next->type==phPAUSE && prev->type==phNASAL && !(p->ph->phflags&phFORTIS))
				p->prepause = 25;

			if(prev->ph->phflags & phBRKAFTER)
				p->prepause = 30;

			if((tr->langopts.word_gap & 0x10) && (p->newword))
				p->prepause = 30;

			if((p->ph->phflags & phSIBILANT) && next->type==phSTOP && !next->newword)
			{
				if(prev->type == phVOWEL)
					p->length = 200;      // ?? should do this if it's from a prefix
				else
					p->length = 150;
			}
			else
				p->length = 256;

			if(type == phVFRICATIVE)
			{
				if(next->type==phVOWEL)
				{
					pre_voiced = 1;
				}
				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
				{
					p->length = (255 + prev->length)/2;
				}
			}
			break;

		case phVSTOP:
			if(prev->type==phVFRICATIVE || prev->type==phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID))
				p->prepause = 30;

			if(next->type==phVOWEL || next->type==phLIQUID)
			{
				if((next->type==phVOWEL) || !next->newword)
					pre_voiced = 1;

				p->prepause = 40;

				if((prev->type == phPAUSE) || (prev->type == phVOWEL)) // || (prev->ph->mnemonic == ('/'*256+'r')))
					p->prepause = 0;
				else
				if(p->newword==0)
				{
					if(prev->type==phLIQUID)
						p->prepause = 20;
					if(prev->type==phNASAL)
						p->prepause = 12;

					if(prev->type==phSTOP && !(prev->ph->phflags & phFORTIS))
						p->prepause = 0;
				}
			}
			if((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20))
				p->prepause = 20;

			break;

		case phLIQUID:
		case phNASAL:
			p->amp = tr->stress_amps[0];  // unless changed later
			p->length = 256;  //  TEMPORARY
			min_drop = 0;
			
			if(p->newword)
			{
				if(prev->type==phLIQUID)
					p->prepause = 25;
				if(prev->type==phVOWEL)
				{
					if(!(p->ph->phflags & phNOPAUSE))
						p->prepause = 12;
				}
			}

			if(next->type==phVOWEL)
			{
				pre_sonorant = 1;
			}
			else
			{
				p->pitch2 = last_pitch;

				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
				{
					p->length = prev->length;
					
					if(p->type == phLIQUID)
					{
						p->length = speed1;
					}
	
					if(next->type == phVSTOP)
					{
						p->length = (p->length * 160)/100;
					}
					if(next->type == phVFRICATIVE)
					{
						p->length = (p->length * 120)/100;
					}
				}
				else
				{
					for(ix2=ix; ix2<n_phoneme_list; ix2++)
					{
						if(phoneme_list[ix2].type == phVOWEL)
						{
							p->pitch2 = phoneme_list[ix2].pitch2;
							break;
						}
					}
				}

				p->pitch1 = p->pitch2-16;
				if(p->pitch2 < 16)
				{
					p->pitch1 = 0;
				}
				p->env = PITCHfall;
				pre_voiced = 0;
			}
			break;

		case phVOWEL:
			min_drop = 0;
			next2 = &phoneme_list[ix+2];
			next3 = &phoneme_list[ix+3];

			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
				p->amp = tr->stress_amps[stress];

			if(emphasized)
				p->amp = 25;

			if(ix >= (n_phoneme_list-3))
			{
				// last phoneme of a clause, limit its amplitude
				if(p->amp > tr->langopts.param[LOPT_MAXAMP_EOC])
					p->amp = tr->langopts.param[LOPT_MAXAMP_EOC];
			}

			// is the last syllable of a word ?
			more_syllables=0;
			end_of_clause = 0;
			for(p2 = p+1; p2->newword== 0; p2++)
			{
				if((p2->type == phVOWEL) && !(p2->ph->phflags & phNONSYLLABIC))
					more_syllables++;

				if(p2->ph->code == phonPAUSE_CLAUSE)
					end_of_clause = 2;
			}
			if(p2->ph->code == phonPAUSE_CLAUSE)
				end_of_clause = 2;

			if((p2->newword & 2) && (more_syllables==0))
			{
				end_of_clause = 2;
			}

			// calc length modifier
			if((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE))
			{
				// if PAUSE_VSHORT is followed by a pause, then use that
				next = next2;
				next2 = next3;
				next3 = &phoneme_list[ix+4];
			}

			if(more_syllables==0)
			{
				len = tr->langopts.length_mods0[next2->ph->length_mod *10+ next->ph->length_mod];

				if((next->newword) && (tr->langopts.word_gap & 0x20))
				{
					// consider as a pause + first phoneme of the next word
					length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2;
				}
				else
					length_mod = len;
			}
			else
			{
				length_mod = tr->langopts.length_mods[next2->ph->length_mod *10+ next->ph->length_mod];

				if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
					length_mod -= 15;
			}

			if(more_syllables==0)
				length_mod *= speed1;
			else
			if(more_syllables==1)
				length_mod *= speed2;
			else
				length_mod *= speed3;

			length_mod = length_mod / 128;

			if(length_mod < 8)
				length_mod = 8;     // restrict how much lengths can be reduced

			if(stress >= 7)
			{
				// tonic syllable, include a constant component so it doesn't decrease directly with speed
				length_mod += tr->langopts.lengthen_tonic;
				if(emphasized)
					length_mod += (tr->langopts.lengthen_tonic/2);
			}
			else
			if(emphasized)
			{
				length_mod += tr->langopts.lengthen_tonic;
			}

			if((len = tr->stress_lengths[stress]) == 0)
				len = tr->stress_lengths[6];

			length_mod = length_mod * len;

			if(p->tone_ph != 0)
			{
				if((tone_mod = phoneme_tab[p->tone_ph]->std_length) > 0)
				{
					// a tone phoneme specifies a percentage change to the length
					length_mod = (length_mod * tone_mod) / 100;
				}
			}


			if((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN))
			{
				// this is the last syllable in the clause, lengthen it - more for short vowels
				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;
			}

			if(length_mod > tr->langopts.max_lengthmod*speed1)
			{
				//limit the vowel length adjustment for some languages
				length_mod = (tr->langopts.max_lengthmod*speed1);
			}

			length_mod = length_mod / 128;

if(p->type != phVOWEL)
{
	length_mod = 256;   // syllabic consonant
	min_drop = 16;
}
			p->length = length_mod;

			if(p->env >= (N_ENVELOPE_DATA-1))
			{
				fprintf(stderr,"espeak: Bad intonation data\n");
				p->env = 0;
			}

			// pre-vocalic part
			// set last-pitch
			env2 = p->env + 1;  // version for use with preceding semi-vowel

			if(p->tone_ph != 0)
			{
				InterpretPhoneme2(p->tone_ph, &phdata_tone);
				pitch_env = GetEnvelope(phdata_tone.pitch_env);
			}
			else
			{
				pitch_env = envelope_data[env2];
			}

			pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256;

			if(pre_sonorant || pre_voiced)
			{
				// set pitch for pre-vocalic part
				if(pitch_start == 255)
					last_pitch = pitch_start;    // pitch is not set

				if(pitch_start - last_pitch > 16)
					last_pitch = pitch_start - 16;

				prev->pitch1 = last_pitch;
				prev->pitch2 = pitch_start;
				if(last_pitch < pitch_start)
				{
					prev->env = PITCHrise;
					p->env = env2;
				}
				else
				{
					prev->env = PITCHfall;
				}

				prev->length = length_mod;

				prev->amp = p->amp;
				if((prev->type != phLIQUID) && (prev->amp > 18))
					prev->amp = 18;
			}

			// vowel & post-vocalic part
			next->synthflags &= ~SFLAG_SEQCONTINUE;
			if(next->type == phNASAL && next2->type != phVOWEL)
				next->synthflags |= SFLAG_SEQCONTINUE;
				
			if(next->type == phLIQUID)
			{
				next->synthflags |= SFLAG_SEQCONTINUE;
					
				if(next2->type == phVOWEL)
				{
					next->synthflags &= ~SFLAG_SEQCONTINUE;
				}

				if(next2->type != phVOWEL)
				{
					if(next->ph->mnemonic == ('/'*256+'r'))
					{
						next->synthflags &= ~SFLAG_SEQCONTINUE;
//						min_drop = 15;
					}
				}
			}

			if((min_drop > 0) && ((p->pitch2 - p->pitch1) < min_drop))
			{
				pitch1 = p->pitch2 - min_drop;
				if(pitch1 < 0)
					pitch1 = 0;
				p->pitch1 = pitch1;
			}

			last_pitch = p->pitch1 + ((p->pitch2-p->pitch1)*envelope_data[p->env][127])/256;
			pre_sonorant = 0;
			pre_voiced = 0;
			break;
		}
	}
}  //  end of CalcLengths