diff options
author | Chris Johnson <jinx6568@sover.net> | 2018-06-03 21:19:24 -0400 |
---|---|---|
committer | Chris Johnson <jinx6568@sover.net> | 2018-06-03 21:19:24 -0400 |
commit | 3a3c2dde62b7c28950898c469c376ad32ac63f39 (patch) | |
tree | ffb5f43117d42b7c65d33d01969d931ff5c8d527 /plugins/LinuxVST/src | |
parent | 4e96c7400c70a1e7bc67e2241727bcc74315c574 (diff) | |
download | airwindows-lv2-port-3a3c2dde62b7c28950898c469c376ad32ac63f39.tar.gz airwindows-lv2-port-3a3c2dde62b7c28950898c469c376ad32ac63f39.tar.bz2 airwindows-lv2-port-3a3c2dde62b7c28950898c469c376ad32ac63f39.zip |
Righteous4 && Channel4
Diffstat (limited to 'plugins/LinuxVST/src')
-rwxr-xr-x | plugins/LinuxVST/src/Channel4/Channel4.cpp | 158 | ||||
-rwxr-xr-x | plugins/LinuxVST/src/Channel4/Channel4.h | 75 | ||||
-rwxr-xr-x | plugins/LinuxVST/src/Channel4/Channel4Proc.cpp | 288 | ||||
-rwxr-xr-x | plugins/LinuxVST/src/Righteous4/Righteous4.cpp | 223 | ||||
-rwxr-xr-x | plugins/LinuxVST/src/Righteous4/Righteous4.h | 134 | ||||
-rwxr-xr-x | plugins/LinuxVST/src/Righteous4/Righteous4Proc.cpp | 1040 |
6 files changed, 1918 insertions, 0 deletions
diff --git a/plugins/LinuxVST/src/Channel4/Channel4.cpp b/plugins/LinuxVST/src/Channel4/Channel4.cpp new file mode 100755 index 0000000..acdd74a --- /dev/null +++ b/plugins/LinuxVST/src/Channel4/Channel4.cpp @@ -0,0 +1,158 @@ +/* ======================================== + * Channel4 - Channel4.h + * Copyright (c) 2016 airwindows, All rights reserved + * ======================================== */ + +#ifndef __Channel4_H +#include "Channel4.h" +#endif + +AudioEffect* createEffectInstance(audioMasterCallback audioMaster) {return new Channel4(audioMaster);} + +Channel4::Channel4(audioMasterCallback audioMaster) : + AudioEffectX(audioMaster, kNumPrograms, kNumParameters) +{ + consoletype = 0.0; + drive = 0.0; + fpNShapeLA = 0.0; + fpNShapeLB = 0.0; + fpNShapeRA = 0.0; + fpNShapeRB = 0.0; + fpFlip = true; + iirSampleLA = 0.0; + iirSampleRA = 0.0; + iirSampleLB = 0.0; + iirSampleRB = 0.0; + lastSampleL = 0.0; + lastSampleR = 0.0; + iirAmount = 0.005832; + threshold = 0.33362176; //instantiating with Neve values + + //this is reset: values being initialized only once. Startup values, whatever they are. + + _canDo.insert("plugAsChannelInsert"); // plug-in can be used as a channel insert effect. + _canDo.insert("plugAsSend"); // plug-in can be used as a send effect. + _canDo.insert("x2in2out"); + setNumInputs(kNumInputs); + setNumOutputs(kNumOutputs); + setUniqueID(kUniqueId); + canProcessReplacing(); // supports output replacing + canDoubleReplacing(); // supports double precision processing + programsAreChunks(true); + vst_strncpy (_programName, "Default", kVstMaxProgNameLen); // default program name +} + +Channel4::~Channel4() {} +VstInt32 Channel4::getVendorVersion () {return 1000;} +void Channel4::setProgramName(char *name) {vst_strncpy (_programName, name, kVstMaxProgNameLen);} +void Channel4::getProgramName(char *name) {vst_strncpy (name, _programName, kVstMaxProgNameLen);} +//airwindows likes to ignore this stuff. Make your own programs, and make a different plugin rather than +//trying to do versioning and preventing people from using older versions. Maybe they like the old one! + +static float pinParameter(float data) +{ + if (data < 0.0f) return 0.0f; + if (data > 1.0f) return 1.0f; + return data; +} + +VstInt32 Channel4::getChunk (void** data, bool isPreset) +{ + float *chunkData = (float *)calloc(kNumParameters, sizeof(float)); + chunkData[0] = consoletype; + chunkData[1] = drive; + /* Note: The way this is set up, it will break if you manage to save settings on an Intel + machine and load them on a PPC Mac. However, it's fine if you stick to the machine you + started with. */ + + *data = chunkData; + return kNumParameters * sizeof(float); +} + +VstInt32 Channel4::setChunk (void* data, VstInt32 byteSize, bool isPreset) +{ + float *chunkData = (float *)data; + consoletype = pinParameter(chunkData[0]); + drive = pinParameter(chunkData[1]); + /* We're ignoring byteSize as we found it to be a filthy liar */ + + /* calculate any other fields you need here - you could copy in + code from setParameter() here. */ + return 0; +} + +void Channel4::setParameter(VstInt32 index, float value) { + switch (index) { + case kParamA: consoletype = value; break; + case kParamB: drive = value; break; + default: throw; // unknown parameter, shouldn't happen! + } + //we can also set other defaults here, and do calculations that only have to happen + //once when parameters actually change. Here is the 'popup' setting its (global) values. + //variables can also be set in the processreplacing loop, and there they'll be set every buffersize + //here they're set when a parameter's actually changed, which should be less frequent, but + //you must use global variables in the Channel4.h file to do it. + switch((VstInt32)( consoletype * 2.999 )) + { + case 0: iirAmount = 0.005832; threshold = 0.33362176; break; //Neve + case 1: iirAmount = 0.004096; threshold = 0.59969536; break; //API + case 2: iirAmount = 0.004913; threshold = 0.84934656; break; //SSL + default: break; //should not happen + } + //this relates to using D as a 'popup' and changing things based on that switch. + //we are using fpFlip just because it's already there globally, as an example. +} + +float Channel4::getParameter(VstInt32 index) { + switch (index) { + case kParamA: return consoletype; break; + case kParamB: return drive; break; + default: break; // unknown parameter, shouldn't happen! + } return 0.0; //we only need to update the relevant name, this is simple to manage +} + +void Channel4::getParameterName(VstInt32 index, char *text) { + switch (index) { + case kParamA: vst_strncpy (text, "Console Type", kVstMaxParamStrLen); break; + case kParamB: vst_strncpy (text, "Drive", kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } //this is our labels for displaying in the VST host +} + +void Channel4::getParameterDisplay(VstInt32 index, char *text) { + switch (index) { + case kParamA: switch((VstInt32)( consoletype * 2.999 )) //0 to almost edge of # of params + { case 0: vst_strncpy (text, "Neve", kVstMaxParamStrLen); break; + case 1: vst_strncpy (text, "API", kVstMaxParamStrLen); break; + case 2: vst_strncpy (text, "SSL", kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } break; //completed consoletype 'popup' parameter, exit + case kParamB: int2string ((VstInt32)(drive*100), text, kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } //this displays the values and handles 'popups' where it's discrete choices +} + +void Channel4::getParameterLabel(VstInt32 index, char *text) { + switch (index) { + case kParamA: vst_strncpy (text, "", kVstMaxParamStrLen); break; + case kParamB: vst_strncpy (text, "%", kVstMaxParamStrLen); break; //the percent + default: break; // unknown parameter, shouldn't happen! + } +} + +VstInt32 Channel4::canDo(char *text) +{ return (_canDo.find(text) == _canDo.end()) ? -1 : 1; } // 1 = yes, -1 = no, 0 = don't know + +bool Channel4::getEffectName(char* name) { + vst_strncpy(name, "Channel4", kVstMaxProductStrLen); return true; +} + +VstPlugCategory Channel4::getPlugCategory() {return kPlugCategEffect;} + +bool Channel4::getProductString(char* text) { + vst_strncpy (text, "airwindows Channel4", kVstMaxProductStrLen); return true; +} + +bool Channel4::getVendorString(char* text) { + vst_strncpy (text, "airwindows", kVstMaxVendorStrLen); return true; +} diff --git a/plugins/LinuxVST/src/Channel4/Channel4.h b/plugins/LinuxVST/src/Channel4/Channel4.h new file mode 100755 index 0000000..0338d0a --- /dev/null +++ b/plugins/LinuxVST/src/Channel4/Channel4.h @@ -0,0 +1,75 @@ +/* ======================================== + * Channel4 - Channel4.h + * Created 8/12/11 by SPIAdmin + * Copyright (c) 2011 __MyCompanyName__, All rights reserved + * ======================================== */ + +#ifndef __Channel4_H +#define __Channel4_H + +#ifndef __audioeffect__ +#include "audioeffectx.h" +#endif + +#include <set> +#include <string> +#include <math.h> + +enum { + kParamA = 0, + kParamB = 1, + kNumParameters = 2 +}; // + +const int kNumPrograms = 0; +const int kNumInputs = 2; +const int kNumOutputs = 2; +const unsigned long kUniqueId = 'cha4'; //Change this to what the AU identity is! + +class Channel4 : + public AudioEffectX +{ +public: + Channel4(audioMasterCallback audioMaster); + ~Channel4(); + virtual bool getEffectName(char* name); // The plug-in name + virtual VstPlugCategory getPlugCategory(); // The general category for the plug-in + virtual bool getProductString(char* text); // This is a unique plug-in string provided by Steinberg + virtual bool getVendorString(char* text); // Vendor info + virtual VstInt32 getVendorVersion(); // Version number + virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames); + virtual void processDoubleReplacing (double** inputs, double** outputs, VstInt32 sampleFrames); + virtual void getProgramName(char *name); // read the name from the host + virtual void setProgramName(char *name); // changes the name of the preset displayed in the host + virtual VstInt32 getChunk (void** data, bool isPreset); + virtual VstInt32 setChunk (void* data, VstInt32 byteSize, bool isPreset); + virtual float getParameter(VstInt32 index); // get the parameter value at the specified index + virtual void setParameter(VstInt32 index, float value); // set the parameter at index to value + virtual void getParameterLabel(VstInt32 index, char *text); // label for the parameter (eg dB) + virtual void getParameterName(VstInt32 index, char *text); // name of the parameter + virtual void getParameterDisplay(VstInt32 index, char *text); // text description of the current value + virtual VstInt32 canDo(char *text); +private: + char _programName[kVstMaxProgNameLen + 1]; + std::set< std::string > _canDo; + + long double fpNShapeLA; + long double fpNShapeLB; + long double fpNShapeRA; + long double fpNShapeRB; + bool fpFlip; + //default stuff + double iirSampleLA; + double iirSampleRA; + double iirSampleLB; + double iirSampleRB; + double lastSampleL; + double lastSampleR; + double iirAmount; + double threshold; + + float consoletype; + float drive; //parameters. Always 0-1, and we scale/alter them elsewhere. +}; + +#endif diff --git a/plugins/LinuxVST/src/Channel4/Channel4Proc.cpp b/plugins/LinuxVST/src/Channel4/Channel4Proc.cpp new file mode 100755 index 0000000..380e52c --- /dev/null +++ b/plugins/LinuxVST/src/Channel4/Channel4Proc.cpp @@ -0,0 +1,288 @@ +/* ======================================== + * Channel4 - Channel4.h + * Copyright (c) 2016 airwindows, All rights reserved + * ======================================== */ + +#ifndef __Channel4_H +#include "Channel4.h" +#endif + +void Channel4::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(); + float fpTemp; + double fpOld = 0.618033988749894848204586; //golden ratio! + double fpNew = 1.0 - fpOld; + + const double localiirAmount = iirAmount / overallscale; + const double localthreshold = threshold / overallscale; + const double density = pow(drive,2); //this doesn't relate to the plugins Density and Drive much + double clamp; + long double bridgerectifier; + + 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. + } + + if (fpFlip) + { + iirSampleLA = (iirSampleLA * (1 - localiirAmount)) + (inputSampleL * localiirAmount); + inputSampleL = inputSampleL - iirSampleLA; + iirSampleRA = (iirSampleRA * (1 - localiirAmount)) + (inputSampleR * localiirAmount); + inputSampleR = inputSampleR - iirSampleRA; + } + else + { + iirSampleLB = (iirSampleLB * (1 - localiirAmount)) + (inputSampleL * localiirAmount); + inputSampleL = inputSampleL - iirSampleLB; + iirSampleRB = (iirSampleRB * (1 - localiirAmount)) + (inputSampleR * localiirAmount); + inputSampleR = inputSampleR - iirSampleRB; + } + //highpass section + + bridgerectifier = fabs(inputSampleL)*1.57079633; + if (bridgerectifier > 1.57079633) bridgerectifier = 1.0; + else bridgerectifier = sin(bridgerectifier); + if (inputSampleL > 0) inputSampleL = (inputSampleL*(1-density))+(bridgerectifier*density); + else inputSampleL = (inputSampleL*(1-density))-(bridgerectifier*density); + + bridgerectifier = fabs(inputSampleR)*1.57079633; + if (bridgerectifier > 1.57079633) bridgerectifier = 1.0; + else bridgerectifier = sin(bridgerectifier); + if (inputSampleR > 0) inputSampleR = (inputSampleR*(1-density))+(bridgerectifier*density); + else inputSampleR = (inputSampleR*(1-density))-(bridgerectifier*density); + //drive section + + clamp = inputSampleL - lastSampleL; + if (clamp > localthreshold) + inputSampleL = lastSampleL + localthreshold; + if (-clamp > localthreshold) + inputSampleL = lastSampleL - localthreshold; + lastSampleL = inputSampleL; + + clamp = inputSampleR - lastSampleR; + if (clamp > localthreshold) + inputSampleR = lastSampleR + localthreshold; + if (-clamp > localthreshold) + inputSampleR = lastSampleR - localthreshold; + lastSampleR = inputSampleR; + //slew section + + //noise shaping to 32-bit floating point + if (fpFlip) { + fpTemp = inputSampleL; + fpNShapeLA = (fpNShapeLA*fpOld)+((inputSampleL-fpTemp)*fpNew); + inputSampleL += fpNShapeLA; + fpTemp = inputSampleR; + fpNShapeRA = (fpNShapeRA*fpOld)+((inputSampleR-fpTemp)*fpNew); + inputSampleR += fpNShapeRA; + } + else { + fpTemp = inputSampleL; + fpNShapeLB = (fpNShapeLB*fpOld)+((inputSampleL-fpTemp)*fpNew); + inputSampleL += fpNShapeLB; + fpTemp = inputSampleR; + fpNShapeRB = (fpNShapeRB*fpOld)+((inputSampleR-fpTemp)*fpNew); + inputSampleR += fpNShapeRB; + } + fpFlip = !fpFlip; + //end noise shaping on 32 bit output + + *out1 = inputSampleL; + *out2 = inputSampleR; + + *in1++; + *in2++; + *out1++; + *out2++; + } +} + +void Channel4::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(); + double fpTemp; //this is different from singlereplacing + double fpOld = 0.618033988749894848204586; //golden ratio! + double fpNew = 1.0 - fpOld; + + const double localiirAmount = iirAmount / overallscale; + const double localthreshold = threshold / overallscale; + const double density = pow(drive,2); //this doesn't relate to the plugins Density and Drive much + double clamp; + long double bridgerectifier; + + 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. + } + + if (fpFlip) + { + iirSampleLA = (iirSampleLA * (1 - localiirAmount)) + (inputSampleL * localiirAmount); + inputSampleL = inputSampleL - iirSampleLA; + iirSampleRA = (iirSampleRA * (1 - localiirAmount)) + (inputSampleR * localiirAmount); + inputSampleR = inputSampleR - iirSampleRA; + } + else + { + iirSampleLB = (iirSampleLB * (1 - localiirAmount)) + (inputSampleL * localiirAmount); + inputSampleL = inputSampleL - iirSampleLB; + iirSampleRB = (iirSampleRB * (1 - localiirAmount)) + (inputSampleR * localiirAmount); + inputSampleR = inputSampleR - iirSampleRB; + } + //highpass section + + bridgerectifier = fabs(inputSampleL)*1.57079633; + if (bridgerectifier > 1.57079633) bridgerectifier = 1.0; + else bridgerectifier = sin(bridgerectifier); + if (inputSampleL > 0) inputSampleL = (inputSampleL*(1-density))+(bridgerectifier*density); + else inputSampleL = (inputSampleL*(1-density))-(bridgerectifier*density); + + bridgerectifier = fabs(inputSampleR)*1.57079633; + if (bridgerectifier > 1.57079633) bridgerectifier = 1.0; + else bridgerectifier = sin(bridgerectifier); + if (inputSampleR > 0) inputSampleR = (inputSampleR*(1-density))+(bridgerectifier*density); + else inputSampleR = (inputSampleR*(1-density))-(bridgerectifier*density); + //drive section + + clamp = inputSampleL - lastSampleL; + if (clamp > localthreshold) + inputSampleL = lastSampleL + localthreshold; + if (-clamp > localthreshold) + inputSampleL = lastSampleL - localthreshold; + lastSampleL = inputSampleL; + + clamp = inputSampleR - lastSampleR; + if (clamp > localthreshold) + inputSampleR = lastSampleR + localthreshold; + if (-clamp > localthreshold) + inputSampleR = lastSampleR - localthreshold; + lastSampleR = inputSampleR; + //slew section + + //noise shaping to 64-bit floating point + if (fpFlip) { + fpTemp = inputSampleL; + fpNShapeLA = (fpNShapeLA*fpOld)+((inputSampleL-fpTemp)*fpNew); + inputSampleL += fpNShapeLA; + fpTemp = inputSampleR; + fpNShapeRA = (fpNShapeRA*fpOld)+((inputSampleR-fpTemp)*fpNew); + inputSampleR += fpNShapeRA; + } + else { + fpTemp = inputSampleL; + fpNShapeLB = (fpNShapeLB*fpOld)+((inputSampleL-fpTemp)*fpNew); + inputSampleL += fpNShapeLB; + fpTemp = inputSampleR; + fpNShapeRB = (fpNShapeRB*fpOld)+((inputSampleR-fpTemp)*fpNew); + inputSampleR += fpNShapeRB; + } + fpFlip = !fpFlip; + //end noise shaping on 64 bit output + + *out1 = inputSampleL; + *out2 = inputSampleR; + + *in1++; + *in2++; + *out1++; + *out2++; + } +}
\ No newline at end of file diff --git a/plugins/LinuxVST/src/Righteous4/Righteous4.cpp b/plugins/LinuxVST/src/Righteous4/Righteous4.cpp new file mode 100755 index 0000000..3c50a74 --- /dev/null +++ b/plugins/LinuxVST/src/Righteous4/Righteous4.cpp @@ -0,0 +1,223 @@ +/* ======================================== + * Righteous4 - Righteous4.h + * Copyright (c) 2016 airwindows, All rights reserved + * ======================================== */ + +#ifndef __Righteous4_H +#include "Righteous4.h" +#endif + +AudioEffect* createEffectInstance(audioMasterCallback audioMaster) {return new Righteous4(audioMaster);} + +Righteous4::Righteous4(audioMasterCallback audioMaster) : + AudioEffectX(audioMaster, kNumPrograms, kNumParameters) +{ + A = 0.0; + B = 0.0; + + leftSampleA = 0.0; + leftSampleB = 0.0; + leftSampleC = 0.0; + leftSampleD = 0.0; + leftSampleE = 0.0; + leftSampleF = 0.0; + leftSampleG = 0.0; + leftSampleH = 0.0; + leftSampleI = 0.0; + leftSampleJ = 0.0; + leftSampleK = 0.0; + leftSampleL = 0.0; + leftSampleM = 0.0; + leftSampleN = 0.0; + leftSampleO = 0.0; + leftSampleP = 0.0; + leftSampleQ = 0.0; + leftSampleR = 0.0; + leftSampleS = 0.0; + leftSampleT = 0.0; + leftSampleU = 0.0; + leftSampleV = 0.0; + leftSampleW = 0.0; + leftSampleX = 0.0; + leftSampleY = 0.0; + leftSampleZ = 0.0; + + rightSampleA = 0.0; + rightSampleB = 0.0; + rightSampleC = 0.0; + rightSampleD = 0.0; + rightSampleE = 0.0; + rightSampleF = 0.0; + rightSampleG = 0.0; + rightSampleH = 0.0; + rightSampleI = 0.0; + rightSampleJ = 0.0; + rightSampleK = 0.0; + rightSampleL = 0.0; + rightSampleM = 0.0; + rightSampleN = 0.0; + rightSampleO = 0.0; + rightSampleP = 0.0; + rightSampleQ = 0.0; + rightSampleR = 0.0; + rightSampleS = 0.0; + rightSampleT = 0.0; + rightSampleU = 0.0; + rightSampleV = 0.0; + rightSampleW = 0.0; + rightSampleX = 0.0; + rightSampleY = 0.0; + rightSampleZ = 0.0; + + bynL[0] = 1000; + bynL[1] = 301; + bynL[2] = 176; + bynL[3] = 125; + bynL[4] = 97; + bynL[5] = 79; + bynL[6] = 67; + bynL[7] = 58; + bynL[8] = 51; + bynL[9] = 46; + bynL[10] = 1000; + noiseShapingL = 0.0; + lastSampleL = 0.0; + IIRsampleL = 0.0; + gwPrevL = 0.0; + gwAL = 0.0; + gwBL = 0.0; + + bynR[0] = 1000; + bynR[1] = 301; + bynR[2] = 176; + bynR[3] = 125; + bynR[4] = 97; + bynR[5] = 79; + bynR[6] = 67; + bynR[7] = 58; + bynR[8] = 51; + bynR[9] = 46; + bynR[10] = 1000; + noiseShapingR = 0.0; + lastSampleR = 0.0; + IIRsampleR = 0.0; + gwPrevR = 0.0; + gwAR = 0.0; + gwBR = 0.0; + + fpNShapeL = 0.0; + fpNShapeR = 0.0; + //this is reset: values being initialized only once. Startup values, whatever they are. + + _canDo.insert("plugAsChannelInsert"); // plug-in can be used as a channel insert effect. + _canDo.insert("plugAsSend"); // plug-in can be used as a send effect. + _canDo.insert("x2in2out"); + setNumInputs(kNumInputs); + setNumOutputs(kNumOutputs); + setUniqueID(kUniqueId); + canProcessReplacing(); // supports output replacing + canDoubleReplacing(); // supports double precision processing + programsAreChunks(true); + vst_strncpy (_programName, "Default", kVstMaxProgNameLen); // default program name +} + +Righteous4::~Righteous4() {} +VstInt32 Righteous4::getVendorVersion () {return 1000;} +void Righteous4::setProgramName(char *name) {vst_strncpy (_programName, name, kVstMaxProgNameLen);} +void Righteous4::getProgramName(char *name) {vst_strncpy (name, _programName, kVstMaxProgNameLen);} +//airwindows likes to ignore this stuff. Make your own programs, and make a different plugin rather than +//trying to do versioning and preventing people from using older versions. Maybe they like the old one! + +static float pinParameter(float data) +{ + if (data < 0.0f) return 0.0f; + if (data > 1.0f) return 1.0f; + return data; +} + +VstInt32 Righteous4::getChunk (void** data, bool isPreset) +{ + float *chunkData = (float *)calloc(kNumParameters, sizeof(float)); + chunkData[0] = A; + chunkData[1] = B; + /* Note: The way this is set up, it will break if you manage to save settings on an Intel + machine and load them on a PPC Mac. However, it's fine if you stick to the machine you + started with. */ + + *data = chunkData; + return kNumParameters * sizeof(float); +} + +VstInt32 Righteous4::setChunk (void* data, VstInt32 byteSize, bool isPreset) +{ + float *chunkData = (float *)data; + A = pinParameter(chunkData[0]); + B = pinParameter(chunkData[1]); + /* We're ignoring byteSize as we found it to be a filthy liar */ + + /* calculate any other fields you need here - you could copy in + code from setParameter() here. */ + return 0; +} + +void Righteous4::setParameter(VstInt32 index, float value) { + switch (index) { + case kParamA: A = value; break; + case kParamB: B = value; break; + default: throw; // unknown parameter, shouldn't happen! + } +} + +float Righteous4::getParameter(VstInt32 index) { + switch (index) { + case kParamA: return A; break; + case kParamB: return B; break; + default: break; // unknown parameter, shouldn't happen! + } return 0.0; //we only need to update the relevant name, this is simple to manage +} + +void Righteous4::getParameterName(VstInt32 index, char *text) { + switch (index) { + case kParamA: vst_strncpy (text, "LTarget", kVstMaxParamStrLen); break; + case kParamB: vst_strncpy (text, "BtDepth", kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } //this is our labels for displaying in the VST host +} + +void Righteous4::getParameterDisplay(VstInt32 index, char *text) { + switch (index) { + case kParamA: float2string ((A*24.0)-28.0, text, kVstMaxParamStrLen); break; + case kParamB: switch((VstInt32)( B * 2.999 )) //0 to almost edge of # of params + {case 0: vst_strncpy (text, "16", kVstMaxParamStrLen); break; + case 1: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 2: vst_strncpy (text, "32", kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } break; + default: break; // unknown parameter, shouldn't happen! + } //this displays the values and handles 'popups' where it's discrete choices +} + +void Righteous4::getParameterLabel(VstInt32 index, char *text) { + switch (index) { + case kParamA: vst_strncpy (text, "dB", kVstMaxParamStrLen); break; + case kParamB: vst_strncpy (text, "bit", kVstMaxParamStrLen); break; + default: break; // unknown parameter, shouldn't happen! + } +} + +VstInt32 Righteous4::canDo(char *text) +{ return (_canDo.find(text) == _canDo.end()) ? -1: 1; } // 1 = yes, -1 = no, 0 = don't know + +bool Righteous4::getEffectName(char* name) { + vst_strncpy(name, "Righteous4", kVstMaxProductStrLen); return true; +} + +VstPlugCategory Righteous4::getPlugCategory() {return kPlugCategEffect;} + +bool Righteous4::getProductString(char* text) { + vst_strncpy (text, "airwindows Righteous4", kVstMaxProductStrLen); return true; +} + +bool Righteous4::getVendorString(char* text) { + vst_strncpy (text, "airwindows", kVstMaxVendorStrLen); return true; +} diff --git a/plugins/LinuxVST/src/Righteous4/Righteous4.h b/plugins/LinuxVST/src/Righteous4/Righteous4.h new file mode 100755 index 0000000..8b9e44b --- /dev/null +++ b/plugins/LinuxVST/src/Righteous4/Righteous4.h @@ -0,0 +1,134 @@ +/* ======================================== + * Righteous4 - Righteous4.h + * Created 8/12/11 by SPIAdmin + * Copyright (c) 2011 __MyCompanyName__, All rights reserved + * ======================================== */ + +#ifndef __Righteous4_H +#define __Righteous4_H + +#ifndef __audioeffect__ +#include "audioeffectx.h" +#endif + +#include <set> +#include <string> +#include <math.h> + +enum { + kParamA = 0, + kParamB = 1, + kNumParameters = 2 +}; // + +const int kNumPrograms = 0; +const int kNumInputs = 2; +const int kNumOutputs = 2; +const unsigned long kUniqueId = 'rigk'; //Change this to what the AU identity is! + +class Righteous4 : + public AudioEffectX +{ +public: + Righteous4(audioMasterCallback audioMaster); + ~Righteous4(); + virtual bool getEffectName(char* name); // The plug-in name + virtual VstPlugCategory getPlugCategory(); // The general category for the plug-in + virtual bool getProductString(char* text); // This is a unique plug-in string provided by Steinberg + virtual bool getVendorString(char* text); // Vendor info + virtual VstInt32 getVendorVersion(); // Version number + virtual void processReplacing (float** inputs, float** outputs, VstInt32 sampleFrames); + virtual void processDoubleReplacing (double** inputs, double** outputs, VstInt32 sampleFrames); + virtual void getProgramName(char *name); // read the name from the host + virtual void setProgramName(char *name); // changes the name of the preset displayed in the host + virtual VstInt32 getChunk (void** data, bool isPreset); + virtual VstInt32 setChunk (void* data, VstInt32 byteSize, bool isPreset); + virtual float getParameter(VstInt32 index); // get the parameter value at the specified index + virtual void setParameter(VstInt32 index, float value); // set the parameter at index to value + virtual void getParameterLabel(VstInt32 index, char *text); // label for the parameter (eg dB) + virtual void getParameterName(VstInt32 index, char *text); // name of the parameter + virtual void getParameterDisplay(VstInt32 index, char *text); // text description of the current value + virtual VstInt32 canDo(char *text); +private: + char _programName[kVstMaxProgNameLen + 1]; + std::set< std::string > _canDo; + + double leftSampleA; + double leftSampleB; + double leftSampleC; + double leftSampleD; + double leftSampleE; + double leftSampleF; + double leftSampleG; + double leftSampleH; + double leftSampleI; + double leftSampleJ; + double leftSampleK; + double leftSampleL; + double leftSampleM; + double leftSampleN; + double leftSampleO; + double leftSampleP; + double leftSampleQ; + double leftSampleR; + double leftSampleS; + double leftSampleT; + double leftSampleU; + double leftSampleV; + double leftSampleW; + double leftSampleX; + double leftSampleY; + double leftSampleZ; + + double rightSampleA; + double rightSampleB; + double rightSampleC; + double rightSampleD; + double rightSampleE; + double rightSampleF; + double rightSampleG; + double rightSampleH; + double rightSampleI; + double rightSampleJ; + double rightSampleK; + double rightSampleL; + double rightSampleM; + double rightSampleN; + double rightSampleO; + double rightSampleP; + double rightSampleQ; + double rightSampleR; + double rightSampleS; + double rightSampleT; + double rightSampleU; + double rightSampleV; + double rightSampleW; + double rightSampleX; + double rightSampleY; + double rightSampleZ; + + double bynL[13]; + long double noiseShapingL; + double lastSampleL; + double IIRsampleL; + double gwPrevL; + double gwAL; + double gwBL; + + double bynR[13]; + long double noiseShapingR; + double lastSampleR; + double IIRsampleR; + double gwPrevR; + double gwAR; + double gwBR; + + long double fpNShapeL; + long double fpNShapeR; + //default stuff + + float A; + float B; +}; + +#endif diff --git a/plugins/LinuxVST/src/Righteous4/Righteous4Proc.cpp b/plugins/LinuxVST/src/Righteous4/Righteous4Proc.cpp new file mode 100755 index 0000000..7ed44cf --- /dev/null +++ b/plugins/LinuxVST/src/Righteous4/Righteous4Proc.cpp @@ -0,0 +1,1040 @@ +/* ======================================== + * Righteous4 - Righteous4.h + * Copyright (c) 2016 airwindows, All rights reserved + * ======================================== */ + +#ifndef __Righteous4_H +#include "Righteous4.h" +#endif + +void Righteous4::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames) +{ + float* in1 = inputs[0]; + float* in2 = inputs[1]; + float* out1 = outputs[0]; + float* out2 = outputs[1]; + long double fpOld = 0.618033988749894848204586; //golden ratio! + long double fpNew = 1.0 - fpOld; + double overallscale = 1.0; + overallscale /= 44100.0; + overallscale *= getSampleRate(); + double IIRscaleback = 0.0002597;//scaleback of harmonic avg + IIRscaleback /= overallscale; + IIRscaleback = 1.0 - IIRscaleback; + double target = (A*24.0)-28.0; + target += 17; //gives us scaled distortion factor based on test conditions + target = pow(10.0,target/20.0); //we will multiply and divide by this + //ShortBuss section + if (target == 0) target = 1; //insanity check + int bitDepth = (VstInt32)( B * 2.999 )+1; // +1 for Reaper bug workaround + double fusswithscale = 149940.0; //corrected + double cutofffreq = 20; //was 46/2.0 + double midAmount = (cutofffreq)/fusswithscale; + midAmount /= overallscale; + double midaltAmount = 1.0 - midAmount; + double gwAfactor = 0.718; + gwAfactor -= (overallscale*0.05); //0.2 at 176K, 0.1 at 88.2K, 0.05 at 44.1K + //reduce slightly to not less than 0.5 to increase effect + double gwBfactor = 1.0 - gwAfactor; + double softness = 0.2135; + double hardness = 1.0 - softness; + double refclip = pow(10.0,-0.0058888); + + while (--sampleFrames >= 0) + { + long double inputSampleL = *in1; + long double 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. + } + double drySampleL = inputSampleL; + double drySampleR = inputSampleR; + //begin the whole distortion dealiebop + inputSampleL /= target; + inputSampleR /= target; + + //running shortbuss on direct sample + IIRsampleL *= IIRscaleback; + double secondharmonicL = sin((2.0 * inputSampleL * inputSampleL) * IIRsampleL); + IIRsampleR *= IIRscaleback; + double secondharmonicR = sin((2.0 * inputSampleR * inputSampleR) * IIRsampleR); + //secondharmonic is calculated before IIRsample is updated, to delay reaction + + long double bridgerectifier = inputSampleL; + if (bridgerectifier > 1.2533141373155) bridgerectifier = 1.2533141373155; + if (bridgerectifier < -1.2533141373155) bridgerectifier = -1.2533141373155; + //clip to 1.2533141373155 to reach maximum output + bridgerectifier = sin(bridgerectifier * fabs(bridgerectifier)) / ((bridgerectifier == 0.0) ?1:fabs(bridgerectifier)); + if (inputSampleL > bridgerectifier) IIRsampleL += ((inputSampleL - bridgerectifier)*0.0009); + if (inputSampleL < -bridgerectifier) IIRsampleL += ((inputSampleL + bridgerectifier)*0.0009); + //manipulate IIRSampleL + inputSampleL = bridgerectifier; + //apply the distortion transform for reals. Has been converted back to -1/1 + + bridgerectifier = inputSampleR; + if (bridgerectifier > 1.2533141373155) bridgerectifier = 1.2533141373155; + if (bridgerectifier < -1.2533141373155) bridgerectifier = -1.2533141373155; + //clip to 1.2533141373155 to reach maximum output + bridgerectifier = sin(bridgerectifier * fabs(bridgerectifier)) / ((bridgerectifier == 0.0) ?1:fabs(bridgerectifier)); + if (inputSampleR > bridgerectifier) IIRsampleR += ((inputSampleR - bridgerectifier)*0.0009); + if (inputSampleR < -bridgerectifier) IIRsampleR += ((inputSampleR + bridgerectifier)*0.0009); + //manipulate IIRSampleR + inputSampleR = bridgerectifier; + //apply the distortion transform for reals. Has been converted back to -1/1 + + + //apply resonant highpass L + double tempSample = inputSampleL; + leftSampleA = (leftSampleA * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleA; double correction = leftSampleA; + leftSampleB = (leftSampleB * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleB; correction += leftSampleB; + leftSampleC = (leftSampleC * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleC; correction += leftSampleC; + leftSampleD = (leftSampleD * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleD; correction += leftSampleD; + leftSampleE = (leftSampleE * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleE; correction += leftSampleE; + leftSampleF = (leftSampleF * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleF; correction += leftSampleF; + leftSampleG = (leftSampleG * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleG; correction += leftSampleG; + leftSampleH = (leftSampleH * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleH; correction += leftSampleH; + leftSampleI = (leftSampleI * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleI; correction += leftSampleI; + leftSampleJ = (leftSampleJ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleJ; correction += leftSampleJ; + leftSampleK = (leftSampleK * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleK; correction += leftSampleK; + leftSampleL = (leftSampleL * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleL; correction += leftSampleL; + leftSampleM = (leftSampleM * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleM; correction += leftSampleM; + leftSampleN = (leftSampleN * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleN; correction += leftSampleN; + leftSampleO = (leftSampleO * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleO; correction += leftSampleO; + leftSampleP = (leftSampleP * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleP; correction += leftSampleP; + leftSampleQ = (leftSampleQ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleQ; correction += leftSampleQ; + leftSampleR = (leftSampleR * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleR; correction += leftSampleR; + leftSampleS = (leftSampleS * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleS; correction += leftSampleS; + leftSampleT = (leftSampleT * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleT; correction += leftSampleT; + leftSampleU = (leftSampleU * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleU; correction += leftSampleU; + leftSampleV = (leftSampleV * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleV; correction += leftSampleV; + leftSampleW = (leftSampleW * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleW; correction += leftSampleW; + leftSampleX = (leftSampleX * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleX; correction += leftSampleX; + leftSampleY = (leftSampleY * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleY; correction += leftSampleY; + leftSampleZ = (leftSampleZ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleZ; correction += leftSampleZ; + correction *= fabs(secondharmonicL); + //scale it directly by second harmonic: DC block is now adding harmonics too + correction -= secondharmonicL*fpOld; + //apply the shortbuss processing to output DCblock by subtracting it + //we are not a peak limiter! not using it to clip or nothin' + //adding it inversely, it's the same as adding to inputsample only we are accumulating 'stuff' in 'correction' + inputSampleL -= correction; + if (inputSampleL < 0) inputSampleL = (inputSampleL * fpNew) - (sin(-inputSampleL)*fpOld); + //lastly, class A clipping on the negative to combat the one-sidedness + //uses bloom/antibloom to dial in previous unconstrained behavior + //end the whole distortion dealiebop + inputSampleL *= target; + //begin simplified Groove Wear, outside the scaling + //varies depending on what sample rate you're at: + //high sample rate makes it more airy + gwBL = gwAL; gwAL = tempSample = (inputSampleL-gwPrevL); + tempSample *= gwAfactor; + tempSample += (gwBL * gwBfactor); + correction = (inputSampleL-gwPrevL) - tempSample; + gwPrevL = inputSampleL; + inputSampleL -= correction; + //simplified Groove Wear L + + //apply resonant highpass R + tempSample = inputSampleR; + rightSampleA = (rightSampleA * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleA; correction = rightSampleA; + rightSampleB = (rightSampleB * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleB; correction += rightSampleB; + rightSampleC = (rightSampleC * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleC; correction += rightSampleC; + rightSampleD = (rightSampleD * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleD; correction += rightSampleD; + rightSampleE = (rightSampleE * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleE; correction += rightSampleE; + rightSampleF = (rightSampleF * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleF; correction += rightSampleF; + rightSampleG = (rightSampleG * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleG; correction += rightSampleG; + rightSampleH = (rightSampleH * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleH; correction += rightSampleH; + rightSampleI = (rightSampleI * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleI; correction += rightSampleI; + rightSampleJ = (rightSampleJ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleJ; correction += rightSampleJ; + rightSampleK = (rightSampleK * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleK; correction += rightSampleK; + rightSampleL = (rightSampleL * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleL; correction += rightSampleL; + rightSampleM = (rightSampleM * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleM; correction += rightSampleM; + rightSampleN = (rightSampleN * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleN; correction += rightSampleN; + rightSampleO = (rightSampleO * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleO; correction += rightSampleO; + rightSampleP = (rightSampleP * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleP; correction += rightSampleP; + rightSampleQ = (rightSampleQ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleQ; correction += rightSampleQ; + rightSampleR = (rightSampleR * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleR; correction += rightSampleR; + rightSampleS = (rightSampleS * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleS; correction += rightSampleS; + rightSampleT = (rightSampleT * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleT; correction += rightSampleT; + rightSampleU = (rightSampleU * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleU; correction += rightSampleU; + rightSampleV = (rightSampleV * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleV; correction += rightSampleV; + rightSampleW = (rightSampleW * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleW; correction += rightSampleW; + rightSampleX = (rightSampleX * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleX; correction += rightSampleX; + rightSampleY = (rightSampleY * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleY; correction += rightSampleY; + rightSampleZ = (rightSampleZ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleZ; correction += rightSampleZ; + correction *= fabs(secondharmonicR); + //scale it directly by second harmonic: DC block is now adding harmonics too + correction -= secondharmonicR*fpOld; + //apply the shortbuss processing to output DCblock by subtracting it + //we are not a peak limiter! not using it to clip or nothin' + //adding it inversely, it's the same as adding to inputsample only we are accumulating 'stuff' in 'correction' + inputSampleR -= correction; + if (inputSampleR < 0) inputSampleR = (inputSampleR * fpNew) - (sin(-inputSampleR)*fpOld); + //lastly, class A clipping on the negative to combat the one-sidedness + //uses bloom/antibloom to dial in previous unconstrained behavior + //end the whole distortion dealiebop + inputSampleR *= target; + //begin simplified Groove Wear, outside the scaling + //varies depending on what sample rate you're at: + //high sample rate makes it more airy + gwBR = gwAR; gwAR = tempSample = (inputSampleR-gwPrevR); + tempSample *= gwAfactor; + tempSample += (gwBR * gwBfactor); + correction = (inputSampleR-gwPrevR) - tempSample; + gwPrevR = inputSampleR; + inputSampleR -= correction; + //simplified Groove Wear R + + //begin simplified ADClip L + drySampleL = inputSampleL; + if (lastSampleL >= refclip) + { + if (inputSampleL < refclip) + { + lastSampleL = ((refclip*hardness) + (inputSampleL * softness)); + } + else lastSampleL = refclip; + } + + if (lastSampleL <= -refclip) + { + if (inputSampleL > -refclip) + { + lastSampleL = ((-refclip*hardness) + (inputSampleL * softness)); + } + else lastSampleL = -refclip; + } + + if (inputSampleL > refclip) + { + if (lastSampleL < refclip) + { + inputSampleL = ((refclip*hardness) + (lastSampleL * softness)); + } + else inputSampleL = refclip; + } + + if (inputSampleL < -refclip) + { + if (lastSampleL > -refclip) + { + inputSampleL = ((-refclip*hardness) + (lastSampleL * softness)); + } + else inputSampleL = -refclip; + } + lastSampleL = drySampleL; + + //begin simplified ADClip R + drySampleR = inputSampleR; + if (lastSampleR >= refclip) + { + if (inputSampleR < refclip) + { + lastSampleR = ((refclip*hardness) + (inputSampleR * softness)); + } + else lastSampleR = refclip; + } + + if (lastSampleR <= -refclip) + { + if (inputSampleR > -refclip) + { + lastSampleR = ((-refclip*hardness) + (inputSampleR * softness)); + } + else lastSampleR = -refclip; + } + + if (inputSampleR > refclip) + { + if (lastSampleR < refclip) + { + inputSampleR = ((refclip*hardness) + (lastSampleR * softness)); + } + else inputSampleR = refclip; + } + + if (inputSampleR < -refclip) + { + if (lastSampleR > -refclip) + { + inputSampleR = ((-refclip*hardness) + (lastSampleR * softness)); + } + else inputSampleR = -refclip; + } + lastSampleR = drySampleR; + + //output dither section + if (bitDepth == 3) { + //noise shaping to 32-bit floating point + float fpTemp = inputSampleL; + fpNShapeL += (inputSampleL-fpTemp); + inputSampleL += fpNShapeL; + fpTemp = inputSampleR; + fpNShapeR += (inputSampleR-fpTemp); + inputSampleR += fpNShapeR; + //for deeper space and warmth, we try a non-oscillating noise shaping + //that is kind of ruthless: it will forever retain the rounding errors + //except we'll dial it back a hair at the end of every buffer processed + //end noise shaping on 32 bit output + } else { + //entire Naturalize section used when not on 32 bit out + + inputSampleL -= noiseShapingL; + inputSampleR -= noiseShapingR; + + if (bitDepth == 2) { + inputSampleL *= 8388608.0; //go to dither at 24 bit + inputSampleR *= 8388608.0; //go to dither at 24 bit + } + if (bitDepth == 1) { + inputSampleL *= 32768.0; //go to dither at 16 bit + inputSampleR *= 32768.0; //go to dither at 16 bit + } + + //begin L + double benfordize = floor(inputSampleL); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + int hotbinA = floor(benfordize); + //hotbin becomes the Benford bin value for this number floored + double totalA = 0; + if ((hotbinA > 0) && (hotbinA < 10)) + { + bynL[hotbinA] += 1; + totalA += (301-bynL[1]); + totalA += (176-bynL[2]); + totalA += (125-bynL[3]); + totalA += (97-bynL[4]); + totalA += (79-bynL[5]); + totalA += (67-bynL[6]); + totalA += (58-bynL[7]); + totalA += (51-bynL[8]); + totalA += (46-bynL[9]); + bynL[hotbinA] -= 1; + } else {hotbinA = 10;} + //produce total number- smaller is closer to Benford real + + benfordize = ceil(inputSampleL); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + int hotbinB = floor(benfordize); + //hotbin becomes the Benford bin value for this number ceiled + double totalB = 0; + if ((hotbinB > 0) && (hotbinB < 10)) + { + bynL[hotbinB] += 1; + totalB += (301-bynL[1]); + totalB += (176-bynL[2]); + totalB += (125-bynL[3]); + totalB += (97-bynL[4]); + totalB += (79-bynL[5]); + totalB += (67-bynL[6]); + totalB += (58-bynL[7]); + totalB += (51-bynL[8]); + totalB += (46-bynL[9]); + bynL[hotbinB] -= 1; + } else {hotbinB = 10;} + //produce total number- smaller is closer to Benford real + + if (totalA < totalB) + { + bynL[hotbinA] += 1; + inputSampleL = floor(inputSampleL); + } + else + { + bynL[hotbinB] += 1; + inputSampleL = ceil(inputSampleL); + } + //assign the relevant one to the delay line + //and floor/ceil signal accordingly + + totalA = bynL[1] + bynL[2] + bynL[3] + bynL[4] + bynL[5] + bynL[6] + bynL[7] + bynL[8] + bynL[9]; + totalA /= 1000; + if (totalA = 0) totalA = 1; + bynL[1] /= totalA; + bynL[2] /= totalA; + bynL[3] /= totalA; + bynL[4] /= totalA; + bynL[5] /= totalA; + bynL[6] /= totalA; + bynL[7] /= totalA; + bynL[8] /= totalA; + bynL[9] /= totalA; + bynL[10] /= 2; //catchall for garbage data + //end L + + //begin R + benfordize = floor(inputSampleR); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + hotbinA = floor(benfordize); + //hotbin becomes the Benford bin value for this number floored + totalA = 0; + if ((hotbinA > 0) && (hotbinA < 10)) + { + bynR[hotbinA] += 1; + totalA += (301-bynR[1]); + totalA += (176-bynR[2]); + totalA += (125-bynR[3]); + totalA += (97-bynR[4]); + totalA += (79-bynR[5]); + totalA += (67-bynR[6]); + totalA += (58-bynR[7]); + totalA += (51-bynR[8]); + totalA += (46-bynR[9]); + bynR[hotbinA] -= 1; + } else {hotbinA = 10;} + //produce total number- smaller is closer to Benford real + + benfordize = ceil(inputSampleR); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + hotbinB = floor(benfordize); + //hotbin becomes the Benford bin value for this number ceiled + totalB = 0; + if ((hotbinB > 0) && (hotbinB < 10)) + { + bynR[hotbinB] += 1; + totalB += (301-bynR[1]); + totalB += (176-bynR[2]); + totalB += (125-bynR[3]); + totalB += (97-bynR[4]); + totalB += (79-bynR[5]); + totalB += (67-bynR[6]); + totalB += (58-bynR[7]); + totalB += (51-bynR[8]); + totalB += (46-bynR[9]); + bynR[hotbinB] -= 1; + } else {hotbinB = 10;} + //produce total number- smaller is closer to Benford real + + if (totalA < totalB) + { + bynR[hotbinA] += 1; + inputSampleR = floor(inputSampleR); + } + else + { + bynR[hotbinB] += 1; + inputSampleR = ceil(inputSampleR); + } + //assign the relevant one to the delay line + //and floor/ceil signal accordingly + + totalA = bynR[1] + bynR[2] + bynR[3] + bynR[4] + bynR[5] + bynR[6] + bynR[7] + bynR[8] + bynR[9]; + totalA /= 1000; + if (totalA = 0) totalA = 1; + bynR[1] /= totalA; + bynR[2] /= totalA; + bynR[3] /= totalA; + bynR[4] /= totalA; + bynR[5] /= totalA; + bynR[6] /= totalA; + bynR[7] /= totalA; + bynR[8] /= totalA; + bynR[9] /= totalA; + bynR[10] /= 2; //catchall for garbage data + //end R + + if (bitDepth == 2) { + inputSampleL /= 8388608.0; + inputSampleR /= 8388608.0; + } + if (bitDepth == 1) { + inputSampleL /= 32768.0; + inputSampleR /= 32768.0; + } + noiseShapingL += inputSampleL - drySampleL; + noiseShapingR += inputSampleR - drySampleR; + } + + if (inputSampleL > refclip) inputSampleL = refclip; + if (inputSampleL < -refclip) inputSampleL = -refclip; + //iron bar prohibits any overs + if (inputSampleR > refclip) inputSampleR = refclip; + if (inputSampleR < -refclip) inputSampleR = -refclip; + //iron bar prohibits any overs + + *out1 = inputSampleL; + *out2 = inputSampleR; + + *in1++; + *in2++; + *out1++; + *out2++; + } + fpNShapeL *= 0.999999; + fpNShapeR *= 0.999999; + //we will just delicately dial back the FP noise shaping, not even every sample + //this is a good place to put subtle 'no runaway' calculations, though bear in mind + //that it will be called more often when you use shorter sample buffers in the DAW. + //So, very low latency operation will call these calculations more often. +} + +void Righteous4::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames) +{ + double* in1 = inputs[0]; + double* in2 = inputs[1]; + double* out1 = outputs[0]; + double* out2 = outputs[1]; + long double fpOld = 0.618033988749894848204586; //golden ratio! + long double fpNew = 1.0 - fpOld; + double overallscale = 1.0; + overallscale /= 44100.0; + overallscale *= getSampleRate(); + double IIRscaleback = 0.0002597;//scaleback of harmonic avg + IIRscaleback /= overallscale; + IIRscaleback = 1.0 - IIRscaleback; + double target = (A*24.0)-28.0; + target += 17; //gives us scaled distortion factor based on test conditions + target = pow(10.0,target/20.0); //we will multiply and divide by this + //ShortBuss section + if (target == 0) target = 1; //insanity check + int bitDepth = (VstInt32)( B * 2.999 )+1; // +1 for Reaper bug workaround + double fusswithscale = 149940.0; //corrected + double cutofffreq = 20; //was 46/2.0 + double midAmount = (cutofffreq)/fusswithscale; + midAmount /= overallscale; + double midaltAmount = 1.0 - midAmount; + double gwAfactor = 0.718; + gwAfactor -= (overallscale*0.05); //0.2 at 176K, 0.1 at 88.2K, 0.05 at 44.1K + //reduce slightly to not less than 0.5 to increase effect + double gwBfactor = 1.0 - gwAfactor; + double softness = 0.2135; + double hardness = 1.0 - softness; + double refclip = pow(10.0,-0.0058888); + + while (--sampleFrames >= 0) + { + long double inputSampleL = *in1; + long double 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. + } + double drySampleL = inputSampleL; + double drySampleR = inputSampleR; + //begin the whole distortion dealiebop + inputSampleL /= target; + inputSampleR /= target; + + //running shortbuss on direct sample + IIRsampleL *= IIRscaleback; + double secondharmonicL = sin((2.0 * inputSampleL * inputSampleL) * IIRsampleL); + IIRsampleR *= IIRscaleback; + double secondharmonicR = sin((2.0 * inputSampleR * inputSampleR) * IIRsampleR); + //secondharmonic is calculated before IIRsample is updated, to delay reaction + + long double bridgerectifier = inputSampleL; + if (bridgerectifier > 1.2533141373155) bridgerectifier = 1.2533141373155; + if (bridgerectifier < -1.2533141373155) bridgerectifier = -1.2533141373155; + //clip to 1.2533141373155 to reach maximum output + bridgerectifier = sin(bridgerectifier * fabs(bridgerectifier)) / ((bridgerectifier == 0.0) ?1:fabs(bridgerectifier)); + if (inputSampleL > bridgerectifier) IIRsampleL += ((inputSampleL - bridgerectifier)*0.0009); + if (inputSampleL < -bridgerectifier) IIRsampleL += ((inputSampleL + bridgerectifier)*0.0009); + //manipulate IIRSampleL + inputSampleL = bridgerectifier; + //apply the distortion transform for reals. Has been converted back to -1/1 + + bridgerectifier = inputSampleR; + if (bridgerectifier > 1.2533141373155) bridgerectifier = 1.2533141373155; + if (bridgerectifier < -1.2533141373155) bridgerectifier = -1.2533141373155; + //clip to 1.2533141373155 to reach maximum output + bridgerectifier = sin(bridgerectifier * fabs(bridgerectifier)) / ((bridgerectifier == 0.0) ?1:fabs(bridgerectifier)); + if (inputSampleR > bridgerectifier) IIRsampleR += ((inputSampleR - bridgerectifier)*0.0009); + if (inputSampleR < -bridgerectifier) IIRsampleR += ((inputSampleR + bridgerectifier)*0.0009); + //manipulate IIRSampleR + inputSampleR = bridgerectifier; + //apply the distortion transform for reals. Has been converted back to -1/1 + + + //apply resonant highpass L + double tempSample = inputSampleL; + leftSampleA = (leftSampleA * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleA; double correction = leftSampleA; + leftSampleB = (leftSampleB * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleB; correction += leftSampleB; + leftSampleC = (leftSampleC * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleC; correction += leftSampleC; + leftSampleD = (leftSampleD * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleD; correction += leftSampleD; + leftSampleE = (leftSampleE * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleE; correction += leftSampleE; + leftSampleF = (leftSampleF * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleF; correction += leftSampleF; + leftSampleG = (leftSampleG * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleG; correction += leftSampleG; + leftSampleH = (leftSampleH * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleH; correction += leftSampleH; + leftSampleI = (leftSampleI * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleI; correction += leftSampleI; + leftSampleJ = (leftSampleJ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleJ; correction += leftSampleJ; + leftSampleK = (leftSampleK * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleK; correction += leftSampleK; + leftSampleL = (leftSampleL * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleL; correction += leftSampleL; + leftSampleM = (leftSampleM * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleM; correction += leftSampleM; + leftSampleN = (leftSampleN * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleN; correction += leftSampleN; + leftSampleO = (leftSampleO * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleO; correction += leftSampleO; + leftSampleP = (leftSampleP * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleP; correction += leftSampleP; + leftSampleQ = (leftSampleQ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleQ; correction += leftSampleQ; + leftSampleR = (leftSampleR * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleR; correction += leftSampleR; + leftSampleS = (leftSampleS * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleS; correction += leftSampleS; + leftSampleT = (leftSampleT * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleT; correction += leftSampleT; + leftSampleU = (leftSampleU * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleU; correction += leftSampleU; + leftSampleV = (leftSampleV * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleV; correction += leftSampleV; + leftSampleW = (leftSampleW * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleW; correction += leftSampleW; + leftSampleX = (leftSampleX * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleX; correction += leftSampleX; + leftSampleY = (leftSampleY * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleY; correction += leftSampleY; + leftSampleZ = (leftSampleZ * midaltAmount) + (tempSample * midAmount); tempSample -= leftSampleZ; correction += leftSampleZ; + correction *= fabs(secondharmonicL); + //scale it directly by second harmonic: DC block is now adding harmonics too + correction -= secondharmonicL*fpOld; + //apply the shortbuss processing to output DCblock by subtracting it + //we are not a peak limiter! not using it to clip or nothin' + //adding it inversely, it's the same as adding to inputsample only we are accumulating 'stuff' in 'correction' + inputSampleL -= correction; + if (inputSampleL < 0) inputSampleL = (inputSampleL * fpNew) - (sin(-inputSampleL)*fpOld); + //lastly, class A clipping on the negative to combat the one-sidedness + //uses bloom/antibloom to dial in previous unconstrained behavior + //end the whole distortion dealiebop + inputSampleL *= target; + //begin simplified Groove Wear, outside the scaling + //varies depending on what sample rate you're at: + //high sample rate makes it more airy + gwBL = gwAL; gwAL = tempSample = (inputSampleL-gwPrevL); + tempSample *= gwAfactor; + tempSample += (gwBL * gwBfactor); + correction = (inputSampleL-gwPrevL) - tempSample; + gwPrevL = inputSampleL; + inputSampleL -= correction; + //simplified Groove Wear L + + //apply resonant highpass R + tempSample = inputSampleR; + rightSampleA = (rightSampleA * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleA; correction = rightSampleA; + rightSampleB = (rightSampleB * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleB; correction += rightSampleB; + rightSampleC = (rightSampleC * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleC; correction += rightSampleC; + rightSampleD = (rightSampleD * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleD; correction += rightSampleD; + rightSampleE = (rightSampleE * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleE; correction += rightSampleE; + rightSampleF = (rightSampleF * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleF; correction += rightSampleF; + rightSampleG = (rightSampleG * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleG; correction += rightSampleG; + rightSampleH = (rightSampleH * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleH; correction += rightSampleH; + rightSampleI = (rightSampleI * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleI; correction += rightSampleI; + rightSampleJ = (rightSampleJ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleJ; correction += rightSampleJ; + rightSampleK = (rightSampleK * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleK; correction += rightSampleK; + rightSampleL = (rightSampleL * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleL; correction += rightSampleL; + rightSampleM = (rightSampleM * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleM; correction += rightSampleM; + rightSampleN = (rightSampleN * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleN; correction += rightSampleN; + rightSampleO = (rightSampleO * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleO; correction += rightSampleO; + rightSampleP = (rightSampleP * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleP; correction += rightSampleP; + rightSampleQ = (rightSampleQ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleQ; correction += rightSampleQ; + rightSampleR = (rightSampleR * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleR; correction += rightSampleR; + rightSampleS = (rightSampleS * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleS; correction += rightSampleS; + rightSampleT = (rightSampleT * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleT; correction += rightSampleT; + rightSampleU = (rightSampleU * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleU; correction += rightSampleU; + rightSampleV = (rightSampleV * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleV; correction += rightSampleV; + rightSampleW = (rightSampleW * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleW; correction += rightSampleW; + rightSampleX = (rightSampleX * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleX; correction += rightSampleX; + rightSampleY = (rightSampleY * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleY; correction += rightSampleY; + rightSampleZ = (rightSampleZ * midaltAmount) + (tempSample * midAmount); tempSample -= rightSampleZ; correction += rightSampleZ; + correction *= fabs(secondharmonicR); + //scale it directly by second harmonic: DC block is now adding harmonics too + correction -= secondharmonicR*fpOld; + //apply the shortbuss processing to output DCblock by subtracting it + //we are not a peak limiter! not using it to clip or nothin' + //adding it inversely, it's the same as adding to inputsample only we are accumulating 'stuff' in 'correction' + inputSampleR -= correction; + if (inputSampleR < 0) inputSampleR = (inputSampleR * fpNew) - (sin(-inputSampleR)*fpOld); + //lastly, class A clipping on the negative to combat the one-sidedness + //uses bloom/antibloom to dial in previous unconstrained behavior + //end the whole distortion dealiebop + inputSampleR *= target; + //begin simplified Groove Wear, outside the scaling + //varies depending on what sample rate you're at: + //high sample rate makes it more airy + gwBR = gwAR; gwAR = tempSample = (inputSampleR-gwPrevR); + tempSample *= gwAfactor; + tempSample += (gwBR * gwBfactor); + correction = (inputSampleR-gwPrevR) - tempSample; + gwPrevR = inputSampleR; + inputSampleR -= correction; + //simplified Groove Wear R + + //begin simplified ADClip L + drySampleL = inputSampleL; + if (lastSampleL >= refclip) + { + if (inputSampleL < refclip) + { + lastSampleL = ((refclip*hardness) + (inputSampleL * softness)); + } + else lastSampleL = refclip; + } + + if (lastSampleL <= -refclip) + { + if (inputSampleL > -refclip) + { + lastSampleL = ((-refclip*hardness) + (inputSampleL * softness)); + } + else lastSampleL = -refclip; + } + + if (inputSampleL > refclip) + { + if (lastSampleL < refclip) + { + inputSampleL = ((refclip*hardness) + (lastSampleL * softness)); + } + else inputSampleL = refclip; + } + + if (inputSampleL < -refclip) + { + if (lastSampleL > -refclip) + { + inputSampleL = ((-refclip*hardness) + (lastSampleL * softness)); + } + else inputSampleL = -refclip; + } + lastSampleL = drySampleL; + + //begin simplified ADClip R + drySampleR = inputSampleR; + if (lastSampleR >= refclip) + { + if (inputSampleR < refclip) + { + lastSampleR = ((refclip*hardness) + (inputSampleR * softness)); + } + else lastSampleR = refclip; + } + + if (lastSampleR <= -refclip) + { + if (inputSampleR > -refclip) + { + lastSampleR = ((-refclip*hardness) + (inputSampleR * softness)); + } + else lastSampleR = -refclip; + } + + if (inputSampleR > refclip) + { + if (lastSampleR < refclip) + { + inputSampleR = ((refclip*hardness) + (lastSampleR * softness)); + } + else inputSampleR = refclip; + } + + if (inputSampleR < -refclip) + { + if (lastSampleR > -refclip) + { + inputSampleR = ((-refclip*hardness) + (lastSampleR * softness)); + } + else inputSampleR = -refclip; + } + lastSampleR = drySampleR; + + //output dither section + if (bitDepth == 3) { + //noise shaping to 32-bit floating point + double fpTemp = inputSampleL; + fpNShapeL += (inputSampleL-fpTemp); + inputSampleL += fpNShapeL; + fpTemp = inputSampleR; + fpNShapeR += (inputSampleR-fpTemp); + inputSampleR += fpNShapeR; + //for deeper space and warmth, we try a non-oscillating noise shaping + //that is kind of ruthless: it will forever retain the rounding errors + //except we'll dial it back a hair at the end of every buffer processed + //end noise shaping on 32 bit output + } else { + //entire Naturalize section used when not on 32 bit out + + inputSampleL -= noiseShapingL; + inputSampleR -= noiseShapingR; + + if (bitDepth == 2) { + inputSampleL *= 8388608.0; //go to dither at 24 bit + inputSampleR *= 8388608.0; //go to dither at 24 bit + } + if (bitDepth == 1) { + inputSampleL *= 32768.0; //go to dither at 16 bit + inputSampleR *= 32768.0; //go to dither at 16 bit + } + + //begin L + double benfordize = floor(inputSampleL); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + int hotbinA = floor(benfordize); + //hotbin becomes the Benford bin value for this number floored + double totalA = 0; + if ((hotbinA > 0) && (hotbinA < 10)) + { + bynL[hotbinA] += 1; + totalA += (301-bynL[1]); + totalA += (176-bynL[2]); + totalA += (125-bynL[3]); + totalA += (97-bynL[4]); + totalA += (79-bynL[5]); + totalA += (67-bynL[6]); + totalA += (58-bynL[7]); + totalA += (51-bynL[8]); + totalA += (46-bynL[9]); + bynL[hotbinA] -= 1; + } else {hotbinA = 10;} + //produce total number- smaller is closer to Benford real + + benfordize = ceil(inputSampleL); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + int hotbinB = floor(benfordize); + //hotbin becomes the Benford bin value for this number ceiled + double totalB = 0; + if ((hotbinB > 0) && (hotbinB < 10)) + { + bynL[hotbinB] += 1; + totalB += (301-bynL[1]); + totalB += (176-bynL[2]); + totalB += (125-bynL[3]); + totalB += (97-bynL[4]); + totalB += (79-bynL[5]); + totalB += (67-bynL[6]); + totalB += (58-bynL[7]); + totalB += (51-bynL[8]); + totalB += (46-bynL[9]); + bynL[hotbinB] -= 1; + } else {hotbinB = 10;} + //produce total number- smaller is closer to Benford real + + if (totalA < totalB) + { + bynL[hotbinA] += 1; + inputSampleL = floor(inputSampleL); + } + else + { + bynL[hotbinB] += 1; + inputSampleL = ceil(inputSampleL); + } + //assign the relevant one to the delay line + //and floor/ceil signal accordingly + + totalA = bynL[1] + bynL[2] + bynL[3] + bynL[4] + bynL[5] + bynL[6] + bynL[7] + bynL[8] + bynL[9]; + totalA /= 1000; + if (totalA = 0) totalA = 1; + bynL[1] /= totalA; + bynL[2] /= totalA; + bynL[3] /= totalA; + bynL[4] /= totalA; + bynL[5] /= totalA; + bynL[6] /= totalA; + bynL[7] /= totalA; + bynL[8] /= totalA; + bynL[9] /= totalA; + bynL[10] /= 2; //catchall for garbage data + //end L + + //begin R + benfordize = floor(inputSampleR); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + hotbinA = floor(benfordize); + //hotbin becomes the Benford bin value for this number floored + totalA = 0; + if ((hotbinA > 0) && (hotbinA < 10)) + { + bynR[hotbinA] += 1; + totalA += (301-bynR[1]); + totalA += (176-bynR[2]); + totalA += (125-bynR[3]); + totalA += (97-bynR[4]); + totalA += (79-bynR[5]); + totalA += (67-bynR[6]); + totalA += (58-bynR[7]); + totalA += (51-bynR[8]); + totalA += (46-bynR[9]); + bynR[hotbinA] -= 1; + } else {hotbinA = 10;} + //produce total number- smaller is closer to Benford real + + benfordize = ceil(inputSampleR); + while (benfordize >= 1.0) {benfordize /= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + if (benfordize < 1.0) {benfordize *= 10;} + hotbinB = floor(benfordize); + //hotbin becomes the Benford bin value for this number ceiled + totalB = 0; + if ((hotbinB > 0) && (hotbinB < 10)) + { + bynR[hotbinB] += 1; + totalB += (301-bynR[1]); + totalB += (176-bynR[2]); + totalB += (125-bynR[3]); + totalB += (97-bynR[4]); + totalB += (79-bynR[5]); + totalB += (67-bynR[6]); + totalB += (58-bynR[7]); + totalB += (51-bynR[8]); + totalB += (46-bynR[9]); + bynR[hotbinB] -= 1; + } else {hotbinB = 10;} + //produce total number- smaller is closer to Benford real + + if (totalA < totalB) + { + bynR[hotbinA] += 1; + inputSampleR = floor(inputSampleR); + } + else + { + bynR[hotbinB] += 1; + inputSampleR = ceil(inputSampleR); + } + //assign the relevant one to the delay line + //and floor/ceil signal accordingly + + totalA = bynR[1] + bynR[2] + bynR[3] + bynR[4] + bynR[5] + bynR[6] + bynR[7] + bynR[8] + bynR[9]; + totalA /= 1000; + if (totalA = 0) totalA = 1; + bynR[1] /= totalA; + bynR[2] /= totalA; + bynR[3] /= totalA; + bynR[4] /= totalA; + bynR[5] /= totalA; + bynR[6] /= totalA; + bynR[7] /= totalA; + bynR[8] /= totalA; + bynR[9] /= totalA; + bynR[10] /= 2; //catchall for garbage data + //end R + + if (bitDepth == 2) { + inputSampleL /= 8388608.0; + inputSampleR /= 8388608.0; + } + if (bitDepth == 1) { + inputSampleL /= 32768.0; + inputSampleR /= 32768.0; + } + noiseShapingL += inputSampleL - drySampleL; + noiseShapingR += inputSampleR - drySampleR; + } + + if (inputSampleL > refclip) inputSampleL = refclip; + if (inputSampleL < -refclip) inputSampleL = -refclip; + //iron bar prohibits any overs + if (inputSampleR > refclip) inputSampleR = refclip; + if (inputSampleR < -refclip) inputSampleR = -refclip; + //iron bar prohibits any overs + + *out1 = inputSampleL; + *out2 = inputSampleR; + + *in1++; + *in2++; + *out1++; + *out2++; + } + fpNShapeL *= 0.999999; + fpNShapeR *= 0.999999; + //we will just delicately dial back the FP noise shaping, not even every sample + //this is a good place to put subtle 'no runaway' calculations, though bear in mind + //that it will be called more often when you use shorter sample buffers in the DAW. + //So, very low latency operation will call these calculations more often. +}
\ No newline at end of file |