1 /*
2 Copyright 2008-2011 David Robillard <http://drobilla.net>
3 Copyright 1999-2000 Paul Kellett (Maxim Digital Audio)
4
5 This is free software: you can redistribute it and/or modify it
6 under the terms of the GNU General Public License as published by
7 the Free Software Foundation, either version 3 of the License,
8 or (at your option) any later version.
9
10 This software is distributed in the hope that it will be useful,
11 but WITHOUT ANY WARRANTY; without even the implied warranty of
12 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
13 See the GNU General Public License for more details.
14
15 You should have received a copy of the GNU General Public License
16 along with this software. If not, see <http://www.gnu.org/licenses/>.
17 */
18
19 #include "mdaBeatBox.h"
20
21 #include <cmath>
22 #include <cstdio>
23 #include <cstdlib>
24 #include <cstring>
25
createEffectInstance(audioMasterCallback audioMaster)26 AudioEffect *createEffectInstance(audioMasterCallback audioMaster)
27 {
28 return new mdaBeatBox(audioMaster);
29 }
30
mdaBeatBox(audioMasterCallback audioMaster)31 mdaBeatBox::mdaBeatBox(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, 1, 12) // programs, parameters
32 {
33 fParam1 = 0.30f; //hat thresh
34 fParam2 = 0.45f; //hat rate
35 fParam3 = 0.50f; //hat mix
36 fParam4 = 0.46f; //kick thresh
37 fParam5 = 0.15f; //kick key
38 fParam6 = 0.50f; //kick mix
39 fParam7 = 0.50f; //snare thresh
40 fParam8 = 0.70f; //snare key
41 fParam9 = 0.50f; //snare mix
42 fParam10 = 0.00f; //dynamics
43 fParam11 = 0.00f; //record
44 fParam12 = 0.00f; //thru mix
45
46 hbuflen = 20000;
47 kbuflen = 20000;
48 sbuflen = 60000;
49 if(getSampleRate()>49000) { hbuflen*=2; kbuflen*=2; sbuflen*=2; }
50
51 hbufpos = 0;
52 kbufpos = 0;
53 sbufpos = 0;
54 hfil = 0;
55 sb1 = 0;
56 sb2 = 0;
57 ksb1 = 0;
58 ksb2 = 0;
59 wwx = 0;
60
61 hbuf = new float[hbuflen];
62 sbuf = new float[sbuflen]; sbuf2 = new float[sbuflen];
63 kbuf = new float[kbuflen];
64
65 setNumInputs(2); // stereo in
66 setNumOutputs(2); // stereo out
67 setUniqueID("mdaBBox"); // identify
68 DECLARE_LVZ_DEPRECATED(canMono) ();
69 canProcessReplacing(); // supports both accumulating and replacing output
70 strcpy(programName, "BeatBox - Drum Replacer"); // default program name
71 synth();
72
73 //calcs here
74 hthr = (float)pow(10.f, 2.f * fParam1 - 2.f);
75 hdel = (int32_t)((0.04 + 0.20 * fParam2) * getSampleRate());
76 sthr = (float)(40.0 * pow(10.f, 2.f * fParam7 - 2.f));
77 sdel = (int32_t)(0.12 * getSampleRate());
78 kthr = (float)(220.0 * pow(10.f, 2.f * fParam4 - 2.f));
79 kdel = (int32_t)(0.10 * getSampleRate());
80
81 hlev = (float)(0.0001f + fParam3 * fParam3 * 4.f);
82 klev = (float)(0.0001f + fParam6 * fParam6 * 4.f);
83 slev = (float)(0.0001f + fParam9 * fParam9 * 4.f);
84
85 kww = (float)pow(10.0,-3.0 + 2.2 * fParam5);
86 ksf1 = (float)cos(3.1415927 * kww); //p
87 ksf2 = (float)sin(3.1415927 * kww); //q
88
89 ww = (float)pow(10.0,-3.0 + 2.2 * fParam8);
90 sf1 = (float)cos(3.1415927 * ww); //p
91 sf2 = (float)sin(3.1415927 * ww); //q
92 sf3 = 0.991f; //r
93 sfx = 0; ksfx = 0;
94 rec=0; recx=0; recpos=0;
95
96 mix = fParam12;
97 dyna = (float)pow(10.0,-1000.0/getSampleRate());
98 dynr = (float)pow(10.0,-6.0/getSampleRate());
99 dyne = 0.f; dynm = fParam10;
100 }
101
getProductString(char * text)102 bool mdaBeatBox::getProductString(char* text) { strcpy(text, "MDA BeatBox"); return true; }
getVendorString(char * text)103 bool mdaBeatBox::getVendorString(char* text) { strcpy(text, "mda"); return true; }
getEffectName(char * name)104 bool mdaBeatBox::getEffectName(char* name) { strcpy(name, "BeatBox"); return true; }
105
setProgramName(char * name)106 void mdaBeatBox::setProgramName(char *name)
107 {
108 strcpy(programName, name);
109 }
110
getProgramName(char * name)111 void mdaBeatBox::getProgramName(char *name)
112 {
113 strcpy(name, programName);
114 }
115
getProgramNameIndexed(int32_t category,int32_t index,char * name)116 bool mdaBeatBox::getProgramNameIndexed (int32_t category, int32_t index, char* name)
117 {
118 if (index == 0)
119 {
120 strcpy(name, programName);
121 return true;
122 }
123 return false;
124 }
125
setParameter(int32_t index,float value)126 void mdaBeatBox::setParameter(int32_t index, float value)
127 {
128 switch(index)
129 {
130 case 0: fParam1 = value; break;
131 case 1: fParam2 = value; break;
132 case 2: fParam3 = value; break;
133 case 3: fParam4 = value; break;
134 case 4: fParam5 = value; break;
135 case 5: fParam6 = value; break;
136 case 6: fParam7 = value; break;
137 case 7: fParam8 = value; break;
138 case 8: fParam9 = value; break;
139 case 9: fParam10= value; break;
140 case 10:fParam11= value; break;
141 case 11:fParam12= value; break;
142 }
143 //calcs here
144 hthr = (float)pow(10.f, 2.f * fParam1 - 2.f);
145 hdel = (int32_t)((0.04 + 0.20 * fParam2) * getSampleRate());
146 sthr = (float)(40.0 * pow(10.f, 2.f * fParam7 - 2.f));
147 kthr = (float)(220.0 * pow(10.f, 2.f * fParam4 - 2.f));
148
149 hlev = (float)(0.0001f + fParam3 * fParam3 * 4.f);
150 klev = (float)(0.0001f + fParam6 * fParam6 * 4.f);
151 slev = (float)(0.0001f + fParam9 * fParam9 * 4.f);
152
153 wwx=ww;
154 ww = (float)pow(10.0,-3.0 + 2.2 * fParam8);
155 sf1 = (float)cos(3.1415927 * ww); //p
156 sf2 = (float)sin(3.1415927 * ww); //q
157 //sfx = 0; ksfx = 0;
158
159 kwwx=kww;
160 kww = (float)pow(10.0,-3.0 + 2.2 * fParam5);
161 ksf1 = (float)cos(3.1415927 * kww); //p
162 ksf2 = (float)sin(3.1415927 * kww); //q
163
164 if(wwx != ww) sfx = (int32_t)(2 * getSampleRate());
165 if(kwwx != kww) ksfx = (int32_t)(2 * getSampleRate());
166
167 rec = (int32_t)(4.9 * fParam11);
168 if ((rec!=recx) && (recpos>0)) //finish sample
169 {
170 switch(rec)
171 {
172 case 2: while(recpos<hbuflen) *(hbuf + recpos++) = 0.f; break;
173 case 3: while(recpos<kbuflen) *(kbuf + recpos++) = 0.f; break;
174 case 4: while(recpos<sbuflen) { *(sbuf + recpos) = 0.f;
175 *(sbuf2 + recpos) = 0.f; recpos++; } break;
176 }
177 }
178 recpos=0; recx=rec;
179 mix = fParam12;
180 dynm = fParam10;
181 }
182
~mdaBeatBox()183 mdaBeatBox::~mdaBeatBox()
184 {
185 if(hbuf) delete [] hbuf;
186 if(kbuf) delete [] kbuf;
187 if(sbuf) delete [] sbuf;
188 if(sbuf2) delete [] sbuf2;
189 }
190
suspend()191 void mdaBeatBox::suspend()
192 {
193 }
194
synth()195 void mdaBeatBox::synth()
196 {
197 int32_t t;
198 float e=0.00012f, de, o=0.0f, o1=0.f, o2=0.f, p=0.2f, dp;
199
200 memset(hbuf, 0, hbuflen * sizeof(float)); //generate hi-hat
201 de = (float)pow(10.0,-36.0/getSampleRate());
202 for(t=0;t<5000;t++)
203 {
204 o = (float)((rand() % 2000) - 1000);
205 *(hbuf + t) = e * ( 2.f * o1 - o2 - o);
206 e *= de; o2=o1; o1=o;
207 }
208
209 memset(kbuf, 0, kbuflen * sizeof(float)); //generate kick
210 de = (float)pow(10.0,-3.8/getSampleRate());
211 e=0.5f; dp = 1588.f / getSampleRate();
212 for(t=0;t<14000;t++)
213 {
214 *(kbuf + t) = e * (float)sin(p);
215 e *= de; p = (float)fmod(p + dp * e ,6.2831853f);
216 }
217
218 memset(sbuf, 0, sbuflen * sizeof(float)); //generate snare
219 de = (float)pow(10.0,-15.0/getSampleRate());
220 e=0.38f; //dp = 1103.f / getSampleRate();
221 for(t=0;t<7000;t++)
222 {
223 o = (0.3f * o) + (float)((rand() % 2000) - 1000);
224 *(sbuf + t) = (float)(e * (sin(p) + 0.0004 * o));
225 *(sbuf2 + t) = *(sbuf + t);
226 e *= de; p = (float)fmod(p + 0.025,6.2831853);
227 }
228 }
229
getParameter(int32_t index)230 float mdaBeatBox::getParameter(int32_t index)
231 {
232 float v=0;
233
234 switch(index)
235 {
236 case 0: v = fParam1; break;
237 case 1: v = fParam2; break;
238 case 2: v = fParam3; break;
239 case 3: v = fParam4; break;
240 case 4: v = fParam5; break;
241 case 5: v = fParam6; break;
242 case 6: v = fParam7; break;
243 case 7: v = fParam8; break;
244 case 8: v = fParam9; break;
245 case 9: v =fParam10; break;
246 case 10:v =fParam11; break;
247 case 11:v =fParam12; break;
248 }
249 return v;
250 }
251
getParameterName(int32_t index,char * label)252 void mdaBeatBox::getParameterName(int32_t index, char *label)
253 {
254 switch(index)
255 {
256 case 0: strcpy(label, "Hat Thr"); break;
257 case 1: strcpy(label, "Hat Rate"); break;
258 case 2: strcpy(label, "Hat Mix"); break;
259 case 3: strcpy(label, "Kik Thr"); break;
260 case 4: strcpy(label, "Kik Trig"); break;
261 case 5: strcpy(label, "Kik Mix"); break;
262 case 6: strcpy(label, "Snr Thr"); break;
263 case 7: strcpy(label, "Snr Trig"); break;
264 case 8: strcpy(label, "Snr Mix"); break;
265 case 9: strcpy(label, "Dynamics"); break;
266 case 10: strcpy(label, "Record"); break;
267 case 11: strcpy(label, "Thru Mix"); break;
268 }
269 }
270
int2strng(int32_t value,char * string)271 static void int2strng(int32_t value, char *string) { sprintf(string, "%d", value); }
float2strng(float value,char * string)272 static void float2strng(float value, char *string) { sprintf(string, "%.2f", value); }
273
getParameterDisplay(int32_t index,char * text)274 void mdaBeatBox::getParameterDisplay(int32_t index, char *text)
275 {
276 switch(index)
277 {
278 case 0: float2strng((float)(40.0*fParam1 - 40.0),text); break;
279 case 1: int2strng((int32_t)(1000.f * hdel / getSampleRate()),text); break;
280 case 2: int2strng((int32_t)(20.f * log10(hlev)),text); break;
281 case 3: float2strng((float)(40.0*fParam4 - 40.0),text); break;
282 case 4: int2strng((int32_t)(0.5 * kww * getSampleRate()), text); break;
283 case 5: int2strng((int32_t)(20.f * log10(klev)),text); break;
284 case 6: float2strng((float)(40.0*fParam7 - 40.0),text); break;
285 case 7: int2strng((int32_t)(0.5 * ww * getSampleRate()), text); break;
286 case 8: int2strng((int32_t)(20.f * log10(slev)),text); break;
287 case 9: int2strng((int32_t)(100.f * fParam10),text); break;
288 case 11: int2strng((int32_t)(20.f * log10(fParam12)),text); break;
289
290 case 10: switch(rec)
291 { case 0: strcpy(text, "-"); break;
292 case 1: strcpy(text, "MONITOR"); break;
293 case 2: strcpy(text, "-> HAT"); break;
294 case 3: strcpy(text, "-> KIK"); break;
295 case 4: strcpy(text, "-> SNR"); break; } break;
296 }
297 }
298
getParameterLabel(int32_t index,char * label)299 void mdaBeatBox::getParameterLabel(int32_t index, char *label)
300 {
301 switch(index)
302 {
303 case 0: strcpy(label, "dB"); break;
304 case 1: strcpy(label, "ms"); break;
305 case 2: strcpy(label, "dB"); break;
306 case 3: strcpy(label, "dB"); break;
307 case 4: strcpy(label, "Hz"); break;
308 case 5: strcpy(label, "dB"); break;
309 case 6: strcpy(label, "dB"); break;
310 case 7: strcpy(label, "Hz"); break;
311 case 8: strcpy(label, "dB"); break;
312 case 9: strcpy(label, "%"); break;
313 case 10:strcpy(label, ""); break;
314 case 11:strcpy(label, "dB"); break;
315 }
316 }
317
318 //--------------------------------------------------------------------------------
319 // process
320
process(float ** inputs,float ** outputs,int32_t sampleFrames)321 void mdaBeatBox::process(float **inputs, float **outputs, int32_t sampleFrames)
322 {
323 float *in1 = inputs[0];
324 float *in2 = inputs[1];
325 float *out1 = outputs[0];
326 float *out2 = outputs[1];
327 float a, b, c, d, e, o, hf=hfil, ht=hthr, mx3=0.f, mx1=mix;
328 int32_t hp=hbufpos, hl=hbuflen-2, hd=hdel;
329 float kt=kthr;
330 int32_t kp=kbufpos, kl=kbuflen-2, kd=kdel;
331 float st=sthr, s, f1=sb1, f2=sb2, b1=sf1, b2=sf2, b3=sf3;
332 float k, kf1=ksb1, kf2=ksb2, kb1=ksf1, kb2=ksf2;
333 float hlv=hlev, klv=klev, slv=slev;
334 int32_t sp=sbufpos, sl=sbuflen-2, sd=sdel;
335 float ya=dyna, yr=dynr, ye=dyne, ym=dynm, mx4;
336
337 if(sfx>0) { mx3=0.08f; slv=0.f; klv=0.f; hlv=0.f; mx1=0.f; sfx-=sampleFrames;} //key listen (snare)
338 if(ksfx>0) { mx3=0.03f; slv=0.f; klv=0.f; hlv=0.f; mx1=0.f; ksfx-=sampleFrames;
339 b1=ksf1; b2=ksf2; } //key listen (kick)
340
341 --in1;
342 --in2;
343 --out1;
344 --out2;
345
346 if(rec==0)
347 {
348 while(--sampleFrames >= 0)
349 {
350 a = *++in1; //input
351 b = *++in2;
352 e = a + b;
353
354 ye = (e<ye)? ye * yr : e - ya * (e - ye); //dynamics envelope
355
356 hf = e - hf; //high
357 if((hp>hd) && (hf>ht)) hp=0; else { hp++; if(hp>hl)hp=hl; }
358 o = hlv * *(hbuf + hp);
359
360 k = e + (kf1 * kb1) - (kf2 * kb2);
361 kf2 = b3 * ((kf1 * kb2) + (kf2 * kb1));
362 kf1 = b3 * k;
363 if((kp>kd) && (k>kt)) kp=0; else { kp++; if(kp>kl)kp=kl; }
364 o += klv * *(kbuf + kp);
365
366 s = hf + (0.3f * e) + (f1 * b1) - (f2 * b2);
367 f2 = b3 * ((f1 * b2) + (f2 * b1));
368 f1 = b3 * s;
369
370 if((sp>sd) && (s>st)) sp=0; else { sp++; if(sp>sl)sp=sl; }
371
372 mx4 = 1.f + ym * (ye + ye - 1.f); //dynamics
373
374 c = out1[1] + mx1*a + mx3*s + mx4*(o + slv * *(sbuf + sp));
375 d = out2[1] + mx1*b + mx3*s + mx4*(o + slv * *(sbuf2 + sp));
376 *++out1 = c;
377 *++out2 = d;
378
379 hf=e;
380 }
381 }
382 else //record
383 {
384 while(--sampleFrames >= 0)
385 {
386
387 a = *++in1;
388 b = *++in2;
389 e = 0.5f * (a + b);
390
391 if((recpos==0) && (fabs(e) < 0.004)) e=0.f;
392 else
393 {
394 switch(rec)
395 {
396 case 1: break; //echo
397 case 2: if(recpos<hl) *(hbuf + recpos++) = e; else e=0.f; break;
398 case 3: if(recpos<kl) *(kbuf + recpos++) = e; else e=0.f; break;
399 case 4: if(recpos<sl)
400 { *(sbuf+recpos)=a; *(sbuf2+recpos)=b; recpos++; }
401 else e=0.f;
402 break;
403 }
404 }
405 c = out1[1] + e;
406 d = out2[1] + e;
407 *++out1 = c;
408 *++out2 = d;
409 }
410 }
411 hfil=hf; hbufpos=hp;
412 sbufpos=sp; sb1 = f1; sb2 = f2;
413 kbufpos=kp; ksb1 = f1; ksb2 = f2;
414 dyne=ye;
415 }
416
processReplacing(float ** inputs,float ** outputs,int32_t sampleFrames)417 void mdaBeatBox::processReplacing(float **inputs, float **outputs, int32_t sampleFrames)
418 {
419 float *in1 = inputs[0];
420 float *in2 = inputs[1];
421 float *out1 = outputs[0];
422 float *out2 = outputs[1];
423 float a, b, e, o, hf=hfil, ht=hthr, mx3=0.f, mx1=mix;
424 int32_t hp=hbufpos, hl=hbuflen-2, hd=hdel;
425 float kt=kthr;
426 int32_t kp=kbufpos, kl=kbuflen-2, kd=kdel;
427 float st=sthr, s, f1=sb1, f2=sb2, b1=sf1, b2=sf2, b3=sf3;
428 float k, kf1=ksb1, kf2=ksb2, kb1=ksf1, kb2=ksf2;
429 float hlv=hlev, klv=klev, slv=slev;
430 int32_t sp=sbufpos, sl=sbuflen-2, sd=sdel;
431 float ya=dyna, yr=dynr, ye=dyne, ym=dynm, mx4;
432
433 if(sfx>0) { mx3=0.08f; slv=0.f; klv=0.f; hlv=0.f; mx1=0.f; sfx-=sampleFrames;} //key listen (snare)
434 if(ksfx>0) { mx3=0.03f; slv=0.f; klv=0.f; hlv=0.f; mx1=0.f; ksfx-=sampleFrames;
435 b1=ksf1; b2=ksf2; } //key listen (kick)
436
437 --in1;
438 --in2;
439 --out1;
440 --out2;
441
442 if(rec==0)
443 {
444 while(--sampleFrames >= 0)
445 {
446 a = *++in1;
447 b = *++in2;
448 e = a + b;
449
450 ye = (e<ye)? ye * yr : e - ya * (e - ye); //dynamics envelope
451
452 hf = e - hf; //high filter
453 if((hp>hd) && (hf>ht)) hp=0; else { hp++; if(hp>hl)hp=hl; }
454 o = hlv * *(hbuf + hp); //hat
455
456 k = e + (kf1 * kb1) - (kf2 * kb2); //low filter
457 kf2 = b3 * ((kf1 * kb2) + (kf2 * kb1));
458 kf1 = b3 * k;
459 if((kp>kd) && (k>kt)) kp=0; else { kp++; if(kp>kl)kp=kl; }
460 o += klv * *(kbuf + kp); //kick
461
462 s = hf + (0.3f * e) + (f1 * b1) - (f2 * b2); //mid filter
463 f2 = b3 * ((f1 * b2) + (f2 * b1));
464 f1 = b3 * s;
465
466 if((sp>sd) && (s>st)) sp=0; else { sp++; if(sp>sl)sp=sl; }
467
468 mx4 = 1.f + ym * (ye + ye - 1.f); //dynamics
469
470 *++out1 = mx1*a + mx3*s + mx4*(o + slv * *(sbuf + sp));
471 *++out2 = mx1*a + mx3*s + mx4*(o + slv * *(sbuf2 + sp));
472
473 hf=e;
474 }
475 }
476 else //record
477 {
478 while(--sampleFrames >= 0)
479 {
480 a = *++in1;
481 b = *++in2;
482 e = 0.5f * (a + b);
483
484 if((recpos==0) && (fabs(e) < 0.004)) e=0.f;
485 else
486 {
487 switch(rec)
488 {
489 case 1: break; //echo
490 case 2: if(recpos<hl) *(hbuf + recpos++) = e; else e=0.f; break;
491 case 3: if(recpos<kl) *(kbuf + recpos++) = e; else e=0.f; break;
492 case 4: if(recpos<sl)
493 { *(sbuf+recpos)=a; *(sbuf2+recpos)=b; recpos++; }
494 else e=0.f;
495 break;
496 }
497 }
498 *++out1 = e;
499 *++out2 = e;
500 }
501 }
502 hfil=hf; hbufpos=hp;
503 sbufpos=sp; sb1 = f1; sb2 = f2;
504 kbufpos=kp; ksb1 = kf1; ksb2 = kf2;
505 dyne=ye;
506 }
507