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