/* ========================================
* ToTape5 - ToTape5.h
* Copyright (c) 2016 airwindows, All rights reserved
* ======================================== */
#ifndef __ToTape5_H
#include "ToTape5.h"
#endif
void ToTape5::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
{
float* in1 = inputs[0];
float* in2 = inputs[1];
float* out1 = outputs[0];
float* out2 = outputs[1];
double overallscale = 1.0;
overallscale /= 44100.0;
overallscale *= getSampleRate();
long double fpOld = 0.618033988749894848204586; //golden ratio!
double inputgain = pow(A+1.0,3);
double outputgain = E;
double wet = F;
double dry = 1.0 - wet;
double trim = 0.211324865405187117745425;
double SoftenControl = pow(B,2);
double tempRandy = 0.06 + (SoftenControl/10.0);
double RollAmount = (1.0-(SoftenControl * 0.45))/overallscale;
double HeadBumpControl = pow(C,2);
int allpasstemp;
int maxdelay = (int)(floor(((HeadBumpControl+0.3)*2.2)*overallscale));
HeadBumpControl *= fabs(HeadBumpControl);
double HeadBumpFreq = 0.044/overallscale;
double iirAmount = 0.000001/overallscale;
double altAmount = 1.0 - iirAmount;
double iirHBoostAmount = 0.0001/overallscale;
double altHBoostAmount = 1.0 - iirAmount;
double depth = pow(D,2)*overallscale;
double fluttertrim = 0.005/overallscale;
double sweeptrim = (0.0006*depth)/overallscale;
double offset;
double tupi = 3.141592653589793238 * 2.0;
double newrate = 0.005/overallscale;
double oldrate = 1.0-newrate;
double flutterrandy;
double randy;
double invrandy;
int count;
double HighsSampleL = 0.0;
double NonHighsSampleL = 0.0;
double HeadBumpL = 0.0;
double SubtractL;
double bridgerectifierL;
double tempSampleL;
double drySampleL;
double HighsSampleR = 0.0;
double NonHighsSampleR = 0.0;
double HeadBumpR = 0.0;
double SubtractR;
double bridgerectifierR;
double tempSampleR;
double drySampleR;
long double inputSampleL;
long double inputSampleR;
while (--sampleFrames >= 0)
{
inputSampleL = *in1;
inputSampleR = *in2;
if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
static int noisesource = 0;
//this declares a variable before anything else is compiled. It won't keep assigning
//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
//but it lets me add this denormalization fix in a single place rather than updating
//it in three different locations. The variable isn't thread-safe but this is only
//a random seed and we can share it with whatever.
noisesource = noisesource % 1700021; noisesource++;
int residue = noisesource * noisesource;
residue = residue % 170003; residue *= residue;
residue = residue % 17011; residue *= residue;
residue = residue % 1709; residue *= residue;
residue = residue % 173; residue *= residue;
residue = residue % 17;
double applyresidue = residue;
applyresidue *= 0.00000001;
applyresidue *= 0.00000001;
inputSampleL = applyresidue;
}
if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
static int noisesource = 0;
noisesource = noisesource % 1700021; noisesource++;
int residue = noisesource * noisesource;
residue = residue % 170003; residue *= residue;
residue = residue % 17011; residue *= residue;
residue = residue % 1709; residue *= residue;
residue = residue % 173; residue *= residue;
residue = residue % 17;
double applyresidue = residue;
applyresidue *= 0.00000001;
applyresidue *= 0.00000001;
inputSampleR = applyresidue;
//this denormalization routine produces a white noise at -300 dB which the noise
//shaping will interact with to produce a bipolar output, but the noise is actually
//all positive. That should stop any variables from going denormal, and the routine
//only kicks in if digital black is input. As a final touch, if you save to 24-bit
//the silence will return to being digital black again.
}
drySampleL = inputSampleL;
drySampleR = inputSampleR;
flutterrandy = (rand()/(double)RAND_MAX);
randy = flutterrandy * tempRandy; //for soften
invrandy = (1.0-randy);
randy /= 2.0;
//we've set up so that we dial in the amount of the alt sections (in pairs) with invrandy being the source section
//now we've got a random flutter, so we're messing with the pitch before tape effects go on
if (gcount < 0 || gcount > 300) {gcount = 300;}
count = gcount;
dL[count+301] = dL[count] = inputSampleL;
dR[count+301] = dR[count] = inputSampleR;
gcount--;
//we will also keep the buffer going, even when not in use
if (depth != 0.0) {
offset = (1.0 + sin(sweep)) * depth;
count += (int)floor(offset);
bridgerectifierL = (dL[count] * (1-(offset-floor(offset))));
bridgerectifierL += (dL[count+1] * (offset-floor(offset)));
bridgerectifierL -= ((dL[count+2] * (offset-floor(offset)))*trim);
bridgerectifierR = (dR[count] * (1-(offset-floor(offset))));
bridgerectifierR += (dR[count+1] * (offset-floor(offset)));
bridgerectifierR -= ((dR[count+2] * (offset-floor(offset)))*trim);
rateof = (nextmax * newrate) + (rateof * oldrate);
sweep += rateof * fluttertrim;
sweep += sweep * sweeptrim;
if (sweep >= tupi){sweep = 0.0; nextmax = 0.02 + (flutterrandy*0.98);}
inputSampleL = bridgerectifierL;
inputSampleR = bridgerectifierR;
//apply to input signal only when flutter is present, interpolate samples
}
if (inputgain != 1.0) {
inputSampleL *= inputgain;
inputSampleR *= inputgain;
}
if (flip < 1 || flip > 3) flip = 1;
switch (flip)
{
case 1:
iirMidRollerAL = (iirMidRollerAL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerAL = (invrandy * iirMidRollerAL) + (randy * iirMidRollerBL) + (randy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerAL;
NonHighsSampleL = iirMidRollerAL;
iirHeadBumpAL += (inputSampleL * 0.05);
iirHeadBumpAL -= (iirHeadBumpAL * iirHeadBumpAL * iirHeadBumpAL * HeadBumpFreq);
iirHeadBumpAL = (invrandy * iirHeadBumpAL) + (randy * iirHeadBumpBL) + (randy * iirHeadBumpCL);
iirMidRollerAR = (iirMidRollerAR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerAR = (invrandy * iirMidRollerAR) + (randy * iirMidRollerBR) + (randy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerAR;
NonHighsSampleR = iirMidRollerAR;
iirHeadBumpAR += (inputSampleR * 0.05);
iirHeadBumpAR -= (iirHeadBumpAR * iirHeadBumpAR * iirHeadBumpAR * HeadBumpFreq);
iirHeadBumpAR = (invrandy * iirHeadBumpAR) + (randy * iirHeadBumpBR) + (randy * iirHeadBumpCR);
break;
case 2:
iirMidRollerBL = (iirMidRollerBL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerBL = (randy * iirMidRollerAL) + (invrandy * iirMidRollerBL) + (randy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerBL;
NonHighsSampleL = iirMidRollerBL;
iirHeadBumpBL += (inputSampleL * 0.05);
iirHeadBumpBL -= (iirHeadBumpBL * iirHeadBumpBL * iirHeadBumpBL * HeadBumpFreq);
iirHeadBumpBL = (randy * iirHeadBumpAL) + (invrandy * iirHeadBumpBL) + (randy * iirHeadBumpCL);
iirMidRollerBR = (iirMidRollerBR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerBR = (randy * iirMidRollerAR) + (invrandy * iirMidRollerBR) + (randy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerBR;
NonHighsSampleR = iirMidRollerBR;
iirHeadBumpBR += (inputSampleR * 0.05);
iirHeadBumpBR -= (iirHeadBumpBR * iirHeadBumpBR * iirHeadBumpBR * HeadBumpFreq);
iirHeadBumpBR = (randy * iirHeadBumpAR) + (invrandy * iirHeadBumpBR) + (randy * iirHeadBumpCR);
break;
case 3:
iirMidRollerCL = (iirMidRollerCL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerCL = (randy * iirMidRollerAL) + (randy * iirMidRollerBL) + (invrandy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerCL;
NonHighsSampleL = iirMidRollerCL;
iirHeadBumpCL += (inputSampleL * 0.05);
iirHeadBumpCL -= (iirHeadBumpCL * iirHeadBumpCL * iirHeadBumpCL * HeadBumpFreq);
iirHeadBumpCL = (randy * iirHeadBumpAL) + (randy * iirHeadBumpBL) + (invrandy * iirHeadBumpCL);
iirMidRollerCR = (iirMidRollerCR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerCR = (randy * iirMidRollerAR) + (randy * iirMidRollerBR) + (invrandy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerCR;
NonHighsSampleR = iirMidRollerCR;
iirHeadBumpCR += (inputSampleR * 0.05);
iirHeadBumpCR -= (iirHeadBumpCR * iirHeadBumpCR * iirHeadBumpCR * HeadBumpFreq);
iirHeadBumpCR = (randy * iirHeadBumpAR) + (randy * iirHeadBumpBR) + (invrandy * iirHeadBumpCR);
break;
}
flip++; //increment the triplet counter
SubtractL = HighsSampleL;
bridgerectifierL = fabs(SubtractL)*1.57079633;
if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
bridgerectifierL = 1-cos(bridgerectifierL);
if (SubtractL > 0) SubtractL = bridgerectifierL;
if (SubtractL < 0) SubtractL = -bridgerectifierL;
inputSampleL -= SubtractL;
SubtractR = HighsSampleR;
bridgerectifierR = fabs(SubtractR)*1.57079633;
if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
bridgerectifierR = 1-cos(bridgerectifierR);
if (SubtractR > 0) SubtractR = bridgerectifierR;
if (SubtractR < 0) SubtractR = -bridgerectifierR;
inputSampleR -= SubtractR;
//Soften works using the MidRoller stuff, defining a bright parallel channel that we apply negative Density
//to, and then subtract from the main audio. That makes the 'highs channel subtract' hit only the loudest
//transients, plus we are subtracting any artifacts we got from the negative Density.
bridgerectifierL = fabs(inputSampleL);
if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
bridgerectifierL = sin(bridgerectifierL);
if (inputSampleL > 0) inputSampleL = bridgerectifierL;
if (inputSampleL < 0) inputSampleL = -bridgerectifierL;
bridgerectifierR = fabs(inputSampleR);
if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
bridgerectifierR = sin(bridgerectifierR);
if (inputSampleR > 0) inputSampleR = bridgerectifierR;
if (inputSampleR < 0) inputSampleR = -bridgerectifierR;
//drive section: the tape sound includes a very gentle saturation curve, which is always an attenuation.
//we cut back on highs before hitting this, and then we're going to subtract highs a second time after.
HeadBumpL = iirHeadBumpAL + iirHeadBumpBL + iirHeadBumpCL;
HeadBumpR = iirHeadBumpAR + iirHeadBumpBR + iirHeadBumpCR;
//begin PhaseNudge
allpasstemp = hcount - 1;
if (allpasstemp < 0 || allpasstemp > maxdelay) {allpasstemp = maxdelay;}
HeadBumpL -= eL[allpasstemp] * fpOld;
eL[hcount] = HeadBumpL;
inputSampleL *= fpOld;
HeadBumpR -= eR[allpasstemp] * fpOld;
eR[hcount] = HeadBumpR;
inputSampleR *= fpOld;
hcount--; if (hcount < 0 || hcount > maxdelay) {hcount = maxdelay;}
HeadBumpL += (eL[hcount]);
HeadBumpR += (eR[hcount]);
//end PhaseNudge on head bump in lieu of delay.
SubtractL -= (HeadBumpL * (HeadBumpControl+iirMinHeadBumpL));
SubtractR -= (HeadBumpR * (HeadBumpControl+iirMinHeadBumpR));
//makes a second soften and a single head bump after saturation.
//we are going to retain this, and then feed it into the highpass filter. That way, we can skip a subtract.
//Head Bump retains a trace which is roughly as large as what the highpass will do.
tempSampleL = inputSampleL;
tempSampleR = inputSampleR;
iirMinHeadBumpL = (iirMinHeadBumpL * altHBoostAmount) + (fabs(inputSampleL) * iirHBoostAmount);
if (iirMinHeadBumpL > 0.01) iirMinHeadBumpL = 0.01;
iirMinHeadBumpR = (iirMinHeadBumpR * altHBoostAmount) + (fabs(inputSampleR) * iirHBoostAmount);
if (iirMinHeadBumpR > 0.01) iirMinHeadBumpR = 0.01;
//we want this one rectified so that it's a relatively steady positive value. Boosts can cause it to be
//greater than 1 so we clamp it in that case.
iirSampleAL = (iirSampleAL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleAL; SubtractL += iirSampleAL;
iirSampleBL = (iirSampleBL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleBL; SubtractL += iirSampleBL;
iirSampleCL = (iirSampleCL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleCL; SubtractL += iirSampleCL;
iirSampleDL = (iirSampleDL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleDL; SubtractL += iirSampleDL;
iirSampleEL = (iirSampleEL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleEL; SubtractL += iirSampleEL;
iirSampleFL = (iirSampleFL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleFL; SubtractL += iirSampleFL;
iirSampleGL = (iirSampleGL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleGL; SubtractL += iirSampleGL;
iirSampleHL = (iirSampleHL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleHL; SubtractL += iirSampleHL;
iirSampleIL = (iirSampleIL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleIL; SubtractL += iirSampleIL;
iirSampleJL = (iirSampleJL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleJL; SubtractL += iirSampleJL;
iirSampleKL = (iirSampleKL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleKL; SubtractL += iirSampleKL;
iirSampleLL = (iirSampleLL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleLL; SubtractL += iirSampleLL;
iirSampleML = (iirSampleML * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleML; SubtractL += iirSampleML;
iirSampleNL = (iirSampleNL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleNL; SubtractL += iirSampleNL;
iirSampleOL = (iirSampleOL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleOL; SubtractL += iirSampleOL;
iirSamplePL = (iirSamplePL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSamplePL; SubtractL += iirSamplePL;
iirSampleQL = (iirSampleQL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleQL; SubtractL += iirSampleQL;
iirSampleRL = (iirSampleRL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleRL; SubtractL += iirSampleRL;
iirSampleSL = (iirSampleSL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleSL; SubtractL += iirSampleSL;
iirSampleTL = (iirSampleTL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleTL; SubtractL += iirSampleTL;
iirSampleUL = (iirSampleUL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleUL; SubtractL += iirSampleUL;
iirSampleVL = (iirSampleVL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleVL; SubtractL += iirSampleVL;
iirSampleWL = (iirSampleWL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleWL; SubtractL += iirSampleWL;
iirSampleXL = (iirSampleXL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleXL; SubtractL += iirSampleXL;
iirSampleYL = (iirSampleYL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleYL; SubtractL += iirSampleYL;
iirSampleZL = (iirSampleZL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleZL; SubtractL += iirSampleZL;
iirSampleAR = (iirSampleAR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleAR; SubtractR += iirSampleAR;
iirSampleBR = (iirSampleBR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleBR; SubtractR += iirSampleBR;
iirSampleCR = (iirSampleCR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleCR; SubtractR += iirSampleCR;
iirSampleDR = (iirSampleDR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleDR; SubtractR += iirSampleDR;
iirSampleER = (iirSampleER * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleER; SubtractR += iirSampleER;
iirSampleFR = (iirSampleFR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleFR; SubtractR += iirSampleFR;
iirSampleGR = (iirSampleGR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleGR; SubtractR += iirSampleGR;
iirSampleHR = (iirSampleHR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleHR; SubtractR += iirSampleHR;
iirSampleIR = (iirSampleIR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleIR; SubtractR += iirSampleIR;
iirSampleJR = (iirSampleJR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleJR; SubtractR += iirSampleJR;
iirSampleKR = (iirSampleKR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleKR; SubtractR += iirSampleKR;
iirSampleLR = (iirSampleLR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleLR; SubtractR += iirSampleLR;
iirSampleMR = (iirSampleMR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleMR; SubtractR += iirSampleMR;
iirSampleNR = (iirSampleNR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleNR; SubtractR += iirSampleNR;
iirSampleOR = (iirSampleOR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleOR; SubtractR += iirSampleOR;
iirSamplePR = (iirSamplePR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSamplePR; SubtractR += iirSamplePR;
iirSampleQR = (iirSampleQR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleQR; SubtractR += iirSampleQR;
iirSampleRR = (iirSampleRR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleRR; SubtractR += iirSampleRR;
iirSampleSR = (iirSampleSR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleSR; SubtractR += iirSampleSR;
iirSampleTR = (iirSampleTR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleTR; SubtractR += iirSampleTR;
iirSampleUR = (iirSampleUR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleUR; SubtractR += iirSampleUR;
iirSampleVR = (iirSampleVR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleVR; SubtractR += iirSampleVR;
iirSampleWR = (iirSampleWR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleWR; SubtractR += iirSampleWR;
iirSampleXR = (iirSampleXR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleXR; SubtractR += iirSampleXR;
iirSampleYR = (iirSampleYR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleYR; SubtractR += iirSampleYR;
iirSampleZR = (iirSampleZR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleZR; SubtractR += iirSampleZR;
//do the IIR on a dummy sample, and store up the correction in a variable at the same scale as the very low level
//numbers being used. Don't keep doing it against the possibly high level signal number.
//This has been known to add a resonant quality to the cutoff, which we're using on purpose.
inputSampleL -= SubtractL;
inputSampleR -= SubtractR;
//apply stored up tiny corrections.
if (outputgain != 1.0) {
inputSampleL *= outputgain;
inputSampleR *= outputgain;
}
if (wet !=1.0) {
inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
}
//stereo 32 bit dither, made small and tidy.
int expon; frexpf((float)inputSampleL, &expon);
long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
frexpf((float)inputSampleR, &expon);
dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
//end 32 bit dither
*out1 = inputSampleL;
*out2 = inputSampleR;
*in1++;
*in2++;
*out1++;
*out2++;
}
}
void ToTape5::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames)
{
double* in1 = inputs[0];
double* in2 = inputs[1];
double* out1 = outputs[0];
double* out2 = outputs[1];
double overallscale = 1.0;
overallscale /= 44100.0;
overallscale *= getSampleRate();
long double fpOld = 0.618033988749894848204586; //golden ratio!
double inputgain = pow(A+1.0,3);
double outputgain = E;
double wet = F;
double dry = 1.0 - wet;
double trim = 0.211324865405187117745425;
double SoftenControl = pow(B,2);
double tempRandy = 0.06 + (SoftenControl/10.0);
double RollAmount = (1.0-(SoftenControl * 0.45))/overallscale;
double HeadBumpControl = pow(C,2);
int allpasstemp;
int maxdelay = (int)(floor(((HeadBumpControl+0.3)*2.2)*overallscale));
HeadBumpControl *= fabs(HeadBumpControl);
double HeadBumpFreq = 0.044/overallscale;
double iirAmount = 0.000001/overallscale;
double altAmount = 1.0 - iirAmount;
double iirHBoostAmount = 0.0001/overallscale;
double altHBoostAmount = 1.0 - iirAmount;
double depth = pow(D,2)*overallscale;
double fluttertrim = 0.005/overallscale;
double sweeptrim = (0.0006*depth)/overallscale;
double offset;
double tupi = 3.141592653589793238 * 2.0;
double newrate = 0.005/overallscale;
double oldrate = 1.0-newrate;
double flutterrandy;
double randy;
double invrandy;
int count;
double HighsSampleL = 0.0;
double NonHighsSampleL = 0.0;
double HeadBumpL = 0.0;
double SubtractL;
double bridgerectifierL;
double tempSampleL;
double drySampleL;
double HighsSampleR = 0.0;
double NonHighsSampleR = 0.0;
double HeadBumpR = 0.0;
double SubtractR;
double bridgerectifierR;
double tempSampleR;
double drySampleR;
long double inputSampleL;
long double inputSampleR;
while (--sampleFrames >= 0)
{
inputSampleL = *in1;
inputSampleR = *in2;
if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
static int noisesource = 0;
//this declares a variable before anything else is compiled. It won't keep assigning
//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
//but it lets me add this denormalization fix in a single place rather than updating
//it in three different locations. The variable isn't thread-safe but this is only
//a random seed and we can share it with whatever.
noisesource = noisesource % 1700021; noisesource++;
int residue = noisesource * noisesource;
residue = residue % 170003; residue *= residue;
residue = residue % 17011; residue *= residue;
residue = residue % 1709; residue *= residue;
residue = residue % 173; residue *= residue;
residue = residue % 17;
double applyresidue = residue;
applyresidue *= 0.00000001;
applyresidue *= 0.00000001;
inputSampleL = applyresidue;
}
if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
static int noisesource = 0;
noisesource = noisesource % 1700021; noisesource++;
int residue = noisesource * noisesource;
residue = residue % 170003; residue *= residue;
residue = residue % 17011; residue *= residue;
residue = residue % 1709; residue *= residue;
residue = residue % 173; residue *= residue;
residue = residue % 17;
double applyresidue = residue;
applyresidue *= 0.00000001;
applyresidue *= 0.00000001;
inputSampleR = applyresidue;
//this denormalization routine produces a white noise at -300 dB which the noise
//shaping will interact with to produce a bipolar output, but the noise is actually
//all positive. That should stop any variables from going denormal, and the routine
//only kicks in if digital black is input. As a final touch, if you save to 24-bit
//the silence will return to being digital black again.
}
drySampleL = inputSampleL;
drySampleR = inputSampleR;
flutterrandy = (rand()/(double)RAND_MAX);
randy = flutterrandy * tempRandy; //for soften
invrandy = (1.0-randy);
randy /= 2.0;
//we've set up so that we dial in the amount of the alt sections (in pairs) with invrandy being the source section
//now we've got a random flutter, so we're messing with the pitch before tape effects go on
if (gcount < 0 || gcount > 300) {gcount = 300;}
count = gcount;
dL[count+301] = dL[count] = inputSampleL;
dR[count+301] = dR[count] = inputSampleR;
gcount--;
//we will also keep the buffer going, even when not in use
if (depth != 0.0) {
offset = (1.0 + sin(sweep)) * depth;
count += (int)floor(offset);
bridgerectifierL = (dL[count] * (1-(offset-floor(offset))));
bridgerectifierL += (dL[count+1] * (offset-floor(offset)));
bridgerectifierL -= ((dL[count+2] * (offset-floor(offset)))*trim);
bridgerectifierR = (dR[count] * (1-(offset-floor(offset))));
bridgerectifierR += (dR[count+1] * (offset-floor(offset)));
bridgerectifierR -= ((dR[count+2] * (offset-floor(offset)))*trim);
rateof = (nextmax * newrate) + (rateof * oldrate);
sweep += rateof * fluttertrim;
sweep += sweep * sweeptrim;
if (sweep >= tupi){sweep = 0.0; nextmax = 0.02 + (flutterrandy*0.98);}
inputSampleL = bridgerectifierL;
inputSampleR = bridgerectifierR;
//apply to input signal only when flutter is present, interpolate samples
}
if (inputgain != 1.0) {
inputSampleL *= inputgain;
inputSampleR *= inputgain;
}
if (flip < 1 || flip > 3) flip = 1;
switch (flip)
{
case 1:
iirMidRollerAL = (iirMidRollerAL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerAL = (invrandy * iirMidRollerAL) + (randy * iirMidRollerBL) + (randy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerAL;
NonHighsSampleL = iirMidRollerAL;
iirHeadBumpAL += (inputSampleL * 0.05);
iirHeadBumpAL -= (iirHeadBumpAL * iirHeadBumpAL * iirHeadBumpAL * HeadBumpFreq);
iirHeadBumpAL = (invrandy * iirHeadBumpAL) + (randy * iirHeadBumpBL) + (randy * iirHeadBumpCL);
iirMidRollerAR = (iirMidRollerAR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerAR = (invrandy * iirMidRollerAR) + (randy * iirMidRollerBR) + (randy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerAR;
NonHighsSampleR = iirMidRollerAR;
iirHeadBumpAR += (inputSampleR * 0.05);
iirHeadBumpAR -= (iirHeadBumpAR * iirHeadBumpAR * iirHeadBumpAR * HeadBumpFreq);
iirHeadBumpAR = (invrandy * iirHeadBumpAR) + (randy * iirHeadBumpBR) + (randy * iirHeadBumpCR);
break;
case 2:
iirMidRollerBL = (iirMidRollerBL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerBL = (randy * iirMidRollerAL) + (invrandy * iirMidRollerBL) + (randy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerBL;
NonHighsSampleL = iirMidRollerBL;
iirHeadBumpBL += (inputSampleL * 0.05);
iirHeadBumpBL -= (iirHeadBumpBL * iirHeadBumpBL * iirHeadBumpBL * HeadBumpFreq);
iirHeadBumpBL = (randy * iirHeadBumpAL) + (invrandy * iirHeadBumpBL) + (randy * iirHeadBumpCL);
iirMidRollerBR = (iirMidRollerBR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerBR = (randy * iirMidRollerAR) + (invrandy * iirMidRollerBR) + (randy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerBR;
NonHighsSampleR = iirMidRollerBR;
iirHeadBumpBR += (inputSampleR * 0.05);
iirHeadBumpBR -= (iirHeadBumpBR * iirHeadBumpBR * iirHeadBumpBR * HeadBumpFreq);
iirHeadBumpBR = (randy * iirHeadBumpAR) + (invrandy * iirHeadBumpBR) + (randy * iirHeadBumpCR);
break;
case 3:
iirMidRollerCL = (iirMidRollerCL * (1.0 - RollAmount)) + (inputSampleL * RollAmount);
iirMidRollerCL = (randy * iirMidRollerAL) + (randy * iirMidRollerBL) + (invrandy * iirMidRollerCL);
HighsSampleL = inputSampleL - iirMidRollerCL;
NonHighsSampleL = iirMidRollerCL;
iirHeadBumpCL += (inputSampleL * 0.05);
iirHeadBumpCL -= (iirHeadBumpCL * iirHeadBumpCL * iirHeadBumpCL * HeadBumpFreq);
iirHeadBumpCL = (randy * iirHeadBumpAL) + (randy * iirHeadBumpBL) + (invrandy * iirHeadBumpCL);
iirMidRollerCR = (iirMidRollerCR * (1.0 - RollAmount)) + (inputSampleR * RollAmount);
iirMidRollerCR = (randy * iirMidRollerAR) + (randy * iirMidRollerBR) + (invrandy * iirMidRollerCR);
HighsSampleR = inputSampleR - iirMidRollerCR;
NonHighsSampleR = iirMidRollerCR;
iirHeadBumpCR += (inputSampleR * 0.05);
iirHeadBumpCR -= (iirHeadBumpCR * iirHeadBumpCR * iirHeadBumpCR * HeadBumpFreq);
iirHeadBumpCR = (randy * iirHeadBumpAR) + (randy * iirHeadBumpBR) + (invrandy * iirHeadBumpCR);
break;
}
flip++; //increment the triplet counter
SubtractL = HighsSampleL;
bridgerectifierL = fabs(SubtractL)*1.57079633;
if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
bridgerectifierL = 1-cos(bridgerectifierL);
if (SubtractL > 0) SubtractL = bridgerectifierL;
if (SubtractL < 0) SubtractL = -bridgerectifierL;
inputSampleL -= SubtractL;
SubtractR = HighsSampleR;
bridgerectifierR = fabs(SubtractR)*1.57079633;
if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
bridgerectifierR = 1-cos(bridgerectifierR);
if (SubtractR > 0) SubtractR = bridgerectifierR;
if (SubtractR < 0) SubtractR = -bridgerectifierR;
inputSampleR -= SubtractR;
//Soften works using the MidRoller stuff, defining a bright parallel channel that we apply negative Density
//to, and then subtract from the main audio. That makes the 'highs channel subtract' hit only the loudest
//transients, plus we are subtracting any artifacts we got from the negative Density.
bridgerectifierL = fabs(inputSampleL);
if (bridgerectifierL > 1.57079633) bridgerectifierL = 1.57079633;
bridgerectifierL = sin(bridgerectifierL);
if (inputSampleL > 0) inputSampleL = bridgerectifierL;
if (inputSampleL < 0) inputSampleL = -bridgerectifierL;
bridgerectifierR = fabs(inputSampleR);
if (bridgerectifierR > 1.57079633) bridgerectifierR = 1.57079633;
bridgerectifierR = sin(bridgerectifierR);
if (inputSampleR > 0) inputSampleR = bridgerectifierR;
if (inputSampleR < 0) inputSampleR = -bridgerectifierR;
//drive section: the tape sound includes a very gentle saturation curve, which is always an attenuation.
//we cut back on highs before hitting this, and then we're going to subtract highs a second time after.
HeadBumpL = iirHeadBumpAL + iirHeadBumpBL + iirHeadBumpCL;
HeadBumpR = iirHeadBumpAR + iirHeadBumpBR + iirHeadBumpCR;
//begin PhaseNudge
allpasstemp = hcount - 1;
if (allpasstemp < 0 || allpasstemp > maxdelay) {allpasstemp = maxdelay;}
HeadBumpL -= eL[allpasstemp] * fpOld;
eL[hcount] = HeadBumpL;
inputSampleL *= fpOld;
HeadBumpR -= eR[allpasstemp] * fpOld;
eR[hcount] = HeadBumpR;
inputSampleR *= fpOld;
hcount--; if (hcount < 0 || hcount > maxdelay) {hcount = maxdelay;}
HeadBumpL += (eL[hcount]);
HeadBumpR += (eR[hcount]);
//end PhaseNudge on head bump in lieu of delay.
SubtractL -= (HeadBumpL * (HeadBumpControl+iirMinHeadBumpL));
SubtractR -= (HeadBumpR * (HeadBumpControl+iirMinHeadBumpR));
//makes a second soften and a single head bump after saturation.
//we are going to retain this, and then feed it into the highpass filter. That way, we can skip a subtract.
//Head Bump retains a trace which is roughly as large as what the highpass will do.
tempSampleL = inputSampleL;
tempSampleR = inputSampleR;
iirMinHeadBumpL = (iirMinHeadBumpL * altHBoostAmount) + (fabs(inputSampleL) * iirHBoostAmount);
if (iirMinHeadBumpL > 0.01) iirMinHeadBumpL = 0.01;
iirMinHeadBumpR = (iirMinHeadBumpR * altHBoostAmount) + (fabs(inputSampleR) * iirHBoostAmount);
if (iirMinHeadBumpR > 0.01) iirMinHeadBumpR = 0.01;
//we want this one rectified so that it's a relatively steady positive value. Boosts can cause it to be
//greater than 1 so we clamp it in that case.
iirSampleAL = (iirSampleAL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleAL; SubtractL += iirSampleAL;
iirSampleBL = (iirSampleBL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleBL; SubtractL += iirSampleBL;
iirSampleCL = (iirSampleCL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleCL; SubtractL += iirSampleCL;
iirSampleDL = (iirSampleDL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleDL; SubtractL += iirSampleDL;
iirSampleEL = (iirSampleEL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleEL; SubtractL += iirSampleEL;
iirSampleFL = (iirSampleFL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleFL; SubtractL += iirSampleFL;
iirSampleGL = (iirSampleGL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleGL; SubtractL += iirSampleGL;
iirSampleHL = (iirSampleHL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleHL; SubtractL += iirSampleHL;
iirSampleIL = (iirSampleIL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleIL; SubtractL += iirSampleIL;
iirSampleJL = (iirSampleJL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleJL; SubtractL += iirSampleJL;
iirSampleKL = (iirSampleKL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleKL; SubtractL += iirSampleKL;
iirSampleLL = (iirSampleLL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleLL; SubtractL += iirSampleLL;
iirSampleML = (iirSampleML * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleML; SubtractL += iirSampleML;
iirSampleNL = (iirSampleNL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleNL; SubtractL += iirSampleNL;
iirSampleOL = (iirSampleOL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleOL; SubtractL += iirSampleOL;
iirSamplePL = (iirSamplePL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSamplePL; SubtractL += iirSamplePL;
iirSampleQL = (iirSampleQL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleQL; SubtractL += iirSampleQL;
iirSampleRL = (iirSampleRL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleRL; SubtractL += iirSampleRL;
iirSampleSL = (iirSampleSL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleSL; SubtractL += iirSampleSL;
iirSampleTL = (iirSampleTL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleTL; SubtractL += iirSampleTL;
iirSampleUL = (iirSampleUL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleUL; SubtractL += iirSampleUL;
iirSampleVL = (iirSampleVL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleVL; SubtractL += iirSampleVL;
iirSampleWL = (iirSampleWL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleWL; SubtractL += iirSampleWL;
iirSampleXL = (iirSampleXL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleXL; SubtractL += iirSampleXL;
iirSampleYL = (iirSampleYL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleYL; SubtractL += iirSampleYL;
iirSampleZL = (iirSampleZL * altAmount) + (tempSampleL * iirAmount); tempSampleL -= iirSampleZL; SubtractL += iirSampleZL;
iirSampleAR = (iirSampleAR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleAR; SubtractR += iirSampleAR;
iirSampleBR = (iirSampleBR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleBR; SubtractR += iirSampleBR;
iirSampleCR = (iirSampleCR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleCR; SubtractR += iirSampleCR;
iirSampleDR = (iirSampleDR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleDR; SubtractR += iirSampleDR;
iirSampleER = (iirSampleER * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleER; SubtractR += iirSampleER;
iirSampleFR = (iirSampleFR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleFR; SubtractR += iirSampleFR;
iirSampleGR = (iirSampleGR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleGR; SubtractR += iirSampleGR;
iirSampleHR = (iirSampleHR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleHR; SubtractR += iirSampleHR;
iirSampleIR = (iirSampleIR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleIR; SubtractR += iirSampleIR;
iirSampleJR = (iirSampleJR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleJR; SubtractR += iirSampleJR;
iirSampleKR = (iirSampleKR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleKR; SubtractR += iirSampleKR;
iirSampleLR = (iirSampleLR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleLR; SubtractR += iirSampleLR;
iirSampleMR = (iirSampleMR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleMR; SubtractR += iirSampleMR;
iirSampleNR = (iirSampleNR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleNR; SubtractR += iirSampleNR;
iirSampleOR = (iirSampleOR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleOR; SubtractR += iirSampleOR;
iirSamplePR = (iirSamplePR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSamplePR; SubtractR += iirSamplePR;
iirSampleQR = (iirSampleQR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleQR; SubtractR += iirSampleQR;
iirSampleRR = (iirSampleRR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleRR; SubtractR += iirSampleRR;
iirSampleSR = (iirSampleSR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleSR; SubtractR += iirSampleSR;
iirSampleTR = (iirSampleTR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleTR; SubtractR += iirSampleTR;
iirSampleUR = (iirSampleUR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleUR; SubtractR += iirSampleUR;
iirSampleVR = (iirSampleVR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleVR; SubtractR += iirSampleVR;
iirSampleWR = (iirSampleWR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleWR; SubtractR += iirSampleWR;
iirSampleXR = (iirSampleXR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleXR; SubtractR += iirSampleXR;
iirSampleYR = (iirSampleYR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleYR; SubtractR += iirSampleYR;
iirSampleZR = (iirSampleZR * altAmount) + (tempSampleR * iirAmount); tempSampleR -= iirSampleZR; SubtractR += iirSampleZR;
//do the IIR on a dummy sample, and store up the correction in a variable at the same scale as the very low level
//numbers being used. Don't keep doing it against the possibly high level signal number.
//This has been known to add a resonant quality to the cutoff, which we're using on purpose.
inputSampleL -= SubtractL;
inputSampleR -= SubtractR;
//apply stored up tiny corrections.
if (outputgain != 1.0) {
inputSampleL *= outputgain;
inputSampleR *= outputgain;
}
if (wet !=1.0) {
inputSampleL = (inputSampleL * wet) + (drySampleL * dry);
inputSampleR = (inputSampleR * wet) + (drySampleR * dry);
}
//stereo 64 bit dither, made small and tidy.
int expon; frexp((double)inputSampleL, &expon);
long double dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
dither /= 536870912.0; //needs this to scale to 64 bit zone
inputSampleL += (dither-fpNShapeL); fpNShapeL = dither;
frexp((double)inputSampleR, &expon);
dither = (rand()/(RAND_MAX*7.737125245533627e+25))*pow(2,expon+62);
dither /= 536870912.0; //needs this to scale to 64 bit zone
inputSampleR += (dither-fpNShapeR); fpNShapeR = dither;
//end 64 bit dither
*out1 = inputSampleL;
*out2 = inputSampleR;
*in1++;
*in2++;
*out1++;
*out2++;
}
}