1 /*
2     modal4.c:
3 
4     Copyright (C) 1996, 1997 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 /*  4 Resonance Modal Synthesis Instrument */
26 /*  by Perry R. Cook, 1995-96              */
27 /*  This instrument contains an excitation */
28 /*  wavetable, an envelope, and four reso- */
29 /*  nances (Non-Sweeping BiQuad Filters).  */
30 /*******************************************/
31 // #include "csdl.h"
32 #include "csoundCore.h"
33 #include "modal4.h"
34 #include "marimba.h"
35 #include "vibraphn.h"
36 #include <math.h>
37 #include "interlocks.h"
make_Modal4(CSOUND * csound,Modal4 * m,MYFLT * ifn,MYFLT vgain,MYFLT vrate)38 static int32_t make_Modal4(CSOUND *csound,
39                        Modal4 *m, MYFLT *ifn, MYFLT vgain, MYFLT vrate)
40 {
41     FUNC        *ftp;
42 
43     if (LIKELY((ftp = csound->FTnp2Find(csound,ifn)) != NULL))
44       m->vibr = ftp;
45     else {                                              /* Expect sine wave */
46      csound->ErrorMsg(csound, Str("No table for Modal4 case"));
47      return NOTOK;
48     }
49     make_Envelope(&m->envelope);
50         /*  We do not make the excitation wave here yet,   */
51         /*  because we do not know what it's going to be.  */
52     make_BiQuad(&m->filters[0]);
53     make_BiQuad(&m->filters[1]);
54     make_BiQuad(&m->filters[2]);
55     make_BiQuad(&m->filters[3]);
56     make_OnePole(&m->onepole);
57 
58     m->v_rate = vrate; /* 6.0; */
59     m->vibrGain = vgain; /* 0.05; */
60 
61 /*     m->directGain = 0.0; */
62     m->masterGain = FL(1.0);
63 /*     m->baseFreq = 440.0; */
64 /*     Modal4_setRatioAndReson(m, 0, 1.00, 0.9997); */    /*  Set some      */
65 /*     Modal4_setRatioAndReson(m, 1, 1.30, 0.9997); */    /*  silly         */
66 /*     Modal4_setRatioAndReson(m, 2, 1.77, 0.9997); */    /*  default       */
67 /*     Modal4_setRatioAndReson(m, 3, 2.37, 0.9997); */    /*  values here   */
68 /*     Modal4_setFiltGain(m, 0, 0.01); */
69 /*     Modal4_setFiltGain(m, 1, 0.01); */
70 /*     Modal4_setFiltGain(m, 2, 0.01); */
71 /*     Modal4_setFiltGain(m, 3, 0.01); */
72 /*     OnePole_clear(&m->onepole); */
73     BiQuad_clear(&m->filters[0]);
74     BiQuad_clear(&m->filters[1]);
75     BiQuad_clear(&m->filters[2]);
76     BiQuad_clear(&m->filters[3]);
77     BiQuad_setEqualGainZeroes(m->filters[0]);
78     BiQuad_setEqualGainZeroes(m->filters[1]);
79     BiQuad_setEqualGainZeroes(m->filters[2]);
80     BiQuad_setEqualGainZeroes(m->filters[3]);
81 /*     stickHardness = 0.5; */
82 /*     strikePosition = 0.561; */
83     return OK;
84 }
85 
Modal4_setFreq(CSOUND * csound,Modal4 * m,MYFLT frequency)86 void Modal4_setFreq(CSOUND *csound, Modal4 *m, MYFLT frequency)
87 {
88     m->baseFreq = frequency;
89     Modal4_setRatioAndReson(csound, m, 0,m->ratios[0],m->resons[0]);
90     Modal4_setRatioAndReson(csound, m, 1,m->ratios[1],m->resons[1]);
91     Modal4_setRatioAndReson(csound, m, 2,m->ratios[2],m->resons[2]);
92     Modal4_setRatioAndReson(csound, m, 3,m->ratios[3],m->resons[3]);
93 }
94 
Modal4_setRatioAndReson(CSOUND * csound,Modal4 * m,int32_t whichOne,MYFLT ratio,MYFLT reson)95 void Modal4_setRatioAndReson(CSOUND *csound,
96                              Modal4 *m, int32_t whichOne, MYFLT ratio,MYFLT reson)
97 {
98     MYFLT temp;
99     if (ratio* m->baseFreq < CS_ESR * FL(0.5)) {
100       m->ratios[whichOne] = ratio;
101     }
102     else {
103       temp = ratio;
104       while (temp* m->baseFreq > FL(0.5)*CS_ESR) temp *= FL(0.5);
105       m->ratios[whichOne] = temp;
106     }
107     m->resons[whichOne] = reson;
108     if (ratio<0)
109       temp = -ratio;
110     else
111       temp = ratio * m->baseFreq;
112     BiQuad_setFreqAndReson(m->filters[whichOne], temp,reson);
113 }
114 
Modal4_strike(CSOUND * csound,Modal4 * m,MYFLT amplitude)115 static void Modal4_strike(CSOUND *csound, Modal4 *m, MYFLT amplitude)
116 {
117     int32_t i;
118     MYFLT temp;
119     Envelope_setRate(csound, &m->envelope, FL(1.0));
120     Envelope_setTarget(&m->envelope, amplitude);
121     OnePole_setPole(&m->onepole, FL(1.0) - amplitude);
122     Envelope_tick(&m->envelope);
123     m->w_time = FL(0.0);
124     //m->w_lastOutput = FL(0.0);
125     m->w_allDone = 0;
126                                 /*     wave->reset(); */
127     for (i=0;i<4;i++)   {
128       if (m->ratios[i] < 0)
129         temp = - m->ratios[i];
130       else
131         temp = m->ratios[i] * m->baseFreq;
132       BiQuad_setFreqAndReson(m->filters[i], temp, m->resons[i]);
133     }
134 }
135 
Modal4_damp(CSOUND * csound,Modal4 * m,MYFLT amplitude)136 static void Modal4_damp(CSOUND *csound, Modal4 *m, MYFLT amplitude)
137 {
138     int32_t i;
139     MYFLT temp;
140     for (i=0;i<4;i++)   {
141       if (m->ratios[i] < 0)
142         temp = - m->ratios[i];
143       else
144         temp = m->ratios[i] * m->baseFreq;
145       BiQuad_setFreqAndReson(m->filters[i], temp, m->resons[i]*amplitude);
146     }
147 }
148 
Modal4_tick(Modal4 * m)149 static MYFLT Modal4_tick(Modal4 *m)
150 {
151     MYFLT temp,temp2;
152     int32 itemp;
153     MYFLT temp_time, alpha, lastOutput;
154     int32_t length = (int32_t)m->wave->flen;
155 
156     m->w_time += m->w_rate;                  /*  Update current time          */
157     if (m->w_time >= length)  {              /*  Check for end of sound       */
158       m->w_time = (MYFLT)(length-1);         /*  stick at end                 */
159       m->w_allDone = 1;                      /*  Information for one-shot use */
160     }
161     else if (m->w_time < FL(0.0))            /*  Check for end of sound       */
162       m->w_time = FL(0.0);                   /*  stick at beg                 */
163 
164     temp_time = m->w_time;
165 
166 #ifdef phase_offset
167     if (m->w_phaseOffset != FL(0.0)) {
168       temp_time += m->w_phaseOffset;         /*  Add phase offset             */
169       if (temp_time >= length)               /*  Check for end of sound       */
170         temp_time = length-1;                /*  stick at end                 */
171       else if (temp_time < FL(0.0))          /*  check for end of sound       */
172         temp_time = FL(0.0);                 /*  stick at beg                 */
173     }
174 #endif
175 
176     itemp = (int32) temp_time;               /* Integer part of time address  */
177     alpha = temp_time - (MYFLT)itemp;      /* fractional part of time address */
178     lastOutput = m->wave->ftable[itemp];     /*  Do linear interpolation      */
179     lastOutput = lastOutput +                /*  same as alpha*data[temp+1]   */
180         (alpha * (m->wave->ftable[itemp+1] -
181                   lastOutput));              /*  + (1-alpha)data[temp]        */
182 
183     temp   = m->masterGain *
184       OnePole_tick(&m->onepole, lastOutput * Envelope_tick(&m->envelope));
185     temp2  = BiQuad_tick(&m->filters[0], temp);
186     temp2 += BiQuad_tick(&m->filters[1], temp);
187     temp2 += BiQuad_tick(&m->filters[2], temp);
188     temp2 += BiQuad_tick(&m->filters[3], temp);
189     temp2  = temp2 - (temp2 * m->directGain);
190     temp2 += m->directGain * temp;
191 
192     if (m->vibrGain != 0.0) {
193                                            /*  Tick on vibrato table  */
194       m->v_time += m->v_rate;              /*  Update current time    */
195       while (m->v_time >= m->vibr->flen)   /*  Check for end of sound */
196         m->v_time -= m->vibr->flen;        /*  loop back to beginning */
197       while (m->v_time < FL(0.0))          /*  Check for end of sound */
198         m->v_time += m->vibr->flen;        /*  loop back to beginning */
199 
200       temp_time = m->v_time;
201 
202 #ifdef phase_offset
203       if (m->v_phaseOffset != FL(0.0)) {
204         temp_time += m->v_phaseOffset;     /*  Add phase offset       */
205         while (temp_time >= m->vibr->flen) /*  Check for end of sound */
206           temp_time -= m->vibr->flen;      /*  loop back to beginning */
207         while (temp_time < FL(0.0))        /*  Check for end of sound */
208           temp_time += m->vibr->flen;      /*  loop back to beginning */
209       }
210 #endif
211 
212       itemp = (int32) temp_time;    /*  Integer part of time address    */
213                                    /*  fractional part of time address */
214       alpha = temp_time - (MYFLT)itemp;
215       lastOutput = m->vibr->ftable[itemp]; /* Do linear interpolation */
216       /*  same as alpha*data[itemp+1] + (1-alpha)data[temp] */
217       lastOutput = /*m->v)*/lastOutput +
218         (alpha * (m->vibr->ftable[itemp+1] - lastOutput));
219       /* End of vibrato tick */
220       temp = FL(1.0) + (lastOutput * m->vibrGain);   /*  Calculate AM      */
221       temp2 = temp * temp2;                          /* and apply to master out */
222     }
223 
224     return (temp2 + temp2);
225 }
226 
227 /*******************************************/
228 /*  Marimba SubClass of Modal4 Instrument, */
229 /*  by Perry R. Cook, 1995-96              */
230 /*                                         */
231 /*   Controls:    stickHardness            */
232 /*                strikePosition           */
233 /*                vibFreq                  */
234 /*                vibAmt                   */
235 /*******************************************/
236 
marimbaset(CSOUND * csound,MARIMBA * p)237 int32_t marimbaset(CSOUND *csound, MARIMBA *p)
238 {
239     Modal4      *m = &(p->m4);
240     MYFLT       temp,temp2;
241     int32_t         itemp;
242     FUNC        *ftp;
243 
244     if (LIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) != NULL))
245       p->m4.wave = ftp;
246     else {                                    /* Expect an impulslything */
247       return csound->InitError(csound, Str("No table for Marimba strike"));
248     }
249 
250     if (UNLIKELY(make_Modal4(csound,
251                              m, p->ivfn, *p->vibAmt, *p->vibFreq)==NOTOK))
252       return NOTOK;
253     p->m4.w_phaseOffset = FL(0.0);
254 /*     p->m4.w_rate = 0.5; */
255     Modal4_setRatioAndReson(csound,m,0, FL(1.00), FL(0.9996)); /* Set all 132.0 */
256     Modal4_setRatioAndReson(csound,m,1, FL(3.99), FL(0.9994)); /* of our  523.0 */
257     Modal4_setRatioAndReson(csound,m,2,FL(10.65), FL(0.9994)); /* default 1405.0 */
258     Modal4_setRatioAndReson(csound,m,3,-FL(18.50),FL(0.999)); /* resonances 2443 */
259     Modal4_setFiltGain(m, 0, FL(0.04));               /*  and        */
260     Modal4_setFiltGain(m, 1, FL(0.01));               /*  gains      */
261     Modal4_setFiltGain(m, 2, FL(0.01));               /*  for each   */
262     Modal4_setFiltGain(m, 3, FL(0.008));              /*  resonance  */
263     p->m4.directGain = FL(0.1);
264     p->multiStrike = 0;
265     p->strikePosition = *p->spos;
266                                 /* Set Stick hardness stuff */
267     p->stickHardness = *p->hardness;
268     p->m4.w_rate = (FL(0.25) * (MYFLT)pow(4.0,(double)p->stickHardness));
269     p->m4.masterGain = (FL(0.1) + (FL(1.8) * p->stickHardness));
270                                 /* Set Strike position */
271     temp2 = p->strikePosition * PI_F;
272     temp = SIN(temp2);
273     BiQuad_setGain(p->m4.filters[0], FL(0.12)*temp); /* 1st mode function of pos.*/
274     temp = SIN(FL(0.05) + (FL(3.9) * temp2));
275     BiQuad_setGain(p->m4.filters[1],
276                    -FL(0.03)*temp); /* 2nd mode function of pos.*/
277     temp = SIN(-FL(0.05) + (FL(11.0) * temp2));
278     BiQuad_setGain(p->m4.filters[2], FL(0.11)*temp); /* 3rd mode function of pos.*/
279                                 /* Strike */
280     {
281       int32_t triples = (*p->triples<=FL(0.0) ? 20 : (int32_t)*p->triples);
282       int32_t doubles = (*p->doubles<=FL(0.0) ? 40 : triples + (int32_t)*p->doubles);
283       itemp = csound->Rand31(&(csound->randSeed1)) % 100;
284       if (itemp < triples) {
285         p->multiStrike = 2;
286         if (csound->oparms->msglevel & RNGEMSG)
287           csound->Message(csound, Str("striking three times here!!!\n"));
288       }
289       else if (itemp < doubles) {
290         p->multiStrike = 1;
291         if (csound->oparms->msglevel & RNGEMSG)
292           csound->Message(csound, Str("striking twice here!!\n"));
293       }
294       else p->multiStrike = 0;
295     }
296     Modal4_strike(csound, m, *p->amplitude * AMP_RSCALE);
297     Modal4_setFreq(csound, m, *p->frequency);
298     p->first = 1;
299     {
300       int32_t relestim = (int32_t) (CS_EKR * *p->dettack);
301       /* 0.1 second decay extention */
302       if (relestim > p->h.insdshead->xtratim)
303         p->h.insdshead->xtratim = relestim;
304     }
305     p->kloop = (int32_t) ((int32_t) (p->h.insdshead->offtim * CS_EKR)
306                       - (int32_t) (CS_EKR * *p->dettack));
307     return OK;
308 }
309 
marimba(CSOUND * csound,MARIMBA * p)310 int32_t marimba(CSOUND *csound, MARIMBA *p)
311 {
312     Modal4      *m = &(p->m4);
313     MYFLT       *ar = p->ar;
314     uint32_t    offset = p->h.insdshead->ksmps_offset;
315     uint32_t    early  = p->h.insdshead->ksmps_no_end;
316     uint32_t    n, nsmps = CS_KSMPS;
317     MYFLT       amp = (*p->amplitude) * AMP_RSCALE; /* Normalise */
318 
319     if (p->kloop>0 && p->h.insdshead->relesing) p->kloop=1;
320     if ((--p->kloop) == 0) {
321       Modal4_damp(csound, m, FL(1.0) - (amp * FL(0.03)));
322     }
323     p->m4.v_rate = *p->vibFreq; /* 6.0; */
324     p->m4.vibrGain = *p->vibAmt; /* 0.05; */
325     if (UNLIKELY(p->first)) {
326       Modal4_strike(csound, m, *p->amplitude * AMP_RSCALE);
327       Modal4_setFreq(csound, m, *p->frequency);
328       p->first = 0;
329     }
330     if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
331     if (UNLIKELY(early)) {
332       nsmps -= early;
333       memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
334     }
335     for (n=offset;n<nsmps;n++) {
336       MYFLT     lastOutput;
337       if (p->multiStrike>0)
338         if (p->m4.w_allDone) {
339           p->m4.w_time = FL(0.0);
340           //p->m4.w_lastOutput = FL(0.0);
341           p->m4.w_allDone = 0;
342           p->multiStrike -= 1;
343         }
344       lastOutput = Modal4_tick(m);
345       ar[n] = lastOutput*AMP_SCALE*FL(0.5);
346     }
347     return OK;
348 }
349 
350 /*******************************************/
351 /*  Vibraphone SubClass of Modal4          */
352 /*  Instrument, by Perry R. Cook, 1995-96  */
353 /*                                         */
354 /*   Controls:    CONTROL1 = stickHardness */
355 /*                CONTROL2 = strikePosition*/
356 /*                CONTROL3 = vibFreq       */
357 /*                MOD_WHEEL= vibAmt        */
358 /*******************************************/
359 
vibraphnset(CSOUND * csound,VIBRAPHN * p)360 int32_t vibraphnset(CSOUND *csound, VIBRAPHN *p)
361 {
362     Modal4      *m = &(p->m4);
363     MYFLT       temp;
364     FUNC        *ftp;
365 
366     if (LIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) != NULL))
367       p->m4.wave = ftp;         /* Expect an impulslything */
368     else {
369       return csound->InitError(csound, Str("No table for Vibraphone strike"));
370     }
371 
372     if (UNLIKELY(make_Modal4(csound, m, p->ivfn, *p->vibAmt, *p->vibFreq)==NOTOK))
373       return NOTOK;
374 
375     p->m4.w_phaseOffset = FL(0.0);
376 /*     p->m4.w_rate = 13.33; */
377     OnePole_setPole(&p->m4.onepole, FL(0.2));
378     Modal4_setRatioAndReson(csound, m, 0, FL(1.0), FL(0.99995)); /*  Set         */
379     Modal4_setRatioAndReson(csound, m, 1, FL(2.01),FL(0.99991)); /*  our         */
380     Modal4_setRatioAndReson(csound, m, 2, FL(3.9), FL(0.99992)); /*  resonance   */
381     Modal4_setRatioAndReson(csound, m, 3,FL(14.37),FL(0.99990)); /*  values here */
382     Modal4_setFiltGain(m, 0, FL(0.025));
383     Modal4_setFiltGain(m, 1, FL(0.015));
384     Modal4_setFiltGain(m, 2, FL(0.015));
385     Modal4_setFiltGain(m, 3, FL(0.015));
386     p->m4.directGain = FL(0.0);
387 /*     vibrGain = 0.2; */
388     p->m4.w_rate = FL(2.0) + (FL(22.66) * *p->hardness);
389     p->m4.masterGain = FL(0.2) + (*p->hardness * FL(1.6));
390                                 /* Set Strike position */
391     temp = (p->strikePosition = *p->spos) * PI_F;
392     BiQuad_setGain(p->m4.filters[0], FL(0.025) * SIN(temp));
393     BiQuad_setGain(p->m4.filters[1], FL(0.015) *
394                    SIN(FL(0.1) + (FL(2.01) * temp)));
395     BiQuad_setGain(p->m4.filters[2], FL(0.015) * SIN(FL(3.95) * temp));
396                                 /* Strike */
397     Modal4_strike(csound, m, *p->amplitude * AMP_RSCALE);
398     Modal4_setFreq(csound, m, *p->frequency);
399     p->first = 1;
400     return OK;
401 }
402 
vibraphn(CSOUND * csound,VIBRAPHN * p)403 int32_t vibraphn(CSOUND *csound, VIBRAPHN *p)
404 {
405     Modal4      *m = &(p->m4);
406     MYFLT       *ar = p->ar;
407     uint32_t    offset = p->h.insdshead->ksmps_offset;
408     uint32_t    early  = p->h.insdshead->ksmps_no_end;
409     uint32_t    n, nsmps = CS_KSMPS;
410     MYFLT       amp = (*p->amplitude)*AMP_RSCALE; /* Normalise */
411 
412     if (p->kloop>0 && p->h.insdshead->relesing) p->kloop=1;
413     if ((--p->kloop) == 0) {
414       Modal4_damp(csound, m, FL(1.0) - (amp * FL(0.03)));
415     }
416     if (UNLIKELY(p->first)) {
417       Modal4_strike(csound, m, *p->amplitude * AMP_RSCALE);
418       Modal4_setFreq(csound, m, *p->frequency);
419       p->first = 0;
420     }
421     p->m4.v_rate = *p->vibFreq;
422     p->m4.vibrGain =*p->vibAmt;
423     if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
424     if (UNLIKELY(early)) {
425       nsmps -= early;
426       memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
427     }
428     for (n=offset;n<nsmps;n++) {
429       MYFLT     lastOutput = Modal4_tick(m);
430       ar[n] = lastOutput*FL(8.0)*AMP_SCALE;/* Times 8 as seems too quiet */
431     }
432     return OK;
433 }
434 
435 /*******************************************/
436 /*  AgogoBell SubClass of Modal4 Instrument*/
437 /*  by Perry R. Cook, 1995-96              */
438 /*                                         */
439 /*   Controls:    CONTROL1 = stickHardness */
440 /*                CONTROL2 = strikePosition*/
441 /*                CONTROL3 = vibFreq       */
442 /*                MOD_WHEEL= vibAmt        */
443 /*******************************************/
444 
445 /*   Modes measured from my Agogo Bell by FFT:  */
446 /*   360, 1470, 2401, 4600                      */
447 
agogobelset(CSOUND * csound,VIBRAPHN * p)448 int32_t agogobelset(CSOUND *csound, VIBRAPHN *p)
449 {
450     Modal4      *m = &(p->m4);
451     FUNC        *ftp;
452     MYFLT       temp;
453 
454     /* Expect an impulslything */
455     if (LIKELY((ftp = csound->FTnp2Find(csound, p->ifn)) != NULL)) p->m4.wave = ftp;
456     else {
457       return csound->InitError(csound, Str("No table for Agogobell strike"));
458     }
459 
460     if (UNLIKELY(make_Modal4(csound, m, p->ivfn, *p->vibAmt, *p->vibFreq)==NOTOK))
461       return NOTOK;
462 
463     p->m4.w_phaseOffset = FL(0.0);
464 /*     p->m4.w_rate = 7.0; */
465     OnePole_setPole(&p->m4.onepole, FL(0.2));
466     Modal4_setRatioAndReson(csound, m, 0, FL(1.00), FL(0.999));   /* Set         */
467     Modal4_setRatioAndReson(csound, m, 1, FL(4.08), FL(0.999));   /* our         */
468     Modal4_setRatioAndReson(csound, m, 2, FL(6.669),FL(0.999));   /* resonance   */
469     Modal4_setRatioAndReson(csound, m, 3,-FL(3725.0), FL(0.999)); /* values here */
470     Modal4_setFiltGain(m, 0, FL(0.06));
471     Modal4_setFiltGain(m, 1, FL(0.05));
472     Modal4_setFiltGain(m, 2, FL(0.03));
473     Modal4_setFiltGain(m, 3, FL(0.02));
474     p->m4.directGain = FL(0.25);
475 /*     vibrGain = 0.2; */
476     p->m4.w_rate = FL(3.0) + (FL(8.0) * *p->hardness);
477     p->m4.masterGain = FL(1.0);
478                                 /* Set Strike position */
479     temp = (p->strikePosition = *p->spos) * PI_F;
480     BiQuad_setGain(p->m4.filters[0], FL(0.08) * SIN(FL(0.7) * temp));
481     BiQuad_setGain(p->m4.filters[1], FL(0.07) * SIN(FL(0.1) + (FL(5.0) * temp)));
482     BiQuad_setGain(p->m4.filters[2], FL(0.04) * SIN(FL(0.2) + (FL(7.0) * temp)));
483                                 /* Strike */
484     Modal4_strike(csound, m, *p->amplitude*AMP_RSCALE);
485     Modal4_setFreq(csound, m, *p->frequency);
486     return OK;
487 }
488 
agogobel(CSOUND * csound,VIBRAPHN * p)489 int32_t agogobel(CSOUND *csound, VIBRAPHN *p)
490 {
491     Modal4      *m = &(p->m4);
492     MYFLT       *ar = p->ar;
493     uint32_t    offset = p->h.insdshead->ksmps_offset;
494     uint32_t    early  = p->h.insdshead->ksmps_no_end;
495     uint32_t    n, nsmps = CS_KSMPS;
496 
497     p->m4.v_rate = *p->vibFreq;
498     p->m4.vibrGain =*p->vibAmt;
499     if (UNLIKELY(p->first)) {
500       Modal4_strike(csound, m, *p->amplitude * AMP_RSCALE);
501       Modal4_setFreq(csound, m, *p->frequency);
502       p->first = 0;
503     }
504     if (UNLIKELY(offset)) memset(ar, '\0', offset*sizeof(MYFLT));
505     if (UNLIKELY(early)) {
506       nsmps -= early;
507       memset(&ar[nsmps], '\0', early*sizeof(MYFLT));
508     }
509     for (n=offset;n<nsmps;n++) {
510       MYFLT     lastOutput = Modal4_tick(m);
511       ar[n] = lastOutput*AMP_SCALE;
512     }
513     return OK;
514 }
515 
516 #define S       sizeof
517 
518 static OENTRY modal4_localops[] =
519   {
520    { "marimba", S(MARIMBA), TR, 3, "a", "kkiiikkiijj",
521      (SUBR)marimbaset, (SUBR)marimba},
522    { "vibes", S(VIBRAPHN),  TR, 3, "a", "kkiiikkii",
523      (SUBR)vibraphnset,(SUBR)vibraphn},
524    { "gogobel",S(VIBRAPHN), TR, 3, "a", "kkiiikki",
525      (SUBR)agogobelset, (SUBR)agogobel},
526 };
527 
528 LINKAGE_BUILTIN(modal4_localops)
529 
530