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