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