]> git.bts.cx Git - benzene.git/blob - third_party/soloud_speech/klatt.cpp
Initial version
[benzene.git] / third_party / soloud_speech / klatt.cpp
1 #include <math.h>
2 #include <stdlib.h>
3 #include "klatt.h"
4 #include "darray.h"
5 #include "resonator.h"
6
7 #ifndef PI
8 #define PI 3.1415926535897932384626433832795f
9 #endif
10
11 #ifndef NULL
12 #define NULL 0
13 #endif
14
15 class Interp
16 {
17 public:
18         float mSteady;
19         float mFixed;
20         char  mProportion;
21         char  mExtDelay;
22         char  mIntDelay;
23 };
24
25
26 enum Eparm_e
27 {
28   ELM_FN, ELM_F1, ELM_F2, ELM_F3, 
29   ELM_B1, ELM_B2, ELM_B3, ELM_AN, 
30   ELM_A1, ELM_A2, ELM_A3, ELM_A4, 
31   ELM_A5, ELM_A6, ELM_AB, ELM_AV, 
32   ELM_AVC, ELM_ASP, ELM_AF, 
33   ELM_COUNT
34 };
35  
36 class Element
37 {
38 public:
39           const char *mName; // unused
40           const char mRK;
41           const char mDU;
42           const char mUD;
43           unsigned char mFont; // unused
44           const char  *mDict; // unused
45           const char  *mIpa; // unused
46           int   mFeat; // only ELM_FEATURE_VWL
47           Interp mInterpolator[ELM_COUNT];
48  };
49
50 enum ELEMENT_FEATURES
51 {
52         ELM_FEATURE_ALV = 0x00000001,
53         ELM_FEATURE_APR = 0x00000002,
54         ELM_FEATURE_BCK = 0x00000004,
55         ELM_FEATURE_BLB = 0x00000008,
56         ELM_FEATURE_CNT = 0x00000010,
57         ELM_FEATURE_DNT = 0x00000020,
58         ELM_FEATURE_FNT = 0x00000040,
59         ELM_FEATURE_FRC = 0x00000080,
60         ELM_FEATURE_GLT = 0x00000100,
61         ELM_FEATURE_HGH = 0x00000200,
62         ELM_FEATURE_LAT = 0x00000400,
63         ELM_FEATURE_LBD = 0x00000800,
64         ELM_FEATURE_LBV = 0x00001000,
65         ELM_FEATURE_LMD = 0x00002000,
66         ELM_FEATURE_LOW = 0x00004000,
67         ELM_FEATURE_MDL = 0x00008000,
68         ELM_FEATURE_NAS = 0x00010000,
69         ELM_FEATURE_PAL = 0x00020000,
70         ELM_FEATURE_PLA = 0x00040000,
71         ELM_FEATURE_RND = 0x00080000,
72         ELM_FEATURE_RZD = 0x00100000,
73         ELM_FEATURE_SMH = 0x00200000,
74         ELM_FEATURE_STP = 0x00400000,
75         ELM_FEATURE_UMD = 0x00800000,
76         ELM_FEATURE_UNR = 0x01000000,
77         ELM_FEATURE_VCD = 0x02000000,
78         ELM_FEATURE_VEL = 0x04000000,
79         ELM_FEATURE_VLS = 0x08000000,
80         ELM_FEATURE_VWL = 0x10000000
81 };
82
83 enum ELEMENTS 
84 {
85         ELM_END = 0,    
86         ELM_Q,  ELM_P,  ELM_PY, ELM_PZ, ELM_T,  ELM_TY, 
87         ELM_TZ, ELM_K,  ELM_KY, ELM_KZ, ELM_B,  ELM_BY, ELM_BZ, 
88         ELM_D,  ELM_DY, ELM_DZ, ELM_G,  ELM_GY, ELM_GZ, ELM_M,  
89         ELM_N,  ELM_NG, ELM_F,  ELM_TH, ELM_S,  ELM_SH, ELM_X,
90         ELM_H,  ELM_V,  ELM_QQ, ELM_DH, ELM_DI, ELM_Z,  ELM_ZZ,
91         ELM_ZH, ELM_CH, ELM_CI, ELM_J,  ELM_JY, ELM_L,  ELM_LL,
92         ELM_RX, ELM_R,  ELM_W,  ELM_Y,  ELM_I,  ELM_E,  ELM_AA,
93         ELM_U,  ELM_O,  ELM_OO, ELM_A,  ELM_EE, ELM_ER, ELM_AR,
94         ELM_AW, ELM_UU, ELM_AI, ELM_IE, ELM_OI, ELM_OU, ELM_OV,
95         ELM_OA, ELM_IA, ELM_IB, ELM_AIR,ELM_OOR,ELM_OR
96 };
97
98 #define PHONEME_COUNT 53
99 #define AMP_ADJ 14
100 #define StressDur(e,s) (s,((e->mDU + e->mUD)/2))
101
102
103
104
105 class PhonemeToElements 
106 {
107 public:
108         int mKey;
109         char mData[8];
110 };
111
112 /* Order is important - 2 byte phonemes first, otherwise
113    the search function will fail*/
114 static PhonemeToElements phoneme_to_elements[PHONEME_COUNT] = 
115 {
116         /* mKey, count, 0-7 elements */
117 /* tS */ 0x5374, 2, ELM_CH, ELM_CI, 0, 0, 0, 0, 0,
118 /* dZ */ 0x5a64, 4, ELM_J, ELM_JY, ELM_QQ, ELM_JY, 0, 0, 0,
119 /* rr */ 0x7272, 3, ELM_R, ELM_QQ, ELM_R, 0, 0, 0, 0,
120 /* eI */ 0x4965, 2, ELM_AI, ELM_I, 0, 0, 0, 0, 0,
121 /* aI */ 0x4961, 2, ELM_IE, ELM_I, 0, 0, 0, 0, 0,
122 /* oI */ 0x496f, 2, ELM_OI, ELM_I, 0, 0, 0, 0, 0,
123 /* aU */ 0x5561, 2, ELM_OU, ELM_OV, 0, 0, 0, 0, 0,
124 /* @U */ 0x5540, 2, ELM_OA, ELM_OV, 0, 0, 0, 0, 0,
125 /* I@ */ 0x4049, 2, ELM_IA, ELM_IB, 0, 0, 0, 0, 0,
126 /* e@ */ 0x4065, 2, ELM_AIR, ELM_IB, 0, 0, 0, 0, 0,
127 /* U@ */ 0x4055, 2, ELM_OOR, ELM_IB, 0, 0, 0, 0, 0,
128 /* O@ */ 0x404f, 2, ELM_OR, ELM_IB, 0, 0, 0, 0, 0,
129 /* oU */ 0x556f, 2, ELM_OI, ELM_OV, 0, 0, 0, 0, 0,
130 /*    */ 0x0020, 1, ELM_Q, 0, 0, 0, 0, 0, 0,
131 /* p  */ 0x0070, 3, ELM_P, ELM_PY, ELM_PZ, 0, 0, 0, 0,
132 /* t  */ 0x0074, 3, ELM_T, ELM_TY, ELM_TZ, 0, 0, 0, 0,
133 /* k  */ 0x006b, 3, ELM_K, ELM_KY, ELM_KZ, 0, 0, 0, 0,
134 /* b  */ 0x0062, 3, ELM_B, ELM_BY, ELM_BZ, 0, 0, 0, 0,
135 /* d  */ 0x0064, 3, ELM_D, ELM_DY, ELM_DZ, 0, 0, 0, 0,
136 /* g  */ 0x0067, 3, ELM_G, ELM_GY, ELM_GZ, 0, 0, 0, 0,
137 /* m  */ 0x006d, 1, ELM_M, 0, 0, 0, 0, 0, 0,
138 /* n  */ 0x006e, 1, ELM_N, 0, 0, 0, 0, 0, 0,
139 /* N  */ 0x004e, 1, ELM_NG, 0, 0, 0, 0, 0, 0,
140 /* f  */ 0x0066, 1, ELM_F, 0, 0, 0, 0, 0, 0,
141 /* T  */ 0x0054, 1, ELM_TH, 0, 0, 0, 0, 0, 0,
142 /* s  */ 0x0073, 1, ELM_S, 0, 0, 0, 0, 0, 0,
143 /* S  */ 0x0053, 1, ELM_SH, 0, 0, 0, 0, 0, 0,
144 /* h  */ 0x0068, 1, ELM_H, 0, 0, 0, 0, 0, 0,
145 /* v  */ 0x0076, 3, ELM_V, ELM_QQ, ELM_V, 0, 0, 0, 0,
146 /* D  */ 0x0044, 3, ELM_DH, ELM_QQ, ELM_DI, 0, 0, 0, 0,
147 /* z  */ 0x007a, 3, ELM_Z, ELM_QQ, ELM_ZZ, 0, 0, 0, 0,
148 /* Z  */ 0x005a, 3, ELM_ZH, ELM_QQ, ELM_ZH, 0, 0, 0, 0,
149 /* l  */ 0x006c, 1, ELM_L, 0, 0, 0, 0, 0, 0,
150 /* r  */ 0x0072, 1, ELM_R, 0, 0, 0, 0, 0, 0,
151 /* R  */ 0x0052, 1, ELM_RX, 0, 0, 0, 0, 0, 0,
152 /* w  */ 0x0077, 1, ELM_W, 0, 0, 0, 0, 0, 0,
153 /* x  */ 0x0078, 1, ELM_X, 0, 0, 0, 0, 0, 0,
154 /* %  */ 0x0025, 1, ELM_QQ, 0, 0, 0, 0, 0, 0,
155 /* j  */ 0x006a, 1, ELM_Y, 0, 0, 0, 0, 0, 0,
156 /* I  */ 0x0049, 1, ELM_I, 0, 0, 0, 0, 0, 0,
157 /* e  */ 0x0065, 1, ELM_E, 0, 0, 0, 0, 0, 0,
158 /* &  */ 0x0026, 1, ELM_AA, 0, 0, 0, 0, 0, 0,
159 /* V  */ 0x0056, 1, ELM_U, 0, 0, 0, 0, 0, 0,
160 /* 0  */ 0x0030, 1, ELM_O, 0, 0, 0, 0, 0, 0,
161 /* U  */ 0x0055, 1, ELM_OO, 0, 0, 0, 0, 0, 0,
162 /* @  */ 0x0040, 1, ELM_A, 0, 0, 0, 0, 0, 0,
163 /* i  */ 0x0069, 1, ELM_EE, 0, 0, 0, 0, 0, 0,
164 /* 3  */ 0x0033, 1, ELM_ER, 0, 0, 0, 0, 0, 0,
165 /* A  */ 0x0041, 1, ELM_AR, 0, 0, 0, 0, 0, 0,
166 /* O  */ 0x004f, 1, ELM_AW, 0, 0, 0, 0, 0, 0,
167 /* u  */ 0x0075, 1, ELM_UU, 0, 0, 0, 0, 0, 0,
168 /* o  */ 0x006f, 1, ELM_OI, 0, 0, 0, 0, 0, 0,
169 /* .  */ 0x002e, 1, ELM_END,0, 0, 0, 0, 0, 0,
170 };
171
172 static Element gElement[] =
173 {
174 #include "Elements.def"
175 };
176
177 static short clip(float input)
178 {
179         int temp = (int)input;
180         /* clip on boundaries of 16-bit word */
181
182         if (temp < -32767)
183         {
184                 //assert?
185                 temp = -32767;
186         }
187         else
188         if (temp > 32767)
189         {
190                 //assert?
191                 temp = 32767;
192         }
193
194         return (short)(temp);
195 }
196
197 /* Convert from decibels to a linear scale factor */
198 static float DBtoLIN(int dB)
199 {
200         /*
201         * Convertion table, db to linear, 87 dB --> 32767
202         *                                 86 dB --> 29491 (1 dB down = 0.5**1/6)
203         *                                 ...
204         *                                 81 dB --> 16384 (6 dB down = 0.5)
205         *                                 ...
206         *                                  0 dB -->     0
207         *
208         * The just noticeable difference for a change in intensity of a vowel
209         *   is approximately 1 dB.  Thus all amplitudes are quantized to 1 dB
210         *   steps.
211         */
212
213         static const float amptable[88] =
214         {
215                 0.0, 0.0, 0.0, 0.0, 0.0,
216                 0.0, 0.0, 0.0, 0.0, 0.0,
217                 0.0, 0.0, 0.0, 6.0, 7.0,
218                 8.0, 9.0, 10.0, 11.0, 13.0,
219                 14.0, 16.0, 18.0, 20.0, 22.0,
220                 25.0, 28.0, 32.0, 35.0, 40.0,
221                 45.0, 51.0, 57.0, 64.0, 71.0,
222                 80.0, 90.0, 101.0, 114.0, 128.0,
223                 142.0, 159.0, 179.0, 202.0, 227.0,
224                 256.0, 284.0, 318.0, 359.0, 405.0,
225                 455.0, 512.0, 568.0, 638.0, 719.0,
226                 811.0, 911.0, 1024.0, 1137.0, 1276.0,
227                 1438.0, 1622.0, 1823.0, 2048.0, 2273.0,
228                 2552.0, 2875.0, 3244.0, 3645.0, 4096.0,
229                 4547.0, 5104.0, 5751.0, 6488.0, 7291.0,
230                 8192.0, 9093.0, 10207.0, 11502.0, 12976.0,
231                 14582.0, 16384.0, 18350.0, 20644.0, 23429.0,
232                 26214.0, 29491.0, 32767.0
233         };
234
235         // Check limits or argument (can be removed in final product)
236         if (dB < 0)
237         {
238                 dB = 0;
239         }
240         else
241         if (dB >= 88)
242         {
243                 dB = 87;
244         }
245
246         return amptable[dB] * 0.001f;
247 }
248
249
250
251 klatt_frame::klatt_frame() :
252         mF0FundamentalFreq(1330),       mVoicingAmpdb(60),                              mFormant1Freq(500),  
253         mFormant1Bandwidth(60),         mFormant2Freq(1500),                    mFormant2Bandwidth(90),
254         mFormant3Freq(2800),            mFormant3Bandwidth(150),                mFormant4Freq(3250), 
255         mFormant4Bandwidth(200),        mFormant5Freq(3700),                    mFormant5Bandwidth(200),  
256         mFormant6Freq(4990),            mFormant6Bandwidth(500),                mNasalZeroFreq(270),  
257         mNasalZeroBandwidth(100),       mNasalPoleFreq(270),                    mNasalPoleBandwidth(100), 
258         mAspirationAmpdb(0),            mNoSamplesInOpenPeriod(30),             mVoicingBreathiness(0),      
259         mVoicingSpectralTiltdb(10), mFricationAmpdb(0),                         mSkewnessOfAlternatePeriods(0),   
260         mFormant1Ampdb(0),                      mFormant1ParallelBandwidth(80), mFormant2Ampdb(0),      
261         mFormant2ParallelBandwidth(200), mFormant3Ampdb(0),                     mFormant3ParallelBandwidth(350),
262         mFormant4Ampdb(0),                      mFormant4ParallelBandwidth(500), mFormant5Ampdb(0),      
263         mFormant5ParallelBandwidth(600), mFormant6Ampdb(0),                     mFormant6ParallelBandwidth(800),    
264         mParallelNasalPoleAmpdb(0), mBypassFricationAmpdb(0),       mPalallelVoicingAmpdb(0),   
265         mOverallGaindb(62)  
266 {
267 };
268
269
270 klatt::klatt() : 
271         mBaseF0(1330),
272         mBaseSpeed(10.0f),
273         mBaseDeclination(0.5f),
274         mBaseWaveform(KW_SAW),
275         mF0Flutter(0), 
276         mSampleRate(0), 
277         mNspFr(0),
278         mF0FundamentalFreq(0),
279         mVoicingAmpdb(0),
280         mSkewnessOfAlternatePeriods(0),
281         mTimeCount(0), 
282         mNPer(0),
283         mT0(0),
284         mNOpen(0),
285         mNMod(0),
286         mAmpVoice(0),
287         mAmpBypas(0),
288         mAmpAspir(0),
289         mAmpFrica(0),
290         mAmpBreth(0),
291         mSkew(0),
292         mVLast(0),
293         mNLast(0),
294         mGlotLast(0),
295         mDecay(0),
296         mOneMd(0),
297         mSeed(5),
298         mElementCount(0),
299         mElement(0),
300         mElementIndex(0),
301         mLastElement(0),
302         mTStress(0),
303         mNTStress(0),
304         mTop(0)
305 {
306 }
307
308 /*
309 function FLUTTER
310
311 This function adds F0 flutter, as specified in:
312
313 "Analysis, synthesis and perception of voice quality variations among
314 female and male talkers" D.H. Klatt and L.C. Klatt JASA 87(2) February 1990.
315 Flutter is added by applying a quasi-random element constructed from three
316 slowly varying sine waves.
317 */
318 void klatt::flutter()
319 {
320         int original_f0 = mFrame.mF0FundamentalFreq / 10;
321         float fla = (float) mF0Flutter / 50;
322         float flb = (float) original_f0 / 100;
323         float flc = (float)sin(2 * PI * 12.7 * mTimeCount);
324         float fld = (float)sin(2 * PI * 7.1 * mTimeCount);
325         float fle = (float)sin(2 * PI * 4.7 * mTimeCount);
326         float delta_f0 = fla * flb * (flc + fld + fle) * 10;
327         mF0FundamentalFreq += (int) delta_f0;
328 }
329
330 /* Vwave is the differentiated glottal flow waveform, there is a weak
331 spectral zero around 800 Hz, magic constants a,b reset pitch-synch
332 */
333
334 float klatt::natural_source(int aNper)
335 {
336         // See if glottis open 
337         if (aNper < mNOpen)
338         {
339                 switch (mBaseWaveform)
340                 {
341                 case KW_TRIANGLE:
342                         return ((aNper % 200) - 100) * 81.92f; // triangle
343                 case KW_SIN:
344                         return (float)(sin(aNper * 0.0314) * 8192); // sin
345                 case KW_SQUARE:
346                         return ((aNper % 200) - 100) > 0 ? 8192.0f : -8192.0f; // square
347                 case KW_PULSE:
348                         return ((aNper % 200) - 100) > 50 ? 8192.0f : -8192.0f; // pulse
349                 case KW_NOISE:
350                         return (int)mNLast & 1 ? -8192.0f : 8192.0f;
351                 case KW_WARBLE:
352                                 return (int)mNLast & 7 ? -8192.0f : 8192.0f;
353                 case KW_SAW: // fallthrough
354                 default:
355                         return (abs((aNper % 200) - 100) - 50) * 163.84f; // saw
356                 }       
357         }
358         else
359         {
360                 // Glottis closed 
361                 return (0.0);
362         }
363         
364 }
365
366 /* Reset selected parameters pitch-synchronously */
367
368 void klatt::pitch_synch_par_reset(int ns)
369 {       
370         if (mF0FundamentalFreq > 0)
371         {
372                 mT0 = (40 * mSampleRate) / mF0FundamentalFreq;
373
374                 /* Period in samp*4 */
375                 mAmpVoice = DBtoLIN(mVoicingAmpdb);
376
377                 /* Duration of period before amplitude modulation */
378                 mNMod = mT0;
379
380                 if (mVoicingAmpdb > 0)
381                 {
382                         mNMod >>= 1;
383                 }
384
385                 /* Breathiness of voicing waveform */
386
387                 mAmpBreth = DBtoLIN(mFrame.mVoicingBreathiness) * 0.1f;
388
389                 /* Set open phase of glottal period */
390                 /* where  40 <= open phase <= 263 */
391
392                 mNOpen = 4 * mFrame.mNoSamplesInOpenPeriod;
393
394                 if (mNOpen >= (mT0 - 1))
395                 {
396                         mNOpen = mT0 - 2;
397                 }
398
399                 if (mNOpen < 40)
400                 {
401                         mNOpen = 40;                  /* F0 max = 1000 Hz */
402                 }
403
404                 int temp;
405                 float temp1;
406
407                 temp = mSampleRate / mNOpen;
408                 mCritDampedGlotLowPassFilter.initResonator(0L, temp, mSampleRate);
409
410                 /* Make gain at F1 about constant */
411
412                 temp1 = mNOpen * .00833f;
413                 mCritDampedGlotLowPassFilter.setGain(temp1 * temp1);
414
415                 /* Truncate skewness so as not to exceed duration of closed phase
416                 of glottal period */
417
418                 temp = mT0 - mNOpen;
419
420                 if (mSkewnessOfAlternatePeriods > temp)
421                 {
422                         mSkewnessOfAlternatePeriods = temp;
423                 }
424
425                 if (mSkew >= 0)
426                 {
427                         mSkew = mSkewnessOfAlternatePeriods;                /* Reset mSkew to requested mSkewnessOfAlternatePeriods */
428                 }
429                 else
430                 {
431                         mSkew = -mSkewnessOfAlternatePeriods;
432                 }
433
434                 /* Add skewness to closed portion of voicing period */
435
436                 mT0 = mT0 + mSkew;
437                 mSkew = -mSkew;
438         }
439         else
440         {
441                 mT0 = 4;                        /* Default for f0 undefined */
442                 mAmpVoice = 0.0;
443                 mNMod = mT0;
444                 mAmpBreth = 0.0;
445         }
446
447         /* Reset these pars pitch synchronously or at update rate if f0=0 */
448
449         if ((mT0 != 4) || (ns == 0))
450         {
451                 /* Set one-pole ELM_FEATURE_LOW-pass filter that tilts glottal source */
452                 mDecay = (0.033f * mFrame.mVoicingSpectralTiltdb);      /* Function of samp_rate ? */
453
454                 if (mDecay > 0.0f)
455                 {
456                         mOneMd = 1.0f - mDecay;
457                 }
458                 else
459                 {
460                         mOneMd = 1.0f;
461                 }
462         }
463 }
464
465
466 /* Get variable parameters from host computer,
467 initially also get definition of fixed pars
468 */
469
470 void klatt::frame_init()
471 {
472         int mOverallGaindb;                       /* Overall gain, 60 dB is unity  0 to   60  */
473         float amp_parF1;                 /* mFormant1Ampdb converted to linear gain  */
474         float amp_parFN;                 /* mParallelNasalPoleAmpdb converted to linear gain  */
475         float amp_parF2;                 /* mFormant2Ampdb converted to linear gain  */
476         float amp_parF3;                 /* mFormant3Ampdb converted to linear gain  */
477         float amp_parF4;                 /* mFormant4Ampdb converted to linear gain  */
478         float amp_parF5;                 /* mFormant5Ampdb converted to linear gain  */
479         float amp_parF6;                 /* mFormant6Ampdb converted to linear gain  */
480
481         /* Read  speech frame definition into temp store
482        and move some parameters into active use immediately
483        (voice-excited ones are updated pitch synchronously
484        to avoid waveform glitches).
485          */
486
487         mF0FundamentalFreq = mFrame.mF0FundamentalFreq;
488         mVoicingAmpdb = mFrame.mVoicingAmpdb - 7;
489
490         if (mVoicingAmpdb < 0) mVoicingAmpdb = 0;
491
492         mAmpAspir = DBtoLIN(mFrame.mAspirationAmpdb) * .05f;
493         mAmpFrica = DBtoLIN(mFrame.mFricationAmpdb) * 0.25f;
494         mSkewnessOfAlternatePeriods = mFrame.mSkewnessOfAlternatePeriods;
495
496         /* Fudge factors (which comprehend affects of formants on each other?)
497        with these in place ALL_PARALLEL should sound as close as
498            possible to CASCADE_PARALLEL.
499            Possible problem feeding in Holmes's amplitudes given this.
500         */
501         amp_parF1 = DBtoLIN(mFrame.mFormant1Ampdb) * 0.4f;      /* -7.96 dB */
502         amp_parF2 = DBtoLIN(mFrame.mFormant2Ampdb) * 0.15f;     /* -16.5 dB */
503         amp_parF3 = DBtoLIN(mFrame.mFormant3Ampdb) * 0.06f;     /* -24.4 dB */
504         amp_parF4 = DBtoLIN(mFrame.mFormant4Ampdb) * 0.04f;     /* -28.0 dB */
505         amp_parF5 = DBtoLIN(mFrame.mFormant5Ampdb) * 0.022f;    /* -33.2 dB */
506         amp_parF6 = DBtoLIN(mFrame.mFormant6Ampdb) * 0.03f;     /* -30.5 dB */
507         amp_parFN = DBtoLIN(mFrame.mParallelNasalPoleAmpdb) * 0.6f;     /* -4.44 dB */
508         mAmpBypas = DBtoLIN(mFrame.mBypassFricationAmpdb) * 0.05f;      /* -26.0 db */
509
510         // Set coeficients of nasal resonator and zero antiresonator 
511         mNasalPole.initResonator(mFrame.mNasalPoleFreq, mFrame.mNasalPoleBandwidth, mSampleRate);
512
513         mNasalZero.initAntiresonator(mFrame.mNasalZeroFreq, mFrame.mNasalZeroBandwidth, mSampleRate);
514
515         // Set coefficients of parallel resonators, and amplitude of outputs 
516         mParallelFormant1.initResonator(mFrame.mFormant1Freq, mFrame.mFormant1ParallelBandwidth, mSampleRate);
517         mParallelFormant1.setGain(amp_parF1);
518
519         mParallelResoNasalPole.initResonator(mFrame.mNasalPoleFreq, mFrame.mNasalPoleBandwidth, mSampleRate);
520         mParallelResoNasalPole.setGain(amp_parFN);
521
522         mParallelFormant2.initResonator(mFrame.mFormant2Freq, mFrame.mFormant2ParallelBandwidth, mSampleRate);
523         mParallelFormant2.setGain(amp_parF2);
524
525         mParallelFormant3.initResonator(mFrame.mFormant3Freq, mFrame.mFormant3ParallelBandwidth, mSampleRate);
526         mParallelFormant3.setGain(amp_parF3);
527
528         mParallelFormant4.initResonator(mFrame.mFormant4Freq, mFrame.mFormant4ParallelBandwidth, mSampleRate);
529         mParallelFormant4.setGain(amp_parF4);
530
531         mParallelFormant5.initResonator(mFrame.mFormant5Freq, mFrame.mFormant5ParallelBandwidth, mSampleRate);
532         mParallelFormant5.setGain(amp_parF5);
533
534         mParallelFormant6.initResonator(mFrame.mFormant6Freq, mFrame.mFormant6ParallelBandwidth, mSampleRate);
535         mParallelFormant6.setGain(amp_parF6);
536
537
538         /* fold overall gain into output resonator */
539         mOverallGaindb = mFrame.mOverallGaindb - 3;
540
541         if (mOverallGaindb <= 0)
542                 mOverallGaindb = 57;
543
544         /* output ELM_FEATURE_LOW-pass filter - resonator with freq 0 and BW = globals->mSampleRate
545         Thus 3db point is globals->mSampleRate/2 i.e. Nyquist limit.
546         Only 3db down seems rather mild...
547         */
548         mOutputLowPassFilter.initResonator(0L, (int)mSampleRate, mSampleRate);
549         mOutputLowPassFilter.setGain(DBtoLIN(mOverallGaindb));
550 }
551
552 /*
553 function PARWAV
554
555 CONVERT FRAME OF PARAMETER DATA TO A WAVEFORM CHUNK
556 Synthesize globals->mNspFr samples of waveform and store in jwave[].
557 */
558
559 void klatt::parwave(short int *jwave)
560 {
561         /* Output of cascade branch, also final output  */
562
563         /* Initialize synthesizer and get specification for current speech
564         frame from host microcomputer */
565
566         frame_init();
567
568         if (mF0Flutter != 0)
569         {
570                 mTimeCount++;                  /* used for f0 flutter */
571                 flutter();       /* add f0 flutter */
572         }
573
574         /* MAIN LOOP, for each output sample of current frame: */
575
576         int ns;
577         for (ns = 0; ns < mNspFr; ns++)
578         {
579                 float noise;
580                 int n4;
581                 float sourc;                   /* Sound source if all-parallel config used  */
582                 float glotout;                 /* Output of glottal sound source  */
583                 float par_glotout;             /* Output of parallelglottal sound sourc  */
584                 float voice = 0;               /* Current sample of voicing waveform  */
585                 float frics;                   /* Frication sound source  */
586                 float aspiration;              /* Aspiration sound source  */
587                 int nrand;                    /* Varible used by random number generator  */
588
589                 /* Our own code like rand(), but portable
590                 whole upper 31 bits of seed random
591                 assumes 32-bit unsigned arithmetic
592                 with untested code to handle larger.
593                 */
594                 mSeed = mSeed * 1664525 + 1;
595
596                 mSeed &= 0xFFFFFFFF;
597
598                 /* Shift top bits of seed up to top of int then back down to LS 14 bits */
599                 /* Assumes 8 bits per sizeof unit i.e. a "byte" */
600                 nrand = (((int) mSeed) << (8 * sizeof(int) - 32)) >> (8 * sizeof(int) - 14);
601
602                 /* Tilt down noise spectrum by soft ELM_FEATURE_LOW-pass filter having
603                 *    a pole near the origin in the z-plane, i.e.
604                 *    output = input + (0.75 * lastoutput) */
605
606                 noise = nrand + (0.75f * mNLast);       /* Function of samp_rate ? */
607
608                 mNLast = noise;
609
610                 /* Amplitude modulate noise (reduce noise amplitude during
611                 second half of glottal period) if voicing simultaneously present
612                 */
613
614                 if (mNPer > mNMod)
615                 {
616                         noise *= 0.5f;
617                 }
618
619                 /* Compute frication noise */
620                 sourc = frics = mAmpFrica * noise;
621
622                 /* Compute voicing waveform : (run glottal source simulation at
623                 4 times normal sample rate to minimize quantization noise in
624                 period of female voice)
625                 */
626
627                 for (n4 = 0; n4 < 4; n4++)
628                 {
629                         /* use a more-natural-shaped source waveform with excitation
630                         occurring both upon opening and upon closure, stronest at closure */
631                         voice = natural_source(mNPer);
632
633                         /* Reset period when counter 'mNPer' reaches mT0 */
634
635                         if (mNPer >= mT0)
636                         {
637                                 mNPer = 0;
638                                 pitch_synch_par_reset(ns);
639                         }
640
641                         /* Low-pass filter voicing waveform before downsampling from 4*globals->mSampleRate */
642                         /* to globals->mSampleRate samples/sec.  Resonator f=.09*globals->mSampleRate, bw=.06*globals->mSampleRate  */
643
644                         voice = mDownSampLowPassFilter.resonate(voice); /* in=voice, out=voice */
645
646                         /* Increment counter that keeps track of 4*globals->mSampleRate samples/sec */
647                         mNPer++;
648                 }
649
650                 /* Tilt spectrum of voicing source down by soft ELM_FEATURE_LOW-pass filtering, amount
651                 of tilt determined by mVoicingSpectralTiltdb
652                 */
653                 voice = (voice * mOneMd) + (mVLast * mDecay);
654
655                 mVLast = voice;
656
657                 /* Add breathiness during glottal open phase */
658                 if (mNPer < mNOpen)
659                 {
660                         /* Amount of breathiness determined by parameter mVoicingBreathiness */
661                         /* Use nrand rather than noise because noise is ELM_FEATURE_LOW-passed */
662                         voice += mAmpBreth * nrand;
663                 }
664
665                 /* Set amplitude of voicing */
666                 glotout = mAmpVoice * voice;
667
668                 /* Compute aspiration amplitude and add to voicing source */
669                 aspiration = mAmpAspir * noise;
670
671                 glotout += aspiration;
672
673                 par_glotout = glotout;
674
675                 /* NIS - rsynth "hack"
676                 As Holmes' scheme is weak at nasals and (physically) nasal cavity
677                 is "back near glottis" feed glottal source through nasal resonators
678                 Don't think this is quite right, but improves things a bit
679                 */
680                 par_glotout = mNasalZero.antiresonate(par_glotout);
681                 par_glotout = mNasalPole.resonate(par_glotout);
682                 /* And just use mParallelFormant1 NOT mParallelResoNasalPole */         
683                 float out = mParallelFormant1.resonate(par_glotout);
684                 /* Sound sourc for other parallel resonators is frication
685                 plus first difference of voicing waveform.
686                 */
687                 sourc += (par_glotout - mGlotLast);
688                 mGlotLast = par_glotout;
689
690                 /* Standard parallel vocal tract
691                 Formants F6,F5,F4,F3,F2, outputs added with alternating sign
692                 */
693                 out = mParallelFormant6.resonate(sourc) - out;
694                 out = mParallelFormant5.resonate(sourc) - out;
695                 out = mParallelFormant4.resonate(sourc) - out;
696                 out = mParallelFormant3.resonate(sourc) - out;
697                 out = mParallelFormant2.resonate(sourc) - out;
698
699                 out = mAmpBypas * sourc - out;
700                 out = mOutputLowPassFilter.resonate(out);
701
702                 *jwave++ = clip(out); /* Convert back to integer */
703         }
704 }
705
706
707
708 static char * phoneme_to_element_lookup(char *s, void ** data)
709 {
710         int key8 = *s;
711         int key16 = key8 + (s[1] << 8);
712         if (s[1] == 0) key16 = -1; // avoid key8==key16
713         int i;
714         for (i = 0; i < PHONEME_COUNT; i++)
715         {
716                 if (phoneme_to_elements[i].mKey == key16)
717                 {
718                         *data = &phoneme_to_elements[i].mData;
719                         return s+2;
720                 }
721                 if (phoneme_to_elements[i].mKey == key8)
722                 {
723                         *data = &phoneme_to_elements[i].mData;
724                         return s+1;
725                 }
726         }
727         // should never happen
728         *data = NULL;
729         return s+1;
730 }
731
732
733
734 int klatt::phone_to_elm(char *aPhoneme, int aCount, darray *aElement)
735 {
736         int stress = 0;
737         char *s = aPhoneme;
738         int t = 0;
739         char *limit = s + aCount;
740
741         while (s < limit && *s)
742         {
743                 char *e = NULL;
744                 s = phoneme_to_element_lookup(s, (void**)&e);
745
746                 if (e)
747                 {
748                         int n = *e++;
749
750                         while (n-- > 0)
751                         {
752                                 int x = *e++;
753                                 Element * p = &gElement[x];
754                                 /* This works because only vowels have mUD != mDU,
755                                 and we set stress just before a vowel
756                                 */
757                                 aElement->put(x);
758
759                                 if (!(p->mFeat & ELM_FEATURE_VWL))
760                                         stress = 0;
761
762                                 int stressdur = StressDur(p,stress);
763
764                                 t += stressdur;
765
766                                 aElement->put(stressdur);
767                                 aElement->put(stress);
768                         }
769                 }
770
771                 else
772                 {
773                         char ch = *s++;
774
775                         switch (ch)
776                         {
777
778                         case '\'':                /* Primary stress */
779                                 stress = 3;
780                                 break;
781
782                         case ',':                 /* Secondary stress */
783                                 stress = 2;
784                                 break;
785
786                         case '+':                 /* Tertiary stress */
787                                 stress = 1;
788                                 break;
789
790                         case '-':                 /* hyphen in input */
791                                 break;
792
793                         default:
794 //                              fprintf(stderr, "Ignoring %c in '%.*s'\n", ch, aCount, aPhoneme);
795                                 break;
796                         }
797                 }
798         }
799
800         return t;
801 }
802
803
804
805 /* 'a' is dominant element, 'b' is dominated
806     ext is flag to say to use external times from 'a' rather
807     than internal i.e. ext != 0 if 'a' is NOT current element.
808  */
809
810 static void set_trans(Slope *t, Element * a, Element * b,int ext, int /* e */)
811 {
812         int i;
813
814         for (i = 0; i < ELM_COUNT; i++)
815         {
816                 t[i].mTime = ((ext) ? a->mInterpolator[i].mExtDelay : a->mInterpolator[i].mIntDelay);
817
818                 if (t[i].mTime)
819                 {
820                         t[i].mValue = a->mInterpolator[i].mFixed + (a->mInterpolator[i].mProportion * b->mInterpolator[i].mSteady) * 0.01f; // mProportion is in scale 0..100, so *0.01.
821                 }
822                 else
823                 {
824                         t[i].mValue = b->mInterpolator[i].mSteady;
825                 }
826         }
827 }
828
829 static float lerp(float a, float b, int t, int d)
830 {
831         if (t <= 0)
832         {
833                 return a;
834         }
835
836         if (t >= d)
837         {
838                 return b;
839         }
840
841         float f = (float)t / (float)d;
842         return a + (b - a) * f;
843 }
844
845 static float interpolate(Slope *aStartSlope, Slope *aEndSlope, float aMidValue, int aTime, int aDuration)
846 {
847         int steadyTime = aDuration - (aStartSlope->mTime + aEndSlope->mTime);
848
849         if (steadyTime >= 0)
850         {
851                 // Interpolate to a midpoint, stay there for a while, then interpolate to end
852
853                 if (aTime < aStartSlope->mTime)
854                 {
855                         // interpolate to the first value
856                         return lerp(aStartSlope->mValue, aMidValue, aTime, aStartSlope->mTime);
857                 }
858                 // reached midpoint
859
860                 aTime -= aStartSlope->mTime;
861
862                 if (aTime <= steadyTime)
863                 {
864                         // still at steady state
865                         return aMidValue;  
866                 }
867
868                 // interpolate to the end
869                 return lerp(aMidValue, aEndSlope->mValue, aTime - steadyTime, aEndSlope->mTime);
870         }
871         else
872         {
873                 // No steady state
874                 float f = 1.0f - ((float) aTime / (float) aDuration);
875                 float sp = lerp(aStartSlope->mValue, aMidValue, aTime, aStartSlope->mTime);
876                 float ep = lerp(aEndSlope->mValue, aMidValue, aDuration - aTime, aEndSlope->mTime);
877                 return f * sp + ((float) 1.0 - f) * ep;
878         }
879 }
880
881
882
883 void klatt::initsynth(int aElementCount,unsigned char *aElement)
884 {
885         mElement = aElement;
886         mElementCount = aElementCount;
887         mElementIndex = 0;
888         mLastElement = &gElement[0];
889         mSeed = 5;
890         mTStress = 0;
891         mNTStress = 0;
892         mFrame.mF0FundamentalFreq = mBaseF0;
893         mTop = 1.1f * mFrame.mF0FundamentalFreq;
894         mFrame.mNasalPoleFreq = (int)mLastElement->mInterpolator[ELM_FN].mSteady;
895         mFrame.mFormant1ParallelBandwidth = mFrame.mFormant1Bandwidth = 60;
896         mFrame.mFormant2ParallelBandwidth = mFrame.mFormant2Bandwidth = 90;
897         mFrame.mFormant3ParallelBandwidth = mFrame.mFormant3Bandwidth = 150;
898 //      mFrame.mFormant4ParallelBandwidth = (default)
899
900         // Set stress attack/decay slope 
901         mStressS.mTime = 40;
902         mStressE.mTime = 40;
903         mStressE.mValue = 0.0;
904 }
905
906 int klatt::synth(int /* aSampleCount */, short *aSamplePointer)
907 {
908         short *samp = aSamplePointer;
909
910         if (mElementIndex >= mElementCount)
911                 return -1;
912
913         Element * currentElement = &gElement[mElement[mElementIndex++]];
914         int dur = mElement[mElementIndex++];
915         mElementIndex++; // skip stress 
916         
917         if (currentElement->mRK == 31) // "END"
918         {
919                 // Reset the fundamental frequency top
920                 mFrame.mF0FundamentalFreq = mBaseF0;
921                 mTop = 1.1f * mFrame.mF0FundamentalFreq;
922         }
923
924         // Skip zero length elements which are only there to affect
925         // boundary values of adjacent elements         
926
927         if (dur > 0)
928         {
929                 Element * ne = (mElementIndex < mElementCount) ? &gElement[mElement[mElementIndex]] : &gElement[0];
930                 Slope start[ELM_COUNT];
931                 Slope end[ELM_COUNT];
932                 int t;
933
934                 if (currentElement->mRK > mLastElement->mRK)
935                 {
936                         set_trans(start, currentElement, mLastElement, 0, 's');
937                         // we dominate last 
938                 }
939                 else
940                 {
941                         set_trans(start, mLastElement, currentElement, 1, 's');
942                         // last dominates us 
943                 }
944
945                 if (ne->mRK > currentElement->mRK)
946                 {
947                         set_trans(end, ne, currentElement, 1, 'e');
948                         // next dominates us 
949                 }
950                 else
951                 {
952                         set_trans(end, currentElement, ne, 0, 'e');
953                         // we dominate next 
954                 }
955
956                 for (t = 0; t < dur; t++, mTStress++)
957                 {
958                         float base = mTop * 0.8f; // 3 * top / 5 
959                         float tp[ELM_COUNT];
960
961                         if (mTStress == mNTStress)
962                         {
963                                 int j = mElementIndex;
964                                 mStressS = mStressE;
965                                 mTStress = 0;
966                                 mNTStress = dur;
967
968                                 while (j <= mElementCount)
969                                 {
970                                         Element * e   = (j < mElementCount) ? &gElement[mElement[j++]] : &gElement[0];
971                                         int du = (j < mElementCount) ? mElement[j++] : 0;
972                                         int s  = (j < mElementCount) ? mElement[j++] : 3;
973
974                                         if (s || e->mFeat & ELM_FEATURE_VWL)
975                                         {
976                                                 int d = 0;
977
978                                                 if (s)
979                                                         mStressE.mValue = (float) s / 3;
980                                                 else
981                                                         mStressE.mValue = (float) 0.1;
982
983                                                 do
984                                                 {
985                                                         d += du;
986                                                         e = (j < mElementCount) ? &gElement[mElement[j++]] : &gElement[0];
987                                                         du = mElement[j++];
988                                                 }
989
990                                                 while ((e->mFeat & ELM_FEATURE_VWL) && mElement[j++] == s);
991
992                                                 mNTStress += d / 2;
993
994                                                 break;
995                                         }
996
997                                         mNTStress += du;
998                                 }
999                         }
1000
1001                         int j;
1002                         for (j = 0; j < ELM_COUNT; j++)
1003                         {
1004                                 tp[j] = interpolate(&start[j], &end[j], (float) currentElement->mInterpolator[j].mSteady, t, dur);
1005                         }
1006
1007                         // Now call the synth for each frame 
1008
1009                         mFrame.mF0FundamentalFreq = (int)(base + (mTop - base) * interpolate(&mStressS, &mStressE, (float)0, mTStress, mNTStress));
1010                         mFrame.mVoicingAmpdb = mFrame.mPalallelVoicingAmpdb = (int)tp[ELM_AV];
1011                         mFrame.mFricationAmpdb = (int)tp[ELM_AF];
1012                         mFrame.mNasalZeroFreq = (int)tp[ELM_FN];
1013                         mFrame.mAspirationAmpdb = (int)tp[ELM_ASP];
1014                         mFrame.mVoicingBreathiness = (int)tp[ELM_AVC];
1015                         mFrame.mFormant1ParallelBandwidth = mFrame.mFormant1Bandwidth = (int)tp[ELM_B1];
1016                         mFrame.mFormant2ParallelBandwidth = mFrame.mFormant2Bandwidth = (int)tp[ELM_B2];
1017                         mFrame.mFormant3ParallelBandwidth = mFrame.mFormant3Bandwidth = (int)tp[ELM_B3];
1018                         mFrame.mFormant1Freq = (int)tp[ELM_F1];
1019                         mFrame.mFormant2Freq = (int)tp[ELM_F2];
1020                         mFrame.mFormant3Freq = (int)tp[ELM_F3];
1021
1022                         // AMP_ADJ + is a kludge to get amplitudes up to klatt-compatible levels
1023                                 
1024                                 
1025                         //pars.mParallelNasalPoleAmpdb  = AMP_ADJ + tp[ELM_AN];
1026                                 
1027                         mFrame.mBypassFricationAmpdb = AMP_ADJ + (int)tp[ELM_AB];
1028                         mFrame.mFormant5Ampdb = AMP_ADJ + (int)tp[ELM_A5];
1029                         mFrame.mFormant6Ampdb = AMP_ADJ + (int)tp[ELM_A6];
1030                         mFrame.mFormant1Ampdb = AMP_ADJ + (int)tp[ELM_A1];
1031                         mFrame.mFormant2Ampdb = AMP_ADJ + (int)tp[ELM_A2];
1032                         mFrame.mFormant3Ampdb = AMP_ADJ + (int)tp[ELM_A3];
1033                         mFrame.mFormant4Ampdb = AMP_ADJ + (int)tp[ELM_A4];
1034
1035                         parwave(samp);
1036
1037                         samp += mNspFr;
1038
1039                         // Declination of f0 envelope 0.25Hz / cS 
1040                         mTop -= mBaseDeclination;// 0.5;
1041                 }
1042         }
1043
1044         mLastElement = currentElement;
1045
1046         return (int)(samp - aSamplePointer);
1047 }
1048
1049
1050 void klatt::init(int aBaseFrequency, float aBaseSpeed, float aBaseDeclination, int aBaseWaveform)
1051 {
1052         mBaseF0 = aBaseFrequency;
1053         mBaseSpeed = aBaseSpeed;
1054         mBaseDeclination = aBaseDeclination;
1055         mBaseWaveform = aBaseWaveform;
1056
1057     mSampleRate = 11025;
1058     mF0Flutter = 0;
1059         mF0FundamentalFreq = mBaseF0;
1060         mFrame.mF0FundamentalFreq = mBaseF0;
1061
1062         int FLPhz = (950 * mSampleRate) / 10000;
1063         int BLPhz = (630 * mSampleRate) / 10000;
1064         mNspFr = (int)(mSampleRate * mBaseSpeed) / 1000; 
1065
1066         mDownSampLowPassFilter.initResonator(FLPhz, BLPhz, mSampleRate);
1067
1068         mNPer = 0;                        /* LG */
1069         mT0 = 0;                          /* LG */
1070
1071         mVLast = 0;                       /* Previous output of voice  */
1072         mNLast = 0;                       /* Previous output of random number generator  */
1073         mGlotLast = 0;                    /* Previous value of glotout  */
1074 }