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