1 /* Copyright (c) 2003-2005 Various contributors
3 * Permission is hereby granted, free of charge, to any person obtaining a copy
4 * of this software and associated documentation files (the "Software"), to
5 * deal in the Software without restriction, including without limitation the
6 * rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
7 * sell copies of the Software, and to permit persons to whom the Software is
8 * furnished to do so, subject to the following conditions:
10 * The above copyright notice and this permission notice shall be included in
11 * all copies or substantial portions of the Software.
13 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
14 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
15 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
16 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
17 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
18 * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
28 #if defined(MACOSX) || defined(SOLARIS) || defined(__MINGW32__)
29 // Older versions of Mac OS X didn't supply a powf function, so using it
30 // will cause a binary incompatibility when trying to run a binary built
31 // on a newer OS X release on an olderr one. And Solaris 8 doesn't provide
32 // powf, floorf, fabsf etc. at all.
33 // Cross-compiled MinGW32 toolchains suffer from a cross-compile bug in
34 // libstdc++. math/stubs.o should be empty, but it comes with a symbol for
35 // powf, resulting in a linker error because of multiple definitions.
36 // Hence we re-define them here. The only potential drawback is that it
37 // might be a little bit slower this way.
38 #define powf(x,y) ((float)pow(x,y))
39 #define floorf(x) ((float)floor(x))
40 #define fabsf(x) ((float)fabs(x))
43 #define FIXEDPOINT_MAKE(x, point) ((Bit32u)((1 << point) * x))
47 //Amplitude time velocity follow exponential coefficients
48 static const double tvcatconst
[5] = {0.0, 0.002791309, 0.005942882, 0.012652792, 0.026938637};
49 static const double tvcatmult
[5] = {1.0, 1.072662811, 1.169129367, 1.288579123, 1.229630539};
51 // These are division constants for the TVF depth key follow
52 static const Bit32u depexp
[5] = {3000, 950, 485, 255, 138};
54 //Envelope time keyfollow exponential coefficients
55 static const double tkcatconst
[5] = {0.0, 0.005853144, 0.011148054, 0.019086143, 0.043333215};
56 static const double tkcatmult
[5] = {1.0, 1.058245688, 1.048488989, 1.016049301, 1.097538067};
60 // Pre-warp the coefficients of a numerator or denominator.
61 // Note that a0 is assumed to be 1, so there is no wrapping
63 static void prewarp(double *a1
, double *a2
, double fc
, double fs
) {
66 wp
= 2.0 * fs
* tan(DOUBLE_PI
* fc
/ fs
);
68 *a2
= *a2
/ (wp
* wp
);
72 // Transform the numerator and denominator coefficients
73 // of s-domain biquad section into corresponding
74 // z-domain coefficients.
76 // Store the 4 IIR coefficients in array pointed by coef
77 // in following order:
78 // beta1, beta2 (denominator)
79 // alpha1, alpha2 (numerator)
82 // a0-a2 - s-domain numerator coefficients
83 // b0-b2 - s-domain denominator coefficients
84 // k - filter gain factor. initially set to 1
85 // and modified by each biquad section in such
86 // a way, as to make it the coefficient by
87 // which to multiply the overall filter gain
88 // in order to achieve a desired overall filter gain,
89 // specified in initial value of k.
90 // fs - sampling rate (Hz)
91 // coef - array of z-domain coefficients to be filled in.
94 // On return, set coef z-domain coefficients
95 static void bilinear(double a0
, double a1
, double a2
, double b0
, double b1
, double b2
, double *k
, double fs
, float *coef
) {
98 // alpha (Numerator in s-domain)
99 ad
= 4. * a2
* fs
* fs
+ 2. * a1
* fs
+ a0
;
100 // beta (Denominator in s-domain)
101 bd
= 4. * b2
* fs
* fs
+ 2. * b1
* fs
+ b0
;
103 // update gain constant for this section
107 *coef
++ = (float)((2. * b0
- 8. * b2
* fs
* fs
) / bd
); // beta1
108 *coef
++ = (float)((4. * b2
* fs
* fs
- 2. * b1
* fs
+ b0
) / bd
); // beta2
111 *coef
++ = (float)((2. * a0
- 8. * a2
* fs
* fs
) / ad
); // alpha1
112 *coef
= (float)((4. * a2
* fs
* fs
- 2. * a1
* fs
+ a0
) / ad
); // alpha2
115 // a0-a2: numerator coefficients
116 // b0-b2: denominator coefficients
117 // fc: Filter cutoff frequency
119 // k: overall gain factor
120 // coef: pointer to 4 iir coefficients
121 static void szxform(double *a0
, double *a1
, double *a2
, double *b0
, double *b1
, double *b2
, double fc
, double fs
, double *k
, float *coef
) {
122 // Calculate a1 and a2 and overwrite the original values
123 prewarp(a1
, a2
, fc
, fs
);
124 prewarp(b1
, b2
, fc
, fs
);
125 bilinear(*a0
, *a1
, *a2
, *b0
, *b1
, *b2
, k
, fs
, coef
);
128 static void initFilter(float fs
, float fc
, float *icoeff
, float Q
) {
130 double a0
, a1
, a2
, b0
, b1
, b2
;
132 double k
= 1.5; // Set overall filter gain factor
133 coef
= icoeff
+ 1; // Skip k, or gain
140 b1
= 0.765367 / Q
; // Divide by resonance or Q
142 szxform(&a0
, &a1
, &a2
, &b0
, &b1
, &b2
, fc
, fs
, &k
, coef
);
143 coef
+= 4; // Point to next filter section
152 szxform(&a0
, &a1
, &a2
, &b0
, &b1
, &b2
, fc
, fs
, &k
, coef
);
154 icoeff
[0] = (float)k
;
157 void Tables::initFiltCoeff(float samplerate
) {
158 for (int j
= 0; j
< FILTERGRAN
; j
++) {
159 for (int res
= 0; res
< 31; res
++) {
160 float tres
= resonanceFactor
[res
];
161 initFilter((float)samplerate
, (((float)(j
+1.0)/FILTERGRAN
)) * ((float)samplerate
/2), filtCoeff
[j
][res
], tres
);
166 void Tables::initEnvelopes(float samplerate
) {
167 for (int lf
= 0; lf
<= 100; lf
++) {
168 float elf
= (float)lf
;
171 // This formula fits observation of the CM-32L by +/- 0.03s or so for the second time value in the filter,
172 // when all other times were 0 and all levels were 100. Note that variations occur depending on the level
173 // delta of the section, which we're not fully emulating.
174 float seconds
= powf(2.0f
, (elf
/ 8.0f
) + 7.0f
) / 32768.0f
;
175 int samples
= (int)(seconds
* samplerate
);
176 envTime
[lf
] = samples
;
178 // Cap on envelope times depending on the level delta
180 envDeltaMaxTime
[lf
] = 63;
182 float cap
= 11.0f
* (float)log(elf
) + 64;
186 envDeltaMaxTime
[lf
] = (int)cap
;
190 // This (approximately) represents the time durations when the target level is 0.
191 // Not sure why this is a special case, but it's seen to be from the real thing.
192 seconds
= powf(2, (elf
/ 8.0f
) + 6) / 32768.0f
;
193 envDecayTime
[lf
] = (int)(seconds
* samplerate
);
195 // I am certain of this: Verified by hand LFO log
196 lfoPeriod
[lf
] = (Bit32u
)(((float)samplerate
) / (powf(1.088883372f
, (float)lf
) * 0.021236044f
));
200 void Tables::initMT32ConstantTables(Synth
*synth
) {
202 synth
->printDebug("Initialising Pitch Tables");
203 for (lf
= -108; lf
<= 108; lf
++) {
204 tvfKeyfollowMult
[lf
+ 108] = (int)(256 * powf(2.0f
, (float)(lf
/ 24.0f
)));
205 //synth->printDebug("KT %d = %d", f, keytable[f+108]);
208 for (int res
= 0; res
< 31; res
++) {
209 resonanceFactor
[res
] = powf((float)res
/ 30.0f
, 5.0f
) + 1.0f
;
214 for (int ang
= 0; ang
< period
; ang
++) {
215 int halfang
= (period
/ 2);
216 int angval
= ang
% halfang
;
217 float tval
= (((float)angval
/ (float)halfang
) - 0.5f
) * 2;
220 sintable
[ang
] = (Bit16s
)(tval
* 50.0f
) + 50;
225 for (velt
= 0; velt
< 128; velt
++) {
226 for (dep
= 0; dep
< 5; dep
++) {
228 float ff
= (float)(exp(3.5f
* tvcatconst
[dep
] * (59.0f
- (float)velt
)) * tvcatmult
[dep
]);
229 tempdep
= 256.0f
* ff
;
230 envTimeVelfollowMult
[dep
][velt
] = (int)tempdep
;
231 //if ((velt % 16) == 0) {
232 // synth->printDebug("Key %d, depth %d, factor %d", velt, dep, (int)tempdep);
235 envTimeVelfollowMult
[dep
][velt
] = 256;
238 for (dep
= -7; dep
< 8; dep
++) {
239 float fldep
= (float)abs(dep
) / 7.0f
;
240 fldep
= powf(fldep
,2.5f
);
242 fldep
= fldep
* -1.0f
;
243 pwVelfollowAdd
[dep
+7][velt
] = Bit32s((fldep
* (float)velt
* 100) / 128.0);
247 for (dep
= 0; dep
<= 100; dep
++) {
248 for (velt
= 0; velt
< 128; velt
++) {
249 float fdep
= (float)dep
* 0.000347013f
; // Another MT-32 constant
250 float fv
= ((float)velt
- 64.0f
)/7.26f
;
251 float flogdep
= powf(10, fdep
* fv
);
255 synth
->tables
.tvfVelfollowMult
[velt
][dep
] = (int)(flogdep
* 256.0);
257 //lff = 1 - (pow(((128.0 - (float)lf) / 64.0),.25) * ((float)velt / 96));
258 fbase
= 1 - (powf(((float)dep
/ 100.0f
),.25f
) * ((float)(64-velt
) / 96.0f
));
259 synth
->tables
.tvfVelfollowMult
[velt
][dep
] = (int)(fbase
* 256.0);
261 //synth->printDebug("Filvel dep %d velt %d = %x", dep, velt, filveltable[velt][dep]);
265 for (lf
= 0; lf
< 128; lf
++) {
266 float veloFract
= lf
/ 127.0f
;
267 for (int velsens
= 0; velsens
<= 100; velsens
++) {
268 float sensFract
= (velsens
- 50) / 50.0f
;
270 tvaVelfollowMult
[lf
][velsens
] = FIXEDPOINT_MAKE(1.0f
/ powf(2.0f
, veloFract
* -sensFract
* 127.0f
/ 20.0f
), 8);
272 tvaVelfollowMult
[lf
][velsens
] = FIXEDPOINT_MAKE(1.0f
/ powf(2.0f
, (1.0f
- veloFract
) * sensFract
* 127.0f
/ 20.0f
), 8);
277 for (lf
= 0; lf
<= 100; lf
++) {
278 // Converts the 0-100 range used by the MT-32 to volume multiplier
279 volumeMult
[lf
] = FIXEDPOINT_MAKE(powf((float)lf
/ 100.0f
, FLOAT_LN
), 7);
282 for (lf
= 0; lf
<= 100; lf
++) {
283 float mv
= lf
/ 100.0f
;
284 float pt
= mv
- 0.5f
;
288 // Original (CC version)
289 //pwFactor[lf] = (int)(pt * 210.04f) + 128;
291 // Approximation from sample comparison
292 pwFactor
[lf
] = (int)(pt
* 179.0f
) + 128;
295 for (unsigned int i
= 0; i
< MAX_SAMPLE_OUTPUT
; i
++) {
298 //myRand = ((myRand - 16383) * 7168) >> 16;
299 // This one is slower but works with all values of RAND_MAX
300 myRand
= (int)((myRand
- RAND_MAX
/ 2) / (float)RAND_MAX
* (7168 / 2));
301 //FIXME:KG: Original ultimately set the lowest two bits to 0, for no obvious reason
302 noiseBuf
[i
] = (Bit16s
)myRand
;
307 for (lf
= 0; lf
<= 50; lf
++) {
317 padjtable
[lf
] = 4 - (0.333333f
);
319 padjtable
[lf
] = 4 - (0.333333f
* 2);
322 else if ((lf
> 6) && (lf
<= 12)) {
323 tdist
= (lf
-6.0f
) / 6.0f
;
324 padjtable
[lf
] = 3.0f
- tdist
;
325 } else if ((lf
> 12) && (lf
<= 25)) {
326 tdist
= (lf
- 12.0f
) / 13.0f
;
327 padjtable
[lf
] = 2.0f
- tdist
;
329 tdist
= (lf
- 25.0f
) / 25.0f
;
330 padjtable
[lf
] = 1.0f
- tdist
;
332 //synth->printDebug("lf %d = padj %f", lf, padjtable[lf]);
335 float lfp
, depf
, finalval
, tlf
;
336 int depat
, pval
, depti
;
337 for (lf
= 0; lf
<= 10; lf
++) {
338 // I believe the depth is cubed or something
340 for (depat
= 0; depat
<= 100; depat
++) {
342 depti
= abs(depat
- 50);
343 tlf
= (float)lf
- padjtable
[depti
];
346 lfp
= (float)exp(0.713619942f
* tlf
) / 407.4945111f
;
349 finalval
= 4096.0f
* powf(2, -lfp
);
351 finalval
= 4096.0f
* powf(2, lfp
);
352 pval
= (int)finalval
;
354 pitchEnvVal
[lf
][depat
] = pval
;
355 //synth->printDebug("lf %d depat %d pval %d tlf %f lfp %f", lf,depat,pval, tlf, lfp);
357 pitchEnvVal
[lf
][depat
] = 4096;
358 //synth->printDebug("lf %d depat %d pval 4096", lf, depat);
362 for (lf
= 0; lf
<= 100; lf
++) {
363 // It's linear - verified on MT-32 - one of the few things linear
364 lfp
= ((float)lf
* 0.1904f
) / 310.55f
;
366 for (depat
= 0; depat
<= 100; depat
++) {
367 depf
= ((float)depat
- 50.0f
) / 50.0f
;
368 //finalval = pow(2, lfp * depf * .5);
369 finalval
= 4096.0f
+ (4096.0f
* lfp
* depf
);
371 pval
= (int)finalval
;
373 lfoShift
[lf
][depat
] = pval
;
375 //synth->printDebug("lf %d depat %d pval %x", lf,depat,pval);
379 for (lf
= 0; lf
<= 12; lf
++) {
380 for (int distval
= 0; distval
< 128; distval
++) {
385 tvaBiasMult
[lf
][distval
] = 256;
388 amplog = powf(1.431817011f, (float)lf) / FLOAT_PI;
389 dval = ((128.0f - (float)distval) / 128.0f);
390 amplog = exp(amplog);
391 dval = powf(amplog, dval) / amplog;
392 tvaBiasMult[lf][distval] = (int)(dval * 256.0);
394 // Lets assume for a second it's linear
396 // Distance of full volume reduction
397 amplog
= (float)(12.0f
/ (float)lf
) * 24.0f
;
398 if (distval
> amplog
) {
399 tvaBiasMult
[lf
][distval
] = 0;
401 dval
= (amplog
- (float)distval
) / amplog
;
402 tvaBiasMult
[lf
][distval
] = (int)(dval
* 256.0f
);
405 //synth->printDebug("Ampbias lf %d distval %d = %f (%x) %f", lf, distval, dval, tvaBiasMult[lf][distval],amplog);
409 for (lf
= 0; lf
<= 14; lf
++) {
410 for (int distval
= 0; distval
< 128; distval
++) {
411 float filval
= fabsf((float)((lf
- 7) * 12) / 7.0f
);
416 tvfBiasMult
[lf
][distval
] = 256;
418 //amplog = pow(1.431817011, filval) / FLOAT_PI;
419 amplog
= powf(1.531817011f
, filval
) / FLOAT_PI
;
420 dval
= (128.0f
- (float)distval
) / 128.0f
;
421 amplog
= (float)exp(amplog
);
422 dval
= powf(amplog
,dval
)/amplog
;
424 tvfBiasMult
[lf
][distval
] = (int)(dval
* 256.0f
);
426 dval
= powf(dval
, 0.3333333f
);
430 tvfBiasMult
[lf
][distval
] = (int)(dval
* 256.0f
);
433 //synth->printDebug("Fbias lf %d distval %d = %f (%x) %f", lf, distval, dval, tvfBiasMult[lf][distval],amplog);
438 // Per-note table initialisation follows
440 static void initSaw(NoteLookup
*noteLookup
, Bit32s div2
) {
441 int tmpdiv
= div2
<< 16;
442 for (int rsaw
= 0; rsaw
<= 100; rsaw
++) {
449 //(66 - (((A8 - 50) / 50) ^ 0.63) * 50) / 132
450 float sawfact
= (66.0f
- (powf((fsaw
- 50.0f
) / 50.0f
, 0.63f
) * 50.0f
)) / 132.0f
;
451 noteLookup
->sawTable
[rsaw
] = (int)(sawfact
* (float)tmpdiv
) >> 16;
452 //synth->printDebug("F %d divtable %d saw %d sawtable %d", f, div, rsaw, sawtable[f][rsaw]);
456 static void initDep(KeyLookup
*keyLookup
, float f
) {
457 for (int dep
= 0; dep
< 5; dep
++) {
459 keyLookup
->envDepthMult
[dep
] = 256;
460 keyLookup
->envTimeMult
[dep
] = 256;
462 float depfac
= 3000.0f
;
464 depfac
= (float)depexp
[dep
];
466 ff
= (f
- (float)MIDDLEC
) / depfac
;
467 tempdep
= powf(2, ff
) * 256.0f
;
468 keyLookup
->envDepthMult
[dep
] = (int)tempdep
;
470 ff
= (float)(exp(tkcatconst
[dep
] * ((float)MIDDLEC
- f
)) * tkcatmult
[dep
]);
471 keyLookup
->envTimeMult
[dep
] = (int)(ff
* 256.0f
);
474 //synth->printDebug("F %f d1 %x d2 %x d3 %x d4 %x d5 %x", f, noteLookup->fildepTable[0], noteLookup->fildepTable[1], noteLookup->fildepTable[2], noteLookup->fildepTable[3], noteLookup->fildepTable[4]);
477 Bit16s
Tables::clampWF(Synth
*synth
, const char *n
, float ampVal
, double input
) {
478 Bit32s x
= (Bit32s
)(input
* ampVal
);
479 if (x
< -ampVal
- 1) {
480 synth
->printDebug("%s==%d<-WGAMP-1!", n
, x
);
481 x
= (Bit32s
)(-ampVal
- 1);
482 } else if (x
> ampVal
) {
483 synth
->printDebug("%s==%d>WGAMP!", n
, x
);
489 File
*Tables::initWave(Synth
*synth
, NoteLookup
*noteLookup
, float ampVal
, float div2
, File
*file
) {
490 int iDiv2
= (int)div2
;
491 noteLookup
->waveformSize
[0] = iDiv2
<< 1;
492 noteLookup
->waveformSize
[1] = iDiv2
<< 1;
493 noteLookup
->waveformSize
[2] = iDiv2
<< 2;
494 for (int i
= 0; i
< 3; i
++) {
495 if (noteLookup
->waveforms
[i
] == NULL
) {
496 noteLookup
->waveforms
[i
] = new Bit16s
[noteLookup
->waveformSize
[i
]];
500 for (int i
= 0; i
< 3 && file
!= NULL
; i
++) {
501 size_t len
= noteLookup
->waveformSize
[i
];
502 for (unsigned int j
= 0; j
< len
; j
++) {
503 if (!file
->readBit16u((Bit16u
*)¬eLookup
->waveforms
[i
][j
])) {
504 synth
->printDebug("Error reading wave file cache!");
513 double sd
= DOUBLE_PI
/ div2
;
515 for (int fa
= 0; fa
< (iDiv2
<< 1); fa
++) {
516 // sa ranges from 0 to 2PI
519 // Calculate a sample for the bandlimited sawtooth wave
521 int sincs
= iDiv2
>> 1;
523 for (int sincNum
= 1; sincNum
<= sincs
; sincNum
++) {
524 saw
+= sin(sinus
* sa
) / sinus
;
528 // This works pretty well
529 // Multiplied by 0.84 so that the spikes caused by bandlimiting don't overdrive the amplitude
530 noteLookup
->waveforms
[0][fa
] = clampWF(synth
, "saw", ampVal
, -saw
/ (0.5 * DOUBLE_PI
) * 0.84);
531 noteLookup
->waveforms
[1][fa
] = clampWF(synth
, "cos", ampVal
, -cos(sa
/ 2.0));
532 noteLookup
->waveforms
[2][fa
* 2] = clampWF(synth
, "cosoff_0", ampVal
, -cos(sa
- DOUBLE_PI
));
533 noteLookup
->waveforms
[2][fa
* 2 + 1] = clampWF(synth
, "cosoff_1", ampVal
, -cos((sa
+ (sd
/ 2)) - DOUBLE_PI
));
539 static void initFiltTable(NoteLookup
*noteLookup
, float freq
, float rate
) {
540 for (int tr
= 0; tr
<= 200; tr
++) {
541 float ftr
= (float)tr
;
543 // Verified exact on MT-32
545 ftr
= 100.0f
+ (powf((ftr
- 100.0f
) / 100.0f
, 3.0f
) * 100.0f
);
547 // I think this is the one
548 float brsq
= powf(10.0f
, (tr
/ 50.0f
) - 1.0f
);
549 noteLookup
->filtTable
[0][tr
] = (int)((freq
* brsq
) / (rate
/ 2) * FILTERGRAN
);
550 if (noteLookup
->filtTable
[0][tr
]>=((FILTERGRAN
*15)/16))
551 noteLookup
->filtTable
[0][tr
] = ((FILTERGRAN
*15)/16);
553 float brsa
= powf(10.0f
, ((tr
/ 55.0f
) - 1.0f
)) / 2.0f
;
554 noteLookup
->filtTable
[1][tr
] = (int)((freq
* brsa
) / (rate
/ 2) * FILTERGRAN
);
555 if (noteLookup
->filtTable
[1][tr
]>=((FILTERGRAN
*15)/16))
556 noteLookup
->filtTable
[1][tr
] = ((FILTERGRAN
*15)/16);
560 static void initNFiltTable(NoteLookup
*noteLookup
, float freq
, float rate
) {
561 for (int cf
= 0; cf
<= 100; cf
++) {
562 float cfmult
= (float)cf
;
564 for (int tf
= 0;tf
<= 100; tf
++) {
565 float tfadd
= (float)tf
;
567 //float freqsum = exp((cfmult + tfadd) / 30.0f) / 4.0f;
568 //float freqsum = 0.15f * exp(0.45f * ((cfmult + tfadd) / 10.0f));
570 float freqsum
= powf(2.0f
, ((cfmult
+ tfadd
) - 40.0f
) / 16.0f
);
572 noteLookup
->nfiltTable
[cf
][tf
] = (int)((freq
* freqsum
) / (rate
/ 2) * FILTERGRAN
);
573 if (noteLookup
->nfiltTable
[cf
][tf
] >= ((FILTERGRAN
* 15) / 16))
574 noteLookup
->nfiltTable
[cf
][tf
] = ((FILTERGRAN
* 15) / 16);
579 File
*Tables::initNote(Synth
*synth
, NoteLookup
*noteLookup
, float note
, float rate
, float masterTune
, PCMWaveEntry
*pcmWaves
, File
*file
) {
580 float freq
= (float)(masterTune
* pow(2.0, ((double)note
- MIDDLEA
) / 12.0));
581 float div2
= rate
* 2.0f
/ freq
;
582 noteLookup
->div2
= (int)div2
;
584 if (noteLookup
->div2
== 0)
585 noteLookup
->div2
= 1;
587 initSaw(noteLookup
, noteLookup
->div2
);
589 //synth->printDebug("Note %f; freq=%f, div=%f", note, freq, rate / freq);
590 file
= initWave(synth
, noteLookup
, (const float)WGAMP
, div2
, file
);
592 // Create the pitch tables
593 if (noteLookup
->wavTable
== NULL
)
594 noteLookup
->wavTable
= new Bit32u
[synth
->controlROMMap
->pcmCount
];
595 double rateMult
= 32000.0 / rate
;
596 double tuner
= freq
* 65536.0f
;
597 for (int pc
= 0; pc
< synth
->controlROMMap
->pcmCount
; pc
++) {
598 noteLookup
->wavTable
[pc
] = (int)(tuner
/ pcmWaves
[pc
].tune
* rateMult
);
601 initFiltTable(noteLookup
, freq
, rate
);
602 initNFiltTable(noteLookup
, freq
, rate
);
606 bool Tables::initNotes(Synth
*synth
, PCMWaveEntry
*pcmWaves
, float rate
, float masterTune
) {
607 const char *NoteNames
[12] = {
608 "C ", "C#", "D ", "D#", "E ", "F ", "F#", "G ", "G#", "A ", "A#", "B "
611 int intRate
= (int)rate
;
612 char version
[4] = {0, 0, 0, 5};
613 sprintf(filename
, "waveformcache-%d-%.2f.raw", intRate
, (double)masterTune
);
617 strncpy(header
, "MT32WAVE", 8);
620 for (int i
= 0; i
< 4; i
++)
621 header
[pos
++] = version
[i
];
622 header
[pos
++] = (char)((intRate
>> 24) & 0xFF);
623 header
[pos
++] = (char)((intRate
>> 16) & 0xFF);
624 header
[pos
++] = (char)((intRate
>> 8) & 0xFF);
625 header
[pos
++] = (char)(intRate
& 0xFF);
626 int intTuning
= (int)masterTune
;
627 header
[pos
++] = (char)((intTuning
>> 8) & 0xFF);
628 header
[pos
++] = (char)(intTuning
& 0xFF);
630 header
[pos
] = (char)((masterTune
- intTuning
) * 10);
631 #if MT32EMU_WAVECACHEMODE < 2
632 bool reading
= false;
633 file
= synth
->openFile(filename
, File::OpenMode_read
);
636 if (file
->read(fileHeader
, 20) == 20) {
637 if (memcmp(fileHeader
, header
, 20) == 0) {
639 if (file
->readBit16u(&endianCheck
)) {
640 if (endianCheck
== 1) {
643 synth
->printDebug("Endian check in %s does not match expected", filename
);
646 synth
->printDebug("Unable to read endian check in %s", filename
);
649 synth
->printDebug("Header of %s does not match expected", filename
);
652 synth
->printDebug("Error reading 16 bytes of %s", filename
);
659 synth
->printDebug("Unable to open %s for reading", filename
);
663 float progress
= 0.0f
;
665 synth
->report(ReportType_progressInit
, &progress
);
666 for (int f
= LOWEST_NOTE
; f
<= HIGHEST_NOTE
; f
++) {
667 synth
->printDebug("Initialising note %s%d", NoteNames
[f
% 12], (f
/ 12) - 2);
668 NoteLookup
*noteLookup
= ¬eLookups
[f
- LOWEST_NOTE
];
669 file
= initNote(synth
, noteLookup
, (float)f
, rate
, masterTune
, pcmWaves
, file
);
670 progress
= (f
- LOWEST_NOTE
+ 1) / (float)NUM_NOTES
;
671 abort
= synth
->report(ReportType_progressInit
, &progress
) != 0;
676 #if MT32EMU_WAVECACHEMODE == 0 || MT32EMU_WAVECACHEMODE == 2
678 file
= synth
->openFile(filename
, File::OpenMode_write
);
680 if (file
->write(header
, 20) == 20 && file
->writeBit16u(1)) {
681 for (int f
= 0; f
< NUM_NOTES
; f
++) {
682 for (int i
= 0; i
< 3 && file
!= NULL
; i
++) {
683 int len
= noteLookups
[f
].waveformSize
[i
];
684 for (int j
= 0; j
< len
; j
++) {
685 if (!file
->writeBit16u(noteLookups
[f
].waveforms
[i
][j
])) {
686 synth
->printDebug("Error writing waveform cache file");
695 synth
->printDebug("Error writing 16-byte header to %s - won't continue saving", filename
);
698 synth
->printDebug("Unable to open %s for writing - won't be created", filename
);
704 synth
->closeFile(file
);
708 void Tables::freeNotes() {
709 for (int t
= 0; t
< 3; t
++) {
710 for (int m
= 0; m
< NUM_NOTES
; m
++) {
711 if (noteLookups
[m
].waveforms
[t
] != NULL
) {
712 delete[] noteLookups
[m
].waveforms
[t
];
713 noteLookups
[m
].waveforms
[t
] = NULL
;
714 noteLookups
[m
].waveformSize
[t
] = 0;
716 if (noteLookups
[m
].wavTable
!= NULL
) {
717 delete[] noteLookups
[m
].wavTable
;
718 noteLookups
[m
].wavTable
= NULL
;
722 initialisedMasterTune
= 0.0f
;
726 initialisedSampleRate
= 0.0f
;
727 initialisedMasterTune
= 0.0f
;
728 memset(¬eLookups
, 0, sizeof(noteLookups
));
731 bool Tables::init(Synth
*synth
, PCMWaveEntry
*pcmWaves
, float sampleRate
, float masterTune
) {
732 if (sampleRate
<= 0.0f
) {
733 synth
->printDebug("Bad sampleRate (%f <= 0.0f)", sampleRate
);
736 if (initialisedSampleRate
== 0.0f
) {
737 initMT32ConstantTables(synth
);
739 if (initialisedSampleRate
!= sampleRate
) {
740 initFiltCoeff(sampleRate
);
741 initEnvelopes(sampleRate
);
742 for (int key
= 12; key
<= 108; key
++) {
743 initDep(&keyLookups
[key
- 12], (float)key
);
746 if (initialisedSampleRate
!= sampleRate
|| initialisedMasterTune
!= masterTune
) {
748 if (!initNotes(synth
, pcmWaves
, sampleRate
, masterTune
)) {
751 initialisedSampleRate
= sampleRate
;
752 initialisedMasterTune
= masterTune
;