1 /* ========================================
2 * ButterComp2 - ButterComp2.h
3 * Copyright (c) 2016 airwindows, All rights reserved
4 * ======================================== */
5
6 #ifndef __ButterComp2_H
7 #include "ButterComp2.h"
8 #endif
9
10 namespace ButterComp2 {
11
12
processReplacing(float ** inputs,float ** outputs,VstInt32 sampleFrames)13 void ButterComp2::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
14 {
15 float* in1 = inputs[0];
16 float* in2 = inputs[1];
17 float* out1 = outputs[0];
18 float* out2 = outputs[1];
19
20 double overallscale = 1.0;
21 overallscale /= 44100.0;
22 overallscale *= getSampleRate();
23
24 double inputgain = pow(10.0,(A*14.0)/20.0);
25 double compfactor = 0.012 * (A / 135.0);
26 double output = B * 2.0;
27 double wet = C;
28 double dry = 1.0 - wet;
29 double outputgain = inputgain;
30 outputgain -= 1.0;
31 outputgain /= 1.5;
32 outputgain += 1.0;
33
34 while (--sampleFrames >= 0)
35 {
36 long double inputSampleL = *in1;
37 long double inputSampleR = *in2;
38
39 static int noisesourceL = 0;
40 static int noisesourceR = 850010;
41 int residue;
42 double applyresidue;
43
44 noisesourceL = noisesourceL % 1700021; noisesourceL++;
45 residue = noisesourceL * noisesourceL;
46 residue = residue % 170003; residue *= residue;
47 residue = residue % 17011; residue *= residue;
48 residue = residue % 1709; residue *= residue;
49 residue = residue % 173; residue *= residue;
50 residue = residue % 17;
51 applyresidue = residue;
52 applyresidue *= 0.00000001;
53 applyresidue *= 0.00000001;
54 inputSampleL += applyresidue;
55 if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
56 inputSampleL -= applyresidue;
57 }
58
59 noisesourceR = noisesourceR % 1700021; noisesourceR++;
60 residue = noisesourceR * noisesourceR;
61 residue = residue % 170003; residue *= residue;
62 residue = residue % 17011; residue *= residue;
63 residue = residue % 1709; residue *= residue;
64 residue = residue % 173; residue *= residue;
65 residue = residue % 17;
66 applyresidue = residue;
67 applyresidue *= 0.00000001;
68 applyresidue *= 0.00000001;
69 inputSampleR += applyresidue;
70 if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
71 inputSampleR -= applyresidue;
72 }
73 //for live air, we always apply the dither noise. Then, if our result is
74 //effectively digital black, we'll subtract it aButterComp2. We want a 'air' hiss
75 double drySampleL = inputSampleL;
76 double drySampleR = inputSampleR;
77
78 inputSampleL *= inputgain;
79 inputSampleR *= inputgain;
80
81 long double divisor = compfactor / (1.0+fabs(lastOutputL));
82 //this is slowing compressor recovery while output waveforms were high
83 divisor /= overallscale;
84 long double remainder = divisor;
85 divisor = 1.0 - divisor;
86 //recalculate divisor every sample
87
88 long double inputposL = inputSampleL + 1.0;
89 if (inputposL < 0.0) inputposL = 0.0;
90 long double outputposL = inputposL / 2.0;
91 if (outputposL > 1.0) outputposL = 1.0;
92 inputposL *= inputposL;
93 targetposL *= divisor;
94 targetposL += (inputposL * remainder);
95 long double calcposL = pow((1.0/targetposL),2);
96
97 long double inputnegL = (-inputSampleL) + 1.0;
98 if (inputnegL < 0.0) inputnegL = 0.0;
99 long double outputnegL = inputnegL / 2.0;
100 if (outputnegL > 1.0) outputnegL = 1.0;
101 inputnegL *= inputnegL;
102 targetnegL *= divisor;
103 targetnegL += (inputnegL * remainder);
104 long double calcnegL = pow((1.0/targetnegL),2);
105 //now we have mirrored targets for comp
106 //outputpos and outputneg go from 0 to 1
107
108 if (inputSampleL > 0)
109 { //working on pos
110 if (flip)
111 {
112 controlAposL *= divisor;
113 controlAposL += (calcposL*remainder);
114
115 }
116 else
117 {
118 controlBposL *= divisor;
119 controlBposL += (calcposL*remainder);
120 }
121 }
122 else
123 { //working on neg
124 if (flip)
125 {
126 controlAnegL *= divisor;
127 controlAnegL += (calcnegL*remainder);
128 }
129 else
130 {
131 controlBnegL *= divisor;
132 controlBnegL += (calcnegL*remainder);
133 }
134 }
135 //this causes each of the four to update only when active and in the correct 'flip'
136
137 divisor = compfactor / (1.0+fabs(lastOutputR));
138 //this is slowing compressor recovery while output waveforms were high
139 divisor /= overallscale;
140 remainder = divisor;
141 divisor = 1.0 - divisor;
142 //recalculate divisor every sample
143
144 long double inputposR = inputSampleR + 1.0;
145 if (inputposR < 0.0) inputposR = 0.0;
146 long double outputposR = inputposR / 2.0;
147 if (outputposR > 1.0) outputposR = 1.0;
148 inputposR *= inputposR;
149 targetposR *= divisor;
150 targetposR += (inputposR * remainder);
151 long double calcposR = pow((1.0/targetposR),2);
152
153 long double inputnegR = (-inputSampleR) + 1.0;
154 if (inputnegR < 0.0) inputnegR = 0.0;
155 long double outputnegR = inputnegR / 2.0;
156 if (outputnegR > 1.0) outputnegR = 1.0;
157 inputnegR *= inputnegR;
158 targetnegR *= divisor;
159 targetnegR += (inputnegR * remainder);
160 long double calcnegR = pow((1.0/targetnegR),2);
161 //now we have mirrored targets for comp
162 //outputpos and outputneg go from 0 to 1
163
164 if (inputSampleR > 0)
165 { //working on pos
166 if (flip)
167 {
168 controlAposR *= divisor;
169 controlAposR += (calcposR*remainder);
170
171 }
172 else
173 {
174 controlBposR *= divisor;
175 controlBposR += (calcposR*remainder);
176 }
177 }
178 else
179 { //working on neg
180 if (flip)
181 {
182 controlAnegR *= divisor;
183 controlAnegR += (calcnegR*remainder);
184 }
185 else
186 {
187 controlBnegR *= divisor;
188 controlBnegR += (calcnegR*remainder);
189 }
190 }
191 //this causes each of the four to update only when active and in the correct 'flip'
192
193 long double totalmultiplierL;
194 long double totalmultiplierR;
195 if (flip)
196 {
197 totalmultiplierL = (controlAposL * outputposL) + (controlAnegL * outputnegL);
198 totalmultiplierR = (controlAposR * outputposR) + (controlAnegR * outputnegR);
199 }
200 else
201 {
202 totalmultiplierL = (controlBposL * outputposL) + (controlBnegL * outputnegL);
203 totalmultiplierR = (controlBposR * outputposR) + (controlBnegR * outputnegR);
204 }
205 //this combines the sides according to flip, blending relative to the input value
206
207 inputSampleL *= totalmultiplierL;
208 inputSampleL /= outputgain;
209
210 inputSampleR *= totalmultiplierR;
211 inputSampleR /= outputgain;
212
213 if (output != 1.0) {
214 inputSampleL *= output;
215 inputSampleR *= output;
216 }
217
218 if (wet !=1.0) {
219 inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
220 inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
221 }
222
223 lastOutputL = inputSampleL;
224 lastOutputR = inputSampleR;
225 //we will make this factor respond to use of dry/wet
226
227 flip = !flip;
228
229 //stereo 32 bit dither, made small and tidy.
230 int expon; frexpf((float)inputSampleL, &expon);
231 long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
232 inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
233 frexpf((float)inputSampleR, &expon);
234 dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
235 inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
236 //end 32 bit dither
237
238 *out1 = inputSampleL;
239 *out2 = inputSampleR;
240
241 in1++;
242 in2++;
243 out1++;
244 out2++;
245 }
246 }
247
processDoubleReplacing(double ** inputs,double ** outputs,VstInt32 sampleFrames)248 void ButterComp2::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames)
249 {
250 double* in1 = inputs[0];
251 double* in2 = inputs[1];
252 double* out1 = outputs[0];
253 double* out2 = outputs[1];
254
255 double overallscale = 1.0;
256 overallscale /= 44100.0;
257 overallscale *= getSampleRate();
258
259 double inputgain = pow(10.0,(A*14.0)/20.0);
260 double compfactor = 0.012 * (A / 135.0);
261 double output = B * 2.0;
262 double wet = C;
263 double dry = 1.0 - wet;
264 double outputgain = inputgain;
265 outputgain -= 1.0;
266 outputgain /= 1.5;
267 outputgain += 1.0;
268
269 while (--sampleFrames >= 0)
270 {
271 long double inputSampleL = *in1;
272 long double inputSampleR = *in2;
273
274 static int noisesourceL = 0;
275 static int noisesourceR = 850010;
276 int residue;
277 double applyresidue;
278
279 noisesourceL = noisesourceL % 1700021; noisesourceL++;
280 residue = noisesourceL * noisesourceL;
281 residue = residue % 170003; residue *= residue;
282 residue = residue % 17011; residue *= residue;
283 residue = residue % 1709; residue *= residue;
284 residue = residue % 173; residue *= residue;
285 residue = residue % 17;
286 applyresidue = residue;
287 applyresidue *= 0.00000001;
288 applyresidue *= 0.00000001;
289 inputSampleL += applyresidue;
290 if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
291 inputSampleL -= applyresidue;
292 }
293
294 noisesourceR = noisesourceR % 1700021; noisesourceR++;
295 residue = noisesourceR * noisesourceR;
296 residue = residue % 170003; residue *= residue;
297 residue = residue % 17011; residue *= residue;
298 residue = residue % 1709; residue *= residue;
299 residue = residue % 173; residue *= residue;
300 residue = residue % 17;
301 applyresidue = residue;
302 applyresidue *= 0.00000001;
303 applyresidue *= 0.00000001;
304 inputSampleR += applyresidue;
305 if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
306 inputSampleR -= applyresidue;
307 }
308 //for live air, we always apply the dither noise. Then, if our result is
309 //effectively digital black, we'll subtract it aButterComp2. We want a 'air' hiss
310 double drySampleL = inputSampleL;
311 double drySampleR = inputSampleR;
312
313 inputSampleL *= inputgain;
314 inputSampleR *= inputgain;
315
316 long double divisor = compfactor / (1.0+fabs(lastOutputL));
317 //this is slowing compressor recovery while output waveforms were high
318 divisor /= overallscale;
319 long double remainder = divisor;
320 divisor = 1.0 - divisor;
321 //recalculate divisor every sample
322
323 long double inputposL = inputSampleL + 1.0;
324 if (inputposL < 0.0) inputposL = 0.0;
325 long double outputposL = inputposL / 2.0;
326 if (outputposL > 1.0) outputposL = 1.0;
327 inputposL *= inputposL;
328 targetposL *= divisor;
329 targetposL += (inputposL * remainder);
330 long double calcposL = pow((1.0/targetposL),2);
331
332 long double inputnegL = (-inputSampleL) + 1.0;
333 if (inputnegL < 0.0) inputnegL = 0.0;
334 long double outputnegL = inputnegL / 2.0;
335 if (outputnegL > 1.0) outputnegL = 1.0;
336 inputnegL *= inputnegL;
337 targetnegL *= divisor;
338 targetnegL += (inputnegL * remainder);
339 long double calcnegL = pow((1.0/targetnegL),2);
340 //now we have mirrored targets for comp
341 //outputpos and outputneg go from 0 to 1
342
343 if (inputSampleL > 0)
344 { //working on pos
345 if (flip)
346 {
347 controlAposL *= divisor;
348 controlAposL += (calcposL*remainder);
349
350 }
351 else
352 {
353 controlBposL *= divisor;
354 controlBposL += (calcposL*remainder);
355 }
356 }
357 else
358 { //working on neg
359 if (flip)
360 {
361 controlAnegL *= divisor;
362 controlAnegL += (calcnegL*remainder);
363 }
364 else
365 {
366 controlBnegL *= divisor;
367 controlBnegL += (calcnegL*remainder);
368 }
369 }
370 //this causes each of the four to update only when active and in the correct 'flip'
371
372 divisor = compfactor / (1.0+fabs(lastOutputR));
373 //this is slowing compressor recovery while output waveforms were high
374 divisor /= overallscale;
375 remainder = divisor;
376 divisor = 1.0 - divisor;
377 //recalculate divisor every sample
378
379 long double inputposR = inputSampleR + 1.0;
380 if (inputposR < 0.0) inputposR = 0.0;
381 long double outputposR = inputposR / 2.0;
382 if (outputposR > 1.0) outputposR = 1.0;
383 inputposR *= inputposR;
384 targetposR *= divisor;
385 targetposR += (inputposR * remainder);
386 long double calcposR = pow((1.0/targetposR),2);
387
388 long double inputnegR = (-inputSampleR) + 1.0;
389 if (inputnegR < 0.0) inputnegR = 0.0;
390 long double outputnegR = inputnegR / 2.0;
391 if (outputnegR > 1.0) outputnegR = 1.0;
392 inputnegR *= inputnegR;
393 targetnegR *= divisor;
394 targetnegR += (inputnegR * remainder);
395 long double calcnegR = pow((1.0/targetnegR),2);
396 //now we have mirrored targets for comp
397 //outputpos and outputneg go from 0 to 1
398
399 if (inputSampleR > 0)
400 { //working on pos
401 if (flip)
402 {
403 controlAposR *= divisor;
404 controlAposR += (calcposR*remainder);
405
406 }
407 else
408 {
409 controlBposR *= divisor;
410 controlBposR += (calcposR*remainder);
411 }
412 }
413 else
414 { //working on neg
415 if (flip)
416 {
417 controlAnegR *= divisor;
418 controlAnegR += (calcnegR*remainder);
419 }
420 else
421 {
422 controlBnegR *= divisor;
423 controlBnegR += (calcnegR*remainder);
424 }
425 }
426 //this causes each of the four to update only when active and in the correct 'flip'
427
428 long double totalmultiplierL;
429 long double totalmultiplierR;
430 if (flip)
431 {
432 totalmultiplierL = (controlAposL * outputposL) + (controlAnegL * outputnegL);
433 totalmultiplierR = (controlAposR * outputposR) + (controlAnegR * outputnegR);
434 }
435 else
436 {
437 totalmultiplierL = (controlBposL * outputposL) + (controlBnegL * outputnegL);
438 totalmultiplierR = (controlBposR * outputposR) + (controlBnegR * outputnegR);
439 }
440 //this combines the sides according to flip, blending relative to the input value
441
442 inputSampleL *= totalmultiplierL;
443 inputSampleL /= outputgain;
444
445 inputSampleR *= totalmultiplierR;
446 inputSampleR /= outputgain;
447
448 if (output != 1.0) {
449 inputSampleL *= output;
450 inputSampleR *= output;
451 }
452
453 if (wet !=1.0) {
454 inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
455 inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
456 }
457
458 lastOutputL = inputSampleL;
459 lastOutputR = inputSampleR;
460 //we will make this factor respond to use of dry/wet
461
462 flip = !flip;
463
464 //stereo 64 bit dither, made small and tidy.
465 int expon; frexp((double)inputSampleL, &expon);
466 long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
467 dither /= 536870912.0; //needs this to scale to 64 bit zone
468 inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
469 frexp((double)inputSampleR, &expon);
470 dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
471 dither /= 536870912.0; //needs this to scale to 64 bit zone
472 inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
473 //end 64 bit dither
474
475 *out1 = inputSampleL;
476 *out2 = inputSampleR;
477
478 in1++;
479 in2++;
480 out1++;
481 out2++;
482 }
483 }
484
485
486 } // end namespace ButterComp2
487
488