1 /***************************************************************************
2 * Copyright (C) 2005 to 2013 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, see: *
17 * <http://www.gnu.org/licenses/>. *
18 ***************************************************************************/
19
20
21 #include "StdAfx.h"
22
23 #include <stdio.h>
24 #include <stdlib.h>
25 #include <ctype.h>
26 #include <wctype.h>
27 #include <string.h>
28
29
30 #include "speak_lib.h"
31 #include "speech.h"
32 #include "phoneme.h"
33 #include "synthesize.h"
34 #include "voice.h"
35 #include "translate.h"
36 #include "wave.h"
37
38 const char *version_string = "1.48.03 04.Mar.14";
39 const int version_phdata = 0x014801;
40
41 int option_device_number = -1;
42 FILE *f_logespeak = NULL;
43 int logging_type;
44
45 // copy the current phoneme table into here
46 int n_phoneme_tab;
47 int current_phoneme_table;
48 PHONEME_TAB *phoneme_tab[N_PHONEME_TAB];
49 unsigned char phoneme_tab_flags[N_PHONEME_TAB]; // bit 0: not inherited
50
51 USHORT *phoneme_index=NULL;
52 char *phondata_ptr=NULL;
53 unsigned char *wavefile_data=NULL;
54 static unsigned char *phoneme_tab_data = NULL;
55
56 int n_phoneme_tables;
57 PHONEME_TAB_LIST phoneme_tab_list[N_PHONEME_TABS];
58 int phoneme_tab_number = 0;
59
60 int wavefile_ix; // a wavefile to play along with the synthesis
61 int wavefile_amp;
62 int wavefile_ix2;
63 int wavefile_amp2;
64
65 int seq_len_adjust;
66 int vowel_transition[4];
67 int vowel_transition0;
68 int vowel_transition1;
69
70 int FormantTransition2(frameref_t *seq, int *n_frames, unsigned int data1, unsigned int data2, PHONEME_TAB *other_ph, int which);
71
72
73
ReadPhFile(void * ptr,const char * fname,int * size)74 static char *ReadPhFile(void *ptr, const char *fname, int *size)
75 {//=============================================================
76 FILE *f_in;
77 char *p;
78 unsigned int length;
79 char buf[sizeof(path_home)+40];
80
81 sprintf(buf,"%s%c%s",path_home,PATHSEP,fname);
82 length = GetFileLength(buf);
83
84 if((f_in = fopen(buf,"rb")) == NULL)
85 {
86 fprintf(stderr,"Can't read data file: '%s'\n",buf);
87 return(NULL);
88 }
89
90 if(ptr != NULL)
91 Free(ptr);
92
93 if((p = Alloc(length)) == NULL)
94 {
95 fclose(f_in);
96 return(NULL);
97 }
98 if(fread(p,1,length,f_in) != length)
99 {
100 fclose(f_in);
101 return(NULL);
102 }
103
104 fclose(f_in);
105 if(size != NULL)
106 *size = length;
107 return(p);
108 } // end of ReadPhFile
109
110
LoadPhData(int * srate)111 int LoadPhData(int *srate)
112 {//========================
113 int ix;
114 int n_phonemes;
115 int version;
116 int result = 1;
117 int length;
118 int rate;
119 unsigned char *p;
120 int *pw;
121
122 if((phoneme_tab_data = (unsigned char *)ReadPhFile((void *)(phoneme_tab_data),"phontab",NULL)) == NULL)
123 return(-1);
124 if((phoneme_index = (USHORT *)ReadPhFile((void *)(phoneme_index),"phonindex",NULL)) == NULL)
125 return(-1);
126 if((phondata_ptr = ReadPhFile((void *)(phondata_ptr),"phondata",NULL)) == NULL)
127 return(-1);
128 if((tunes = (TUNE *)ReadPhFile((void *)(tunes),"intonations",&length)) == NULL)
129 return(-1);
130 wavefile_data = (unsigned char *)phondata_ptr;
131 n_tunes = length / sizeof(TUNE);
132
133 // read the version number and sample rate from the first 8 bytes of phondata
134 version = 0; // bytes 0-3, version number
135 rate = 0; // bytes 4-7, sample rate
136 for(ix=0; ix<4; ix++)
137 {
138 version += (wavefile_data[ix] << (ix*8));
139 rate += (wavefile_data[ix+4] << (ix*8));
140 }
141
142 if(version != version_phdata)
143 {
144 result = version;
145 }
146
147 // set up phoneme tables
148 p = phoneme_tab_data;
149 n_phoneme_tables = p[0];
150 p+=4;
151
152 for(ix=0; ix<n_phoneme_tables; ix++)
153 {
154 n_phonemes = p[0];
155 phoneme_tab_list[ix].n_phonemes = p[0];
156 phoneme_tab_list[ix].includes = p[1];
157 pw = (int *)p;
158 phoneme_tab_list[ix].equivalence_tables = Reverse4Bytes(pw[1]);
159 p += 8;
160 memcpy(phoneme_tab_list[ix].name,p,N_PHONEME_TAB_NAME);
161 p += N_PHONEME_TAB_NAME;
162 phoneme_tab_list[ix].phoneme_tab_ptr = (PHONEME_TAB *)p;
163 p += (n_phonemes * sizeof(PHONEME_TAB));
164 }
165
166 if(phoneme_tab_number >= n_phoneme_tables)
167 phoneme_tab_number = 0;
168
169 if(srate != NULL)
170 *srate = rate;
171 return(result);
172 } // end of LoadPhData
173
174
FreePhData(void)175 void FreePhData(void)
176 {//==================
177 Free(phoneme_tab_data);
178 Free(phoneme_index);
179 Free(phondata_ptr);
180 Free(tunes);
181 phoneme_tab_data=NULL;
182 phoneme_index=NULL;
183 phondata_ptr=NULL;
184 tunes=NULL;
185 }
186
187
PhonemeCode(unsigned int mnem)188 int PhonemeCode(unsigned int mnem)
189 {//===============================
190 int ix;
191
192 for(ix=0; ix<n_phoneme_tab; ix++)
193 {
194 if(phoneme_tab[ix] == NULL)
195 continue;
196 if(phoneme_tab[ix]->mnemonic == mnem)
197 return(phoneme_tab[ix]->code);
198 }
199 return(0);
200 }
201
202
LookupPhonemeString(const char * string)203 int LookupPhonemeString(const char *string)
204 {//========================================
205 int ix;
206 unsigned char c;
207 unsigned int mnem;
208
209 // Pack up to 4 characters into a word
210 mnem = 0;
211 for(ix=0; ix<4; ix++)
212 {
213 if(string[ix]==0) break;
214 c = string[ix];
215 mnem |= (c << (ix*8));
216 }
217
218 return(PhonemeCode(mnem));
219 }
220
221
222
223
LookupSpect(PHONEME_TAB * this_ph,int which,FMT_PARAMS * fmt_params,int * n_frames,PHONEME_LIST * plist)224 frameref_t *LookupSpect(PHONEME_TAB *this_ph, int which, FMT_PARAMS *fmt_params, int *n_frames, PHONEME_LIST *plist)
225 {//===================================================================================================================
226 int ix;
227 int nf;
228 int nf1;
229 int seq_break;
230 frameref_t *frames;
231 int length1;
232 int length_std;
233 int length_factor;
234 SPECT_SEQ *seq, *seq2;
235 SPECT_SEQK *seqk, *seqk2;
236 frame_t *frame;
237 static frameref_t frames_buf[N_SEQ_FRAMES];
238
239 seq = (SPECT_SEQ *)(&phondata_ptr[fmt_params->fmt_addr]);
240 seqk = (SPECT_SEQK *)seq;
241 nf = seq->n_frames;
242
243
244 if(nf >= N_SEQ_FRAMES)
245 nf = N_SEQ_FRAMES - 1;
246
247 seq_len_adjust = fmt_params->fmt2_lenadj + fmt_params->fmt_length;
248 seq_break = 0;
249
250 for(ix=0; ix<nf; ix++)
251 {
252 if(seq->frame[0].frflags & FRFLAG_KLATT)
253 frame = &seqk->frame[ix];
254 else
255 frame = (frame_t *)&seq->frame[ix];
256 frames_buf[ix].frame = frame;
257 frames_buf[ix].frflags = frame->frflags;
258 frames_buf[ix].length = frame->length;
259 if(frame->frflags & FRFLAG_VOWEL_CENTRE)
260 seq_break = ix;
261 }
262
263 frames = &frames_buf[0];
264 if(seq_break > 0)
265 {
266 if(which==1)
267 {
268 nf = seq_break + 1;
269 }
270 else
271 {
272 frames = &frames_buf[seq_break]; // body of vowel, skip past initial frames
273 nf -= seq_break;
274 }
275 }
276
277 // do we need to modify a frame for blending with a consonant?
278 if((this_ph->type == phVOWEL) && (fmt_params->fmt2_addr == 0) && (fmt_params->use_vowelin))
279 {
280 seq_len_adjust += FormantTransition2(frames,&nf,fmt_params->transition0,fmt_params->transition1,NULL,which);
281 }
282
283 length1 = 0;
284 nf1 = nf - 1;
285 for(ix=0; ix<nf1; ix++)
286 length1 += frames[ix].length;
287
288 if(fmt_params->fmt2_addr != 0)
289 {
290 // a secondary reference has been returned, which is not a wavefile
291 // add these spectra to the main sequence
292 seq2 = (SPECT_SEQ *)(&phondata_ptr[fmt_params->fmt2_addr]);
293 seqk2 = (SPECT_SEQK *)seq2;
294
295 // first frame of the addition just sets the length of the last frame of the main seq
296 nf--;
297 for(ix=0; ix<seq2->n_frames; ix++)
298 {
299 if(seq2->frame[0].frflags & FRFLAG_KLATT)
300 frame = &seqk2->frame[ix];
301 else
302 frame = (frame_t *)&seq2->frame[ix];
303
304 frames[nf].length = frame->length;
305 if(ix > 0)
306 {
307 frames[nf].frame = frame;
308 frames[nf].frflags = frame->frflags;
309 }
310 nf++;
311 }
312 wavefile_ix = 0;
313 }
314
315 if(length1 > 0)
316 {
317 if(which==2)
318 {
319 // adjust the length of the main part to match the standard length specified for the vowel
320 // less the front part of the vowel and any added suffix
321
322 length_std = fmt_params->std_length + seq_len_adjust - 45;
323 if(length_std < 10)
324 length_std = 10;
325 if(plist->synthflags & SFLAG_LENGTHEN)
326 length_std += (phoneme_tab[phonLENGTHEN]->std_length * 2); // phoneme was followed by an extra : symbol
327
328 // can adjust vowel length for stressed syllables here
329
330
331 length_factor = (length_std * 256)/ length1;
332
333 for(ix=0; ix<nf1; ix++)
334 {
335 frames[ix].length = (frames[ix].length * length_factor)/256;
336 }
337 }
338 else
339 {
340 if(which == 1)
341 {
342 // front of a vowel
343 if(fmt_params->fmt_control == 1)
344 {
345 // This is the default start of a vowel.
346 // Allow very short vowels to have shorter front parts
347 if(fmt_params->std_length < 130)
348 frames[0].length = (frames[0].length * fmt_params->std_length)/130;
349 }
350 }
351 else
352 {
353 //not a vowel
354 if(fmt_params->std_length > 0)
355 {
356 seq_len_adjust += (fmt_params->std_length - length1);
357 }
358 }
359
360 if(seq_len_adjust != 0)
361 {
362 length_factor = ((length1 + seq_len_adjust) * 256)/length1;
363 for(ix=0; ix<nf1; ix++)
364 {
365 frames[ix].length = (frames[ix].length * length_factor)/256;
366 }
367 }
368 }
369 }
370
371 *n_frames = nf;
372 return(frames);
373 } // end of LookupSpect
374
375
376
GetEnvelope(int index)377 unsigned char *GetEnvelope(int index)
378 {//==================================
379 if(index==0)
380 {
381 fprintf(stderr,"espeak: No envelope\n");
382 return(envelope_data[0]); // not found, use a default envelope
383 }
384 return((unsigned char *)&phondata_ptr[index]);
385 }
386
387
SetUpPhonemeTable(int number,int recursing)388 static void SetUpPhonemeTable(int number, int recursing)
389 {//=====================================================
390 int ix;
391 int includes;
392 int ph_code;
393 PHONEME_TAB *phtab;
394
395 if(recursing==0)
396 {
397 memset(phoneme_tab_flags,0,sizeof(phoneme_tab_flags));
398 }
399
400 if((includes = phoneme_tab_list[number].includes) > 0)
401 {
402 // recursively include base phoneme tables
403 SetUpPhonemeTable(includes-1,1);
404 }
405
406 // now add the phonemes from this table
407 phtab = phoneme_tab_list[number].phoneme_tab_ptr;
408 for(ix=0; ix<phoneme_tab_list[number].n_phonemes; ix++)
409 {
410 ph_code = phtab[ix].code;
411 phoneme_tab[ph_code] = &phtab[ix];
412 if(ph_code > n_phoneme_tab)
413 n_phoneme_tab = ph_code;
414
415 if(recursing == 0)
416 phoneme_tab_flags[ph_code] |= 1; // not inherited
417 }
418 } // end of SetUpPhonemeTable
419
420
SelectPhonemeTable(int number)421 void SelectPhonemeTable(int number)
422 {//================================
423 n_phoneme_tab = 0;
424 SetUpPhonemeTable(number,0); // recursively for included phoneme tables
425 n_phoneme_tab++;
426 current_phoneme_table = number;
427 } // end of SelectPhonemeTable
428
429
LookupPhonemeTable(const char * name)430 int LookupPhonemeTable(const char *name)
431 {//=====================================
432 int ix;
433
434 for(ix=0; ix<n_phoneme_tables; ix++)
435 {
436 if(strcmp(name,phoneme_tab_list[ix].name)==0)
437 {
438 phoneme_tab_number = ix;
439 break;
440 }
441 }
442 if(ix == n_phoneme_tables)
443 return(-1);
444
445 return(ix);
446 }
447
448
SelectPhonemeTableName(const char * name)449 int SelectPhonemeTableName(const char *name)
450 {//=========================================
451 // Look up a phoneme set by name, and select it if it exists
452 // Returns the phoneme table number
453 int ix;
454
455 if((ix = LookupPhonemeTable(name)) == -1)
456 return(-1);
457
458 SelectPhonemeTable(ix);
459 return(ix);
460 } // end of DelectPhonemeTableName
461
462
463
464
LoadConfig(void)465 void LoadConfig(void)
466 {//==================
467 // Load configuration file, if one exists
468 char buf[sizeof(path_home)+10];
469 FILE *f;
470 int ix;
471 char c1;
472 char *p;
473 char string[200];
474
475 logging_type = 0;
476
477 for(ix=0; ix<N_SOUNDICON_SLOTS; ix++)
478 {
479 soundicon_tab[ix].filename = NULL;
480 soundicon_tab[ix].data = NULL;
481 }
482
483 sprintf(buf,"%s%c%s",path_home,PATHSEP,"config");
484 if((f = fopen(buf,"r"))==NULL)
485 {
486 return;
487 }
488
489 while(fgets(buf,sizeof(buf),f)!=NULL)
490 {
491 if(buf[0] == '/') continue;
492
493 if(memcmp(buf,"log",3)==0)
494 {
495 if(sscanf(&buf[4],"%d %s",&logging_type,string)==2)
496 f_logespeak = fopen(string,"w");
497 }
498 else
499 if(memcmp(buf,"tone",4)==0)
500 {
501 ReadTonePoints(&buf[5],tone_points);
502 }
503 else
504 if(memcmp(buf,"pa_device",9)==0)
505 {
506 sscanf(&buf[10],"%d",&option_device_number);
507 }
508 else
509 if(memcmp(buf,"soundicon",9)==0)
510 {
511 ix = sscanf(&buf[10],"_%c %s",&c1,string);
512 if(ix==2)
513 {
514 soundicon_tab[n_soundicon_tab].name = c1;
515 p = Alloc(strlen(string)+1);
516 strcpy(p,string);
517 soundicon_tab[n_soundicon_tab].filename = p;
518 soundicon_tab[n_soundicon_tab++].length = 0;
519 }
520 }
521 }
522 fclose(f);
523 } // end of LoadConfig
524
525
526
527
528 PHONEME_DATA this_ph_data;
529
530
InvalidInstn(PHONEME_TAB * ph,int instn)531 static void InvalidInstn(PHONEME_TAB *ph, int instn)
532 {//====================================================
533 fprintf(stderr,"Invalid instruction %.4x for phoneme '%s'\n", instn, WordToString(ph->mnemonic));
534 }
535
536
StressCondition(Translator * tr,PHONEME_LIST * plist,int condition,int control)537 static bool StressCondition(Translator *tr, PHONEME_LIST *plist, int condition, int control)
538 {//========================================================================================
539 // condition:
540 // 0 if diminished, 1 if unstressed, 2 if not stressed, 3 if stressed, 4 if max stress
541
542 int stress_level;
543 PHONEME_LIST *pl;
544 static int condition_level[4] = {1,2,4,15};
545
546 if(phoneme_tab[plist[0].phcode]->type == phVOWEL)
547 {
548 pl = plist;
549 }
550 else
551 {
552 // consonant, get stress from the following vowel
553 if(phoneme_tab[plist[1].phcode]->type == phVOWEL)
554 {
555 pl = &plist[1];
556 }
557 else
558 return(false); // no stress elevel for this consonant
559 }
560
561 stress_level = pl->stresslevel & 0xf;
562
563 if(tr != NULL)
564 {
565 if((control & 1) && (plist->synthflags & SFLAG_DICTIONARY) && ((tr->langopts.param[LOPT_REDUCE] & 1)==0))
566 {
567 // change phoneme. Don't change phonemes which are given for the word in the dictionary.
568 return(false);
569 }
570
571 if((tr->langopts.param[LOPT_REDUCE] & 0x2) && (stress_level >= pl->wordstress))
572 {
573 // treat the most stressed syllable in an unstressed word as stressed
574 stress_level = 4;
575 }
576 }
577
578 if(condition == 4)
579 {
580 return(stress_level >= pl->wordstress);
581 }
582
583 if(condition == 3)
584 {
585 // if stressed
586 if(stress_level > 3)
587 return(true);
588 }
589 else
590 {
591 if(stress_level < condition_level[condition])
592 return(true);
593 }
594 return(false);
595
596 } // end of StressCondition
597
598
CountVowelPosition(PHONEME_LIST * plist)599 static int CountVowelPosition(PHONEME_LIST *plist)
600 {//===============================================
601 int count = 0;
602
603 for(;;)
604 {
605 if(plist->ph->type == phVOWEL)
606 count++;
607 if(plist->sourceix != 0)
608 break;
609 plist--;
610 }
611 return(count);
612 } // end of CoundVowelPosition
613
614
InterpretCondition(Translator * tr,int control,PHONEME_LIST * plist,USHORT * p_prog,WORD_PH_DATA * worddata)615 static bool InterpretCondition(Translator *tr, int control, PHONEME_LIST *plist, USHORT *p_prog, WORD_PH_DATA *worddata)
616 {//========================================================================================================================
617 int which;
618 int ix;
619 unsigned int data;
620 int instn;
621 int instn2;
622 int count;
623 PHONEME_TAB *ph;
624 PHONEME_LIST *plist_this;
625
626 // instruction: 2xxx, 3xxx
627
628 // bits 8-10 = 0 to 5, which phoneme, =6 the 'which' information is in the next instruction.
629 // bit 11 = 0, bits 0-7 are a phoneme code
630 // bit 11 = 1, bits 5-7 type of data, bits 0-4 data value
631
632 // bits 8-10 = 7, other conditions
633
634 instn = (*p_prog) & 0xfff;
635 data = instn & 0xff;
636 instn2 = instn >> 8;
637
638 if(instn2 < 14)
639 {
640 plist_this = plist;
641 which = (instn2) % 7;
642
643 if(which==6)
644 {
645 // the 'which' code is in the next instruction
646 p_prog++;
647 which = (*p_prog);
648 }
649
650 if(which==4)
651 {
652 // nextPhW not word boundary
653 if(plist[1].sourceix)
654 return(false);
655 }
656 if(which==5)
657 {
658 // prevPhW, not word boundary
659 if(plist[0].sourceix)
660 return(false);
661 }
662 if(which==6)
663 {
664 // next2PhW, not word boundary
665 if(plist[1].sourceix || plist[2].sourceix)
666 return(false);
667 }
668
669
670 switch(which)
671 {
672 case 0: // prevPh
673 case 5: // prevPhW
674 plist--;
675 break;
676
677 case 1: // thisPh
678 break;
679
680 case 2: // nextPh
681 case 4: // nextPhW
682 plist++;
683 break;
684
685 case 3: // next2Ph
686 case 6: // next2PhW
687 plist += 2;
688 break;
689
690 case 7:
691 // nextVowel, not word boundary
692 for(which=1;;which++)
693 {
694 if(plist[which].sourceix)
695 return(false);
696 if(phoneme_tab[plist[which].phcode]->type == phVOWEL)
697 {
698 plist = &plist[which];
699 break;
700 }
701 }
702 break;
703
704 case 8: // prevVowel in this word
705 if((worddata==NULL) || (worddata->prev_vowel.ph == NULL))
706 return(false); // no previous vowel
707 plist = &(worddata->prev_vowel);
708 break;
709
710 case 9: // next3PhW
711 for(ix=1; ix<=3; ix++)
712 {
713 if(plist[ix].sourceix)
714 return(false);
715 }
716 plist = &plist[3];
717 break;
718
719 case 10: // prev2PhW
720 if((plist[0].sourceix) || (plist[-1].sourceix))
721 return(false);
722 plist-=2;
723 break;
724 }
725
726 if((which == 0) || (which == 5))
727 {
728 if(plist->phcode == 1)
729 {
730 // This is a NULL phoneme, a phoneme has been deleted so look at the previous phoneme
731 plist--;
732 }
733 }
734
735 if(control & 0x100)
736 {
737 // "change phonemes" pass
738 plist->ph = phoneme_tab[plist->phcode];
739 }
740 ph = plist->ph;
741
742 if(instn2 < 7)
743 {
744 // 'data' is a phoneme number
745 if((phoneme_tab[data]->mnemonic == ph->mnemonic) == true)
746 return(true);
747 if((which == 0) && (ph->type == phVOWEL))
748 return(data == ph->end_type); // prevPh() match on end_type
749 return(data == ph->start_type); // thisPh() or nextPh(), match on start_type
750 }
751
752 data = instn & 0x1f;
753
754 switch(instn & 0xe0)
755 {
756 case 0x00:
757 // phoneme type, vowel, nasal, fricative, etc
758 return(ph->type == data);
759 break;
760
761 case 0x20:
762 // place of articulation
763 return(((ph->phflags >> 16) & 0xf) == data);
764 break;
765
766 case 0x40:
767 // is a bit set in phoneme flags
768 return((ph->phflags & (1 << data)) != 0);
769 break;
770
771 case 0x80:
772 switch(data)
773 {
774 case 0:
775 case 1:
776 case 2:
777 case 3:
778 case 4:
779 return(StressCondition(tr, plist, data, 0));
780
781 case 5: // isBreak, Either pause phoneme, or (stop/vstop/vfric not followed by vowel or (liquid in same word))
782 return((ph->type == phPAUSE) || (plist_this->synthflags & SFLAG_NEXT_PAUSE));
783
784 case 6: // isWordStart
785 return(plist->sourceix != 0);
786
787 case 7: // notWordStart
788 return(plist->sourceix == 0);
789
790 case 8: // isWordEnd
791 return(plist[1].sourceix || (plist[1].ph->type == phPAUSE));
792 break;
793
794 case 9: // isAfterStress
795 if(plist->sourceix != 0)
796 return(false);
797 do {
798 plist--;
799 if((plist->stresslevel & 0xf) >= 4)
800 return(true);
801
802 } while (plist->sourceix == 0);
803 break;
804
805 case 10: // isNotVowel
806 return(ph->type != phVOWEL);
807
808 case 11: // isFinalVowel
809 for(;;)
810 {
811 plist++;
812 plist->ph = phoneme_tab[plist->phcode];
813 if(plist->sourceix != 0)
814 return(true); // start of next word, without finding another vowel
815 if(plist->ph->type == phVOWEL)
816 return(false);
817 }
818 break;
819
820 case 12: // isVoiced
821 return((ph->type == phVOWEL) || (ph->type == phLIQUID) || (ph->phflags & phVOICED));
822
823 case 13: // isFirstVowel
824 return(CountVowelPosition(plist)==1);
825
826 case 14: // isSecondVowel
827 return(CountVowelPosition(plist)==2);
828
829 case 15: // isSeqFlag1
830 // is this preceded by a sequence if 1 or more vowels which have 'flag1' ? (lang=hi)
831 if(plist->sourceix != 0)
832 return(false); // this is the first phoneme in the word, so no.
833
834 count = 0;
835 for(;;)
836 {
837 plist--;
838 if(plist->ph->type == phVOWEL)
839 {
840 if(plist->ph->phflags & phFLAG1)
841 count++;
842 else
843 break; // stop when we find a vowel without flag1
844 }
845 if(plist->sourceix != 0)
846 break;
847 }
848 return(count > 0);
849
850 case 0x10: // isTranslationGiven
851 return((plist->synthflags & SFLAG_DICTIONARY) != 0);
852 }
853 break;
854
855 }
856 return(false);
857 }
858 else
859 if(instn2 == 0xf)
860 {
861 // Other conditions
862 switch(data)
863 {
864 case 1: // PreVoicing
865 return(control & 1);
866 case 2: // KlattSynth
867 return(voice->klattv[0] != 0);
868 case 3: // MbrolaSynth
869 return(mbrola_name[0] != 0);
870 }
871 }
872 return(false);
873 } // end of InterpretCondition
874
875
SwitchOnVowelType(PHONEME_LIST * plist,PHONEME_DATA * phdata,USHORT ** p_prog,int instn_type)876 static void SwitchOnVowelType(PHONEME_LIST *plist, PHONEME_DATA *phdata, USHORT **p_prog, int instn_type)
877 {//========================================================================================================
878 USHORT *prog;
879 int voweltype;
880 signed char x;
881
882 if(instn_type == 2)
883 {
884 phdata->pd_control |= pd_FORNEXTPH;
885 voweltype = plist[1].ph->start_type; // SwitchNextVowelType
886 }
887 else
888 {
889 voweltype = plist[-1].ph->end_type; // SwitchPrevVowelType
890 }
891
892 voweltype -= phonVOWELTYPES;
893 if((voweltype >= 0) && (voweltype < 6))
894 {
895 prog = *p_prog + voweltype*2;
896 phdata->sound_addr[instn_type] = (((prog[1] & 0xf) << 16) + prog[2]) * 4;
897 x = (prog[1] >> 4) & 0xff;
898 phdata->sound_param[instn_type] = x; // sign extend
899 }
900
901 *p_prog += 12;
902 } // end of SwitchVowelType
903
904
NumInstnWords(USHORT * prog)905 int NumInstnWords(USHORT *prog)
906 {//============================
907 int instn;
908 int instn2;
909 int instn_type;
910 int n;
911 int type2;
912 static const char n_words[16] = {0,1,0,0,1,1,0,1,1,2,4,0,0,0,0,0};
913
914 instn = *prog;
915 instn_type = instn >> 12;
916 if((n = n_words[instn_type]) > 0)
917 return(n);
918
919 switch(instn_type)
920 {
921 case 0:
922 if(((instn & 0xf00) >> 8) == i_IPA_NAME)
923 {
924 n = ((instn & 0xff) + 1) / 2;
925 return(n+1);
926 }
927 return(1);;
928
929 case 6:
930 type2 = (instn & 0xf00) >> 9;
931 if((type2 == 5) || (type2 == 6))
932 return(12); // switch on vowel type
933 return(1);
934
935 case 2:
936 case 3:
937 // a condition, check for a 2-word instruction
938 if(((n = instn & 0x0f00) == 0x600) || (n == 0x0d00))
939 return(2);
940 return(1);
941
942 default:
943 // instn_type 11 to 15, 2 words
944 instn2 = prog[2];
945 if((instn2 >> 12) == 0xf)
946 {
947 // This instruction is followed by addWav(), 2 more words
948 return(4);
949 }
950 if(instn2 == i_CONTINUE)
951 {
952 return(3);
953 }
954 return(2);
955 }
956 } // end of NumInstnWords
957
958
959
InterpretPhoneme(Translator * tr,int control,PHONEME_LIST * plist,PHONEME_DATA * phdata,WORD_PH_DATA * worddata)960 void InterpretPhoneme(Translator *tr, int control, PHONEME_LIST *plist, PHONEME_DATA *phdata, WORD_PH_DATA *worddata)
961 {//===================================================================================================================
962 // control:
963 //bit 0: PreVoicing
964 //bit 8: change phonemes
965 PHONEME_TAB *ph;
966 USHORT *prog;
967 USHORT instn;
968 int instn2;
969 int or_flag;
970 bool truth;
971 bool truth2;
972 int data;
973 int end_flag;
974 int ix;
975 signed char param_sc;
976
977 #define N_RETURN 10
978 int n_return=0;
979 USHORT *return_addr[N_RETURN]; // return address stack
980
981 ph = plist->ph;
982
983 if((worddata != NULL) && (plist->sourceix))
984 {
985 // start of a word, reset word data
986 worddata->prev_vowel.ph = NULL;
987 }
988
989 memset(phdata, 0, sizeof(PHONEME_DATA));
990 phdata->pd_param[i_SET_LENGTH] = ph->std_length;
991 phdata->pd_param[i_LENGTH_MOD] = ph->length_mod;
992
993 if(ph->program == 0)
994 {
995 return;
996 }
997
998 end_flag = 0;
999
1000 for(prog = &phoneme_index[ph->program]; end_flag != 1; prog++)
1001 {
1002 instn = *prog;
1003 instn2 = (instn >> 8) & 0xf;
1004 or_flag = 0;
1005
1006 switch(instn >> 12)
1007 {
1008 case 0: // 0xxx
1009 data = instn & 0xff;
1010
1011 if(instn2 == 0)
1012 {
1013 // instructions with no operand
1014 switch(data)
1015 {
1016 case i_RETURN:
1017 end_flag = 1;
1018 break;
1019
1020 case i_CONTINUE:
1021 break;
1022
1023 default:
1024 InvalidInstn(ph,instn);
1025 break;
1026 }
1027 }
1028 else
1029 if(instn2 == i_APPEND_IFNEXTVOWEL)
1030 {
1031 if(phoneme_tab[plist[1].phcode]->type == phVOWEL)
1032 phdata->pd_param[i_APPEND_PHONEME] = data;
1033 }
1034 else
1035 if(instn2 == i_ADD_LENGTH)
1036 {
1037 if(data & 0x80)
1038 {
1039 // a negative value, do sign extension
1040 data = -(0x100 - data);
1041 }
1042 phdata->pd_param[i_SET_LENGTH] += data;
1043 }
1044 else
1045 if(instn2 == i_IPA_NAME)
1046 {
1047 // followed by utf-8 characters, 2 per instn word
1048 for(ix=0; (ix < data) && (ix < 16); ix += 2)
1049 {
1050 prog++;
1051 phdata->ipa_string[ix] = prog[0] >> 8;
1052 phdata->ipa_string[ix+1] = prog[0] & 0xff;
1053 }
1054 phdata->ipa_string[ix] = 0;
1055 }
1056 else
1057 if(instn2 < N_PHONEME_DATA_PARAM)
1058 {
1059 if(instn2 == i_CHANGE_PHONEME2)
1060 {
1061 phdata->pd_param[i_CHANGE_PHONEME] = data; // also set ChangePhoneme
1062 }
1063 phdata->pd_param[instn2] = data;
1064 if((instn2 == i_CHANGE_PHONEME) && (control & 0x100))
1065 {
1066 // found ChangePhoneme() in PhonemeList mode, exit
1067 end_flag = 1;
1068 }
1069 }
1070 else
1071 {
1072 InvalidInstn(ph,instn);
1073 }
1074 break;
1075
1076 case 1:
1077 if(tr == NULL)
1078 break; // ignore if in synthesis stage
1079
1080 if(instn2 < 8)
1081 {
1082 // ChangeIf
1083 if(StressCondition(tr, plist, instn2 & 7, 1) == true)
1084 {
1085 phdata->pd_param[i_CHANGE_PHONEME] = instn & 0xff;
1086 end_flag = 1; // change phoneme, exit
1087 }
1088 }
1089 break;
1090
1091 case 2:
1092 case 3:
1093 // conditions
1094 or_flag = 0;
1095 truth = true;
1096 while((instn & 0xe000) == 0x2000)
1097 {
1098 // process a sequence of conditions, using boolean accumulator
1099 truth2 = InterpretCondition(tr, control, plist, prog, worddata);
1100 prog += NumInstnWords(prog);
1101 if(*prog == i_NOT)
1102 {
1103 truth2 = truth2 ^ 1;
1104 prog++;
1105 }
1106
1107 if(or_flag)
1108 truth = truth || truth2;
1109 else
1110 truth = truth && truth2;
1111 or_flag = instn & 0x1000;
1112 instn = *prog;
1113 }
1114
1115 if(truth == false)
1116 {
1117 if((instn & 0xf800) == i_JUMP_FALSE)
1118 {
1119 prog += instn & 0xff;
1120 }
1121 else
1122 {
1123 // instruction after a condition is not JUMP_FALSE, so skip the instruction.
1124 prog += NumInstnWords(prog);
1125 if((prog[0] & 0xfe00) == 0x6000)
1126 prog++; // and skip ELSE jump
1127 }
1128 }
1129 prog--;
1130 break;
1131
1132 case 6:
1133 // JUMP
1134 switch(instn2 >> 1)
1135 {
1136 case 0:
1137 prog += (instn & 0xff) - 1;
1138 break;
1139
1140 case 4:
1141 // conditional jumps should have been processed in the Condition section
1142 break;
1143
1144 case 5: // NexttVowelStarts
1145 SwitchOnVowelType(plist, phdata, &prog, 2);
1146 break;
1147
1148 case 6: // PrevVowelTypeEndings
1149 SwitchOnVowelType(plist, phdata, &prog, 3);
1150 break;
1151 }
1152 break;
1153
1154 case 9:
1155 data = ((instn & 0xf) << 16) + prog[1];
1156 prog++;
1157 switch(instn2)
1158 {
1159 case 1:
1160 // call a procedure or another phoneme
1161 if(n_return < N_RETURN)
1162 {
1163 return_addr[n_return++] = prog;
1164 prog = &phoneme_index[data] - 1;
1165 }
1166 break;
1167
1168 case 2:
1169 // pitch envelope
1170 phdata->pitch_env = data;
1171 break;
1172
1173 case 3:
1174 // amplitude envelope
1175 phdata->amp_env = data;
1176 break;
1177 }
1178 break;
1179
1180 case 10: // Vowelin, Vowelout
1181 if(instn2 == 1)
1182 ix = 0;
1183 else
1184 ix = 2;
1185
1186 phdata->vowel_transition[ix] = ((prog[0] & 0xff) << 16) + prog[1];
1187 phdata->vowel_transition[ix+1] = (prog[2] << 16) + prog[3];
1188 prog += 3;
1189 break;
1190
1191 case 11: // FMT
1192 case 12: // WAV
1193 case 13: // VowelStart
1194 case 14: // VowelEnd
1195 case 15: // addWav
1196 instn2 = (instn >> 12) - 11;
1197 phdata->sound_addr[instn2] = ((instn & 0xf) << 18) + (prog[1] << 2);
1198 param_sc = phdata->sound_param[instn2] = (instn >> 4) & 0xff;
1199 prog++;
1200
1201 if(prog[1] != i_CONTINUE)
1202 {
1203 if(instn2 < 2)
1204 {
1205 // FMT() and WAV() imply Return
1206 end_flag = 1;
1207 if((prog[1] >> 12) == 0xf)
1208 {
1209 // Return after the following addWav()
1210 end_flag = 2;
1211 }
1212 }
1213 else
1214 if(instn2 ==pd_ADDWAV)
1215 {
1216 // addWav(), return if previous instruction was FMT() or WAV()
1217 end_flag--;
1218 }
1219
1220 if((instn2 == pd_VWLSTART) || (instn2 == pd_VWLEND))
1221 {
1222 // VowelStart or VowelEnding.
1223 phdata->sound_param[instn2] = param_sc; // sign extend
1224 }
1225 }
1226 break;
1227
1228 default:
1229 InvalidInstn(ph,instn);
1230 break;
1231 }
1232
1233 if(ph->phflags & phSINGLE_INSTN)
1234 {
1235 end_flag = 1; // this phoneme has a one-instruction program, with an implicit Return
1236 }
1237
1238 if((end_flag == 1) && (n_return > 0))
1239 {
1240 // return from called procedure or phoneme
1241 end_flag = 0;
1242 prog = return_addr[--n_return];
1243 }
1244 }
1245
1246 if((worddata != NULL) && (plist->type == phVOWEL))
1247 {
1248 memcpy(&worddata->prev_vowel, &plist[0], sizeof(PHONEME_LIST));
1249 }
1250
1251 #ifdef _ESPEAKEDIT
1252 plist->std_length = phdata->pd_param[i_SET_LENGTH];
1253 if(phdata->sound_addr[0] != 0)
1254 {
1255 plist->phontab_addr = phdata->sound_addr[0]; // FMT address
1256 plist->sound_param = phdata->sound_param[0];
1257 }
1258 else
1259 {
1260 plist->phontab_addr = phdata->sound_addr[1]; // WAV address
1261 plist->sound_param = phdata->sound_param[1];
1262 }
1263 #endif
1264 } // end of InterpretPhoneme
1265
1266
InterpretPhoneme2(int phcode,PHONEME_DATA * phdata)1267 void InterpretPhoneme2(int phcode, PHONEME_DATA *phdata)
1268 {//=====================================================
1269 // Examine the program of a single isolated phoneme
1270 int ix;
1271 PHONEME_LIST plist[4];
1272 memset(plist, 0, sizeof(plist));
1273
1274 for(ix=0; ix<4; ix++)
1275 {
1276 plist[ix].phcode = phonPAUSE;
1277 plist[ix].ph = phoneme_tab[phonPAUSE];
1278 }
1279
1280 plist[1].phcode = phcode;
1281 plist[1].ph = phoneme_tab[phcode];
1282 plist[2].sourceix = 1;
1283
1284 InterpretPhoneme(NULL, 0, &plist[1], phdata, NULL);
1285 } // end of InterpretPhoneme2
1286