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