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