1 /*
2 fm4op.c:
3
4 Copyright (C) 1998 Perry Cook, John ffitch
5
6 This file is part of Csound.
7
8 The Csound Library is free software; you can redistribute it
9 and/or modify it under the terms of the GNU Lesser General Public
10 License as published by the Free Software Foundation; either
11 version 2.1 of the License, or (at your option) any later version.
12
13 Csound is distributed in the hope that it will be useful,
14 but WITHOUT ANY WARRANTY; without even the implied warranty of
15 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
16 GNU Lesser General Public License for more details.
17
18 You should have received a copy of the GNU Lesser General Public
19 License along with Csound; if not, write to the Free Software
20 Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21 02110-1301 USA
22 */
23
24 /*********************************************************/
25 /* Master Class for 4 Operator FM Synth */
26 /* by Perry R. Cook, 1995-96; recoded John ffitch 97/98 */
27 /* This instrument contains 4 waves, 4 adsr, and */
28 /* various state vars. */
29 /* */
30 /* The basic Chowning/Stanford FM patent expired April */
31 /* 1995, but there exist follow-on patents, mostly */
32 /* assigned to Yamaha. If you are of the type who */
33 /* should worry about this (making money) worry away. */
34 /* */
35 /*********************************************************/
36
37 #include "csoundCore.h"
38 #include "fm4op.h"
39
40 /***********************************************************/
41 /* Two Zero Filter Class, */
42 /* by Perry R. Cook, 1995-96; recoded John ffitch 97/98 */
43 /* See books on filters to understand more about how this */
44 /* works. Nothing out of the ordinary in this version. */
45 /***********************************************************/
46
47 /* Used by moog1.c as well */
make_TwoZero(TwoZero * p)48 void make_TwoZero(TwoZero *p)
49 {
50 p->zeroCoeffs[0] = FL(0.0);
51 p->zeroCoeffs[1] = FL(0.0);
52 p->gain = FL(1.0);
53 p->inputs[0] = FL(0.0);
54 p->inputs[1] = FL(0.0);
55 p->lastOutput = FL(0.0);
56 }
57
TwoZero_setZeroCoeffs(TwoZero * p,MYFLT * coeffs)58 void TwoZero_setZeroCoeffs(TwoZero* p, MYFLT *coeffs)
59 {
60 p->zeroCoeffs[0] = coeffs[0];
61 p->zeroCoeffs[1] = coeffs[1];
62 }
63
TwoZero_tick(TwoZero * p,MYFLT sample)64 MYFLT TwoZero_tick(TwoZero *p, MYFLT sample)
65 /* Perform Filter Operation */
66 { /* TwoZero is a two zero filter (duh!) */
67 /* Look it up in your favorite DSP text */
68 MYFLT lastOutput = p->zeroCoeffs[0] * p->inputs[0] +
69 p->zeroCoeffs[1] * p->inputs[1];
70 p->inputs[1] = p->inputs[0];
71 p->inputs[0] = p->gain * sample;
72 p->lastOutput = (lastOutput += p->inputs[0]);
73 return lastOutput;
74 }
75
Wave_tick(MYFLT * vTime,int32_t len,MYFLT * data,MYFLT rate,MYFLT phase)76 MYFLT Wave_tick(MYFLT *vTime, int32_t len, MYFLT *data, MYFLT rate, MYFLT phase)
77 { /* Tick on vibrato table */
78 int32 temp;
79 MYFLT alpha;
80 MYFLT lastOutput;
81 MYFLT vvTime = *vTime;
82
83 vvTime += rate; /* Update current time */
84 while (vvTime >= len) /* Check for end of sound */
85 vvTime -= len; /* loop back to beginning */
86 while (vvTime < FL(0.0)) /* Check for end of sound */
87 vvTime += len; /* loop back to beginning */
88
89 *vTime = vvTime;
90
91 if (phase != FL(0.0)) {
92 vvTime += phase; /* Add phase offset */
93 while (vvTime >= len) /* Check for end of sound */
94 vvTime -= len; /* loop back to beginning */
95 while (vvTime < FL(0.0)) /* Check for end of sound */
96 vvTime += len; /* loop back to beginning */
97 }
98 temp = (int32) vvTime; /* Integer part of time address */
99 /* fractional part of time address */
100 alpha = vvTime - (MYFLT)temp;
101 lastOutput = data[temp]; /* Do linear interpolation */
102 /* same as alpha*data[temp+1] + (1-alpha)data[temp] */
103 lastOutput += (alpha * (data[temp+1] - lastOutput));
104 /* End of vibrato tick */
105 return lastOutput;
106 }
107
108 /* ---------------------------------------------------------------------- */
109
110 static int32_t FM_tabs_built = 0;
111 static MYFLT FM4Op_gains[100];
112 static MYFLT FM4Op_susLevels[16];
113 static MYFLT FM4Op_attTimes[32];
114
build_FM(void)115 void build_FM(void)
116 { /* The following tables are pre-built */
117 MYFLT temp = FL(1.0);
118 int32_t i;
119
120 for (i=99; i>=0; i--) {
121 FM4Op_gains[i] = temp;
122 temp *= FL(0.933033);
123 }
124 temp = FL(1.0);
125 for (i=15; i>=0; i--) {
126 FM4Op_susLevels[i] = temp;
127 temp *= FL(0.707106781186547524400844362104849);
128 }
129 temp = FL(8.498186);
130 for (i=0; i<32; i++) {
131 FM4Op_attTimes[i] = temp;
132 temp *= FL(0.707106781186547524400844362104849);
133 }
134 FM_tabs_built = 1;
135 }
136
make_FM4Op(CSOUND * csound,FM4OP * p)137 int32_t make_FM4Op(CSOUND *csound, FM4OP *p)
138 {
139 MYFLT tempCoeffs[2] = {FL(0.0), -FL(1.0)};
140 FUNC *ftp;
141
142 if (!FM_tabs_built) build_FM(); /* Ensure tables exist */
143
144 make_ADSR(&p->adsr[0]);
145 make_ADSR(&p->adsr[1]);
146 make_ADSR(&p->adsr[2]);
147 make_ADSR(&p->adsr[3]);
148 make_TwoZero(&p->twozero);
149 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->vifn)) == NULL))
150 goto err1;
151 p->vibWave = ftp;
152 p->baseFreq = csound->A4;
153 p->ratios[0] = FL(1.0);
154 p->ratios[1] = FL(1.0);
155 p->ratios[2] = FL(1.0);
156 p->ratios[3] = FL(1.0);
157 p->gains[0] = FL(1.0);
158 p->gains[1] = FL(1.0);
159 p->gains[2] = FL(1.0);
160 p->gains[3] = FL(1.0);
161 TwoZero_setZeroCoeffs(&p->twozero, tempCoeffs);
162 p->twozero.gain = FL(0.0);
163 p->w_phase[3] = 0; /* *** FIDDLE???? *** */
164 return OK;
165 err1:
166 /* Expect sine wave */
167 return csound->InitError(csound, Str("No table for VibWaveato"));
168 }
169
FM4Op_loadWaves(CSOUND * csound,FM4OP * p)170 static int32_t FM4Op_loadWaves(CSOUND *csound, FM4OP *p)
171 {
172 FUNC *ftp;
173
174 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn0)) == NULL)) goto err1;
175 p->waves[0] = ftp;
176 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn1)) == NULL)) goto err1;
177 p->waves[1] = ftp;
178 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn2)) == NULL)) goto err1;
179 p->waves[2] = ftp;
180 if (UNLIKELY((ftp = csound->FTnp2Finde(csound, p->ifn3)) == NULL)) goto err1;
181 p->waves[3] = ftp;
182 p->w_time[0] = p->w_time[1] = p->w_time[2] = p->w_time[3] = FL(0.0);
183 return OK;
184 err1:
185 return csound->InitError(csound, Str("No table for FM4Op"));
186 }
187
FM4Op_setRatio(FM4OP * p,int32_t whichOne,MYFLT ratio)188 void FM4Op_setRatio(FM4OP *p, int32_t whichOne, MYFLT ratio)
189 {
190 p->ratios[whichOne] = ratio;
191 if (ratio>FL(0.0))
192 p->w_rate[whichOne] = p->baseFreq * ratio;
193 else
194 p->w_rate[whichOne] = ratio;
195 }
196
FM4Op_keyOff(FM4OP * p)197 void FM4Op_keyOff(FM4OP *p)
198 {
199 ADSR_keyOff(&p->adsr[0]);
200 ADSR_keyOff(&p->adsr[1]);
201 ADSR_keyOff(&p->adsr[2]);
202 ADSR_keyOff(&p->adsr[3]);
203 }
204
205 /*********************************************************/
206 /* Algorithm 5 (TX81Z) Subclass of 4 Operator FM Synth */
207 /* by Perry R. Cook, 1995-96; recoded John ffitch 97/98 */
208 /* This connection topology is 2 simple FM Pairs summed */
209 /* together, like: */
210 /* */
211 /* Alg 5 is : 4->3--\ */
212 /* + --> Out */
213 /* 2->1--/ */
214 /* */
215 /* Controls: control1 = mod index 1 */
216 /* control2 = crossfade of two outputs */
217 /* */
218 /*********************************************************/
219
FM4Alg5_tick(FM4OP * p,MYFLT c1,MYFLT c2)220 MYFLT FM4Alg5_tick(FM4OP *p, MYFLT c1, MYFLT c2)
221 {
222 MYFLT temp,temp2;
223 MYFLT lastOutput;
224
225 temp = p->gains[1] * ADSR_tick(&p->adsr[1]) *
226 Wave_tick(&p->w_time[1], (int32_t)p->waves[1]->flen, p->waves[1]->ftable,
227 p->w_rate[1], p->w_phase[1]);
228 temp = temp * c1;
229 p->w_phase[0] = p->waves[0]->flen * temp; /* addPhaseOffset */
230 p->w_phase[3] = p->waves[0]->flen * p->twozero.lastOutput;
231 temp = p->gains[3] * ADSR_tick(&p->adsr[3]) *
232 Wave_tick(&p->w_time[3], (int32_t)p->waves[3]->flen, p->waves[3]->ftable,
233 p->w_rate[3], p->w_phase[3]);
234 TwoZero_tick(&p->twozero, temp);
235 p->w_phase[2] = p->waves[2]->flen * temp; /* addPhaseOffset */
236 temp = (FL(1.0) - ( c2 * FL(0.5))) * p->gains[0] *
237 ADSR_tick(&p->adsr[0]) *
238 Wave_tick(&p->w_time[0], (int32_t)p->waves[0]->flen, p->waves[0]->ftable,
239 p->w_rate[0], p->w_phase[0]);
240 temp += c2 * FL(0.5) * p->gains[2] * ADSR_tick(&p->adsr[2]) *
241 Wave_tick(&p->w_time[2], (int32_t)p->waves[2]->flen, p->waves[2]->ftable,
242 p->w_rate[2], p->w_phase[2]);
243
244 temp2 = Wave_tick(&p->v_time, (int32_t)p->vibWave->flen,
245 p->vibWave->ftable, p->v_rate, FL(0.0)) *
246 *p->modDepth; /* Calculate amplitude mod */
247 temp = temp * (FL(1.0) + temp2); /* and apply it to output */
248
249 lastOutput = temp * FL(0.5);
250 return lastOutput;
251 }
252
253 /***************************************************************/
254 /* Tubular Bell (Orch. Chime) Subclass of Algorithm 5 (TX81Z) */
255 /* Subclass of 4 Operator FM Synth by Perry R. Cook, 1995-96 */
256 /* Recoded in C by John ffitch 1997-98 */
257 /***************************************************************/
258
tubebellset(CSOUND * csound,FM4OP * p)259 int32_t tubebellset(CSOUND *csound, FM4OP *p)
260 {
261 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
262 MYFLT opt = *p->opt;
263
264 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
265 if (UNLIKELY(FM4Op_loadWaves(csound,p)))
266 return NOTOK; /* 4 x "rawwaves/sinewave.raw" */
267
268 FM4Op_setRatio(p, 0, FL(1.0) * FL(0.995));
269 FM4Op_setRatio(p, 1, FL(1.414) * FL(0.995));
270 FM4Op_setRatio(p, 2, FL(1.0) * FL(1.005));
271 FM4Op_setRatio(p, 3, FL(1.414) );
272 p->gains[0] = amp * FM4Op_gains[94];
273 p->gains[1] = amp * FM4Op_gains[76];
274 p->gains[2] = amp * FM4Op_gains[99];
275 p->gains[3] = amp * FM4Op_gains[71];
276 if (opt<= FL(0.0)) opt = FL(4.0);
277 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.005), opt, FL(0.0), FL(0.04));
278 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.005), opt, FL(0.0), FL(0.04));
279 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.001),FL(0.5)*opt,FL(0.0), FL(0.04));
280 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.004), opt, FL(0.0), FL(0.04));
281 /* ADSR_setAll(csound, &p->adsr[0], 0.03f,0.00001f,FL(0.0),0.02f); */
282 /* ADSR_setAll(csound, &p->adsr[1], 0.03f,0.00001f,FL(0.0),0.02f); */
283 /* ADSR_setAll(csound, &p->adsr[2], 0.07f,0.00002f,FL(0.0),0.02f); */
284 /* ADSR_setAll(csound, &p->adsr[3], FL(0.04),0.00001f,FL(0.0),0.02f); */
285 p->twozero.gain = FL(0.5);
286 p->v_rate = FL(2.0) * p->vibWave->flen * csound->onedsr; /* Vib rate */
287 /* Set Freq */
288 p->baseFreq = *p->frequency;
289 p->w_rate[0] = p->baseFreq * p->ratios[0] * p->waves[0]->flen * csound->onedsr;
290 p->w_rate[1] = p->baseFreq * p->ratios[1] * p->waves[1]->flen * csound->onedsr;
291 p->w_rate[2] = p->baseFreq * p->ratios[2] * p->waves[2]->flen * csound->onedsr;
292 p->w_rate[3] = p->baseFreq * p->ratios[3] * p->waves[3]->flen * csound->onedsr;
293 ADSR_keyOn(&p->adsr[0]);
294 ADSR_keyOn(&p->adsr[1]);
295 ADSR_keyOn(&p->adsr[2]);
296 ADSR_keyOn(&p->adsr[3]);
297 return OK;
298 }
299
tubebell(CSOUND * csound,FM4OP * p)300 int32_t tubebell(CSOUND *csound, FM4OP *p)
301 {
302 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
303 MYFLT *ar = p->ar;
304 uint32_t offset = p->h.insdshead->ksmps_offset;
305 uint32_t early = p->h.insdshead->ksmps_no_end;
306 uint32_t n, nsmps = CS_KSMPS;
307 MYFLT c1 = *p->control1;
308 MYFLT c2 = *p->control2;
309
310 /* Set Freq */
311 p->baseFreq = *p->frequency;
312 p->gains[0] = amp * FM4Op_gains[94];
313 p->gains[1] = amp * FM4Op_gains[76];
314 p->gains[2] = amp * FM4Op_gains[99];
315 p->gains[3] = amp * FM4Op_gains[71];
316 p->w_rate[0] = p->baseFreq * p->ratios[0] * p->waves[0]->flen * csound->onedsr;
317 p->w_rate[1] = p->baseFreq * p->ratios[1] * p->waves[1]->flen * csound->onedsr;
318 p->w_rate[2] = p->baseFreq * p->ratios[2] * p->waves[2]->flen * csound->onedsr;
319 p->w_rate[3] = p->baseFreq * p->ratios[3] * p->waves[3]->flen * csound->onedsr;
320 p->v_rate = *p->vibFreq * p->vibWave->flen * csound->onedsr;
321
322 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
323 if (UNLIKELY(early)) {
324 nsmps -= early;
325 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
326 }
327 for (n=offset;n<nsmps;n++) {
328 MYFLT lastOutput = FM4Alg5_tick(p, c1, c2);
329 ar[n] = lastOutput*AMP_SCALE*FL(1.8);
330 }
331 return OK;
332 }
333
334 /*****************************************************************/
335 /* Fender Rhodes Electric Piano Subclass of Algorithm 5 (TX81Z) */
336 /* Subclass of 4 Operator FM Synth by Perry R. Cook, 1995-96 */
337 /* Recoded in C by John ffitch 1997-98 */
338 /*****************************************************************/
339
rhodeset(CSOUND * csound,FM4OP * p)340 int32_t rhodeset(CSOUND *csound, FM4OP *p)
341 {
342 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
343
344 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
345 if (UNLIKELY(FM4Op_loadWaves(csound,p))) return NOTOK; /* 3 times "sinewave.raw";
346 1 x fwavblnk.raw */
347
348 FM4Op_setRatio(p, 0, FL(1.0));
349 FM4Op_setRatio(p, 1, FL(0.5));
350 FM4Op_setRatio(p, 2, FL(1.0));
351 FM4Op_setRatio(p, 3, FL(15.0));
352 p->gains[0] = amp * FM4Op_gains[99];
353 p->gains[1] = amp * FM4Op_gains[90];
354 p->gains[2] = amp * FM4Op_gains[99];
355 p->gains[3] = amp * FM4Op_gains[67];
356 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.001), FL(1.50), FL(0.0), FL(0.04));
357 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.001), FL(1.50), FL(0.0), FL(0.04));
358 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.001), FL(1.00), FL(0.0), FL(0.04));
359 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.001), FL(0.25), FL(0.0), FL(0.04));
360 /* ADSR_setAll(&p->adsr[0], 0.05f,0.00003f,FL(0.0),0.02f); */
361 /* ADSR_setAll(&p->adsr[1], 0.05f,0.00003f,FL(0.0),0.02f); */
362 /* ADSR_setAll(&p->adsr[2], 0.05f,0.00005f,FL(0.0),0.02f); */
363 /* ADSR_setAll(&p->adsr[3], 0.05f,0.0002f,FL(0.0),0.02f); */
364 p->twozero.gain = FL(1.0);
365 p->v_rate = FL(2.0) * p->vibWave->flen * csound->onedsr; /* Vib rate */
366 /* Set Freq */
367 p->baseFreq = *p->frequency;
368 p->w_rate[0] = p->baseFreq * p->ratios[0] * p->waves[0]->flen * csound->onedsr;
369 p->w_rate[1] = p->baseFreq * p->ratios[1] * p->waves[1]->flen * csound->onedsr;
370 p->w_rate[2] = p->baseFreq * p->ratios[2] * p->waves[2]->flen * csound->onedsr;
371 p->w_rate[3] = p->baseFreq * p->ratios[3] * p->waves[3]->flen * csound->onedsr;
372 ADSR_keyOn(&p->adsr[0]);
373 ADSR_keyOn(&p->adsr[1]);
374 ADSR_keyOn(&p->adsr[2]);
375 ADSR_keyOn(&p->adsr[3]);
376 return OK;
377 }
378
379 /***************************************************************/
380 /* Wurlitzer Electric Piano Subclass of Algorithm 5 (TX81Z) */
381 /* Subclass of 4 Operator FM Synth by Perry R. Cook, 1995-96 */
382 /* Recoded in C by John ffitch 1997-98 */
383 /***************************************************************/
384
wurleyset(CSOUND * csound,FM4OP * p)385 int32_t wurleyset(CSOUND *csound, FM4OP *p)
386 {
387 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
388
389 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
390 if (UNLIKELY(FM4Op_loadWaves(csound,p))) return NOTOK; /* 3 x "sinewave.raw";
391 1 x fwavblnk.raw */
392
393 FM4Op_setRatio(p, 0, FL(1.0));
394 FM4Op_setRatio(p, 1, FL(4.05));
395 FM4Op_setRatio(p, 2, -FL(510.0));
396 FM4Op_setRatio(p, 3, -FL(510.0));
397 p->gains[0] = amp * FM4Op_gains[99];
398 p->gains[1] = amp * FM4Op_gains[82];
399 p->gains[2] = amp * FM4Op_gains[82];
400 p->gains[3] = amp * FM4Op_gains[68];
401 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.001), FL(1.50), FL(0.0), FL(0.04));
402 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.001), FL(1.50), FL(0.0), FL(0.04));
403 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.001), FL(0.25), FL(0.0), FL(0.04));
404 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.001), FL(0.15), FL(0.0), FL(0.04));
405 /* ADSR_setAll(&p->adsr[0], 0.05f,0.00003f,FL(0.0),0.02f); */
406 /* ADSR_setAll(&p->adsr[1], 0.05f,0.00003f,FL(0.0),0.02f); */
407 /* ADSR_setAll(&p->adsr[2], 0.05f,0.0002f,FL(0.0),0.02f); */
408 /* ADSR_setAll(&p->adsr[3], 0.05f,0.0003f,FL(0.0),0.02f); */
409 p->twozero.gain = FL(2.0);
410 /* Set Freq */
411 p->baseFreq = *p->frequency;
412 p->w_rate[0] = p->baseFreq * p->ratios[0] * p->waves[0]->flen * csound->onedsr;
413 p->w_rate[1] = p->baseFreq * p->ratios[1] * p->waves[1]->flen * csound->onedsr;
414 p->w_rate[2] = p->ratios[2] * p->waves[2]->flen * csound->onedsr;
415 p->w_rate[3] = p->ratios[3] * p->waves[3]->flen * csound->onedsr;
416 ADSR_keyOn(&p->adsr[0]);
417 ADSR_keyOn(&p->adsr[1]);
418 ADSR_keyOn(&p->adsr[2]);
419 ADSR_keyOn(&p->adsr[3]);
420 return OK;
421 }
422
wurley(CSOUND * csound,FM4OP * p)423 int32_t wurley(CSOUND *csound, FM4OP *p)
424 {
425 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
426 MYFLT *ar = p->ar;
427 uint32_t offset = p->h.insdshead->ksmps_offset;
428 uint32_t early = p->h.insdshead->ksmps_no_end;
429 uint32_t n, nsmps = CS_KSMPS;
430 MYFLT c1 = *p->control1;
431 MYFLT c2 = *p->control2;
432
433 /* Set Freq */
434 p->baseFreq = *p->frequency;
435 p->gains[0] = amp * FM4Op_gains[99];
436 p->gains[1] = amp * FM4Op_gains[82];
437 p->gains[2] = amp * FM4Op_gains[82];
438 p->gains[3] = amp * FM4Op_gains[68];
439 p->w_rate[0] = p->baseFreq * p->ratios[0] * p->waves[0]->flen * csound->onedsr;
440 p->w_rate[1] = p->baseFreq * p->ratios[1] * p->waves[1]->flen * csound->onedsr;
441 p->w_rate[2] = p->ratios[2] * p->waves[2]->flen * csound->onedsr;
442 p->w_rate[3] = p->ratios[3] * p->waves[3]->flen * csound->onedsr;
443 p->v_rate = *p->vibFreq * p->vibWave->flen * csound->onedsr;
444
445 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
446 if (UNLIKELY(early)) {
447 nsmps -= early;
448 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
449 }
450 for (n=offset;n<nsmps;n++) {
451 MYFLT lastOutput = FM4Alg5_tick(p, c1, c2);
452 ar[n] = lastOutput*AMP_SCALE*FL(1.9);
453 }
454 return OK;
455 }
456
457 /*********************************************************/
458 /* Algorithm 3 (TX81Z) Subclass of 4 Operator FM Synth */
459 /* by Perry R. Cook, 1995-96; recoded John ffitch 97/98 */
460 /* */
461 /* Alg 3 is : 4--\ */
462 /* 3-->2-- + -->1-->Out */
463 /* */
464 /* Controls: control1 = total mod index */
465 /* control2 = crossfade of two modulators */
466 /* */
467 /*********************************************************/
468
FM4Alg3_tick(FM4OP * p,MYFLT c1,MYFLT c2)469 MYFLT FM4Alg3_tick(FM4OP *p, MYFLT c1, MYFLT c2)
470 {
471 MYFLT temp;
472 MYFLT lastOutput;
473
474 temp = *p->modDepth * FL(0.2) *
475 Wave_tick(&p->v_time, (int32_t)p->vibWave->flen,
476 p->vibWave->ftable, p->v_rate, FL(0.0));
477 p->w_rate[0] = p->baseFreq * (FL(1.0) + temp) * p->ratios[0];
478 p->w_rate[1] = p->baseFreq * (FL(1.0) + temp) * p->ratios[1];
479 p->w_rate[2] = p->baseFreq * (FL(1.0) + temp) * p->ratios[2];
480 p->w_rate[3] = p->baseFreq * (FL(1.0) + temp) * p->ratios[3];
481
482 temp = p->gains[2] * ADSR_tick(&p->adsr[2]) *
483 Wave_tick(&p->w_time[2], (int32_t)p->waves[2]->flen, p->waves[2]->ftable,
484 p->w_rate[2], p->w_phase[2]);
485 p->w_phase[1] = p->waves[1]->flen * temp;
486 p->w_phase[3] = p->waves[3]->flen * p->twozero.lastOutput;
487 temp = (FL(1.0) - (c2 * FL(0.5))) * p->gains[3] * ADSR_tick(&p->adsr[3]) *
488 Wave_tick(&p->w_time[3], (int32_t)p->waves[3]->flen, p->waves[3]->ftable,
489 p->w_rate[3], p->w_phase[3]);
490 TwoZero_tick(&p->twozero, temp);
491
492 temp += c2 * FL(0.5) * p->gains[1] * ADSR_tick(&p->adsr[1]) *
493 Wave_tick(&p->w_time[1], (int32_t)p->waves[1]->flen, p->waves[1]->ftable,
494 p->w_rate[1], p->w_phase[1]);
495 temp = temp * c1;
496
497 p->w_phase[0] = p->waves[0]->flen * temp;
498 temp = p->gains[0] * ADSR_tick(&p->adsr[0]) *
499 Wave_tick(&p->w_time[0], (int32_t)p->waves[0]->flen, p->waves[0]->ftable,
500 p->w_rate[0], p->w_phase[0]);
501
502 lastOutput = temp * FL(0.5);
503 return lastOutput;
504 }
505
heavymetset(CSOUND * csound,FM4OP * p)506 int32_t heavymetset(CSOUND *csound, FM4OP *p)
507 {
508 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
509 if (UNLIKELY(FM4Op_loadWaves(csound,p))) return NOTOK; /* Mixed -- 2 x sine;
510 1 x fwavblnk */
511 FM4Op_setRatio(p, 0, FL(1.00) );
512 FM4Op_setRatio(p, 1, FL(4.00) * FL(0.999));
513 FM4Op_setRatio(p, 2, FL(3.00) * FL(1.001));
514 FM4Op_setRatio(p, 3, FL(0.50) * FL(1.002));
515 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.001), FL(0.001), FL(1.0), FL(0.01));
516 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.001), FL(0.010), FL(1.0), FL(0.50));
517 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.010), FL(0.005), FL(1.0), FL(0.20));
518 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.030), FL(0.010), FL(0.2), FL(0.20));
519 /* ADSR_setAll(&p->adsr[0], 0.050f, 0.0100f, FL(1.0), FL(0.001)); */
520 /* ADSR_setAll(&p->adsr[1], 0.050f, 0.0010f, FL(1.0), 0.0001f); */
521 /* ADSR_setAll(&p->adsr[2], FL(0.001), 0.0020f, FL(1.0), 0.0002f); */
522 /* ADSR_setAll(&p->adsr[3], 0.050f, 0.0010f, FL(0.2), 0.0002f); */
523 p->twozero.gain = FL(2.0);
524 /* p->v_rate = 5.5 * p->vibWave->flen * csound->onedsr; Vib rate */
525 ADSR_keyOn(&p->adsr[0]);
526 ADSR_keyOn(&p->adsr[1]);
527 ADSR_keyOn(&p->adsr[2]);
528 ADSR_keyOn(&p->adsr[3]);
529 return OK;
530 }
531
heavymet(CSOUND * csound,FM4OP * p)532 int32_t heavymet(CSOUND *csound, FM4OP *p)
533 {
534 MYFLT *ar = p->ar;
535 uint32_t offset = p->h.insdshead->ksmps_offset;
536 uint32_t early = p->h.insdshead->ksmps_no_end;
537 uint32_t n, nsmps = CS_KSMPS;
538 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
539 MYFLT c1 = *p->control1;
540 MYFLT c2 = *p->control2;
541 MYFLT temp;
542
543 p->baseFreq = *p->frequency;
544 p->gains[0] = amp * FM4Op_gains[92];
545 p->gains[1] = amp * FM4Op_gains[76];
546 p->gains[2] = amp * FM4Op_gains[91];
547 p->gains[3] = amp * FM4Op_gains[68];
548
549 temp = p->baseFreq * csound->onedsr;
550 p->w_rate[0] = temp * p->ratios[0] * p->waves[0]->flen;
551 p->w_rate[1] = temp * p->ratios[1] * p->waves[1]->flen;
552 p->w_rate[2] = temp * p->ratios[2] * p->waves[2]->flen;
553 p->w_rate[3] = temp * p->ratios[3] * p->waves[3]->flen;
554 p->v_rate = *p->vibFreq * p->vibWave->flen * csound->onedsr;
555 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
556 if (UNLIKELY(early)) {
557 nsmps -= early;
558 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
559 }
560 for (n=offset;n<nsmps;n++) {
561 MYFLT lastOutput;
562 lastOutput = FM4Alg3_tick(p, c1, c2);
563 ar[n] = lastOutput*AMP_SCALE*FL(2.0);
564 }
565 return OK;
566 }
567
568 /**********************************************************/
569 /* Algorithm 8 (TX81Z) Subclass of 4 Operator FM Synth */
570 /* by Perry R. Cook, 1995-96; recoded John ffitch 97-98 */
571 /* This connection topology is simple Additive Synthesis */
572 /* */
573 /* 1 --. */
574 /* 2 -\| */
575 /* +-> Out */
576 /* 3 -/| */
577 /* 4 -- */
578 /* */
579 /* Controls: control1 = op4 (fb) gain */
580 /* control2 = op3 gain */
581 /* */
582 /**********************************************************/
583
FM4Alg8_tick(FM4OP * p,MYFLT c1,MYFLT c2)584 MYFLT FM4Alg8_tick(FM4OP *p, MYFLT c1, MYFLT c2)
585 {
586 MYFLT temp;
587 MYFLT lastOutput;
588
589 p->w_phase[3] = p->waves[3]->flen * p->twozero.lastOutput;
590
591 temp = c1 * FL(2.0) * p->gains[3] * ADSR_tick(&p->adsr[3]) *
592 Wave_tick(&p->w_time[3], (int32_t)p->waves[3]->flen, p->waves[3]->ftable,
593 p->w_rate[3], p->w_phase[3]);
594 TwoZero_tick(&p->twozero, temp);
595 temp += c2 * FL(2.0) * p->gains[2] * ADSR_tick(&p->adsr[2]) *
596 Wave_tick(&p->w_time[2], (int32_t)p->waves[2]->flen, p->waves[2]->ftable,
597 p->w_rate[2], p->w_phase[2]);
598 temp += p->gains[1] * ADSR_tick(&p->adsr[1]) *
599 Wave_tick(&p->w_time[1], (int32_t)p->waves[1]->flen, p->waves[1]->ftable,
600 p->w_rate[1], p->w_phase[1]);
601 temp += p->gains[0] * ADSR_tick(&p->adsr[0]) *
602 Wave_tick(&p->w_time[0], (int32_t)p->waves[0]->flen, p->waves[0]->ftable,
603 p->w_rate[0], p->w_phase[0]);
604
605 lastOutput = temp * FL(0.125);
606 return lastOutput;
607 }
608
609 /**************************************************************/
610 /* Hammond(OID) Organ Subclass of Algorithm 8 (TX81Z) */
611 /* Subclass of 4 Operator FM Synth by Perry R. Cook, 1995-96 */
612 /* Recoded in C by John ffitch 1997-98 */
613 /**************************************************************/
614
b3set(CSOUND * csound,FM4OP * p)615 int32_t b3set(CSOUND *csound, FM4OP *p)
616 {
617 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
618 MYFLT temp = p->baseFreq * csound->onedsr;
619
620 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
621 if (UNLIKELY(FM4Op_loadWaves(csound,p))) return NOTOK; /* sines */
622 FM4Op_setRatio(p, 0, FL(0.999));
623 FM4Op_setRatio(p, 1, FL(1.997));
624 FM4Op_setRatio(p, 2, FL(3.006));
625 FM4Op_setRatio(p, 3, FL(6.009));
626
627 p->gains[0] = amp * FM4Op_gains[95];
628 p->gains[1] = amp * FM4Op_gains[95];
629 p->gains[2] = amp * FM4Op_gains[99];
630 p->gains[3] = amp * FM4Op_gains[95];
631 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.005), FL(0.003), FL(1.0), FL(0.01));
632 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.005), FL(0.003), FL(1.0), FL(0.01));
633 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.005), FL(0.003), FL(1.0), FL(0.01));
634 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.005), FL(0.001), FL(0.4), FL(0.03));
635 p->twozero.gain = FL(0.1);
636 ADSR_keyOn(&p->adsr[0]);
637 ADSR_keyOn(&p->adsr[1]);
638 ADSR_keyOn(&p->adsr[2]);
639 ADSR_keyOn(&p->adsr[3]);
640 p->w_rate[0] = p->ratios[0] * temp * p->waves[0]->flen;
641 p->w_rate[1] = p->ratios[1] * temp * p->waves[1]->flen;
642 p->w_rate[2] = p->ratios[2] * temp * p->waves[2]->flen;
643 p->w_rate[3] = p->ratios[3] * temp * p->waves[3]->flen;
644 return OK;
645 }
646
hammondB3(CSOUND * csound,FM4OP * p)647 int32_t hammondB3(CSOUND *csound, FM4OP *p)
648 {
649 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
650 MYFLT *ar = p->ar;
651 uint32_t offset = p->h.insdshead->ksmps_offset;
652 uint32_t early = p->h.insdshead->ksmps_no_end;
653 uint32_t n, nsmps = CS_KSMPS;
654 MYFLT c1 = *p->control1;
655 MYFLT c2 = *p->control2;
656 MYFLT temp;
657 MYFLT moddep = *p->modDepth;
658
659 p->baseFreq = *p->frequency;
660 p->gains[0] = amp * FM4Op_gains[95];
661 p->gains[1] = amp * FM4Op_gains[95];
662 p->gains[2] = amp * FM4Op_gains[99];
663 p->gains[3] = amp * FM4Op_gains[95];
664 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
665 if (UNLIKELY(early)) {
666 nsmps -= early;
667 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
668 }
669 for (n=offset;n<nsmps;n++) {
670 MYFLT lastOutput;
671 if (moddep > FL(0.0)) {
672 p->v_rate = *p->vibFreq * p->vibWave->flen * csound->onedsr;
673 temp = FL(1.0) + (moddep * FL(0.1) *
674 Wave_tick(&p->v_time, (int32_t)p->vibWave->flen,
675 p->vibWave->ftable, p->v_rate, FL(0.0)));
676 temp *= p->baseFreq * csound->onedsr;
677 p->w_rate[0] = p->ratios[0] * temp * p->waves[0]->flen;
678 p->w_rate[1] = p->ratios[1] * temp * p->waves[1]->flen;
679 p->w_rate[2] = p->ratios[2] * temp * p->waves[2]->flen;
680 p->w_rate[3] = p->ratios[3] * temp * p->waves[3]->flen;
681 }
682 // *** if modDepth is zero it looks as if w_rate should be initialised
683 // *** but it make no difference ***
684 lastOutput = FM4Alg8_tick(p, c1, c2);
685 ar[n]= lastOutput*AMP_SCALE;
686 }
687 return OK;
688 }
689
690 /************************************************************/
691 /* Algorithm 6 (TX81Z) Subclass of 4 Operator FM Synth */
692 /* by Perry R. Cook, 1995-96; recoded John ffitch 97-98 */
693 /* This connection topology is three Carriers and a common */
694 /* Modulator /->1 -\ */
695 /* 4-|-->2 - +-> Out */
696 /* \->3 -/ */
697 /* */
698 /* Controls: control1 = vowel */
699 /* control2 = spectral tilt */
700 /* */
701 /************************************************************/
702
FM4Alg6_tick(CSOUND * csound,FM4OPV * q)703 MYFLT FM4Alg6_tick(CSOUND *csound, FM4OPV *q)
704 {
705 MYFLT temp,temp2;
706 FM4OP *p = (FM4OP*)q;
707
708 temp = p->gains[3] * ADSR_tick(&p->adsr[3]) *
709 Wave_tick(&p->w_time[3], (int32_t)p->waves[3]->flen, p->waves[3]->ftable,
710 p->w_rate[3], p->w_phase[3]);
711 /* Calculate frequency mod */
712 temp2 = Wave_tick(&p->v_time, (int32_t)p->vibWave->flen, p->vibWave->ftable,
713 p->v_rate, FL(0.0)) * *p->modDepth * FL(0.1);
714
715 temp2 = (FL(1.0) + temp2) * p->baseFreq * csound->onedsr;
716 p->w_rate[0] = temp2 * p->ratios[0] * p->waves[0]->flen;
717 p->w_rate[1] = temp2 * p->ratios[1] * p->waves[1]->flen;
718 p->w_rate[2] = temp2 * p->ratios[2] * p->waves[2]->flen;
719 p->w_rate[3] = temp2 * p->ratios[3] * p->waves[3]->flen;
720
721 p->w_phase[0] = p->waves[0]->flen * temp * q->mods[0];
722 p->w_phase[1] = p->waves[1]->flen * temp * q->mods[1];
723 p->w_phase[2] = p->waves[2]->flen * temp * q->mods[2];
724 p->w_phase[3] = p->waves[3]->flen * p->twozero.lastOutput;
725
726 TwoZero_tick(&p->twozero, temp);
727
728 temp = p->gains[0] * q->tilt[0] * ADSR_tick(&p->adsr[0]) *
729 Wave_tick(&p->w_time[0], (int32_t)p->waves[0]->flen, p->waves[0]->ftable,
730 p->w_rate[0], p->w_phase[0]);
731 temp += p->gains[1] * q->tilt[1] * ADSR_tick(&p->adsr[1]) *
732 Wave_tick(&p->w_time[1], (int32_t)p->waves[1]->flen, p->waves[1]->ftable,
733 p->w_rate[1], p->w_phase[1]);
734 temp += p->gains[2] * q->tilt[2] * ADSR_tick(&p->adsr[2]) *
735 Wave_tick(&p->w_time[2], (int32_t)p->waves[2]->flen, p->waves[2]->ftable,
736 p->w_rate[2], p->w_phase[2]);
737
738 return temp * FL(0.33);
739 }
740
741 MYFLT phonGains[32][2] =
742 {{FL(1.0), FL(0.0)}, /* eee */
743 {FL(1.0), FL(0.0)}, /* ihh */
744 {FL(1.0), FL(0.0)}, /* ehh */
745 {FL(1.0), FL(0.0)}, /* aaa */
746
747 {FL(1.0), FL(0.0)}, /* ahh */
748 {FL(1.0), FL(0.0)}, /* aww */
749 {FL(1.0), FL(0.0)}, /* ohh */
750 {FL(1.0), FL(0.0)}, /* uhh */
751
752 {FL(1.0), FL(0.0)}, /* uuu */
753 {FL(1.0), FL(0.0)}, /* ooo */
754 {FL(1.0), FL(0.0)}, /* rrr */
755 {FL(1.0), FL(0.0)}, /* lll */
756
757 {FL(1.0), FL(0.0)}, /* mmm */
758 {FL(1.0), FL(0.0)}, /* nnn */
759 {FL(1.0), FL(0.0)}, /* nng */
760 {FL(1.0), FL(0.0)}, /* ngg */
761
762 {FL(0.0), FL(1.0)}, /* fff */
763 {FL(0.0), FL(1.0)}, /* sss */
764 {FL(0.0), FL(1.0)}, /* thh */
765 {FL(0.0), FL(1.0)}, /* shh */
766
767 {FL(0.0), FL(1.0)}, /* xxx */
768 {FL(0.0), FL(0.1)}, /* hee */
769 {FL(0.0), FL(0.1)}, /* hoo */
770 {FL(0.0), FL(0.1)}, /* hah */
771
772 {FL(1.0), FL(0.1)}, /* bbb */
773 {FL(1.0), FL(0.1)}, /* ddd */
774 {FL(1.0), FL(0.1)}, /* jjj */
775 {FL(1.0), FL(0.1)}, /* ggg */
776
777 {FL(1.0), FL(1.0)}, /* vvv */
778 {FL(1.0), FL(1.0)}, /* zzz */
779 {FL(1.0), FL(1.0)}, /* thz */
780 {FL(1.0), FL(1.0)} /* zhh */
781 };
782
783 MYFLT phonParams[32][4][3] =
784 {{ { FL(273.0), FL(0.996), FL(0.0)}, /* eee (beet) */
785 {FL(2086.0), FL(0.945), -FL(16.0)},
786 {FL(2754.0), FL(0.979), -FL(12.0)},
787 {FL(3270.0), FL(0.440), -FL(17.0)}},
788 { { FL(385.0), FL(0.987), FL(10.0)}, /* ihh (bit) */
789 {FL(2056.0), FL(0.930), -FL(20.0)},
790 {FL(2587.0), FL(0.890), -FL(20.0)},
791 {FL(3150.0), FL(0.400), -FL(20.0)}},
792 { { FL(515.0), FL(0.977), FL(10.0)}, /* ehh (bet) */
793 {FL(1805.0), FL(0.810), -FL(10.0)},
794 {FL(2526.0), FL(0.875), -FL(10.0)},
795 {FL(3103.0), FL(0.400), -FL(13.0)}},
796 { { FL(773.0), FL(0.950), FL(10.0)}, /* aaa (bat) */
797 {FL(1676.0), FL(0.830), -FL(6.0)},
798 {FL(2380.0), FL(0.880), -FL(20.0)},
799 {FL(3027.0), FL(0.600), -FL(20.0)}},
800
801 { { FL(770.0), FL(0.950), FL(0.0)}, /* ahh (father) */
802 {FL(1153.0), FL(0.970), -FL(9.0)},
803 {FL(2450.0), FL(0.780), -FL(29.0)},
804 {FL(3140.0), FL(0.800), -FL(39.0)}},
805 { { FL(637.0), FL(0.910), FL(0.0)}, /* aww (bought) */
806 { FL(895.0), FL(0.900), -FL(3.0)},
807 {FL(2556.0), FL(0.950), -FL(17.0)},
808 {FL(3070.0), FL(0.910), -FL(20.0)}},
809 { { FL(637.0), FL(0.910), FL(0.0)}, /* ohh (bone) */
810 /*NOTE:: same as aww (bought) */
811 { FL(895.0), FL(0.900), -FL(3.0)},
812 {FL(2556.0), FL(0.950), -FL(17.0)},
813 {FL(3070.0), FL(0.910), -FL(20.0)}},
814 { { FL(561.0), FL(0.965), FL(0.0)}, /* uhh (but) */
815 {FL(1084.0), FL(0.930), -FL(10.0)},
816 {FL(2541.0), FL(0.930), -FL(15.0)},
817 {FL(3345.0), FL(0.900), -FL(20.0)}},
818
819 { { FL(515.0), FL(0.976), FL(0.0)}, /* uuu (foot) */
820 {FL(1031.0), FL(0.950), -FL(3.0)},
821 {FL(2572.0), FL(0.960), -FL(11.0)},
822 {FL(3345.0), FL(0.960), -FL(20.0)}},
823 { { FL(349.0), FL(0.986), -FL(10.0)}, /* ooo (boot) */
824 { FL(918.0), FL(0.940), -FL(20.0)},
825 {FL(2350.0), FL(0.960), -FL(27.0)},
826 {FL(2731.0), FL(0.950), -FL(33.0)}},
827 { { FL(394.0), FL(0.959), -FL(10.0)}, /* rrr (bird) */
828 {FL(1297.0), FL(0.780), -FL(16.0)},
829 {FL(1441.0), FL(0.980), -FL(16.0)},
830 {FL(2754.0), FL(0.950), -FL(40.0)}},
831 { { FL(462.0), FL(0.990), +FL(5.0)}, /* lll (lull) */
832 {FL(1200.0), FL(0.640), -FL(10.0)},
833 {FL(2500.0), FL(0.200), -FL(20.0)},
834 {FL(3000.0), FL(0.100), -FL(30.0)}},
835
836 { { FL(265.0), FL(0.987), -FL(10.0)}, /* mmm (mom) */
837 {FL(1176.0), FL(0.940), -FL(22.0)},
838 {FL(2352.0), FL(0.970), -FL(20.0)},
839 {FL(3277.0), FL(0.940), -FL(31.0)}},
840 { { FL(204.0), FL(0.980), -FL(10.0)}, /* nnn (nun) */
841 {FL(1570.0), FL(0.940), -FL(15.0)},
842 {FL(2481.0), FL(0.980), -FL(12.0)},
843 {FL(3133.0), FL(0.800), -FL(30.0)}},
844 { { FL(204.0), FL(0.980), -FL(10.0)}, /* nng (sang) NOTE:: same as nnn */
845 {FL(1570.0), FL(0.940), -FL(15.0)},
846 {FL(2481.0), FL(0.980), -FL(12.0)},
847 {FL(3133.0), FL(0.800), -FL(30.0)}},
848 { { FL(204.0), FL(0.980), -FL(10.0)}, /* ngg (bong) NOTE:: same as nnn */
849 {FL(1570.0), FL(0.940), -FL(15.0)},
850 {FL(2481.0), FL(0.980), -FL(12.0)},
851 {FL(3133.0), FL(0.800), -FL(30.0)}},
852
853 { {FL(1000.0), FL(0.300), FL(0.0)}, /* fff */
854 {FL(2800.0), FL(0.860), -FL(10.0)},
855 {FL(7425.0), FL(0.740), FL(0.0)},
856 {FL(8140.0), FL(0.860), FL(0.0)}},
857 { {FL(0.0), FL(0.000), FL(0.0)}, /* sss */
858 {FL(2000.0), FL(0.700), -FL(15.0)},
859 {FL(5257.0), FL(0.750), -FL(3.0)},
860 {FL(7171.0), FL(0.840), FL(0.0)}},
861 { { FL(100.0), FL(0.900), FL(0.0)}, /* thh */
862 {FL(4000.0), FL(0.500), -FL(20.0)},
863 {FL(5500.0), FL(0.500), -FL(15.0)},
864 {FL(8000.0), FL(0.400), -FL(20.0)}},
865 { {FL(2693.0), FL(0.940), FL(0.0)}, /* shh */
866 {FL(4000.0), FL(0.720), -FL(10.0)},
867 {FL(6123.0), FL(0.870), -FL(10.0)},
868 {FL(7755.0), FL(0.750), -FL(18.0)}},
869
870 { {FL(1000.0), FL(0.300), -FL(10.0)}, /* xxx NOTE:: Not Really Done Yet */
871 {FL(2800.0), FL(0.860), -FL(10.0)},
872 {FL(7425.0), FL(0.740), FL(0.0)},
873 {FL(8140.0), FL(0.860), FL(0.0)}},
874 { { FL(273.0), FL(0.996), -FL(40.0)}, /* hee (beet) (noisy eee) */
875 {FL(2086.0), FL(0.945), -FL(16.0)},
876 {FL(2754.0), FL(0.979), -FL(12.0)},
877 {FL(3270.0), FL(0.440), -FL(17.0)}},
878 { { FL(349.0), FL(0.986), -FL(40.0)}, /* hoo (boot) (noisy ooo) */
879 { FL(918.0), FL(0.940), -FL(10.0)},
880 {FL(2350.0), FL(0.960), -FL(17.0)},
881 {FL(2731.0), FL(0.950), -FL(23.0)}},
882 { { FL(770.0), FL(0.950), -FL(40.0)}, /* hah (father) (noisy ahh) */
883 {FL(1153.0), FL(0.970), -FL(3.0)},
884 {FL(2450.0), FL(0.780), -FL(20.0)},
885 {FL(3140.0), FL(0.800), -FL(32.0)}},
886
887 { {FL(2000.0), FL(0.700), -FL(20.0)}, /* bbb NOTE:: Not Really Done Yet */
888 {FL(5257.0), FL(0.750), -FL(15.0)},
889 {FL(7171.0), FL(0.840), -FL(3.0)},
890 {FL(9000.0), FL(0.900), FL(0.0)}},
891 { { FL(100.0), FL(0.900), FL(0.0)}, /* ddd NOTE:: Not Really Done Yet */
892 {FL(4000.0), FL(0.500), -FL(20.0)},
893 {FL(5500.0), FL(0.500), -FL(15.0)},
894 {FL(8000.0), FL(0.400), -FL(20.0)}},
895 { {FL(2693.0), FL(0.940), FL(0.0)}, /* jjj NOTE:: Not Really Done Yet */
896 {FL(4000.0), FL(0.720), -FL(10.0)},
897 {FL(6123.0), FL(0.870), -FL(10.0)},
898 {FL(7755.0), FL(0.750), -FL(18.0)}},
899 { {FL(2693.0), FL(0.940), FL(0.0)}, /* ggg NOTE:: Not Really Done Yet */
900 {FL(4000.0), FL(0.720), -FL(10.0)},
901 {FL(6123.0), FL(0.870), -FL(10.0)},
902 {FL(7755.0), FL(0.750), -FL(18.0)}},
903
904 { {FL(2000.0), FL(0.700), -FL(20.0)}, /* vvv NOTE:: Not Really Done Yet */
905 {FL(5257.0), FL(0.750), -FL(15.0)},
906 {FL(7171.0), FL(0.840), -FL(3.0)},
907 {FL(9000.0), FL(0.900), FL(0.0)}},
908 { { FL(100.0), FL(0.900), FL(0.0)}, /* zzz NOTE:: Not Really Done Yet */
909 {FL(4000.0), FL(0.500), -FL(20.0)},
910 {FL(5500.0), FL(0.500), -FL(15.0)},
911 {FL(8000.0), FL(0.400), -FL(20.0)}},
912 { {FL(2693.0), FL(0.940), FL(0.0)}, /* thz NOTE:: Not Really Done Yet */
913 {FL(4000.0), FL(0.720), -FL(10.0)},
914 {FL(6123.0), FL(0.870), -FL(10.0)},
915 {FL(7755.0), FL(0.750), -FL(18.0)}},
916 { {FL(2693.0), FL(0.940), FL(0.0)}, /* zhh NOTE:: Not Really Done Yet */
917 {FL(4000.0), FL(0.720), -FL(10.0)},
918 {FL(6123.0), FL(0.870), -FL(10.0)},
919 {FL(7755.0), FL(0.750), -FL(18.0)}}
920 };
921
922 #define currentVowel (*q->control1)
923
FMVoices_setFreq(FM4OPV * q,MYFLT frequency)924 void FMVoices_setFreq(FM4OPV *q, MYFLT frequency)
925 {
926 MYFLT temp,temp2 = FL(0.0);
927 int32_t tempi,tempi2 = 0;
928
929 if (currentVowel < 32) {
930 tempi2 = (int32_t)currentVowel;
931 temp2 = FL(0.9);
932 }
933 else if (currentVowel < 64) {
934 tempi2 =(int32_t) currentVowel - 32;
935 temp2 = FL(1.0);
936 }
937 else if (currentVowel < 96) {
938 tempi2 = (int32_t)currentVowel - 64;
939 temp2 = FL(1.1);
940 }
941 else if (currentVowel < 128) {
942 tempi2 = (int32_t)currentVowel - 96;
943 temp2 = FL(1.2);
944 }
945 q->baseFreq = frequency;
946 temp = (temp2 * phonParams[tempi2][0][0] / q->baseFreq) + FL(0.5);
947 tempi = (int32_t) temp;
948 FM4Op_setRatio((FM4OP*)q, 0, (MYFLT) tempi);
949 temp = (temp2 * phonParams[tempi2][1][0] / q->baseFreq) + FL(0.5);
950 tempi = (int32_t) temp;
951 FM4Op_setRatio((FM4OP*)q, 1, (MYFLT) tempi);
952 temp = (temp2 * phonParams[tempi2][2][0] / q->baseFreq) + FL(0.5);
953 tempi = (int32_t) temp;
954 FM4Op_setRatio((FM4OP*)q, 2, (MYFLT) tempi);
955 q->gains[0] = FL(1.0); /* pow(10.0f,phonParams[tempi2][0][2] * 0.05f); */
956 q->gains[1] = FL(1.0); /* pow(10.0f,phonParams[tempi2][1][2] * 0.05f); */
957 q->gains[2] = FL(1.0); /* pow(10.0f,phonParams[tempi2][2][2] * 0.05f); */
958 }
959
FMVoiceset(CSOUND * csound,FM4OPV * q)960 int32_t FMVoiceset(CSOUND *csound, FM4OPV *q)
961 {
962 FM4OP *p = (FM4OP *)q;
963 MYFLT amp = *q->amp * AMP_RSCALE;
964
965 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
966 if (UNLIKELY(FM4Op_loadWaves(csound,p))) return NOTOK;
967 FM4Op_setRatio(p, 0, FL(2.00));
968 FM4Op_setRatio(p, 1, FL(4.00));
969 FM4Op_setRatio(p, 2, FL(12.0));
970 FM4Op_setRatio(p, 3, FL(1.00));
971 p->gains[3] = FM4Op_gains[80];
972 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.050), FL(0.050),
973 FM4Op_susLevels[15], FL(0.050));
974 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.050), FL(0.050),
975 FM4Op_susLevels[15], FL(0.050));
976 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.050), FL(0.050),
977 FM4Op_susLevels[15], FL(0.050));
978 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.001), FL(0.010),
979 FM4Op_susLevels[15], FL(0.500));
980 p->twozero.gain = FL(0.0);
981 /* modDepth = 0.005; */
982 q->tilt[0] = FL(1.0);
983 q->tilt[1] = FL(0.5);
984 q->tilt[2] = FL(0.2);
985 q->mods[0] = FL(1.0);
986 q->mods[1] = FL(1.1);
987 q->mods[2] = FL(1.1);
988 p->baseFreq = FL(110.0);
989 FMVoices_setFreq(q, FL(110.0));
990 q->tilt[0] = amp;
991 q->tilt[1] = amp * amp;
992 q->tilt[2] = amp * amp * amp;
993 ADSR_keyOn(&p->adsr[0]);
994 ADSR_keyOn(&p->adsr[1]);
995 ADSR_keyOn(&p->adsr[2]);
996 ADSR_keyOn(&p->adsr[3]);
997 q->last_control = -FL(1.0);
998 return OK;
999 }
1000
FMVoice(CSOUND * csound,FM4OPV * q)1001 int32_t FMVoice(CSOUND *csound, FM4OPV *q)
1002 {
1003 FM4OP *p = (FM4OP *)q;
1004 MYFLT amp = *q->amp * AMP_RSCALE;
1005 MYFLT *ar = q->ar;
1006 uint32_t offset = p->h.insdshead->ksmps_offset;
1007 uint32_t early = p->h.insdshead->ksmps_no_end;
1008 uint32_t n, nsmps = CS_KSMPS;
1009
1010 if (p->baseFreq != *q->frequency || *q->control1 != q->last_control) {
1011 q->last_control = *q->control1;
1012 p->baseFreq = *q->frequency;
1013 FMVoices_setFreq(q, p->baseFreq);
1014 }
1015 q->tilt[0] = amp;
1016 q->tilt[1] = amp * amp;
1017 q->tilt[2] = amp * amp * amp;
1018 p->gains[3] = FM4Op_gains[(int32_t) (*p->control2 * FL(0.78125))];
1019
1020 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
1021 if (UNLIKELY(early)) {
1022 nsmps -= early;
1023 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
1024 }
1025 for (n=offset;n<nsmps;n++) {
1026 MYFLT lastOutput;
1027 lastOutput = FM4Alg6_tick(csound,q);
1028 ar[n] = lastOutput*AMP_SCALE*FL(0.8);
1029 }
1030
1031 return OK;
1032 }
1033
1034 /* ********************************************************************** */
1035
1036 /*********************************************************/
1037 /* Algorithm 4 (TX81Z) Subclass of 4 Operator FM Synth */
1038 /* by Perry R. Cook, 1995-96 Recoded John ffitch 97/98 */
1039 /* */
1040 /* Alg 4 is : 4->3--\ */
1041 /* 2-- + -->1-->Out */
1042 /* */
1043 /* Controls: control1 = total mod index */
1044 /* control2 = crossfade of two */
1045 /* modulators */
1046 /* */
1047 /*********************************************************/
1048
FM4Alg4_tick(CSOUND * csound,FM4OP * p,MYFLT c1,MYFLT c2)1049 MYFLT FM4Alg4_tick(CSOUND *csound, FM4OP *p, MYFLT c1, MYFLT c2)
1050 {
1051 MYFLT temp;
1052 MYFLT lastOutput;
1053
1054 temp = Wave_tick(&p->v_time, (int32_t)p->vibWave->flen,
1055 p->vibWave->ftable, p->v_rate, FL(0.0)) *
1056 *p->modDepth * FL(0.2);
1057 temp = p-> baseFreq * (FL(1.0) + temp)* csound->onedsr;
1058 p->w_rate[0] = p->ratios[0] * temp * p->waves[0]->flen;
1059 p->w_rate[1] = p->ratios[1] * temp * p->waves[1]->flen;
1060 p->w_rate[2] = p->ratios[2] * temp * p->waves[2]->flen;
1061 p->w_rate[3] = p->ratios[3] * temp * p->waves[3]->flen;
1062
1063 p->w_phase[3] = p->waves[3]->flen * p->twozero.lastOutput;
1064 temp = p->gains[3] * ADSR_tick(&p->adsr[3]) *
1065 Wave_tick(&p->w_time[3], (int32_t)p->waves[3]->flen, p->waves[3]->ftable,
1066 p->w_rate[3], p->w_phase[3]);
1067 TwoZero_tick(&p->twozero, temp);
1068 p->w_phase[2] = p->waves[2]->flen * temp;
1069 temp = (FL(1.0) - (c2 * FL(0.5))) * p->gains[2] * ADSR_tick(&p->adsr[2]) *
1070 Wave_tick(&p->w_time[2], (int32_t)p->waves[2]->flen, p->waves[2]->ftable,
1071 p->w_rate[2], p->w_phase[2]);
1072 temp += c2 * FL(0.5) * p->gains[1] * ADSR_tick(&p->adsr[1]) *
1073 Wave_tick(&p->w_time[1], (int32_t)p->waves[1]->flen, p->waves[1]->ftable,
1074 p->w_rate[1], p->w_phase[1]);
1075 temp = temp * c1;
1076 p->w_phase[0] = p->waves[0]->flen * temp;
1077 temp = p->gains[0] * ADSR_tick(&p->adsr[0]) *
1078 Wave_tick(&p->w_time[0], (int32_t)p->waves[0]->flen, p->waves[0]->ftable,
1079 p->w_rate[0], p->w_phase[0]);
1080
1081 lastOutput = temp * FL(0.5);
1082 return lastOutput;
1083 }
1084
percfluteset(CSOUND * csound,FM4OP * p)1085 int32_t percfluteset(CSOUND *csound, FM4OP *p)
1086 {
1087 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
1088
1089 if (UNLIKELY(make_FM4Op(csound,p))) return NOTOK;
1090 if (UNLIKELY(FM4Op_loadWaves(csound,p)))
1091 return NOTOK; /* 3 x sines; 1 x fwavblnk */
1092
1093 FM4Op_setRatio(p, 0, FL(1.50) );
1094 FM4Op_setRatio(p, 1, FL(3.00) * FL(0.995));
1095 FM4Op_setRatio(p, 2, FL(2.99) * FL(1.005));
1096 FM4Op_setRatio(p, 3, FL(6.00) * FL(0.997));
1097
1098 p->gains[0] = amp * FM4Op_gains[99];
1099 p->gains[1] = amp * FM4Op_gains[71];
1100 p->gains[2] = amp * FM4Op_gains[93];
1101 p->gains[3] = amp * FM4Op_gains[85];
1102 ADSR_setAllTimes(csound, &p->adsr[0], FL(0.05), FL(0.05),
1103 FM4Op_susLevels[14], FL(0.05));
1104 ADSR_setAllTimes(csound, &p->adsr[1], FL(0.02), FL(0.50),
1105 FM4Op_susLevels[13], FL(0.5));
1106 ADSR_setAllTimes(csound, &p->adsr[2], FL(0.02), FL(0.30),
1107 FM4Op_susLevels[11], FL(0.05));
1108 ADSR_setAllTimes(csound, &p->adsr[3], FL(0.02), FL(0.05),
1109 FM4Op_susLevels[13], FL(0.01));
1110 p->twozero.gain = FL(0.0);
1111 /* modDepth = FL(0.005); */
1112 ADSR_keyOn(&p->adsr[0]);
1113 ADSR_keyOn(&p->adsr[1]);
1114 ADSR_keyOn(&p->adsr[2]);
1115 ADSR_keyOn(&p->adsr[3]);
1116 return OK;
1117 }
1118
percflute(CSOUND * csound,FM4OP * p)1119 int32_t percflute(CSOUND *csound, FM4OP *p)
1120 {
1121 MYFLT *ar = p->ar;
1122 uint32_t offset = p->h.insdshead->ksmps_offset;
1123 uint32_t early = p->h.insdshead->ksmps_no_end;
1124 uint32_t n, nsmps = CS_KSMPS;
1125 MYFLT amp = *p->amp * AMP_RSCALE; /* Normalised */
1126 MYFLT c1 = *p->control1;
1127 MYFLT c2 = *p->control2;
1128
1129 p->baseFreq = *p->frequency;
1130 p->gains[0] = amp * FM4Op_gains[99] * FL(0.5);
1131 p->gains[1] = amp * FM4Op_gains[71] * FL(0.5);
1132 p->gains[2] = amp * FM4Op_gains[93] * FL(0.5);
1133 p->gains[3] = amp * FM4Op_gains[85] * FL(0.5);
1134 p->v_rate = *p->vibFreq * p->vibWave->flen * csound->onedsr;
1135
1136 if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
1137 if (UNLIKELY(early)) {
1138 nsmps -= early;
1139 memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
1140 }
1141 for (n=offset;n<nsmps;n++) {
1142 MYFLT lastOutput = FM4Alg4_tick(csound, p, c1, c2);
1143 ar[n] = lastOutput*AMP_SCALE*FL(2.0);
1144 }
1145 return OK;
1146 }
1147
1148