1 /***************************************************************************
2  *   Copyright (C) 2005 to 2011 by Jonathan Duddington                     *
3  *   email: jonsd@users.sourceforge.net                                    *
4  *                                                                         *
5  *   This program is free software; you can redistribute it and/or modify  *
6  *   it under the terms of the GNU General Public License as published by  *
7  *   the Free Software Foundation; either version 3 of the License, or     *
8  *   (at your option) any later version.                                   *
9  *                                                                         *
10  *   This program is distributed in the hope that it will be useful,       *
11  *   but WITHOUT ANY WARRANTY; without even the implied warranty of        *
12  *   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the         *
13  *   GNU General Public License for more details.                          *
14  *                                                                         *
15  *   You should have received a copy of the GNU General Public License     *
16  *   along with this program; if not, write see:                           *
17  *               <http://www.gnu.org/licenses/>.                           *
18  ***************************************************************************/
19 
20 #include "StdAfx.h"
21 
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <wctype.h>
25 
26 #include "speak_lib.h"
27 #include "speech.h"
28 #include "phoneme.h"
29 #include "synthesize.h"
30 #include "voice.h"
31 #include "translate.h"
32 
33 extern int GetAmplitude(void);
34 extern void DoSonicSpeed(int value);
35 extern int saved_parameters[];
36 
37 
38 // convert from words-per-minute to internal speed factor
39 // Use this to calibrate speed for wpm 80-350
40 static unsigned char speed_lookup[] = {
41  255, 255, 255, 255, 255,   // 80
42  253, 249, 245, 242, 238,   // 85
43  235, 232, 228, 225, 222,   // 90
44  218, 216, 213, 210, 207,   // 95
45  204, 201, 198, 196, 193,   // 100
46  191, 188, 186, 183, 181,   // 105
47  179, 176, 174, 172, 169,   // 110
48  168, 165, 163, 161, 159,   // 115
49  158, 155, 153, 152, 150,   // 120
50  148, 146, 145, 143, 141,   // 125
51  139, 137, 136, 135, 133,   // 130
52  131, 130, 129, 127, 126,   // 135
53  124, 123, 122, 120, 119,   // 140
54  118, 117, 115, 114, 113,   // 145
55  112, 111, 110, 109, 107,   // 150
56  106, 105, 104, 103, 102,   // 155
57  101, 100,  99,  98,  97,   // 160
58   96,  95,  94,  93,  92,   // 165
59   91,  90,  89,  89,  88,   // 170
60   87,  86,  85,  84,  83,   // 175
61   82,  82,  81,  80,  80,   // 180
62   79,  78,  77,  76,  76,   // 185
63   75,  75,  74,  73,  72,   // 190
64   71,  71,  70,  69,  69,   // 195
65   68,  67,  67,  66,  66,   // 200
66   65,  64,  64,  63,  62,   // 205
67   62,  61,  61,  60,  59,   // 210
68   59,  58,  58,  57,  57,   // 215
69   56,  56,  55,  54,  54,   // 220
70   53,  53,  52,  52,  52,   // 225
71   51,  50,  50,  49,  49,   // 230
72   48,  48,  47,  47,  46,   // 235
73   46,  46,  45,  45,  44,   // 240
74   44,  44,  43,  43,  42,   // 245
75   41,  40,  40,  40,  39,   // 250
76   39,  39,  38,  38,  38,   // 255
77   37,  37,  37,  36,  36,   // 260
78   35,  35,  35,  35,  34,   // 265
79   34,  34,  33,  33,  33,   // 270
80   32,  32,  31,  31,  31,   // 275
81   30,  30,  30,  29,  29,   // 280
82   29,  29,  28,  28,  27,   // 285
83   27,  27,  27,  26,  26,   // 290
84   26,  26,  25,  25,  25,   // 295
85   24,  24,  24,  24,  23,   // 300
86   23,  23,  23,  22,  22,   // 305
87   22,  21,  21,  21,  21,   // 310
88   20,  20,  20,  20,  19,   // 315
89   19,  19,  18,  18,  17,   // 320
90   17,  17,  16,  16,  16,   // 325
91   16,  16,  16,  15,  15,   // 330
92   15,  15,  14,  14,  14,   // 335
93   13,  13,  13,  12,  12,   // 340
94   12,  12,  11,  11,  11,   // 345
95   11,  10,  10,  10,   9,   // 350
96    9,   9,   8,   8,   8,   // 355
97 };
98 
99 
100 // speed_factor1 adjustments for speeds 350 to 374: pauses
101 static unsigned char pause_factor_350[] = {
102 22,22,22,22,22,22,22,21,21,21,  // 350
103 21,20,20,19,19,18,17,16,15,15,  // 360
104 15,15,15,15,15};                // 370
105 
106 // wav_factor adjustments for speeds 350 to 450
107 // Use this to calibrate speed for wpm 350-450
108 static unsigned char wav_factor_350[] = {
109  120, 121, 120, 119, 119,   // 350
110  118, 118, 117, 116, 116,   // 355
111  115, 114, 113, 112, 112,   // 360
112  111, 111, 110, 109, 108,   // 365
113  107, 106, 106, 104, 103,   // 370
114  103, 102, 102, 102, 101,   // 375
115  101,  99,  98,  98,  97,   // 380
116   96,  96,  95,  94,  93,   // 385
117   91,  90,  91,  90,  89,   // 390
118   88,  86,  85,  86,  85,   // 395
119   85,  84,  82,  81,  80,   // 400
120   79,  77,  78,  78,  76,   // 405
121   77,  75,  75,  74,  73,   // 410
122   71,  72,  70,  69,  69,   // 415
123   69,  67,  65,  64,  63,   // 420
124   63,  63,  61,  61,  59,   // 425
125   59,  59,  58,  56,  57,   // 430
126   58,  56,  54,  53,  52,   // 435
127   52,  53,  52,  52,  50,   // 440
128   48,  47,  47,  45,  46,   // 445
129   45};   // 450
130 
131 static int speed1 = 130;
132 static int speed2 = 121;
133 static int speed3 = 118;
134 
135 
136 
137 //#define TEST_SPEED
138 
139 #ifdef INCLUDE_SONIC
140 
SetSpeed(int control)141 void SetSpeed(int control)
142 {//=======================
143 	int x;
144 	int s1;
145 	int wpm;
146 	int wpm2;
147 	int wpm_value;
148 	double sonic;
149 
150 	speed.loud_consonants = 0;
151 	speed.min_sample_len = 450;
152 	speed.lenmod_factor = 110;   // controls the effect of FRFLAG_LEN_MOD reduce length change
153 	speed.lenmod2_factor = 100;
154 	speed.min_pause = 5;
155 
156 	wpm = embedded_value[EMBED_S];
157 	if(control == 2)
158 		wpm = embedded_value[EMBED_S2];
159 
160 	wpm_value = wpm;
161 
162 	if(voice->speed_percent > 0)
163 	{
164 		wpm = (wpm * voice->speed_percent)/100;
165 	}
166 
167 	if(control & 2)
168 	{
169 		DoSonicSpeed(1 * 1024);
170 	}
171 	if((wpm_value > 450) || ((wpm_value > speed.fast_settings[0]) && (wpm > 350)))
172 	{
173 		wpm2 = wpm;
174 		wpm = 175;
175 
176 		// set special eSpeak speed parameters for Sonic use
177 		// The eSpeak output will be speeded up by at least x2
178 		x = 73;
179 		if(control & 1)
180 		{
181 			speed1 = (x * voice->speedf1)/256;
182 			speed2 = (x * voice->speedf2)/256;
183 			speed3 = (x * voice->speedf3)/256;
184 		}
185 		if(control & 2)
186 		{
187 			sonic = ((double)wpm2)/wpm;
188 			DoSonicSpeed((int)(sonic * 1024));
189 			speed.pause_factor = 85;
190 			speed.clause_pause_factor = 80;
191 			speed.min_pause = 22;
192 			speed.min_sample_len = 450*2;
193 			speed.wav_factor = 211;
194 			speed.lenmod_factor = 210;
195 			speed.lenmod2_factor = 170;
196 		}
197 		return;
198 	}
199 
200 
201 #ifdef TEST_SPEED
202 	if(wpm > 1000)
203 	{
204 		// TESTING
205 //		test = wpm / 1000;
206 		wpm = wpm % 1000;
207 	}
208 #endif
209 
210 	if(wpm > 450)
211 		wpm = 450;
212 
213 	if(wpm > 360)
214 	{
215 		speed.loud_consonants = (wpm - 360) / 8;
216 	}
217 
218 	wpm2 = wpm;
219 	if(wpm > 359) wpm2 = 359;
220 	if(wpm < 80) wpm2 = 80;
221 	x = speed_lookup[wpm2-80];
222 
223 	if(wpm >= 380)
224 		x = 7;
225 	if(wpm >= 400)
226 		x = 6;
227 
228 	if(control & 1)
229 	{
230 		// set speed factors for different syllable positions within a word
231 		// these are used in CalcLengths()
232 		speed1 = (x * voice->speedf1)/256;
233 		speed2 = (x * voice->speedf2)/256;
234 		speed3 = (x * voice->speedf3)/256;
235 
236 		if(x <= 7)
237 		{
238 			speed1 = x;
239 			speed2 = speed3 = x - 1;
240 		}
241 	}
242 
243 	if(control & 2)
244 	{
245 		// these are used in synthesis file
246 
247 		if(wpm > 350)
248 		{
249 			speed.lenmod_factor = 85 - (wpm - 350) / 3;
250 			speed.lenmod2_factor = 60 - (wpm - 350) / 8;
251 		}
252 		else
253 		if(wpm > 250)
254 		{
255 			speed.lenmod_factor = 110 - (wpm - 250)/4;
256 			speed.lenmod2_factor = 110 - (wpm - 250)/2;
257 		}
258 
259 		s1 = (x * voice->speedf1)/256;
260 
261 		if(wpm >= 170)
262 			speed.wav_factor = 110 + (150*s1)/128;  // reduced speed adjustment, used for playing recorded sounds
263 		else
264 			speed.wav_factor = 128 + (128*s1)/130;  // = 215 at 170 wpm
265 
266 		if(wpm >= 350)
267 		{
268 			speed.wav_factor = wav_factor_350[wpm-350];
269 		}
270 
271 		if(wpm >= 390)
272 		{
273 			speed.min_sample_len = 450 - (wpm - 400)/2;
274 			if(wpm > 440)
275 				speed.min_sample_len = 420 - (wpm - 440);
276 		}
277 
278 // adjust for different sample rates
279 speed.min_sample_len = (speed.min_sample_len * samplerate_native) / 22050;
280 
281 		speed.pause_factor = (256 * s1)/115;      // full speed adjustment, used for pause length
282 		speed.clause_pause_factor = 0;
283 
284 		if(wpm > 430)
285 		{
286 			speed.pause_factor = 12;
287 //			speed.clause_pause_factor = 15;
288 		}
289 		else
290 		if(wpm > 400)
291 		{
292 			speed.pause_factor = 13;
293 //			speed.clause_pause_factor = 15;
294 		}
295 		else
296 		if(wpm > 374)
297 		{
298 			speed.pause_factor = 14;
299 		}
300 		else
301 		if(wpm > 350)
302 		{
303 			speed.pause_factor = pause_factor_350[wpm - 350];
304 		}
305 
306 		if(speed.clause_pause_factor == 0)
307 		{
308 			// restrict the reduction of pauses between clauses
309 			if((speed.clause_pause_factor = speed.pause_factor) < 16)
310 				speed.clause_pause_factor = 16;
311 		}
312 	}
313 
314 #ifdef TEST_SPEED
315 //if(control==3)
316 printf("%3d: speedf %d %d %d   pause=%d %d   wav=%d  lenmod=%d %d\n",wpm,speed1,speed2,speed3, speed.pause_factor,speed.clause_pause_factor, speed.wav_factor,speed.lenmod_factor,speed.lenmod2_factor);
317 #endif
318 }  //  end of SetSpeed
319 
320 #else  // not using sonic speed-up
321 
SetSpeed(int control)322 void SetSpeed(int control)
323 {//=======================
324 // This is the earlier version of SetSpeed() before sonic speed-up was added
325 	int x;
326 	int s1;
327 	int wpm;
328 	int wpm2;
329 
330 	speed.loud_consonants = 0;
331 	speed.min_sample_len = 450;
332 	speed.lenmod_factor = 110;   // controls the effect of FRFLAG_LEN_MOD reduce length change
333 	speed.lenmod2_factor = 100;
334 
335 	wpm = embedded_value[EMBED_S];
336 	if(control == 2)
337 		wpm = embedded_value[EMBED_S2];
338 
339 #ifdef TEST_SPEED
340 	if(wpm > 1000)
341 	{
342 		// TESTING
343 		test = wpm / 1000;
344 		wpm = wpm % 1000;
345 	}
346 #endif
347 
348 	if(voice->speed_percent > 0)
349 	{
350 		wpm = (wpm * voice->speed_percent)/100;
351 	}
352 	if(wpm > 450)
353 		wpm = 450;
354 
355 	if(wpm > 360)
356 	{
357 		speed.loud_consonants = (wpm - 360) / 8;
358 	}
359 
360 	wpm2 = wpm;
361 	if(wpm > 359) wpm2 = 359;
362 	if(wpm < 80) wpm2 = 80;
363 	x = speed_lookup[wpm2-80];
364 
365 	if(wpm >= 380)
366 		x = 7;
367 	if(wpm >= 400)
368 		x = 6;
369 
370 	if(control & 1)
371 	{
372 		// set speed factors for different syllable positions within a word
373 		// these are used in CalcLengths()
374 		speed1 = (x * voice->speedf1)/256;
375 		speed2 = (x * voice->speedf2)/256;
376 		speed3 = (x * voice->speedf3)/256;
377 
378 		if(x <= 7)
379 		{
380 			speed1 = x;
381 			speed2 = speed3 = x - 1;
382 		}
383 	}
384 
385 	if(control & 2)
386 	{
387 		// these are used in synthesis file
388 
389 		if(wpm > 350)
390 		{
391 			speed.lenmod_factor = 85 - (wpm - 350) / 3;
392 			speed.lenmod2_factor = 60 - (wpm - 350) / 8;
393 		}
394 		else
395 		if(wpm > 250)
396 		{
397 			speed.lenmod_factor = 110 - (wpm - 250)/4;
398 			speed.lenmod2_factor = 110 - (wpm - 250)/2;
399 		}
400 
401 		s1 = (x * voice->speedf1)/256;
402 
403 		if(wpm >= 170)
404 			speed.wav_factor = 110 + (150*s1)/128;  // reduced speed adjustment, used for playing recorded sounds
405 		else
406 			speed.wav_factor = 128 + (128*s1)/130;  // = 215 at 170 wpm
407 
408 		if(wpm >= 350)
409 		{
410 			speed.wav_factor = wav_factor_350[wpm-350];
411 		}
412 
413 		if(wpm >= 390)
414 		{
415 			speed.min_sample_len = 450 - (wpm - 400)/2;
416 			if(wpm > 440)
417 				speed.min_sample_len = 420 - (wpm - 440);
418 		}
419 
420 		speed.pause_factor = (256 * s1)/115;      // full speed adjustment, used for pause length
421 		speed.clause_pause_factor = 0;
422 
423 		if(wpm > 430)
424 		{
425 			speed.pause_factor = 12;
426 //			speed.clause_pause_factor = 15;
427 		}
428 		else
429 		if(wpm > 400)
430 		{
431 			speed.pause_factor = 13;
432 //			speed.clause_pause_factor = 15;
433 		}
434 		else
435 		if(wpm > 374)
436 		{
437 			speed.pause_factor = 14;
438 		}
439 		else
440 		if(wpm > 350)
441 		{
442 			speed.pause_factor = pause_factor_350[wpm - 350];
443 		}
444 
445 		if(speed.clause_pause_factor == 0)
446 		{
447 			// restrict the reduction of pauses between clauses
448 			if((speed.clause_pause_factor = speed.pause_factor) < 16)
449 				speed.clause_pause_factor = 16;
450 		}
451 	}
452 
453 #ifdef TEST_SPEED
454 //if(control==3)
455 printf("%3d: speedf %d %d %d   pause=%d %d   wav=%d  lenmod=%d %d\n",wpm,speed1,speed2,speed3, speed.pause_factor,speed.clause_pause_factor, speed.wav_factor,speed.lenmod_factor,speed.lenmod2_factor);
456 #endif
457 }  //  end of SetSpeed
458 
459 #endif   // of INCLUDE_SONIC
460 
461 
462 #ifdef deleted
SetAmplitude(int amp)463 void SetAmplitude(int amp)
464 {//=======================
465 	static unsigned char amplitude_factor[] = {0,5,6,7,9,11,14,17,21,26, 32, 38,44,50,56,63,70,77,84,91,100 };
466 
467 	if((amp >= 0) && (amp <= 20))
468 	{
469 		option_amplitude = (amplitude_factor[amp] * 480)/256;
470 	}
471 }
472 #endif
473 
474 
475 
SetParameter(int parameter,int value,int relative)476 void SetParameter(int parameter, int value, int relative)
477 {//======================================================
478 // parameter: reset-all, amp, pitch, speed, linelength, expression, capitals, number grouping
479 // relative 0=absolute  1=relative
480 
481 	int new_value = value;
482 	int default_value;
483 
484 	if(relative)
485 	{
486 		if(parameter < 5)
487 		{
488 			default_value = param_defaults[parameter];
489 			new_value = default_value + (default_value * value)/100;
490 		}
491 	}
492 	param_stack[0].parameter[parameter] = new_value;
493 	saved_parameters[parameter] = new_value;
494 
495 	switch(parameter)
496 	{
497 	case espeakRATE:
498 		embedded_value[EMBED_S] = new_value;
499 		embedded_value[EMBED_S2] = new_value;
500 		SetSpeed(3);
501 		break;
502 
503 	case espeakVOLUME:
504 		embedded_value[EMBED_A] = new_value;
505 		GetAmplitude();
506 		break;
507 
508 	case espeakPITCH:
509 		if(new_value > 99) new_value = 99;
510 		if(new_value < 0) new_value = 0;
511 		embedded_value[EMBED_P] = new_value;
512 		break;
513 
514 	case espeakRANGE:
515 		if(new_value > 99) new_value = 99;
516 		embedded_value[EMBED_R] = new_value;
517 		break;
518 
519 	case espeakLINELENGTH:
520 		option_linelength = new_value;
521 		break;
522 
523 	case espeakWORDGAP:
524 		option_wordgap = new_value;
525 		break;
526 
527 	case espeakINTONATION:
528 		if((new_value & 0xff) != 0)
529 			translator->langopts.intonation_group = new_value & 0xff;
530 		option_tone_flags = new_value;
531 		break;
532 
533 	default:
534 		break;
535 	}
536 }  // end of SetParameter
537 
538 
539 
DoEmbedded2(int * embix)540 static void DoEmbedded2(int *embix)
541 {//================================
542 	// There were embedded commands in the text at this point
543 
544 	unsigned int word;
545 
546 	do {
547 		word = embedded_list[(*embix)++];
548 
549 		if((word & 0x1f) == EMBED_S)
550 		{
551 			// speed
552 			SetEmbedded(word & 0x7f, word >> 8);   // adjusts embedded_value[EMBED_S]
553 			SetSpeed(1);
554 		}
555 	} while((word & 0x80) == 0);
556 }
557 
558 
CalcLengths(Translator * tr)559 void CalcLengths(Translator *tr)
560 {//==============================
561 	int ix;
562 	int ix2;
563 	PHONEME_LIST *prev;
564 	PHONEME_LIST *next;
565 	PHONEME_LIST *next2;
566 	PHONEME_LIST *next3;
567 	PHONEME_LIST *p;
568 	PHONEME_LIST *p2;
569 
570 	int  stress;
571 	int  type;
572 	static int  more_syllables=0;
573 	int  pre_sonorant=0;
574 	int  pre_voiced=0;
575 	int  last_pitch = 0;
576 	int  pitch_start;
577 	int  length_mod;
578 	int  next2type;
579 	int  len;
580 	int  env2;
581 	int  end_of_clause;
582 	int  embedded_ix = 0;
583 	int  min_drop;
584 	int  pitch1;
585 	int emphasized;
586 	int  tone_mod;
587 	unsigned char *pitch_env=NULL;
588 	PHONEME_DATA phdata_tone;
589 
590 	for(ix=1; ix<n_phoneme_list; ix++)
591 	{
592 		prev = &phoneme_list[ix-1];
593 		p = &phoneme_list[ix];
594 		stress = p->stresslevel & 0x7;
595 		emphasized = p->stresslevel & 0x8;
596 
597 		next = &phoneme_list[ix+1];
598 
599 		if(p->synthflags & SFLAG_EMBEDDED)
600 		{
601 			DoEmbedded2(&embedded_ix);
602 		}
603 
604 		type = p->type;
605 		if(p->synthflags & SFLAG_SYLLABLE)
606 			type = phVOWEL;
607 
608 		switch(type)
609 		{
610 		case phPAUSE:
611 			last_pitch = 0;
612 			break;
613 
614 		case phSTOP:
615 			last_pitch = 0;
616 			if(prev->type == phFRICATIVE)
617 				p->prepause = 25;
618 			else
619 			if((more_syllables > 0) || (stress < 4))
620 				p->prepause = 48;
621 			else
622 				p->prepause = 60;
623 
624 			if(prev->type == phSTOP)
625 				p->prepause = 60;
626 
627 			if((tr->langopts.word_gap & 0x10) && (p->newword))
628 				p->prepause = 60;
629 
630 			if(p->ph->phflags & phLENGTHENSTOP)
631 				p->prepause += 30;
632 
633 			if(p->synthflags & SFLAG_LENGTHEN)
634 				p->prepause += tr->langopts.long_stop;
635 			break;
636 
637 		case phVFRICATIVE:
638 		case phFRICATIVE:
639 			if(p->newword)
640 			{
641 				if((prev->type == phVOWEL) && (p->ph->phflags & phNOPAUSE))
642 				{
643 				}
644 				else
645 				{
646 					p->prepause = 15;
647 				}
648 			}
649 
650 			if(next->type==phPAUSE && prev->type==phNASAL && !(p->ph->phflags&phFORTIS))
651 				p->prepause = 25;
652 
653 			if(prev->ph->phflags & phBRKAFTER)
654 				p->prepause = 30;
655 
656 			if((tr->langopts.word_gap & 0x10) && (p->newword))
657 				p->prepause = 30;
658 
659 			if((p->ph->phflags & phSIBILANT) && next->type==phSTOP && !next->newword)
660 			{
661 				if(prev->type == phVOWEL)
662 					p->length = 200;      // ?? should do this if it's from a prefix
663 				else
664 					p->length = 150;
665 			}
666 			else
667 				p->length = 256;
668 
669 			if(type == phVFRICATIVE)
670 			{
671 				if(next->type==phVOWEL)
672 				{
673 					pre_voiced = 1;
674 				}
675 				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
676 				{
677 					p->length = (255 + prev->length)/2;
678 				}
679 			}
680 			break;
681 
682 		case phVSTOP:
683 			if(prev->type==phVFRICATIVE || prev->type==phFRICATIVE || (prev->ph->phflags & phSIBILANT) || (prev->type == phLIQUID))
684 				p->prepause = 30;
685 
686 			if(next->type==phVOWEL || next->type==phLIQUID)
687 			{
688 				if((next->type==phVOWEL) || !next->newword)
689 					pre_voiced = 1;
690 
691 				p->prepause = 40;
692 
693 				if(prev->type == phVOWEL)
694 				{
695 					p->prepause = 0;   // use murmur instead to link from the preceding vowel
696 				}
697 				else
698 				if(prev->type == phPAUSE)
699 				{
700 					// reduce by the length of the preceding pause
701 					if(prev->length < p->prepause)
702 						p->prepause -= prev->length;
703 					else
704 						p->prepause = 0;
705 				}
706 				else
707 				if(p->newword==0)
708 				{
709 					if(prev->type==phLIQUID)
710 						p->prepause = 20;
711 					if(prev->type==phNASAL)
712 						p->prepause = 12;
713 
714 					if(prev->type==phSTOP && !(prev->ph->phflags & phFORTIS))
715 						p->prepause = 0;
716 				}
717 			}
718 			if((tr->langopts.word_gap & 0x10) && (p->newword) && (p->prepause < 20))
719 				p->prepause = 20;
720 
721 			break;
722 
723 		case phLIQUID:
724 		case phNASAL:
725 			p->amp = tr->stress_amps[0];  // unless changed later
726 			p->length = 256;  //  TEMPORARY
727 			min_drop = 0;
728 
729 			if(p->newword)
730 			{
731 				if(prev->type==phLIQUID)
732 					p->prepause = 25;
733 				if(prev->type==phVOWEL)
734 				{
735 					if(!(p->ph->phflags & phNOPAUSE))
736 						p->prepause = 12;
737 				}
738 			}
739 
740 			if(next->type==phVOWEL)
741 			{
742 				pre_sonorant = 1;
743 			}
744 			else
745 			{
746 				p->pitch2 = last_pitch;
747 
748 				if((prev->type==phVOWEL) || (prev->type == phLIQUID))
749 				{
750 					p->length = prev->length;
751 
752 					if(p->type == phLIQUID)
753 					{
754 						p->length = speed1;
755 					}
756 
757 					if(next->type == phVSTOP)
758 					{
759 						p->length = (p->length * 160)/100;
760 					}
761 					if(next->type == phVFRICATIVE)
762 					{
763 						p->length = (p->length * 120)/100;
764 					}
765 				}
766 				else
767 				{
768 					for(ix2=ix; ix2<n_phoneme_list; ix2++)
769 					{
770 						if(phoneme_list[ix2].type == phVOWEL)
771 						{
772 							p->pitch2 = phoneme_list[ix2].pitch2;
773 							break;
774 						}
775 					}
776 				}
777 
778 				p->pitch1 = p->pitch2-16;
779 				if(p->pitch2 < 16)
780 				{
781 					p->pitch1 = 0;
782 				}
783 				p->env = PITCHfall;
784 				pre_voiced = 0;
785 			}
786 			break;
787 
788 		case phVOWEL:
789 			min_drop = 0;
790 			next2 = &phoneme_list[ix+2];
791 			next3 = &phoneme_list[ix+3];
792 
793 			if(stress > 7) stress = 7;
794 
795 if(stress <= 1)
796 {
797   stress = stress ^ 1;  // swap diminished and unstressed (until we swap stress_amps,stress_lengths in tr_languages)
798 }
799 			if(pre_sonorant)
800 				p->amp = tr->stress_amps[stress]-1;
801 			else
802 				p->amp = tr->stress_amps[stress];
803 
804 			if(emphasized)
805 				p->amp = 25;
806 
807 			if(ix >= (n_phoneme_list-3))
808 			{
809 				// last phoneme of a clause, limit its amplitude
810 				if(p->amp > tr->langopts.param[LOPT_MAXAMP_EOC])
811 					p->amp = tr->langopts.param[LOPT_MAXAMP_EOC];
812 			}
813 
814 			// is the last syllable of a word ?
815 			more_syllables=0;
816 			end_of_clause = 0;
817 			for(p2 = p+1; p2->newword== 0; p2++)
818 			{
819 				if((p2->type == phVOWEL) && !(p2->ph->phflags & phNONSYLLABIC))
820 					more_syllables++;
821 
822 				if(p2->ph->code == phonPAUSE_CLAUSE)
823 					end_of_clause = 2;
824 			}
825 			if(p2->ph->code == phonPAUSE_CLAUSE)
826 				end_of_clause = 2;
827 
828 			if((p2->newword & 2) && (more_syllables==0))
829 			{
830 				end_of_clause = 2;
831 			}
832 
833 			// calc length modifier
834 			if((next->ph->code == phonPAUSE_VSHORT) && (next2->type == phPAUSE))
835 			{
836 				// if PAUSE_VSHORT is followed by a pause, then use that
837 				next = next2;
838 				next2 = next3;
839 				next3 = &phoneme_list[ix+4];
840 			}
841 
842 			next2type = next2->ph->length_mod;
843 			if(more_syllables==0)
844 			{
845 				if(next->newword || next2->newword)
846 				{
847 					// don't use 2nd phoneme over a word boundary, unless it's a pause
848 					if(next2type != 1)
849 						next2type = 0;
850 				}
851 
852 				len = tr->langopts.length_mods0[next2type *10+ next->ph->length_mod];
853 
854 				if((next->newword) && (tr->langopts.word_gap & 0x20))
855 				{
856 					// consider as a pause + first phoneme of the next word
857 					length_mod = (len + tr->langopts.length_mods0[next->ph->length_mod *10+ 1])/2;
858 				}
859 				else
860 					length_mod = len;
861 			}
862 			else
863 			{
864 				length_mod = tr->langopts.length_mods[next2type *10+ next->ph->length_mod];
865 
866 				if((next->type == phNASAL) && (next2->type == phSTOP || next2->type == phVSTOP) && (next3->ph->phflags & phFORTIS))
867 					length_mod -= 15;
868 			}
869 
870 			if(more_syllables==0)
871 				length_mod *= speed1;
872 			else
873 			if(more_syllables==1)
874 				length_mod *= speed2;
875 			else
876 				length_mod *= speed3;
877 
878 			length_mod = length_mod / 128;
879 
880 			if(length_mod < 8)
881 				length_mod = 8;     // restrict how much lengths can be reduced
882 
883 			if(stress >= 7)
884 			{
885 				// tonic syllable, include a constant component so it doesn't decrease directly with speed
886 				length_mod += tr->langopts.lengthen_tonic;
887 				if(emphasized)
888 					length_mod += (tr->langopts.lengthen_tonic/2);
889 			}
890 			else
891 			if(emphasized)
892 			{
893 				length_mod += tr->langopts.lengthen_tonic;
894 			}
895 
896 			if((len = tr->stress_lengths[stress]) == 0)
897 				len = tr->stress_lengths[6];
898 
899 			length_mod = length_mod * len;
900 
901 			if(p->tone_ph != 0)
902 			{
903 				if((tone_mod = phoneme_tab[p->tone_ph]->std_length) > 0)
904 				{
905 					// a tone phoneme specifies a percentage change to the length
906 					length_mod = (length_mod * tone_mod) / 100;
907 				}
908 			}
909 
910 
911 			if((end_of_clause == 2) && !(tr->langopts.stress_flags & S_NO_EOC_LENGTHEN))
912 			{
913 				// this is the last syllable in the clause, lengthen it - more for short vowels
914 				len = (p->ph->std_length * 2);
915 				if(tr->langopts.stress_flags & S_EO_CLAUSE1)
916 					len=200;  // don't lengthen short vowels more than long vowels at end-of-clause
917 				length_mod = length_mod * (256 + (280 - len)/3)/256;
918 			}
919 
920 			if(length_mod > tr->langopts.max_lengthmod*speed1)
921 			{
922 				//limit the vowel length adjustment for some languages
923 				length_mod = (tr->langopts.max_lengthmod*speed1);
924 			}
925 
926 			length_mod = length_mod / 128;
927 
928 if(p->type != phVOWEL)
929 {
930 	length_mod = 256;   // syllabic consonant
931 	min_drop = 16;
932 }
933 			p->length = length_mod;
934 
935 			if(p->env >= (N_ENVELOPE_DATA-1))
936 			{
937 				fprintf(stderr,"espeak: Bad intonation data\n");
938 				p->env = 0;
939 			}
940 
941 			// pre-vocalic part
942 			// set last-pitch
943 			env2 = p->env + 1;  // version for use with preceding semi-vowel
944 
945 			if(p->tone_ph != 0)
946 			{
947 				InterpretPhoneme2(p->tone_ph, &phdata_tone);
948 				pitch_env = GetEnvelope(phdata_tone.pitch_env);
949 			}
950 			else
951 			{
952 				pitch_env = envelope_data[env2];
953 			}
954 
955 			pitch_start = p->pitch1 + ((p->pitch2-p->pitch1)*pitch_env[0])/256;
956 
957 			if(pre_sonorant || pre_voiced)
958 			{
959 				// set pitch for pre-vocalic part
960 				if(pitch_start == 255)
961 					last_pitch = pitch_start;    // pitch is not set
962 
963 				if(pitch_start - last_pitch > 16)
964 					last_pitch = pitch_start - 16;
965 
966 				prev->pitch1 = last_pitch;
967 				prev->pitch2 = pitch_start;
968 				if(last_pitch < pitch_start)
969 				{
970 					prev->env = PITCHrise;
971 					p->env = env2;
972 				}
973 				else
974 				{
975 					prev->env = PITCHfall;
976 				}
977 
978 				prev->length = length_mod;
979 
980 				prev->amp = p->amp;
981 				if((prev->type != phLIQUID) && (prev->amp > 18))
982 					prev->amp = 18;
983 			}
984 
985 			// vowel & post-vocalic part
986 			next->synthflags &= ~SFLAG_SEQCONTINUE;
987 			if(next->type == phNASAL && next2->type != phVOWEL)
988 				next->synthflags |= SFLAG_SEQCONTINUE;
989 
990 			if(next->type == phLIQUID)
991 			{
992 				next->synthflags |= SFLAG_SEQCONTINUE;
993 
994 				if(next2->type == phVOWEL)
995 				{
996 					next->synthflags &= ~SFLAG_SEQCONTINUE;
997 				}
998 
999 				if(next2->type != phVOWEL)
1000 				{
1001 					if(next->ph->mnemonic == ('/'*256+'r'))
1002 					{
1003 						next->synthflags &= ~SFLAG_SEQCONTINUE;
1004 //						min_drop = 15;
1005 					}
1006 				}
1007 			}
1008 
1009 			if((min_drop > 0) && ((p->pitch2 - p->pitch1) < min_drop))
1010 			{
1011 				pitch1 = p->pitch2 - min_drop;
1012 				if(pitch1 < 0)
1013 					pitch1 = 0;
1014 				p->pitch1 = pitch1;
1015 			}
1016 
1017 			last_pitch = p->pitch1 + ((p->pitch2-p->pitch1)*envelope_data[p->env][127])/256;
1018 			pre_sonorant = 0;
1019 			pre_voiced = 0;
1020 			break;
1021 		}
1022 	}
1023 }  //  end of CalcLengths
1024 
1025