1 /*
2  * ZaMultiComp multiband compressor
3  * Copyright (C) 2014  Damien Zammit <damien@zamaudio.com>
4  *
5  * This program is free software; you can redistribute it and/or
6  * modify it under the terms of the GNU General Public License as
7  * published by the Free Software Foundation; either version 2 of
8  * the License, or (at your option) any later version.
9  *
10  * This program 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. See the
13  * GNU General Public License for more details.
14  *
15  * For a full copy of the GNU General Public License see the doc/GPL.txt file.
16  */
17 
18 #include "ZaMultiCompPlugin.hpp"
19 
20 START_NAMESPACE_DISTRHO
21 
22 // -----------------------------------------------------------------------
23 
ZaMultiCompPlugin()24 ZaMultiCompPlugin::ZaMultiCompPlugin()
25     : Plugin(paramCount, 2, 0)
26 {
27     // set default values
28     loadProgram(0);
29 }
30 
31 // -----------------------------------------------------------------------
32 // Init
33 
initParameter(uint32_t index,Parameter & parameter)34 void ZaMultiCompPlugin::initParameter(uint32_t index, Parameter& parameter)
35 {
36     switch (index)
37     {
38     case paramAttack1:
39         parameter.hints      = kParameterIsAutomable;
40         parameter.name       = "Attack1";
41         parameter.symbol     = "att1";
42         parameter.unit       = "ms";
43         parameter.ranges.def = 10.0f;
44         parameter.ranges.min = 0.1f;
45         parameter.ranges.max = 100.0f;
46         break;
47     case paramAttack2:
48         parameter.hints      = kParameterIsAutomable;
49         parameter.name       = "Attack2";
50         parameter.symbol     = "att2";
51         parameter.unit       = "ms";
52         parameter.ranges.def = 10.0f;
53         parameter.ranges.min = 0.1f;
54         parameter.ranges.max = 100.0f;
55         break;
56     case paramAttack3:
57         parameter.hints      = kParameterIsAutomable;
58         parameter.name       = "Attack3";
59         parameter.symbol     = "att3";
60         parameter.unit       = "ms";
61         parameter.ranges.def = 10.0f;
62         parameter.ranges.min = 0.1f;
63         parameter.ranges.max = 100.0f;
64         break;
65     case paramRelease1:
66         parameter.hints      = kParameterIsAutomable;
67         parameter.name       = "Release1";
68         parameter.symbol     = "rel1";
69         parameter.unit       = "ms";
70         parameter.ranges.def = 80.0f;
71         parameter.ranges.min = 1.0f;
72         parameter.ranges.max = 500.0f;
73         break;
74     case paramRelease2:
75         parameter.hints      = kParameterIsAutomable;
76         parameter.name       = "Release2";
77         parameter.symbol     = "rel2";
78         parameter.unit       = "ms";
79         parameter.ranges.def = 80.0f;
80         parameter.ranges.min = 1.0f;
81         parameter.ranges.max = 500.0f;
82         break;
83     case paramRelease3:
84         parameter.hints      = kParameterIsAutomable;
85         parameter.name       = "Release3";
86         parameter.symbol     = "rel3";
87         parameter.unit       = "ms";
88         parameter.ranges.def = 80.0f;
89         parameter.ranges.min = 1.0f;
90         parameter.ranges.max = 500.0f;
91         break;
92     case paramKnee1:
93         parameter.hints      = kParameterIsAutomable;
94         parameter.name       = "Knee1";
95         parameter.symbol     = "kn1";
96         parameter.unit       = "dB";
97         parameter.ranges.def = 0.0f;
98         parameter.ranges.min = 0.0f;
99         parameter.ranges.max = 8.0f;
100         break;
101     case paramKnee2:
102         parameter.hints      = kParameterIsAutomable;
103         parameter.name       = "Knee2";
104         parameter.symbol     = "kn2";
105         parameter.unit       = "dB";
106         parameter.ranges.def = 0.0f;
107         parameter.ranges.min = 0.0f;
108         parameter.ranges.max = 8.0f;
109         break;
110     case paramKnee3:
111         parameter.hints      = kParameterIsAutomable;
112         parameter.name       = "Knee3";
113         parameter.symbol     = "kn3";
114         parameter.unit       = "dB";
115         parameter.ranges.def = 0.0f;
116         parameter.ranges.min = 0.0f;
117         parameter.ranges.max = 8.0f;
118         break;
119     case paramRatio1:
120         parameter.hints      = kParameterIsAutomable | kParameterIsLogarithmic;
121         parameter.name       = "Ratio1";
122         parameter.symbol     = "rat1";
123         parameter.unit       = " ";
124         parameter.ranges.def = 4.0f;
125         parameter.ranges.min = 1.0f;
126         parameter.ranges.max = 20.0f;
127         break;
128     case paramRatio2:
129         parameter.hints      = kParameterIsAutomable | kParameterIsLogarithmic;
130         parameter.name       = "Ratio2";
131         parameter.symbol     = "rat2";
132         parameter.unit       = " ";
133         parameter.ranges.def = 4.0f;
134         parameter.ranges.min = 1.0f;
135         parameter.ranges.max = 20.0f;
136         break;
137     case paramRatio3:
138         parameter.hints      = kParameterIsAutomable | kParameterIsLogarithmic;
139         parameter.name       = "Ratio3";
140         parameter.symbol     = "rat3";
141         parameter.unit       = " ";
142         parameter.ranges.def = 4.0f;
143         parameter.ranges.min = 1.0f;
144         parameter.ranges.max = 20.0f;
145         break;
146     case paramThresh1:
147         parameter.hints      = kParameterIsAutomable;
148         parameter.name       = "Threshold 1";
149         parameter.symbol     = "thr1";
150         parameter.unit       = "dB";
151         parameter.ranges.def = -20.0f;
152         parameter.ranges.min = -60.0f;
153         parameter.ranges.max = 0.0f;
154         break;
155     case paramThresh2:
156         parameter.hints      = kParameterIsAutomable;
157         parameter.name       = "Threshold 2";
158         parameter.symbol     = "thr2";
159         parameter.unit       = "dB";
160         parameter.ranges.def = -18.0f;
161         parameter.ranges.min = -60.0f;
162         parameter.ranges.max = 0.0f;
163         break;
164     case paramThresh3:
165         parameter.hints      = kParameterIsAutomable;
166         parameter.name       = "Threshold 3";
167         parameter.symbol     = "thr3";
168         parameter.unit       = "dB";
169         parameter.ranges.def = -16.0f;
170         parameter.ranges.min = -60.0f;
171         parameter.ranges.max = 0.0f;
172         break;
173     case paramMakeup1:
174         parameter.hints      = kParameterIsAutomable;
175         parameter.name       = "Makeup 1";
176         parameter.symbol     = "mak1";
177         parameter.unit       = "dB";
178         parameter.ranges.def = 0.0f;
179         parameter.ranges.min = 0.0f;
180         parameter.ranges.max = 30.0f;
181         break;
182     case paramMakeup2:
183         parameter.hints      = kParameterIsAutomable;
184         parameter.name       = "Makeup 2";
185         parameter.symbol     = "mak2";
186         parameter.unit       = "dB";
187         parameter.ranges.def = 0.0f;
188         parameter.ranges.min = 0.0f;
189         parameter.ranges.max = 30.0f;
190         break;
191     case paramMakeup3:
192         parameter.hints      = kParameterIsAutomable;
193         parameter.name       = "Makeup 3";
194         parameter.symbol     = "mak3";
195         parameter.unit       = "dB";
196         parameter.ranges.def = 0.0f;
197         parameter.ranges.min = 0.0f;
198         parameter.ranges.max = 30.0f;
199         break;
200     case paramGainR1:
201         parameter.hints      = kParameterIsAutomable | kParameterIsOutput;
202         parameter.name       = "Gain Reduction 1";
203         parameter.symbol     = "gr1";
204         parameter.unit       = "dB";
205         parameter.ranges.def = 0.0f;
206         parameter.ranges.min = 0.0f;
207         parameter.ranges.max = 20.0f;
208         break;
209     case paramGainR2:
210         parameter.hints      = kParameterIsAutomable | kParameterIsOutput;
211         parameter.name       = "Gain Reduction 2";
212         parameter.symbol     = "gr2";
213         parameter.unit       = "dB";
214         parameter.ranges.def = 0.0f;
215         parameter.ranges.min = 0.0f;
216         parameter.ranges.max = 20.0f;
217         break;
218     case paramGainR3:
219         parameter.hints      = kParameterIsAutomable | kParameterIsOutput;
220         parameter.name       = "Gain Reduction 3";
221         parameter.symbol     = "gr3";
222         parameter.unit       = "dB";
223         parameter.ranges.def = 0.0f;
224         parameter.ranges.min = 0.0f;
225         parameter.ranges.max = 20.0f;
226         break;
227     case paramXover1:
228         parameter.hints      = kParameterIsAutomable | kParameterIsLogarithmic;
229         parameter.name       = "Crossover freq 1";
230         parameter.symbol     = "xover1";
231         parameter.unit       = "Hz";
232         parameter.ranges.def = 160.0f;
233         parameter.ranges.min = 20.0f;
234         parameter.ranges.max = 1400.0f;
235         break;
236     case paramXover2:
237         parameter.hints      = kParameterIsAutomable | kParameterIsLogarithmic;
238         parameter.name       = "Crossover freq 2";
239         parameter.symbol     = "xover2";
240         parameter.unit       = "Hz";
241         parameter.ranges.def = 1400.0f;
242         parameter.ranges.min = 1400.0f;
243         parameter.ranges.max = 14000.0f;
244         break;
245     case paramToggle1:
246         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
247         parameter.name       = "ZamComp 1 ON";
248         parameter.symbol     = "toggle1";
249         parameter.unit       = " ";
250         parameter.ranges.def = 0.0f;
251         parameter.ranges.min = 0.0f;
252         parameter.ranges.max = 1.0f;
253         break;
254     case paramToggle2:
255         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
256         parameter.name       = "ZamComp 2 ON";
257         parameter.symbol     = "toggle2";
258         parameter.unit       = " ";
259         parameter.ranges.def = 0.0f;
260         parameter.ranges.min = 0.0f;
261         parameter.ranges.max = 1.0f;
262         break;
263     case paramToggle3:
264         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
265         parameter.name       = "ZamComp 3 ON";
266         parameter.symbol     = "toggle3";
267         parameter.unit       = " ";
268         parameter.ranges.def = 0.0f;
269         parameter.ranges.min = 0.0f;
270         parameter.ranges.max = 1.0f;
271         break;
272     case paramListen1:
273         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
274         parameter.name       = "Listen 1";
275         parameter.symbol     = "listen1";
276         parameter.unit       = " ";
277         parameter.ranges.def = 0.0f;
278         parameter.ranges.min = 0.0f;
279         parameter.ranges.max = 1.0f;
280         break;
281     case paramListen2:
282         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
283         parameter.name       = "Listen 2";
284         parameter.symbol     = "listen2";
285         parameter.unit       = " ";
286         parameter.ranges.def = 0.0f;
287         parameter.ranges.min = 0.0f;
288         parameter.ranges.max = 1.0f;
289         break;
290     case paramListen3:
291         parameter.hints      = kParameterIsAutomable | kParameterIsBoolean;
292         parameter.name       = "Listen 3";
293         parameter.symbol     = "listen3";
294         parameter.unit       = " ";
295         parameter.ranges.def = 0.0f;
296         parameter.ranges.min = 0.0f;
297         parameter.ranges.max = 1.0f;
298         break;
299     case paramGlobalGain:
300         parameter.hints      = kParameterIsAutomable;
301         parameter.name       = "Master Trim";
302         parameter.symbol     = "globalgain";
303         parameter.unit       = "dB";
304         parameter.ranges.def = 0.0f;
305         parameter.ranges.min = -12.0f;
306         parameter.ranges.max = 12.0f;
307         break;
308     case paramOutputLevel:
309         parameter.hints      = kParameterIsOutput;
310         parameter.name       = "Output";
311         parameter.symbol     = "out";
312         parameter.unit       = "dB";
313         parameter.ranges.def = -45.0f;
314         parameter.ranges.min = -45.0f;
315         parameter.ranges.max = 20.0f;
316         break;
317     case paramOutputLevelLow:
318         parameter.hints      = kParameterIsOutput;
319         parameter.name       = "Output low";
320         parameter.symbol     = "outlo";
321         parameter.unit       = "dB";
322         parameter.ranges.def = -45.0f;
323         parameter.ranges.min = -45.0f;
324         parameter.ranges.max = 20.0f;
325         break;
326     case paramOutputLevelMed:
327         parameter.hints      = kParameterIsOutput;
328         parameter.name       = "Output medium";
329         parameter.symbol     = "outmed";
330         parameter.unit       = "dB";
331         parameter.ranges.def = -45.0f;
332         parameter.ranges.min = -45.0f;
333         parameter.ranges.max = 20.0f;
334         break;
335     case paramOutputLevelHigh:
336         parameter.hints      = kParameterIsOutput;
337         parameter.name       = "Output high";
338         parameter.symbol     = "outhi";
339         parameter.unit       = "dB";
340         parameter.ranges.def = -45.0f;
341         parameter.ranges.min = -45.0f;
342         parameter.ranges.max = 20.0f;
343         break;
344     }
345 }
346 
initProgramName(uint32_t index,String & programName)347 void ZaMultiCompPlugin::initProgramName(uint32_t index, String& programName)
348 {
349 	switch(index) {
350 	case 0:
351 		programName = "Zero";
352 		break;
353 	case 1:
354 		programName = "Presence";
355 		break;
356 	}
357 }
358 
loadProgram(uint32_t index)359 void ZaMultiCompPlugin::loadProgram(uint32_t index)
360 {
361 	switch(index) {
362 	case 0:
363 		attack[0] = 10.0;
364 		attack[1] = 10.0;
365 		attack[2] = 10.0;
366 		release[0] = 80.0;
367 		release[1] = 80.0;
368 		release[2] = 80.0;
369 		knee[0] = 0.0;
370 		knee[1] = 0.0;
371 		knee[2] = 0.0;
372 		ratio[0] = 4.0;
373 		ratio[1] = 4.0;
374 		ratio[2] = 4.0;
375 		thresdb[0] = -20.0;
376 		thresdb[1] = -18.0;
377 		thresdb[2] = -16.0;
378 		makeup[0] = 0.0;
379 		makeup[1] = 0.0;
380 		makeup[2] = 0.0;
381 		xover1 = 160.0;
382 		xover2 = 1400.0;
383 		gainr[0] = 0.0;
384 		gainr[1] = 0.0;
385 		gainr[2] = 0.0;
386 		toggle[0] = 0.0;
387 		toggle[1] = 0.0;
388 		toggle[2] = 0.0;
389 		listen[0] = 0.0;
390 		listen[1] = 0.0;
391 		listen[2] = 0.0;
392 		globalgain = 0.0;
393 		out = -45.0;
394 		outlevel[0] = -45;
395 		outlevel[1] = -45;
396 		outlevel[2] = -45;
397 		break;
398 	case 1:
399 		attack[0] = 10.0;
400 		attack[1] = 10.0;
401 		attack[2] = 10.0;
402 		release[0] = 200.0;
403 		release[1] = 200.0;
404 		release[2] = 200.0;
405 		knee[0] = 3.0;
406 		knee[1] = 3.0;
407 		knee[2] = 3.0;
408 		ratio[0] = 5.0;
409 		ratio[1] = 5.0;
410 		ratio[2] = 5.0;
411 		thresdb[0] = -20.0;
412 		thresdb[1] = -18.0;
413 		thresdb[2] = -16.0;
414 		makeup[0] = 9.0;
415 		makeup[1] = 6.0;
416 		makeup[2] = 6.0;
417 		xover1 = 160.0;
418 		xover2 = 1400.0;
419 		gainr[0] = 0.0;
420 		gainr[1] = 0.0;
421 		gainr[2] = 0.0;
422 		toggle[0] = 1.0;
423 		toggle[1] = 1.0;
424 		toggle[2] = 1.0;
425 		listen[0] = 0.0;
426 		listen[1] = 0.0;
427 		listen[2] = 0.0;
428 		globalgain = 0.0;
429 		out = -45.0;
430 		outlevel[0] = -45.0;
431 		outlevel[1] = -45.0;
432 		outlevel[2] = -45.0;
433 		break;
434 	}
435     /* Default variable values */
436     max = 0.f;
437     limit = 0.f;
438 
439     /* reset filter values */
440     activate();
441 }
442 
443 // -----------------------------------------------------------------------
444 // Internal data
445 
getParameterValue(uint32_t index) const446 float ZaMultiCompPlugin::getParameterValue(uint32_t index) const
447 {
448     switch (index)
449     {
450     case paramAttack1:
451         return attack[0];
452         break;
453     case paramAttack2:
454         return attack[1];
455         break;
456     case paramAttack3:
457         return attack[2];
458         break;
459     case paramRelease1:
460         return release[0];
461         break;
462     case paramRelease2:
463         return release[1];
464         break;
465     case paramRelease3:
466         return release[2];
467         break;
468     case paramKnee1:
469         return knee[0];
470         break;
471     case paramKnee2:
472         return knee[1];
473         break;
474     case paramKnee3:
475         return knee[2];
476         break;
477     case paramRatio1:
478         return ratio[0];
479         break;
480     case paramRatio2:
481         return ratio[1];
482         break;
483     case paramRatio3:
484         return ratio[2];
485         break;
486     case paramThresh1:
487         return thresdb[0];
488         break;
489     case paramThresh2:
490         return thresdb[1];
491         break;
492     case paramThresh3:
493         return thresdb[2];
494         break;
495     case paramMakeup1:
496         return makeup[0];
497         break;
498     case paramMakeup2:
499         return makeup[1];
500         break;
501     case paramMakeup3:
502         return makeup[2];
503         break;
504     case paramGainR1:
505         return gainr[0];
506         break;
507     case paramGainR2:
508         return gainr[1];
509         break;
510     case paramGainR3:
511         return gainr[2];
512         break;
513     case paramXover1:
514         return xover1;
515         break;
516     case paramXover2:
517         return xover2;
518         break;
519     case paramToggle1:
520         return toggle[0];
521         break;
522     case paramToggle2:
523         return toggle[1];
524         break;
525     case paramToggle3:
526         return toggle[2];
527         break;
528     case paramListen1:
529         return listen[0];
530         break;
531     case paramListen2:
532         return listen[1];
533         break;
534     case paramListen3:
535         return listen[2];
536         break;
537     case paramGlobalGain:
538         return globalgain;
539         break;
540     case paramOutputLevel:
541         return out;
542         break;
543     case paramOutputLevelLow:
544         return outlevel[0];
545         break;
546     case paramOutputLevelMed:
547         return outlevel[1];
548         break;
549     case paramOutputLevelHigh:
550         return outlevel[2];
551         break;
552     default:
553         return 0.0f;
554     }
555 }
556 
setParameterValue(uint32_t index,float value)557 void ZaMultiCompPlugin::setParameterValue(uint32_t index, float value)
558 {
559     switch (index)
560     {
561     case paramAttack1:
562         attack[0] = value;
563         break;
564     case paramAttack2:
565         attack[1] = value;
566         break;
567     case paramAttack3:
568         attack[2] = value;
569         break;
570     case paramRelease1:
571         release[0] = value;
572         break;
573     case paramRelease2:
574         release[1] = value;
575         break;
576     case paramRelease3:
577         release[2] = value;
578         break;
579     case paramKnee1:
580         knee[0] = value;
581         break;
582     case paramKnee2:
583         knee[1] = value;
584         break;
585     case paramKnee3:
586         knee[2] = value;
587         break;
588     case paramRatio1:
589         ratio[0] = value;
590         break;
591     case paramRatio2:
592         ratio[1] = value;
593         break;
594     case paramRatio3:
595         ratio[2] = value;
596         break;
597     case paramThresh1:
598         thresdb[0] = value;
599         break;
600     case paramThresh2:
601         thresdb[1] = value;
602         break;
603     case paramThresh3:
604         thresdb[2] = value;
605         break;
606     case paramMakeup1:
607         makeup[0] = value;
608         break;
609     case paramMakeup2:
610         makeup[1] = value;
611         break;
612     case paramMakeup3:
613         makeup[2] = value;
614         break;
615     case paramGainR1:
616         gainr[0] = value;
617         break;
618     case paramGainR2:
619         gainr[1] = value;
620         break;
621     case paramGainR3:
622         gainr[2] = value;
623         break;
624     case paramXover1:
625         xover1 = value;
626         break;
627     case paramXover2:
628         xover2 = value;
629         break;
630     case paramToggle1:
631         toggle[0] = value;
632         if (value == 0.f)
633 	    gainr[0] = 0.f;
634         break;
635     case paramToggle2:
636         toggle[1] = value;
637         if (value == 0.f)
638 	    gainr[1] = 0.f;
639         break;
640     case paramToggle3:
641         toggle[2] = value;
642         if (value == 0.f)
643 	    gainr[2] = 0.f;
644         break;
645     case paramListen1:
646         listen[0] = value;
647         if (value == 0.f)
648 	    gainr[0] = 0.f;
649         break;
650     case paramListen2:
651         listen[1] = value;
652         if (value == 0.f)
653 	    gainr[1] = 0.f;
654         break;
655     case paramListen3:
656         listen[2] = value;
657         if (value == 0.f)
658 	    gainr[2] = 0.f;
659         break;
660     case paramGlobalGain:
661         globalgain = value;
662         break;
663     case paramOutputLevel:
664         out = value;
665         break;
666     case paramOutputLevelLow:
667         outlevel[0] = value;
668         break;
669     case paramOutputLevelMed:
670         outlevel[1] = value;
671         break;
672     case paramOutputLevelHigh:
673         outlevel[2] = value;
674         break;
675     }
676 }
677 
getState(const char *) const678 String ZaMultiCompPlugin::getState(const char*) const
679 {
680     return String();
681 }
682 
setState(const char *,const char *)683 void ZaMultiCompPlugin::setState(const char*, const char*)
684 {
685     reset = true;
686 }
687 
initState(unsigned int,String &,String &)688 void ZaMultiCompPlugin::initState(unsigned int, String&, String&)
689 {
690 }
691 
692 // -----------------------------------------------------------------------
693 // Process
694 
activate()695 void ZaMultiCompPlugin::activate()
696 {
697         int i;
698         for (i = 0; i < MAX_COMP; i++)
699                 old_yl[i]=old_y1[i]=old_yg[i]=0.f;
700 
701 	old_ll=old_l1=0.f;
702 
703 	for (i = 0; i < MAX_FILT; i++) {
704 		simper[0][i].k = 0.f;
705 		simper[0][i].g = 0.f;
706 		simper[0][i].s[0] = 0.f;
707 		simper[0][i].s[1] = 0.f;
708 
709 		simper[1][i].k = 0.f;
710 		simper[1][i].g = 0.f;
711 		simper[1][i].s[0] = 0.f;
712 		simper[1][i].s[1] = 0.f;
713 	}
714 	max = 0.f;
715 	pos[0] = 0;
716 	pos[1] = 0;
717 	pos[2] = 0;
718 
719 	oldxover1 = 0.f;
720 	oldxover2 = 0.f;
721 }
722 
723 /*
724  * A. Simper's filters
725  * https://cytomic.com/files/dsp/SvfInputMixing.pdf
726  */
727 
linear_svf_set_xover(struct linear_svf * self,float sample_rate,float cutoff,float resonance)728 void ZaMultiCompPlugin::linear_svf_set_xover(struct linear_svf *self, float sample_rate, float cutoff, float resonance)
729 {
730 	double w;
731 
732 	self->k = 2. - 2. * resonance;
733 	w = M_PI * cutoff / sample_rate;
734 	self->g = tan(w);
735 
736 }
737 
linear_svf_reset(struct linear_svf * self)738 void ZaMultiCompPlugin::linear_svf_reset(struct linear_svf *self)
739 {
740 	self->s[0] = self->s[1] = 0.f;
741 }
742 
run_linear_svf_xover(struct linear_svf * self,float in,float mixlow,float mixhigh)743 float ZaMultiCompPlugin::run_linear_svf_xover(struct linear_svf *self, float in, float mixlow, float mixhigh)
744 {
745 	double v[3];
746 	double g = self->g;
747 	double k = self->k;
748 	double s0 = self->s[0];
749 	double s1 = self->s[1];
750 	double g2 = g*g;
751 	double vhigh = in * mixhigh;
752 	double vband = in * 0.75;
753 	double vlow = in * mixlow;
754 
755 	v[0] = in;
756 	v[1] = -1. / (1. + g2 + g*k) * (-s0 + g*s1 - g*k*s0 + g2*vband + g*vhigh - g*vlow - g2*k*vlow);
757 	v[2] = -1. / (1. + g2 + g*k) * (-g*s0 - s1 - g*vband + g2*vhigh + g*k*vhigh - g2*vlow);
758 	self->s[0] = 2. * v[1] - s0;
759 	self->s[1] = 2. * v[2] - s1;
760 
761 	return (float)(vhigh + v[2]);
762 }
763 
calc_lr4(float f,int i)764 void ZaMultiCompPlugin::calc_lr4(float f, int i)
765 {
766 	float srate = getSampleRate();
767 
768 	linear_svf_set_xover(&simper[0][i], srate, f, 0.25);
769 	linear_svf_set_xover(&simper[1][i], srate, f, 0.25);
770 }
771 
run_lr4(int i,float in,float * outlo,float * outhi)772 void ZaMultiCompPlugin::run_lr4(int i, float in, float *outlo, float *outhi)
773 {
774 	*outlo = run_linear_svf_xover(&simper[0][i], in, 1., 0.);
775 	*outhi = run_linear_svf_xover(&simper[1][i], in, 0., 1.);
776 }
777 
run_comp(int k,float in,float * out)778 void ZaMultiCompPlugin::run_comp(int k, float in, float *out)
779 {
780 	float srate = getSampleRate();
781         float width = (6.f * knee[k]) + 0.01;
782         float attack_coeff = exp(-1000.f/(attack[k] * srate));
783         float release_coeff = exp(-1000.f/(release[k] * srate));
784 
785 	float checkwidth = 0.f;
786         float cdb=0.f;
787         float Lgain = 1.f;
788         float Lxg, Lyg;
789         float Lxl, Lyl;
790 
791         Lyg = 0.f;
792 	in = sanitize_denormal(in);
793         Lxg = (in==0.f) ? -160.f : to_dB(fabsf(in));
794         Lxg = sanitize_denormal(Lxg);
795 
796 	checkwidth = 2.f*fabsf(Lxg-thresdb[k]);
797 	if (2.f*(Lxg-thresdb[k]) < -width) {
798 		Lyg = Lxg;
799 	} else if (checkwidth <= width) {
800 		Lyg = Lxg + (1.f/ratio[k]-1.f)*(Lxg-thresdb[k]+width/2.f)*(Lxg-thresdb[k]+width/2.f)/(2.f*width);
801 		Lyg = sanitize_denormal(Lyg);
802 	} else if (2.f*(Lxg-thresdb[k]) > width) {
803 		Lyg = thresdb[k] + (Lxg-thresdb[k])/ratio[k];
804 		Lyg = sanitize_denormal(Lyg);
805 	}
806 
807         Lxl = Lxg - Lyg;
808 
809 	old_yl[k] = sanitize_denormal(old_yl[k]);
810 
811 	if (Lxl < old_yl[k]) {
812 		Lyl = release_coeff * old_yl[k] + (1.f-release_coeff)*Lxl;
813 	} else if (Lxl > old_yl[k]) {
814 		Lyl = attack_coeff * old_yl[k]+(1.f-attack_coeff)*Lxl;
815 	} else {
816 		Lyl = Lxl;
817 	}
818         Lyl = sanitize_denormal(Lyl);
819 
820         cdb = -Lyl;
821         Lgain = from_dB(cdb);
822 
823 	gainr[k] = Lyl;
824 
825 	*out = in * Lgain;
826 
827         old_yl[k] = Lyl;
828         old_yg[k] = Lyg;
829 }
830 
pushsample(float sample,int k)831 void ZaMultiCompPlugin::pushsample(float sample, int k)
832 {
833 	const float rate = 2. * M_PI * 5.;
834 	float lpf = rate / (rate + getSampleRate());
835 
836 	average[k] += lpf * (sample*sample - average[k]);
837 }
838 
run(const float ** inputs,float ** outputs,uint32_t frames)839 void ZaMultiCompPlugin::run(const float** inputs, float** outputs, uint32_t frames)
840 {
841 	float maxx = max;
842 
843         int tog1 = (toggle[0] > 0.5f) ? 1 : 0;
844         int tog2 = (toggle[1] > 0.5f) ? 1 : 0;
845         int tog3 = (toggle[2] > 0.5f) ? 1 : 0;
846 
847         int listen1 = (listen[0] > 0.5f) ? 1 : 0;
848         int listen2 = (listen[1] > 0.5f) ? 1 : 0;
849         int listen3 = (listen[2] > 0.5f) ? 1 : 0;
850 
851         if (oldxover1 != xover1) {
852 		// recalculate coeffs
853 		calc_lr4(xover1, 0);
854 		oldxover1 = xover1;
855 	}
856         if (oldxover2 != xover2) {
857 		// recalculate coeffs
858 		calc_lr4(xover2, 1);
859 		oldxover2 = xover2;
860 	}
861 
862         for (uint32_t i = 0; i < frames; ++i) {
863                 float tmp1[2], tmp2[2], tmp3[2];
864 		float fil1[2], fil2[2], fil3[2], fil4[2];
865 		float outL[MAX_COMP+1] = {0.f};
866 		float inl = sanitize_denormal(inputs[0][i]);
867 		inl = (fabsf(inl) < DANGER) ? inl : 0.f;
868 
869 		int listenmode = 0;
870 
871 		// Interleaved channel processing
872                 run_lr4(0, inl, &fil1[0], &fil2[0]);
873                 run_lr4(1, fil2[0], &fil3[0], &fil4[0]);
874 
875 		pushsample(fil1[0], 0);
876 		outlevel[0] = sqrt(average[0]);
877 		outlevel[0] = (outlevel[0] == 0.f) ? -45.0 : to_dB(outlevel[0]);
878 		if (tog1)
879 			run_comp(0, fil1[0], &outL[0]);
880 
881 		tmp1[0] = tog1 ? outL[0] * from_dB(makeup[0]) : fil1[0];
882 
883 		pushsample(fil3[0], 1);
884 		outlevel[1] = sqrt(average[1]);
885 		outlevel[1] = (outlevel[1] == 0.f) ? -45.0 : to_dB(outlevel[1]);
886 		if (tog2)
887 			run_comp(1, fil3[0], &outL[1]);
888 
889                 tmp2[0] = tog2 ? outL[1] * from_dB(makeup[1]) : fil3[0];
890 
891 		pushsample(fil4[0], 2);
892 		outlevel[2] = sqrt(average[2]);
893 		outlevel[2] = (outlevel[2] == 0.f) ? -45.0 : to_dB(outlevel[2]);
894 		if (tog3)
895 			run_comp(2, fil4[0], &outL[2]);
896 
897                 tmp3[0] = tog3 ? outL[2] * from_dB(makeup[2]) : fil4[0];
898 
899 		outputs[0][i] = 0.f;
900 		if (listen1) {
901 			listenmode = 1;
902 			outputs[0][i] += outL[0] * tog1*from_dB(makeup[0])
903 					+ (1.-tog1) * tmp1[0];
904 		}
905 		if (listen2) {
906 			listenmode = 1;
907 			outputs[0][i] += outL[1] * tog2*from_dB(makeup[1])
908 					+ (1.-tog2) * tmp2[0];
909 		}
910 		if (listen3) {
911 			listenmode = 1;
912 			outputs[0][i] += outL[2] * tog3*from_dB(makeup[2])
913 					+ (1.-tog3) * tmp3[0];
914 		}
915 		if (!listenmode) {
916 			outputs[0][i] = tmp1[0] + tmp2[0] + tmp3[0];
917 		}
918                 outputs[0][i] = sanitize_denormal(outputs[0][i]);
919                 outputs[0][i] *= from_dB(globalgain);
920 
921 		if (reset) {
922 			max = fabsf(outputs[0][i]);
923 			reset = false;
924 		} else {
925 			maxx = (fabsf(outputs[0][i]) > maxx) ? fabsf(outputs[0][i]) : sanitize_denormal(maxx);
926 		}
927         }
928 	out = (maxx <= 0.f) ? -160.f : to_dB(maxx);
929 }
930 
931 // -----------------------------------------------------------------------
932 
createPlugin()933 Plugin* createPlugin()
934 {
935     return new ZaMultiCompPlugin();
936 }
937 
938 // -----------------------------------------------------------------------
939 
940 END_NAMESPACE_DISTRHO
941