1 /* ========================================
2  *  HardVacuum - HardVacuum.h
3  *  Copyright (c) 2016 airwindows, All rights reserved
4  * ======================================== */
5 
6 #ifndef __HardVacuum_H
7 #include "HardVacuum.h"
8 #endif
9 
10 namespace HardVacuum {
11 
12 
processReplacing(float ** inputs,float ** outputs,VstInt32 sampleFrames)13 void HardVacuum::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 multistage = A*2.0;
21 	if (multistage > 1) multistage *= multistage;
22 	//WE MAKE LOUD NOISE! RAWWWK!
23 	double countdown;
24 	double warmth = B;
25 	double invwarmth = 1.0-warmth;
26 	warmth /= 1.57079633;
27 	double aura = C*3.1415926;
28 	double out = D;
29 	double wet = E;
30 	double dry = 1.0-wet;
31 	double drive;
32 	double positive;
33 	double negative;
34 	double bridgerectifierL;
35 	double bridgerectifierR;
36 	double skewL;
37 	double skewR;
38 
39 
40 	double drySampleL;
41 	double drySampleR;
42 	long double inputSampleL;
43 	long double inputSampleR;
44 
45     while (--sampleFrames >= 0)
46     {
47 		inputSampleL = *in1;
48 		inputSampleR = *in2;
49 		if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
50 			static int noisesource = 0;
51 			//this declares a variable before anything else is compiled. It won't keep assigning
52 			//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
53 			//but it lets me add this denormalization fix in a single place rather than updating
54 			//it in three different locations. The variable isn't thread-safe but this is only
55 			//a random seed and we can share it with whatever.
56 			noisesource = noisesource % 1700021; noisesource++;
57 			int residue = noisesource * noisesource;
58 			residue = residue % 170003; residue *= residue;
59 			residue = residue % 17011; residue *= residue;
60 			residue = residue % 1709; residue *= residue;
61 			residue = residue % 173; residue *= residue;
62 			residue = residue % 17;
63 			double applyresidue = residue;
64 			applyresidue *= 0.00000001;
65 			applyresidue *= 0.00000001;
66 			inputSampleL = applyresidue;
67 		}
68 		if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
69 			static int noisesource = 0;
70 			noisesource = noisesource % 1700021; noisesource++;
71 			int residue = noisesource * noisesource;
72 			residue = residue % 170003; residue *= residue;
73 			residue = residue % 17011; residue *= residue;
74 			residue = residue % 1709; residue *= residue;
75 			residue = residue % 173; residue *= residue;
76 			residue = residue % 17;
77 			double applyresidue = residue;
78 			applyresidue *= 0.00000001;
79 			applyresidue *= 0.00000001;
80 			inputSampleR = applyresidue;
81 			//this denormalization routine produces a white noise at -300 dB which the noise
82 			//shaping will interact with to produce a bipolar output, but the noise is actually
83 			//all positive. That should stop any variables from going denormal, and the routine
84 			//only kicks in if digital black is input. As a final touch, if you save to 24-bit
85 			//the silence will return to being digital black again.
86 		}
87 		drySampleL = inputSampleL;
88 		drySampleR = inputSampleR;
89 
90 		skewL = (inputSampleL - lastSampleL);
91 		skewR = (inputSampleR - lastSampleR);
92 		lastSampleL = inputSampleL;
93 		lastSampleR = inputSampleR;
94 		//skew will be direction/angle
95 		bridgerectifierL = fabs(skewL);
96 		bridgerectifierR = fabs(skewR);
97 		if (bridgerectifierL > 3.1415926) bridgerectifierL = 3.1415926;
98 		if (bridgerectifierR > 3.1415926) bridgerectifierR = 3.1415926;
99 		//for skew we want it to go to zero effect again, so we use full range of the sine
100 
101 		bridgerectifierL = sin(bridgerectifierL);
102 		bridgerectifierR = sin(bridgerectifierR);
103 		if (skewL > 0) skewL = bridgerectifierL*aura;
104 		else skewL = -bridgerectifierL*aura;
105 		if (skewR > 0) skewR = bridgerectifierR*aura;
106 		else skewR = -bridgerectifierR*aura;
107 		//skew is now sined and clamped and then re-amplified again
108 		skewL *= inputSampleL;
109 		skewR *= inputSampleR;
110 		//cools off sparkliness and crossover distortion
111 		skewL *= 1.557079633;
112 		skewR *= 1.557079633;
113 		//crank up the gain on this so we can make it sing
114 		//We're doing all this here so skew isn't incremented by each stage
115 
116 		countdown = multistage;
117 		//begin the torture
118 
119 		while (countdown > 0)
120 		{
121 			if (countdown > 1.0) drive = 1.557079633;
122 			else drive = countdown * (1.0+(0.557079633*invwarmth));
123 			//full crank stages followed by the proportional one
124 			//whee. 1 at full warmth to 1.5570etc at no warmth
125 			positive = drive - warmth;
126 			negative = drive + warmth;
127 			//set up things so we can do repeated iterations, assuming that
128 			//wet is always going to be 0-1 as in the previous plug.
129 			bridgerectifierL = fabs(inputSampleL);
130 			bridgerectifierR = fabs(inputSampleR);
131 			bridgerectifierL += skewL;
132 			bridgerectifierR += skewR;
133 			//apply it here so we don't overload
134 			if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
135 			if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
136 			bridgerectifierL = sin(bridgerectifierL);
137 			bridgerectifierR = sin(bridgerectifierR);
138 			//the distortion section.
139 			bridgerectifierL *= drive;
140 			bridgerectifierR *= drive;
141 			bridgerectifierL += skewL;
142 			bridgerectifierR += skewR;
143 			//again
144 			if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
145 			if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
146 			bridgerectifierL = sin(bridgerectifierL);
147 			bridgerectifierR = sin(bridgerectifierR);
148 			if (inputSampleL > 0)
149 			{
150 				inputSampleL = (inputSampleL*(1-positive+skewL))+(bridgerectifierL*(positive+skewL));
151 			}
152 			else
153 			{
154 				inputSampleL = (inputSampleL*(1-negative+skewL))-(bridgerectifierL*(negative+skewL));
155 			}
156 			if (inputSampleR > 0)
157 			{
158 				inputSampleR = (inputSampleR*(1-positive+skewR))+(bridgerectifierR*(positive+skewR));
159 			}
160 			else
161 			{
162 				inputSampleR = (inputSampleR*(1-negative+skewR))-(bridgerectifierR*(negative+skewR));
163 			}
164 			//blend according to positive and negative controls
165 			countdown -= 1.0;
166 			//step down a notch and repeat.
167 		}
168 
169 		if (out != 1.0) {
170 			inputSampleL *= out;
171 			inputSampleR *= out;
172 		}
173 
174 		if (wet !=1.0) {
175 			inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
176 			inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
177 		}
178 
179 		//stereo 32 bit dither, made small and tidy.
180 		int expon; frexpf((float)inputSampleL, &expon);
181 		long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
182 		inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
183 		frexpf((float)inputSampleR, &expon);
184 		dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
185 		inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
186 		//end 32 bit dither
187 
188 		*out1 = inputSampleL;
189 		*out2 = inputSampleR;
190 
191 		in1++;
192 		in2++;
193 		out1++;
194 		out2++;
195     }
196 }
197 
processDoubleReplacing(double ** inputs,double ** outputs,VstInt32 sampleFrames)198 void HardVacuum::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames)
199 {
200     double* in1  =  inputs[0];
201     double* in2  =  inputs[1];
202     double* out1 = outputs[0];
203     double* out2 = outputs[1];
204 
205 	double multistage = A*2.0;
206 	if (multistage > 1) multistage *= multistage;
207 	//WE MAKE LOUD NOISE! RAWWWK!
208 	double countdown;
209 	double warmth = B;
210 	double invwarmth = 1.0-warmth;
211 	warmth /= 1.57079633;
212 	double aura = C*3.1415926;
213 	double out = D;
214 	double wet = E;
215 	double dry = 1.0-wet;
216 	double drive;
217 	double positive;
218 	double negative;
219 	double bridgerectifierL;
220 	double bridgerectifierR;
221 	double skewL;
222 	double skewR;
223 
224 
225 	double drySampleL;
226 	double drySampleR;
227 	long double inputSampleL;
228 	long double inputSampleR;
229 
230 
231     while (--sampleFrames >= 0)
232     {
233 		inputSampleL = *in1;
234 		inputSampleR = *in2;
235 		if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
236 			static int noisesource = 0;
237 			//this declares a variable before anything else is compiled. It won't keep assigning
238 			//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
239 			//but it lets me add this denormalization fix in a single place rather than updating
240 			//it in three different locations. The variable isn't thread-safe but this is only
241 			//a random seed and we can share it with whatever.
242 			noisesource = noisesource % 1700021; noisesource++;
243 			int residue = noisesource * noisesource;
244 			residue = residue % 170003; residue *= residue;
245 			residue = residue % 17011; residue *= residue;
246 			residue = residue % 1709; residue *= residue;
247 			residue = residue % 173; residue *= residue;
248 			residue = residue % 17;
249 			double applyresidue = residue;
250 			applyresidue *= 0.00000001;
251 			applyresidue *= 0.00000001;
252 			inputSampleL = applyresidue;
253 		}
254 		if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
255 			static int noisesource = 0;
256 			noisesource = noisesource % 1700021; noisesource++;
257 			int residue = noisesource * noisesource;
258 			residue = residue % 170003; residue *= residue;
259 			residue = residue % 17011; residue *= residue;
260 			residue = residue % 1709; residue *= residue;
261 			residue = residue % 173; residue *= residue;
262 			residue = residue % 17;
263 			double applyresidue = residue;
264 			applyresidue *= 0.00000001;
265 			applyresidue *= 0.00000001;
266 			inputSampleR = applyresidue;
267 			//this denormalization routine produces a white noise at -300 dB which the noise
268 			//shaping will interact with to produce a bipolar output, but the noise is actually
269 			//all positive. That should stop any variables from going denormal, and the routine
270 			//only kicks in if digital black is input. As a final touch, if you save to 24-bit
271 			//the silence will return to being digital black again.
272 		}
273 		drySampleL = inputSampleL;
274 		drySampleR = inputSampleR;
275 
276 		skewL = (inputSampleL - lastSampleL);
277 		skewR = (inputSampleR - lastSampleR);
278 		lastSampleL = inputSampleL;
279 		lastSampleR = inputSampleR;
280 		//skew will be direction/angle
281 		bridgerectifierL = fabs(skewL);
282 		bridgerectifierR = fabs(skewR);
283 		if (bridgerectifierL > 3.1415926) bridgerectifierL = 3.1415926;
284 		if (bridgerectifierR > 3.1415926) bridgerectifierR = 3.1415926;
285 		//for skew we want it to go to zero effect again, so we use full range of the sine
286 
287 		bridgerectifierL = sin(bridgerectifierL);
288 		bridgerectifierR = sin(bridgerectifierR);
289 		if (skewL > 0) skewL = bridgerectifierL*aura;
290 		else skewL = -bridgerectifierL*aura;
291 		if (skewR > 0) skewR = bridgerectifierR*aura;
292 		else skewR = -bridgerectifierR*aura;
293 		//skew is now sined and clamped and then re-amplified again
294 		skewL *= inputSampleL;
295 		skewR *= inputSampleR;
296 		//cools off sparkliness and crossover distortion
297 		skewL *= 1.557079633;
298 		skewR *= 1.557079633;
299 		//crank up the gain on this so we can make it sing
300 		//We're doing all this here so skew isn't incremented by each stage
301 
302 		countdown = multistage;
303 		//begin the torture
304 
305 		while (countdown > 0)
306 		{
307 			if (countdown > 1.0) drive = 1.557079633;
308 			else drive = countdown * (1.0+(0.557079633*invwarmth));
309 			//full crank stages followed by the proportional one
310 			//whee. 1 at full warmth to 1.5570etc at no warmth
311 			positive = drive - warmth;
312 			negative = drive + warmth;
313 			//set up things so we can do repeated iterations, assuming that
314 			//wet is always going to be 0-1 as in the previous plug.
315 			bridgerectifierL = fabs(inputSampleL);
316 			bridgerectifierR = fabs(inputSampleR);
317 			bridgerectifierL += skewL;
318 			bridgerectifierR += skewR;
319 			//apply it here so we don't overload
320 			if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
321 			if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
322 			bridgerectifierL = sin(bridgerectifierL);
323 			bridgerectifierR = sin(bridgerectifierR);
324 			//the distortion section.
325 			bridgerectifierL *= drive;
326 			bridgerectifierR *= drive;
327 			bridgerectifierL += skewL;
328 			bridgerectifierR += skewR;
329 			//again
330 			if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
331 			if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
332 			bridgerectifierL = sin(bridgerectifierL);
333 			bridgerectifierR = sin(bridgerectifierR);
334 			if (inputSampleL > 0)
335 			{
336 				inputSampleL = (inputSampleL*(1-positive+skewL))+(bridgerectifierL*(positive+skewL));
337 			}
338 			else
339 			{
340 				inputSampleL = (inputSampleL*(1-negative+skewL))-(bridgerectifierL*(negative+skewL));
341 			}
342 			if (inputSampleR > 0)
343 			{
344 				inputSampleR = (inputSampleR*(1-positive+skewR))+(bridgerectifierR*(positive+skewR));
345 			}
346 			else
347 			{
348 				inputSampleR = (inputSampleR*(1-negative+skewR))-(bridgerectifierR*(negative+skewR));
349 			}
350 			//blend according to positive and negative controls
351 			countdown -= 1.0;
352 			//step down a notch and repeat.
353 		}
354 
355 		if (out != 1.0) {
356 		 inputSampleL *= out;
357 		 inputSampleR *= out;
358 		 }
359 
360 		if (wet !=1.0) {
361 			inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
362 			inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
363 		}
364 
365 		//stereo 64 bit dither, made small and tidy.
366 		int expon; frexp((double)inputSampleL, &expon);
367 		long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
368 		dither /= 536870912.0; //needs this to scale to 64 bit zone
369 		inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
370 		frexp((double)inputSampleR, &expon);
371 		dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
372 		dither /= 536870912.0; //needs this to scale to 64 bit zone
373 		inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
374 		//end 64 bit dither
375 
376 		*out1 = inputSampleL;
377 		*out2 = inputSampleR;
378 
379 		in1++;
380 		in2++;
381 		out1++;
382 		out2++;
383     }
384 }
385 
386 } // end namespace HardVacuum
387 
388