This commit is contained in:
Christopher Johnson 2024-11-03 16:32:16 -05:00
parent 04874c800b
commit 59635ea5d9
43 changed files with 6200 additions and 1319 deletions

View file

@ -39,7 +39,7 @@ Reverb: Galactic3, kCathedral3, CreamCoat, kPlateD, kPlateB, kPlateA, kPlateC, C
Saturation: Creature, Huge, NCSeventeen, Tube2, Tube, Spiral2, PurestDrive, Focus, Mojo, Dyno, Spiral, UnBox, Desk4, Righteous4
Stereo: Srsly, Srsly2, Wider, StereoFX, ToVinyl4, AutoPan, LRFlipTimer, MSFlipTimer, Sidepass, SideDull
Stereo: Srsly3, Srsly2, Srsly, Wider, StereoFX, ToVinyl4, AutoPan, LRFlipTimer, MSFlipTimer, Sidepass, SideDull
Subtlety: Discontinuity, Hype, Shape, Inflamer, Sweeten, PurestWarm2, PurestWarm, Coils2, Interstage, PhaseNudge, Remap, SingleEndedTriode, Coils, Desk, TransDesk, TubeDesk
@ -4189,6 +4189,18 @@ But. But. BUT. What I was asked for, was to accomplish a particular effect, wher
Thats my hope, anyhow. Hope you like it! I know Ill be using it on stuff.
############ Srsly3 is Srsly2, with a Nonlin control to analogify the filters.
Those who are familiar with Airwindows know that Srsly is a sort of take on a famous stereo processor, the Hughes SRS. The first version, Srsly, uses a bank of very tight resonant filters to adjust space psychoacoustically and simulate the sound of ambience around human ears (based on illustrations that ran in Popular Mechanics). The second, Srsly2, took that and added aggressive mid/side processing to more closely resemble existing SRS boxes, thanks to a Crate SRS box I was able to get by way of example.
Srsly3 is the same thing as Srsly2, except all those filters are replaced with the kinds of biquad filter found in Airwindows BiquadNonlin. That's the one where I figured out how to apply the filter modulating used in Capacitor2, which simulates nonlinearity in cutoff frequency of ceramic capacitors (specifically Murata capacitors made of barium titanate), but applied to biquad filters which are a lot more adaptable than Capacitor was.
You don't have to understand any of that, it's just the way I got to this result.
It means you get a Nonlin control, where setting it to 0 means you have Srsly2 again. And then when you turn it up, especially when you have your filters at a higher Q setting (sharper resonances), the filters get modulated by the voltage pressures they themselves see from the signal passing through. And it fuzzes them out in a way that makes Srsly3 sound more analog than it's ever sounded before, with more of a vibe and texture to the vivid stereo sounds it can make.
I would say play with it and see what kinds of settings sound good to you. And if you liked Srsly2 and found it useful, now you've got this which starts where Srsly2 left off, and then takes it to new places. BiquadNonLin really sounds most interesting on tight resonant peaks, which is what Srsly is made out of, so with a bit of luck this will really click for Srsly enjoyers. Hope you like it!
############ StarChild is a weird digital ambience/echo plugin.
For all that we try to make plugins have natural, acoustic or electric, retro vibe qualities, sometimes theres a thing which breaks the rules by creating a distinctive voice that has nothing to do with naturalness. Ive got an old Alesis reverb like that: very primitive, but deep as anything. There have always been odd little boxes with a style all their own, like the Delta Labs Effectron, which is low-fi but uses delta-sigma modulation like an SACD (but much more crudely!)

View file

@ -21,6 +21,7 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
G = 0.5;
H = 0.5;
I = 0.0;
J = 1.0;
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
@ -36,6 +37,62 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
//this is reset: values being initialized only once. Startup values, whatever they are.
@ -78,6 +135,7 @@ VstInt32 Mastering::getChunk (void** data, bool isPreset)
chunkData[6] = G;
chunkData[7] = H;
chunkData[8] = I;
chunkData[9] = J;
/* 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. */
@ -98,6 +156,7 @@ VstInt32 Mastering::setChunk (void* data, VstInt32 byteSize, bool isPreset)
G = pinParameter(chunkData[6]);
H = pinParameter(chunkData[7]);
I = pinParameter(chunkData[8]);
J = pinParameter(chunkData[9]);
/* We're ignoring byteSize as we found it to be a filthy liar */
/* calculate any other fields you need here - you could copy in
@ -116,6 +175,7 @@ void Mastering::setParameter(VstInt32 index, float value) {
case kParamG: G = value; break;
case kParamH: H = value; break;
case kParamI: I = value; break;
case kParamJ: J = value; break;
default: throw; // unknown parameter, shouldn't happen!
}
}
@ -131,6 +191,7 @@ float Mastering::getParameter(VstInt32 index) {
case kParamG: return G; break;
case kParamH: return H; break;
case kParamI: return I; break;
case kParamJ: return J; break;
default: break; // unknown parameter, shouldn't happen!
} return 0.0; //we only need to update the relevant name, this is simple to manage
}
@ -146,6 +207,7 @@ void Mastering::getParameterName(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "Zoom", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "DarkF", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "Ratio", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "Dither", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} //this is our labels for displaying in the VST host
}
@ -161,6 +223,15 @@ void Mastering::getParameterDisplay(VstInt32 index, char *text) {
case kParamG: float2string (G, text, kVstMaxParamStrLen); break;
case kParamH: float2string (H, text, kVstMaxParamStrLen); break;
case kParamI: float2string (I, text, kVstMaxParamStrLen); break;
case kParamJ: switch((VstInt32)( J * 5.999 )) //0 to almost edge of # of params
{ case 0: vst_strncpy (text, "Dark", kVstMaxParamStrLen); break;
case 1: vst_strncpy (text, "TenNines", kVstMaxParamStrLen); break;
case 2: vst_strncpy (text, "TPDFWde", kVstMaxParamStrLen); break;
case 3: vst_strncpy (text, "PaulWde", kVstMaxParamStrLen); break;
case 4: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break;
case 5: vst_strncpy (text, "Bypass", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} break; //completed consoletype 'popup' parameter, exit
default: break; // unknown parameter, shouldn't happen!
} //this displays the values and handles 'popups' where it's discrete choices
}
@ -176,6 +247,7 @@ void Mastering::getParameterLabel(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
}
}

View file

@ -25,7 +25,8 @@ enum {
kParamG =6,
kParamH =7,
kParamI =8,
kNumParameters = 9
kParamJ =9,
kNumParameters = 10
}; //
const int kNumPrograms = 0;
@ -69,6 +70,7 @@ private:
float G;
float H;
float I;
float J;
enum {
pvAL1,
@ -151,6 +153,41 @@ private:
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
//default stuff

View file

@ -36,6 +36,10 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
@ -270,14 +274,388 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit stereo floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;
@ -318,7 +696,11 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
double inputSampleL = *in1;
@ -552,14 +934,388 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 64 bit stereo floating point dither
int expon; frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 64 bit stereo floating point dither
frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;

View file

@ -19,7 +19,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>DthX</string>
<string>Dthr</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*
@ -68,6 +68,7 @@ Mastering::Mastering(AudioUnit component)
SetParameter(kParam_G, kDefaultValue_ParamG );
SetParameter(kParam_H, kDefaultValue_ParamH );
SetParameter(kParam_I, kDefaultValue_ParamI );
SetParameter(kParam_J, kDefaultValue_ParamJ );
#if AU_DEBUG_DISPATCHER
mDebugDispatcher = new AUDebugDispatcher (this);
@ -83,7 +84,26 @@ ComponentResult Mastering::GetParameterValueStrings(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
CFArrayRef * outStrings)
{
if ((inScope == kAudioUnitScope_Global) && (inParameterID == kParam_J)) //ID must be actual name of parameter identifier, not number
{
if (outStrings == NULL) return noErr;
CFStringRef strings [] =
{
kMenuItem_Dark,
kMenuItem_TenNines,
kMenuItem_TPDFWide,
kMenuItem_PaulWide,
kMenuItem_NJAD,
kMenuItem_Bypass,
};
*outStrings = CFArrayCreate (
NULL,
(const void **) strings,
(sizeof (strings) / sizeof (strings [0])),
NULL
);
return noErr;
}
return kAudioUnitErr_InvalidProperty;
}
@ -167,7 +187,14 @@ ComponentResult Mastering::GetParameterInfo(AudioUnitScope inScope,
outParameterInfo.maxValue = 1.0;
outParameterInfo.defaultValue = kDefaultValue_ParamI;
break;
default:
case kParam_J:
AUBase::FillInParameterName (outParameterInfo, kParameterJName, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Indexed;
outParameterInfo.minValue = kDark;
outParameterInfo.maxValue = kBypass;
outParameterInfo.defaultValue = kDefaultValue_ParamJ;
break;
default:
result = kAudioUnitErr_InvalidParameter;
break;
}
@ -192,6 +219,21 @@ ComponentResult Mastering::GetPropertyInfo (AudioUnitPropertyID inID,
return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// state that plugin supports only stereo-in/stereo-out processing
UInt32 Mastering::SupportedNumChannels(const AUChannelInfo ** outInfo)
{
if (outInfo != NULL)
{
static AUChannelInfo info;
info.inChannels = 2;
info.outChannels = 2;
*outInfo = &info;
}
return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::GetProperty
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -220,31 +262,96 @@ ComponentResult Mastering::Initialize()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::MasteringKernel::Reset()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Mastering::MasteringKernel::Reset()
ComponentResult Mastering::Reset(AudioUnitScope inScope, AudioUnitElement inElement)
{
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
lastSinewL = 0.0;
lastSample = 0.0;
wasPosClip = false;
wasNegClip = false;
for (int x = 0; x < 16; x++) {intermediate[x] = 0.0;}
fpd = 1.0; while (fpd < 16386) fpd = rand()*UINT32_MAX;
lastSinewR = 0.0;
lastSampleL = 0.0;
wasPosClipL = false;
wasNegClipL = false;
lastSampleR = 0.0;
wasPosClipR = false;
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
return noErr;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::MasteringKernel::Process
// Mastering::ProcessBufferLists
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool &ioSilence )
OSStatus Mastering::ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess)
{
Float32 * inputL = (Float32*)(inBuffer.mBuffers[0].mData);
Float32 * inputR = (Float32*)(inBuffer.mBuffers[1].mData);
Float32 * outputL = (Float32*)(outBuffer.mBuffers[0].mData);
Float32 * outputR = (Float32*)(outBuffer.mBuffers[1].mData);
UInt32 nSampleFrames = inFramesToProcess;
const Float32 *sourceP = inSourceP;
Float32 *destP = inDestP;
double overallscale = 1.0;
overallscale /= 44100.0;
overallscale *= GetSampleRate();
@ -267,11 +374,18 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
double depthSinew = GetParameter( kParam_I );
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) GetParameter( kParam_J );
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (nSampleFrames-- > 0) {
long double inputSampleL = *sourceP;
if (fabs(inputSampleL)<1.18e-23) inputSampleL = fpd * 1.18e-17;
double inputSampleL = *inputL;
double inputSampleR = *inputR;
if (fabs(inputSampleL)<1.18e-23) inputSampleL = fpdL * 1.18e-17;
if (fabs(inputSampleR)<1.18e-23) inputSampleR = fpdR * 1.18e-17;
double drySampleL = inputSampleL;
double drySampleR = inputSampleR;
//begin Air3L
air[pvSL4] = air[pvAL4] - air[pvAL3]; air[pvSL3] = air[pvAL3] - air[pvAL2];
@ -286,10 +400,25 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
air[pvAL2] = air[pvAL1]; air[pvAL1] = (air[gainAL] * air[outAL]) + drySampleL;
long double midL = drySampleL - ((air[outAL]*0.5)+(drySampleL*(0.457-(0.017*overallscale))));
long double temp = (midL + air[gndavgL])*0.5; air[gndavgL] = midL; midL = temp;
//we have a single averaging stage to smooth stuff out
long double trebleL = drySampleL-midL;
//end Air3L
//begin Air3R
air[pvSR4] = air[pvAR4] - air[pvAR3]; air[pvSR3] = air[pvAR3] - air[pvAR2];
air[pvSR2] = air[pvAR2] - air[pvAR1]; air[pvSR1] = air[pvAR1] - inputSampleR;
air[accSR3] = air[pvSR4] - air[pvSR3]; air[accSR2] = air[pvSR3] - air[pvSR2];
air[accSR1] = air[pvSR2] - air[pvSR1];
air[acc2SR2] = air[accSR3] - air[accSR2]; air[acc2SR1] = air[accSR2] - air[accSR1];
air[outAR] = -(air[pvAR1] + air[pvSR3] + air[acc2SR2] - ((air[acc2SR2] + air[acc2SR1])*0.5));
air[gainAR] *= 0.5; air[gainAR] += fabs(drySampleR-air[outAR])*0.5;
if (air[gainAR] > 0.3*sqrt(overallscale)) air[gainAR] = 0.3*sqrt(overallscale);
air[pvAR4] = air[pvAR3]; air[pvAR3] = air[pvAR2];
air[pvAR2] = air[pvAR1]; air[pvAR1] = (air[gainAR] * air[outAR]) + drySampleR;
long double midR = drySampleR - ((air[outAR]*0.5)+(drySampleR*(0.457-(0.017*overallscale))));
temp = (midR + air[gndavgR])*0.5; air[gndavgR] = midR; midR = temp;
long double trebleR = drySampleR-midR;
//end Air3R
//begin KalmanML
temp = midL;
kalM[prevSlewL3] += kalM[prevSampL3] - kalM[prevSampL2]; kalM[prevSlewL3] *= 0.5;
@ -302,7 +431,7 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
kalM[accSlewL3] += (kalM[accSlewL2] - kalM[accSlewL1]); kalM[accSlewL3] *= 0.5;
//entering the abyss, what even is this
kalM[kalOutL] += kalM[prevSampL1] + kalM[prevSlewL2] + kalM[accSlewL3]; kalM[kalOutL] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalM[kalGainL] += fabs(temp-kalM[kalOutL])*kalMid*8.0; kalM[kalGainL] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
@ -318,6 +447,34 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
midL -= bassL;
//end KalmanML
//begin KalmanMR
temp = midR;
kalM[prevSlewR3] += kalM[prevSampR3] - kalM[prevSampR2]; kalM[prevSlewR3] *= 0.5;
kalM[prevSlewR2] += kalM[prevSampR2] - kalM[prevSampR1]; kalM[prevSlewR2] *= 0.5;
kalM[prevSlewR1] += kalM[prevSampR1] - midR; kalM[prevSlewR1] *= 0.5;
//make slews from each set of samples used
kalM[accSlewR2] += kalM[prevSlewR3] - kalM[prevSlewR2]; kalM[accSlewR2] *= 0.5;
kalM[accSlewR1] += kalM[prevSlewR2] - kalM[prevSlewR1]; kalM[accSlewR1] *= 0.5;
//differences between slews: rate of change of rate of change
kalM[accSlewR3] += (kalM[accSlewR2] - kalM[accSlewR1]); kalM[accSlewR3] *= 0.5;
//entering the abyss, what even is this
kalM[kalOutR] += kalM[prevSampR1] + kalM[prevSlewR2] + kalM[accSlewR3]; kalM[kalOutR] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalM[kalGainR] += fabs(temp-kalM[kalOutR])*kalMid*8.0; kalM[kalGainR] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
if (kalM[kalGainR] > kalMid*0.5) kalM[kalGainR] = kalMid*0.5;
//attempts to avoid explosions
kalM[kalOutR] += (temp*(1.0-(0.68+(kalMid*0.157))));
//this is for tuning a really complete cancellation up around Nyquist
kalM[prevSampR3] = kalM[prevSampR2]; kalM[prevSampR2] = kalM[prevSampR1];
kalM[prevSampR1] = (kalM[kalGainR] * kalM[kalOutR]) + ((1.0-kalM[kalGainR])*temp);
//feed the chain of previous samples
long double bassR = (kalM[kalOutR]+kalM[kalAvgR])*0.5;
kalM[kalAvgR] = kalM[kalOutR];
midR -= bassR;
//end KalmanMR
//begin KalmanSL
temp = bassL;
kalS[prevSlewL3] += kalS[prevSampL3] - kalS[prevSampL2]; kalS[prevSlewL3] *= 0.5;
@ -345,44 +502,100 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
bassL -= subL;
//end KalmanSL
//begin KalmanSR
temp = bassR;
kalS[prevSlewR3] += kalS[prevSampR3] - kalS[prevSampR2]; kalS[prevSlewR3] *= 0.5;
kalS[prevSlewR2] += kalS[prevSampR2] - kalS[prevSampR1]; kalS[prevSlewR2] *= 0.5;
kalS[prevSlewR1] += kalS[prevSampR1] - bassR; kalS[prevSlewR1] *= 0.5;
//make slews from each set of samples used
kalS[accSlewR2] += kalS[prevSlewR3] - kalS[prevSlewR2]; kalS[accSlewR2] *= 0.5;
kalS[accSlewR1] += kalS[prevSlewR2] - kalS[prevSlewR1]; kalS[accSlewR1] *= 0.5;
//differences between slews: rate of change of rate of change
kalS[accSlewR3] += (kalS[accSlewR2] - kalS[accSlewR1]); kalS[accSlewR3] *= 0.5;
//entering the abyss, what even is this
kalS[kalOutR] += kalS[prevSampR1] + kalS[prevSlewR2] + kalS[accSlewR3]; kalS[kalOutR] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalS[kalGainR] += fabs(temp-kalS[kalOutR])*kalSub*8.0; kalS[kalGainR] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
if (kalS[kalGainR] > kalSub*0.5) kalS[kalGainR] = kalSub*0.5;
//attempts to avoid explosions
kalS[kalOutR] += (temp*(1.0-(0.68+(kalSub*0.157))));
//this is for tuning a really complete cancellation up around Nyquist
kalS[prevSampR3] = kalS[prevSampR2]; kalS[prevSampR2] = kalS[prevSampR1];
kalS[prevSampR1] = (kalS[kalGainR] * kalS[kalOutR]) + ((1.0-kalS[kalGainR])*temp);
//feed the chain of previous samples
long double subR = (kalS[kalOutR]+kalS[kalAvgR])*0.5;
kalS[kalAvgR] = kalS[kalOutR];
bassR -= subR;
//end KalmanSR
inputSampleL = (subL*subGain);
inputSampleL += (bassL*bassGain);
inputSampleL += (midL*midGain);
inputSampleL += (trebleL*trebleGain);
inputSampleR = (subR*subGain);
inputSampleR += (bassR*bassGain);
inputSampleR += (midR*midGain);
inputSampleR += (trebleR*trebleGain);
for (int count = 0; count < zoomStages; count++) {
if (zoom > 0.0) {
long double closer = inputSampleL * 1.57079633;
double closer = inputSampleL * 1.57079633;
if (closer > 1.57079633) closer = 1.57079633;
if (closer < -1.57079633) closer = -1.57079633;
inputSampleL = (inputSampleL*(1.0-zoom))+(sin(closer)*zoom);
closer = inputSampleR * 1.57079633;
if (closer > 1.57079633) closer = 1.57079633;
if (closer < -1.57079633) closer = -1.57079633;
inputSampleR = (inputSampleR*(1.0-zoom))+(sin(closer)*zoom);
} //zooming in will make the body of the sound louder: it's just Density
if (zoom < 0.0) {
long double farther = fabs(inputSampleL) * 1.57079633;
double farther = fabs(inputSampleL) * 1.57079633;
if (farther > 1.57079633) farther = 1.0;
else farther = 1.0-cos(farther);
if (inputSampleL > 0.0) inputSampleL = (inputSampleL*(1.0+zoom))-(farther*zoom*1.57079633);
if (inputSampleL < 0.0) inputSampleL = (inputSampleL*(1.0+zoom))+(farther*zoom*1.57079633);
farther = fabs(inputSampleR) * 1.57079633;
if (farther > 1.57079633) farther = 1.0;
else farther = 1.0-cos(farther);
if (inputSampleR > 0.0) inputSampleR = (inputSampleR*(1.0+zoom))-(farther*zoom*1.57079633);
if (inputSampleR < 0.0) inputSampleR = (inputSampleR*(1.0+zoom))+(farther*zoom*1.57079633);
} //zooming out boosts the hottest peaks but cuts back softer stuff
}
//begin ClipOnly2 as a little, compressed chunk that can be dropped into code
//begin ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
if (inputSampleL > 4.0) inputSampleL = 4.0; if (inputSampleL < -4.0) inputSampleL = -4.0;
if (wasPosClip == true) { //current will be over
if (inputSampleL<lastSample) lastSample=0.7058208+(inputSampleL*0.2609148);
else lastSample = 0.2491717+(lastSample*0.7390851);
} wasPosClip = false;
if (inputSampleL>0.9549925859) {wasPosClip=true;inputSampleL=0.7058208+(lastSample*0.2609148);}
if (wasNegClip == true) { //current will be -over
if (inputSampleL > lastSample) lastSample=-0.7058208+(inputSampleL*0.2609148);
else lastSample=-0.2491717+(lastSample*0.7390851);
} wasNegClip = false;
if (inputSampleL<-0.9549925859) {wasNegClip=true;inputSampleL=-0.7058208+(lastSample*0.2609148);}
intermediate[spacing] = inputSampleL;
inputSampleL = lastSample; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediate[x-1] = intermediate[x];
lastSample = intermediate[0]; //run a little buffer to handle this
//end ClipOnly2 as a little, compressed chunk that can be dropped into code
if (wasPosClipL == true) { //current will be over
if (inputSampleL<lastSampleL) lastSampleL=0.7058208+(inputSampleL*0.2609148);
else lastSampleL = 0.2491717+(lastSampleL*0.7390851);
} wasPosClipL = false;
if (inputSampleL>0.9549925859) {wasPosClipL=true;inputSampleL=0.7058208+(lastSampleL*0.2609148);}
if (wasNegClipL == true) { //current will be -over
if (inputSampleL > lastSampleL) lastSampleL=-0.7058208+(inputSampleL*0.2609148);
else lastSampleL=-0.2491717+(lastSampleL*0.7390851);
} wasNegClipL = false;
if (inputSampleL<-0.9549925859) {wasNegClipL=true;inputSampleL=-0.7058208+(lastSampleL*0.2609148);}
intermediateL[spacing] = inputSampleL;
inputSampleL = lastSampleL; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediateL[x-1] = intermediateL[x];
lastSampleL = intermediateL[0]; //run a little buffer to handle this
if (inputSampleR > 4.0) inputSampleR = 4.0; if (inputSampleR < -4.0) inputSampleR = -4.0;
if (wasPosClipR == true) { //current will be over
if (inputSampleR<lastSampleR) lastSampleR=0.7058208+(inputSampleR*0.2609148);
else lastSampleR = 0.2491717+(lastSampleR*0.7390851);
} wasPosClipR = false;
if (inputSampleR>0.9549925859) {wasPosClipR=true;inputSampleR=0.7058208+(lastSampleR*0.2609148);}
if (wasNegClipR == true) { //current will be -over
if (inputSampleR > lastSampleR) lastSampleR=-0.7058208+(inputSampleR*0.2609148);
else lastSampleR=-0.2491717+(lastSampleR*0.7390851);
} wasNegClipR = false;
if (inputSampleR<-0.9549925859) {wasNegClipR=true;inputSampleR=-0.7058208+(lastSampleR*0.2609148);}
intermediateR[spacing] = inputSampleR;
inputSampleR = lastSampleR; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediateR[x-1] = intermediateR[x];
lastSampleR = intermediateR[0]; //run a little buffer to handle this
//end ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
temp = inputSampleL;
long double sinew = threshSinew * cos(lastSinewL*lastSinewL);
@ -390,17 +603,405 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
if (-(inputSampleL - lastSinewL) > sinew) temp = lastSinewL - sinew;
lastSinewL = temp;
inputSampleL = (inputSampleL * (1.0-depthSinew))+(lastSinewL*depthSinew);
temp = inputSampleR;
sinew = threshSinew * cos(lastSinewR*lastSinewR);
if (inputSampleR - lastSinewR > sinew) temp = lastSinewR + sinew;
if (-(inputSampleR - lastSinewR) > sinew) temp = lastSinewR - sinew;
lastSinewR = temp;
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpd ^= fpd << 13; fpd ^= fpd >> 17; fpd ^= fpd << 5;
inputSampleL += ((double(fpd)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*destP = inputSampleL;
*outputL = inputSampleL;
*outputR = inputSampleR;
//direct stereo out
sourceP += inNumChannels; destP += inNumChannels;
inputL += 1;
inputR += 1;
outputL += 1;
outputR += 1;
}
return noErr;
}

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*
@ -63,6 +63,20 @@ static const float kDefaultValue_ParamF = 0.5;
static const float kDefaultValue_ParamG = 0.5;
static const float kDefaultValue_ParamH = 0.5;
static const float kDefaultValue_ParamI = 0.0;
static const int kDark = 1;
static const int kTenNines = 2;
static const int kTPDFWide = 3;
static const int kPaulWide = 4;
static const int kNJAD = 5;
static const int kBypass = 6;
static const int kDefaultValue_ParamJ = kBypass;
static CFStringRef kMenuItem_Dark = CFSTR ("Dark");
static CFStringRef kMenuItem_TenNines = CFSTR ("Ten Nines");
static CFStringRef kMenuItem_TPDFWide = CFSTR ("TPDFWide");
static CFStringRef kMenuItem_PaulWide = CFSTR ("PaulWide");
static CFStringRef kMenuItem_NJAD = CFSTR ("NJAD");
static CFStringRef kMenuItem_Bypass = CFSTR ("Bypass");
static CFStringRef kParameterAName = CFSTR("Air");
static CFStringRef kParameterBName = CFSTR("Mid");
@ -73,6 +87,7 @@ static CFStringRef kParameterFName = CFSTR("XvL-S");
static CFStringRef kParameterGName = CFSTR("Zoom");
static CFStringRef kParameterHName = CFSTR("DarkF");
static CFStringRef kParameterIName = CFSTR("Ratio");
static CFStringRef kParameterJName = CFSTR("Dither");
enum {
kParam_A =0,
@ -84,8 +99,9 @@ enum {
kParam_G =6,
kParam_H =7,
kParam_I =8,
kParam_J =9,
//Add your parameters here...
kNumberOfParameters=9
kNumberOfParameters=10
};
#pragma mark ____Mastering
@ -97,8 +113,13 @@ public:
virtual ~Mastering () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new MasteringKernel(this); }
virtual ComponentResult Reset(AudioUnitScope inScope, AudioUnitElement inElement);
virtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer, AudioBufferList & outBuffer,
UInt32 inFramesToProcess);
virtual UInt32 SupportedNumChannels(const AUChannelInfo ** outInfo);
virtual ComponentResult GetParameterValueStrings(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
CFArrayRef * outStrings);
@ -117,7 +138,7 @@ public:
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual ComponentResult Initialize();
virtual bool SupportsTail () { return true; }
virtual Float64 GetTailTime() {return (1.0/GetSampleRate())*0.0;} //in SECONDS! gsr * a number = in samples
@ -126,78 +147,126 @@ public:
/*! @method Version */
virtual ComponentResult Version() { return kMasteringVersion; }
private:
protected:
class MasteringKernel : public AUKernelBase // most of the real work happens here
{
public:
MasteringKernel(AUEffectBase *inAudioUnit )
: AUKernelBase(inAudioUnit)
{
}
// *Required* overides for the process method for this effect
// processes one channel of interleaved samples
virtual void Process( const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool &ioSilence);
virtual void Reset();
private:
enum {
pvAL1,
pvSL1,
accSL1,
acc2SL1,
pvAL2,
pvSL2,
accSL2,
acc2SL2,
pvAL3,
pvSL3,
accSL3,
pvAL4,
pvSL4,
gndavgL,
outAL,
gainAL,
air_total
};
double air[air_total];
enum {
prevSampL1,
prevSlewL1,
accSlewL1,
prevSampL2,
prevSlewL2,
accSlewL2,
prevSampL3,
prevSlewL3,
accSlewL3,
kalGainL,
kalOutL,
kalAvgL,
kal_total
};
double kalM[kal_total];
double kalS[kal_total];
long double lastSinewL;
//this is overkill, used to run both Zoom and Sinew stages as they are after
//the summing in StoneFire, which sums three doubles to a long double.
double lastSample; //this doesn't touch the audio unless it's clipping
double intermediate[16];
bool wasPosClip;
bool wasNegClip;
uint32_t fpd;
enum {
pvAL1,
pvSL1,
accSL1,
acc2SL1,
pvAL2,
pvSL2,
accSL2,
acc2SL2,
pvAL3,
pvSL3,
accSL3,
pvAL4,
pvSL4,
gndavgL,
outAL,
gainAL,
pvAR1,
pvSR1,
accSR1,
acc2SR1,
pvAR2,
pvSR2,
accSR2,
acc2SR2,
pvAR3,
pvSR3,
accSR3,
pvAR4,
pvSR4,
gndavgR,
outAR,
gainAR,
air_total
};
double air[air_total];
enum {
prevSampL1,
prevSlewL1,
accSlewL1,
prevSampL2,
prevSlewL2,
accSlewL2,
prevSampL3,
prevSlewL3,
accSlewL3,
kalGainL,
kalOutL,
kalAvgL,
prevSampR1,
prevSlewR1,
accSlewR1,
prevSampR2,
prevSlewR2,
accSlewR2,
prevSampR3,
prevSlewR3,
accSlewR3,
kalGainR,
kalOutR,
kalAvgR,
kal_total
};
double kalM[kal_total];
double kalS[kal_total];
long double lastSinewL;
long double lastSinewR;
//this is overkill, used to run both Zoom and Sinew stages as they are after
//the summing in StoneFire, which sums three doubles to a long double.
double lastSampleL;
double intermediateL[16];
bool wasPosClipL;
bool wasNegClipL;
double lastSampleR;
double intermediateR[16];
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*

View file

@ -251,7 +251,7 @@
<dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array>
<real>186</real>
<real>299</real>
</array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array>
@ -264,19 +264,22 @@
<array>
<string>089C166AFE841209C02AAC07</string>
<string>08FB77ADFE841716C02AAC07</string>
<string>8BA05AEB0720742700365D66</string>
<string>8BA05A7D072073D200365D66</string>
<string>8BA05A7E072073D200365D66</string>
<string>1C37FBAC04509CD000000102</string>
<string>1C37FABC05509CD000000102</string>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>20</integer>
<integer>19</integer>
<integer>6</integer>
<integer>5</integer>
<integer>4</integer>
<integer>1</integer>
<integer>0</integer>
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 0}, {186, 445}}</string>
<string>{{0, 0}, {299, 445}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -288,19 +291,19 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {203, 463}}</string>
<string>{{0, 0}, {316, 463}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>186</real>
<real>299</real>
</array>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
<key>Proportion</key>
<string>203pt</string>
<string>316pt</string>
</dict>
<dict>
<key>Dock</key>
@ -311,15 +314,13 @@
<key>PBXProjectModuleGUID</key>
<string>1CE0B20306471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>MyNewFile14.java</string>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>1CE0B20406471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>MyNewFile14.java</string>
</dict>
<key>SplitCount</key>
<string>1</string>
@ -330,14 +331,14 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {580, 269}}</string>
<string>{{0, 0}, {467, 0}}</string>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>269pt</string>
<string>0pt</string>
</dict>
<dict>
<key>ContentConfiguration</key>
@ -350,18 +351,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 274}, {580, 189}}</string>
<string>{{0, 5}, {467, 458}}</string>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
<key>Proportion</key>
<string>189pt</string>
<string>458pt</string>
</dict>
</array>
<key>Proportion</key>
<string>580pt</string>
<string>467pt</string>
</dict>
</array>
<key>Name</key>
@ -376,9 +377,9 @@
</array>
<key>TableOfContents</key>
<array>
<string>8B563EC9161B5E170067FE32</string>
<string>8BDD47AA1A48BB8900FB2F61</string>
<string>1CE0B1FE06471DED0097A5F4</string>
<string>8B563ECA161B5E170067FE32</string>
<string>8BDD47AB1A48BB8900FB2F61</string>
<string>1CE0B20306471E060097A5F4</string>
<string>1CE0B20506471E060097A5F4</string>
</array>
@ -517,10 +518,10 @@
<key>WindowOrderList</key>
<array>
<string>8BD3CCBD148831C90062E48C</string>
<string>/Developer/Library/Xcode/Project Templates/System Plug-in/Audio Unit Effect/Audio Unit Effect/StarterAU.xcodeproj</string>
<string>/Developer/Library/Xcode/Project Templates/System Plug-in/Audio Unit Effect/Audio Unit Effect with Cocoa View/StarterAU.xcodeproj</string>
</array>
<key>WindowString</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>
@ -597,7 +598,7 @@
<key>TableOfContents</key>
<array>
<string>8BD3CCBD148831C90062E48C</string>
<string>8B563ECB161B5E170067FE32</string>
<string>8BDD47AC1A48BB8900FB2F61</string>
<string>1CD0528F0623707200166675</string>
<string>XCMainBuildResultsModuleGUID</string>
</array>

View file

@ -10,7 +10,7 @@
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
292,
364,
20,
48,
43,
@ -32,7 +32,7 @@
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
252,
188,
60,
20,
48,
@ -49,14 +49,12 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 750255310;
PBXWorkspaceStateSaveDate = 750255310;
PBXPerProjectTemplateStateSaveDate = 751290936;
PBXWorkspaceStateSaveDate = 751290936;
};
perUserProjectItems = {
8BA3DC492CB5EC1900B899C2 /* PlistBookmark */ = 8BA3DC492CB5EC1900B899C2 /* PlistBookmark */;
8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */ = 8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */;
8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */ = 8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */;
8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */ = 8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */;
8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */ = 8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */;
8BC437832CC7CCED0098AE55 /* PBXTextBookmark */ = 8BC437832CC7CCED0098AE55 /* PBXTextBookmark */;
};
sourceControlManager = 8BD3CCB8148830B20062E48C /* Source Control */;
userBuildSettings = {
@ -64,38 +62,53 @@
};
8BA05A660720730100365D66 /* Mastering.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {822, 7380}}";
sepNavSelRange = "{17032, 0}";
sepNavVisRange = "{15387, 90}";
sepNavWindowFrame = "{{12, 53}, {1040, 821}}";
sepNavIntBoundsRect = "{{0, 0}, {849, 18270}}";
sepNavSelRange = "{31815, 0}";
sepNavVisRange = "{31575, 221}";
sepNavWindowFrame = "{{8, 49}, {1061, 821}}";
};
};
8BA05A690720730100365D66 /* MasteringVersion.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1056, 1062}}";
sepNavSelRange = "{2906, 0}";
sepNavVisRange = "{1069, 1900}";
sepNavWindowFrame = "{{15, 52}, {1040, 821}}";
sepNavSelRange = "{2907, 0}";
sepNavVisRange = "{1070, 1900}";
sepNavWindowFrame = "{{15, 52}, {1061, 821}}";
};
};
8BA3DC492CB5EC1900B899C2 /* PlistBookmark */ = {
isa = PlistBookmark;
fRef = 8D01CCD10486CAD60068D4B7 /* Info.plist */;
fallbackIsa = PBXBookmark;
isK = 0;
kPath = (
CFBundleName,
);
name = /Users/christopherjohnson/Desktop/Mastering/Info.plist;
8BA05A7F072073D200365D66 /* AUBase.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {516, 23430}}";
sepNavSelRange = "{0, 0}";
sepNavVisRange = "{0, 1336}";
};
};
8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 693";
rLen = 0;
rLoc = 9223372036854775808;
rLoc = 31815;
rType = 0;
vrLen = 252;
vrLoc = 31544;
};
8BC437832CC7CCED0098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 693";
rLen = 0;
rLoc = 31815;
rType = 0;
vrLen = 221;
vrLoc = 31575;
};
8BC6025B073B072D006C4272 /* Mastering.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1056, 3132}}";
sepNavSelRange = "{3665, 0}";
sepNavVisRange = "{2605, 1167}";
sepNavWindowFrame = "{{38, 57}, {1040, 821}}";
sepNavIntBoundsRect = "{{0, 0}, {1146, 4950}}";
sepNavSelRange = "{7725, 0}";
sepNavVisRange = "{7429, 835}";
sepNavWindowFrame = "{{26, 47}, {1061, 821}}";
};
};
8BD3CCB8148830B20062E48C /* Source Control */ = {
@ -112,36 +125,6 @@
isa = PBXCodeSenseManager;
indexTemplatePath = "";
};
8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 347";
rLen = 0;
rLoc = 17032;
rType = 0;
vrLen = 38;
vrLoc = 15492;
};
8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BC6025B073B072D006C4272 /* Mastering.h */;
name = "Mastering.h: 65";
rLen = 0;
rLoc = 3252;
rType = 0;
vrLen = 52;
vrLoc = 3253;
};
8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 347";
rLen = 0;
rLoc = 17032;
rType = 0;
vrLen = 90;
vrLoc = 15387;
};
8D01CCC60486CAD60068D4B7 /* Mastering */ = {
activeExec = 0;
};

View file

@ -178,7 +178,7 @@
<key>FavBarConfig</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274F1D46E5A5000176F0</string>
<string>8BC435772CC6F8650098AE55</string>
<key>XCBarModuleItemNames</key>
<dict/>
<key>XCBarModuleItems</key>
@ -225,8 +225,8 @@
<array/>
<key>PerspectiveWidths</key>
<array>
<integer>841</integer>
<integer>841</integer>
<integer>810</integer>
<integer>810</integer>
</array>
<key>Perspectives</key>
<array>
@ -282,7 +282,7 @@
<dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array>
<real>288</real>
<real>185</real>
</array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array>
@ -296,8 +296,6 @@
<string>089C166AFE841209C02AAC07</string>
<string>08FB77ADFE841716C02AAC07</string>
<string>8BA05A56072072A900365D66</string>
<string>089C167CFE841241C02AAC07</string>
<string>1C37FBAC04509CD000000102</string>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
@ -309,7 +307,7 @@
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 0}, {288, 595}}</string>
<string>{{0, 0}, {185, 428}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -319,19 +317,19 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {305, 613}}</string>
<string>{{0, 0}, {202, 446}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>288</real>
<real>185</real>
</array>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
<key>Proportion</key>
<string>305pt</string>
<string>202pt</string>
</dict>
<dict>
<key>Dock</key>
@ -340,7 +338,7 @@
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274A1D46E5A5000176F0</string>
<string>8BC435722CC6F8650098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>Mastering.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -348,18 +346,16 @@
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274B1D46E5A5000176F0</string>
<string>8BC435732CC6F8650098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>Mastering.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BF17B712CB7FF3300FAAF3F</string>
<string>8BC437832CC7CCED0098AE55</string>
<key>history</key>
<array>
<string>8BA3DC492CB5EC1900B899C2</string>
<string>8BF17B702CB7FF3300FAAF3F</string>
<string>8BF17B272CB7FB4400FAAF3F</string>
<string>8BC4371D2CC70EE00098AE55</string>
</array>
</dict>
<key>SplitCount</key>
@ -373,18 +369,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {531, 56}}</string>
<string>{{0, 0}, {603, 86}}</string>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>56pt</string>
<string>86pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>552pt</string>
<string>355pt</string>
<key>Tabs</key>
<array>
<dict>
@ -398,9 +394,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {531, 525}}</string>
<string>{{10, 27}, {603, 328}}</string>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -454,7 +450,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {531, 507}}</string>
<string>{{10, 27}, {603, 282}}</string>
</dict>
<key>Module</key>
<string>PBXBuildResultsModule</string>
@ -463,7 +459,7 @@
</dict>
</array>
<key>Proportion</key>
<string>531pt</string>
<string>603pt</string>
</dict>
</array>
<key>Name</key>
@ -482,11 +478,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>8BF17B722CB7FF3300FAAF3F</string>
<string>8BC437842CC7CCED0098AE55</string>
<string>1CA23ED40692098700951B8B</string>
<string>8BF17B732CB7FF3300FAAF3F</string>
<string>8BD7274A1D46E5A5000176F0</string>
<string>8BF17B742CB7FF3300FAAF3F</string>
<string>8BC437852CC7CCED0098AE55</string>
<string>8BC435722CC6F8650098AE55</string>
<string>8BC437862CC7CCED0098AE55</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -523,7 +519,7 @@
<key>Identifier</key>
<string>perspective.debug</string>
<key>IsVertical</key>
<true/>
<integer>1</integer>
<key>Layout</key>
<array>
<dict>
@ -542,7 +538,7 @@
<key>Module</key>
<string>PBXDebugCLIModule</string>
<key>Proportion</key>
<string>0pt</string>
<string>0%</string>
</dict>
<dict>
<key>ContentConfiguration</key>
@ -561,8 +557,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {395, 214}}</string>
<string>{{395, 0}, {415, 214}}</string>
<string>{{0, 0}, {395, 213}}</string>
<string>{{395, 0}, {415, 213}}</string>
</array>
</dict>
<key>VerticalSplitView</key>
@ -577,8 +573,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {810, 214}}</string>
<string>{{0, 214}, {810, 227}}</string>
<string>{{0, 0}, {810, 213}}</string>
<string>{{0, 213}, {810, 225}}</string>
</array>
</dict>
</dict>
@ -591,6 +587,8 @@
</dict>
<key>GeometryConfiguration</key>
<dict>
<key>DebugConsoleDrawerSize</key>
<string>{100, 120}</string>
<key>DebugConsoleVisible</key>
<string>None</string>
<key>DebugConsoleWindowFrame</key>
@ -598,54 +596,32 @@
<key>DebugSTDIOWindowFrame</key>
<string>{{200, 200}, {500, 300}}</string>
<key>Frame</key>
<string>{{0, 5}, {810, 441}}</string>
<key>PBXDebugSessionStackFrameViewKey</key>
<dict>
<key>DebugVariablesTableConfiguration</key>
<array>
<string>Name</string>
<real>120</real>
<string>Value</string>
<real>85</real>
<string>Summary</string>
<real>185</real>
</array>
<key>Frame</key>
<string>{{395, 0}, {415, 214}}</string>
</dict>
<string>{{0, 7}, {810, 438}}</string>
</dict>
<key>Module</key>
<string>PBXDebugSessionModule</string>
<key>Proportion</key>
<string>441pt</string>
<string>443pt</string>
</dict>
</array>
<key>Name</key>
<string>Debug</string>
<key>ServiceClasses</key>
<array>
<string>XCModuleDock</string>
<string>XCModuleDock</string>
<string>PBXDebugCLIModule</string>
<string>PBXDebugSessionModule</string>
<string>PBXDebugProcessAndThreadModule</string>
<string>PBXDebugProcessViewModule</string>
<string>PBXDebugThreadViewModule</string>
<string>PBXDebugStackFrameViewModule</string>
<string>PBXNavigatorGroup</string>
<string>XCConsole</string>
</array>
<key>TableOfContents</key>
<array>
<string>8BD727EC1D46ECF1000176F0</string>
<string>1CC8E6A5069209BD00BB180A</string>
<string>1CC8E6A6069209BD00BB180A</string>
<string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string>
<string>8BD727ED1D46ECF1000176F0</string>
<string>8BD727EE1D46ECF1000176F0</string>
<string>8BD727EF1D46ECF1000176F0</string>
<string>8BD727F01D46ECF1000176F0</string>
<string>8BD727E71D46ECD9000176F0</string>
<string>1CC8E6A7069209BD00BB180A</string>
</array>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarConfiguration</key>
<string>xcode.toolbar.config.debugV3</string>
</dict>
@ -659,7 +635,7 @@
<key>StatusbarIsVisible</key>
<true/>
<key>TimeStamp</key>
<real>750255923.53302801</real>
<real>751291629.93373895</real>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarDisplayMode</key>
@ -676,11 +652,11 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>8BF17B752CB7FF3300FAAF3F</string>
<string>8BC437872CC7CCED0098AE55</string>
<string>/Users/christopherjohnson/Desktop/airwindows/plugins/MacAU/Mastering/Mastering.xcodeproj</string>
</array>
<key>WindowString</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*

View file

@ -0,0 +1,5 @@
//
// Prefix header for all source files of the '«PROJECTNAMEASIDENTIFIER»' target in the '«PROJECTNAMEASIDENTIFIER»' project.
//
#include <CoreServices/CoreServices.h>

View file

@ -38,7 +38,7 @@
<key>CFBundleShortVersionString</key>
<string>1.0</string>
<key>CFBundleSignature</key>
<string>DthX</string>
<string>Dthr</string>
<key>CFBundleVersion</key>
<string>1.0</string>
<key>CSResourcesFileMapped</key>

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*
@ -68,6 +68,7 @@ Mastering::Mastering(AudioUnit component)
SetParameter(kParam_G, kDefaultValue_ParamG );
SetParameter(kParam_H, kDefaultValue_ParamH );
SetParameter(kParam_I, kDefaultValue_ParamI );
SetParameter(kParam_J, kDefaultValue_ParamJ );
#if AU_DEBUG_DISPATCHER
mDebugDispatcher = new AUDebugDispatcher (this);
@ -83,7 +84,26 @@ ComponentResult Mastering::GetParameterValueStrings(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
CFArrayRef * outStrings)
{
if ((inScope == kAudioUnitScope_Global) && (inParameterID == kParam_J)) //ID must be actual name of parameter identifier, not number
{
if (outStrings == NULL) return noErr;
CFStringRef strings [] =
{
kMenuItem_Dark,
kMenuItem_TenNines,
kMenuItem_TPDFWide,
kMenuItem_PaulWide,
kMenuItem_NJAD,
kMenuItem_Bypass,
};
*outStrings = CFArrayCreate (
NULL,
(const void **) strings,
(sizeof (strings) / sizeof (strings [0])),
NULL
);
return noErr;
}
return kAudioUnitErr_InvalidProperty;
}
@ -167,7 +187,14 @@ ComponentResult Mastering::GetParameterInfo(AudioUnitScope inScope,
outParameterInfo.maxValue = 1.0;
outParameterInfo.defaultValue = kDefaultValue_ParamI;
break;
default:
case kParam_J:
AUBase::FillInParameterName (outParameterInfo, kParameterJName, false);
outParameterInfo.unit = kAudioUnitParameterUnit_Indexed;
outParameterInfo.minValue = kDark;
outParameterInfo.maxValue = kBypass;
outParameterInfo.defaultValue = kDefaultValue_ParamJ;
break;
default:
result = kAudioUnitErr_InvalidParameter;
break;
}
@ -192,6 +219,21 @@ ComponentResult Mastering::GetPropertyInfo (AudioUnitPropertyID inID,
return AUEffectBase::GetPropertyInfo (inID, inScope, inElement, outDataSize, outWritable);
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// state that plugin supports only stereo-in/stereo-out processing
UInt32 Mastering::SupportedNumChannels(const AUChannelInfo ** outInfo)
{
if (outInfo != NULL)
{
static AUChannelInfo info;
info.inChannels = 2;
info.outChannels = 2;
*outInfo = &info;
}
return 1;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::GetProperty
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
@ -220,31 +262,96 @@ ComponentResult Mastering::Initialize()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::MasteringKernel::Reset()
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Mastering::MasteringKernel::Reset()
ComponentResult Mastering::Reset(AudioUnitScope inScope, AudioUnitElement inElement)
{
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
lastSinewL = 0.0;
lastSample = 0.0;
wasPosClip = false;
wasNegClip = false;
for (int x = 0; x < 16; x++) {intermediate[x] = 0.0;}
fpd = 1.0; while (fpd < 16386) fpd = rand()*UINT32_MAX;
lastSinewR = 0.0;
lastSampleL = 0.0;
wasPosClipL = false;
wasNegClipL = false;
lastSampleR = 0.0;
wasPosClipR = false;
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
return noErr;
}
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
// Mastering::MasteringKernel::Process
// Mastering::ProcessBufferLists
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool &ioSilence )
OSStatus Mastering::ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer,
AudioBufferList & outBuffer,
UInt32 inFramesToProcess)
{
Float32 * inputL = (Float32*)(inBuffer.mBuffers[0].mData);
Float32 * inputR = (Float32*)(inBuffer.mBuffers[1].mData);
Float32 * outputL = (Float32*)(outBuffer.mBuffers[0].mData);
Float32 * outputR = (Float32*)(outBuffer.mBuffers[1].mData);
UInt32 nSampleFrames = inFramesToProcess;
const Float32 *sourceP = inSourceP;
Float32 *destP = inDestP;
double overallscale = 1.0;
overallscale /= 44100.0;
overallscale *= GetSampleRate();
@ -267,11 +374,18 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
double depthSinew = GetParameter( kParam_I );
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) GetParameter( kParam_J );
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (nSampleFrames-- > 0) {
long double inputSampleL = *sourceP;
if (fabs(inputSampleL)<1.18e-23) inputSampleL = fpd * 1.18e-17;
double inputSampleL = *inputL;
double inputSampleR = *inputR;
if (fabs(inputSampleL)<1.18e-23) inputSampleL = fpdL * 1.18e-17;
if (fabs(inputSampleR)<1.18e-23) inputSampleR = fpdR * 1.18e-17;
double drySampleL = inputSampleL;
double drySampleR = inputSampleR;
//begin Air3L
air[pvSL4] = air[pvAL4] - air[pvAL3]; air[pvSL3] = air[pvAL3] - air[pvAL2];
@ -286,10 +400,25 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
air[pvAL2] = air[pvAL1]; air[pvAL1] = (air[gainAL] * air[outAL]) + drySampleL;
long double midL = drySampleL - ((air[outAL]*0.5)+(drySampleL*(0.457-(0.017*overallscale))));
long double temp = (midL + air[gndavgL])*0.5; air[gndavgL] = midL; midL = temp;
//we have a single averaging stage to smooth stuff out
long double trebleL = drySampleL-midL;
//end Air3L
//begin Air3R
air[pvSR4] = air[pvAR4] - air[pvAR3]; air[pvSR3] = air[pvAR3] - air[pvAR2];
air[pvSR2] = air[pvAR2] - air[pvAR1]; air[pvSR1] = air[pvAR1] - inputSampleR;
air[accSR3] = air[pvSR4] - air[pvSR3]; air[accSR2] = air[pvSR3] - air[pvSR2];
air[accSR1] = air[pvSR2] - air[pvSR1];
air[acc2SR2] = air[accSR3] - air[accSR2]; air[acc2SR1] = air[accSR2] - air[accSR1];
air[outAR] = -(air[pvAR1] + air[pvSR3] + air[acc2SR2] - ((air[acc2SR2] + air[acc2SR1])*0.5));
air[gainAR] *= 0.5; air[gainAR] += fabs(drySampleR-air[outAR])*0.5;
if (air[gainAR] > 0.3*sqrt(overallscale)) air[gainAR] = 0.3*sqrt(overallscale);
air[pvAR4] = air[pvAR3]; air[pvAR3] = air[pvAR2];
air[pvAR2] = air[pvAR1]; air[pvAR1] = (air[gainAR] * air[outAR]) + drySampleR;
long double midR = drySampleR - ((air[outAR]*0.5)+(drySampleR*(0.457-(0.017*overallscale))));
temp = (midR + air[gndavgR])*0.5; air[gndavgR] = midR; midR = temp;
long double trebleR = drySampleR-midR;
//end Air3R
//begin KalmanML
temp = midL;
kalM[prevSlewL3] += kalM[prevSampL3] - kalM[prevSampL2]; kalM[prevSlewL3] *= 0.5;
@ -302,7 +431,7 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
kalM[accSlewL3] += (kalM[accSlewL2] - kalM[accSlewL1]); kalM[accSlewL3] *= 0.5;
//entering the abyss, what even is this
kalM[kalOutL] += kalM[prevSampL1] + kalM[prevSlewL2] + kalM[accSlewL3]; kalM[kalOutL] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalM[kalGainL] += fabs(temp-kalM[kalOutL])*kalMid*8.0; kalM[kalGainL] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
@ -318,6 +447,34 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
midL -= bassL;
//end KalmanML
//begin KalmanMR
temp = midR;
kalM[prevSlewR3] += kalM[prevSampR3] - kalM[prevSampR2]; kalM[prevSlewR3] *= 0.5;
kalM[prevSlewR2] += kalM[prevSampR2] - kalM[prevSampR1]; kalM[prevSlewR2] *= 0.5;
kalM[prevSlewR1] += kalM[prevSampR1] - midR; kalM[prevSlewR1] *= 0.5;
//make slews from each set of samples used
kalM[accSlewR2] += kalM[prevSlewR3] - kalM[prevSlewR2]; kalM[accSlewR2] *= 0.5;
kalM[accSlewR1] += kalM[prevSlewR2] - kalM[prevSlewR1]; kalM[accSlewR1] *= 0.5;
//differences between slews: rate of change of rate of change
kalM[accSlewR3] += (kalM[accSlewR2] - kalM[accSlewR1]); kalM[accSlewR3] *= 0.5;
//entering the abyss, what even is this
kalM[kalOutR] += kalM[prevSampR1] + kalM[prevSlewR2] + kalM[accSlewR3]; kalM[kalOutR] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalM[kalGainR] += fabs(temp-kalM[kalOutR])*kalMid*8.0; kalM[kalGainR] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
if (kalM[kalGainR] > kalMid*0.5) kalM[kalGainR] = kalMid*0.5;
//attempts to avoid explosions
kalM[kalOutR] += (temp*(1.0-(0.68+(kalMid*0.157))));
//this is for tuning a really complete cancellation up around Nyquist
kalM[prevSampR3] = kalM[prevSampR2]; kalM[prevSampR2] = kalM[prevSampR1];
kalM[prevSampR1] = (kalM[kalGainR] * kalM[kalOutR]) + ((1.0-kalM[kalGainR])*temp);
//feed the chain of previous samples
long double bassR = (kalM[kalOutR]+kalM[kalAvgR])*0.5;
kalM[kalAvgR] = kalM[kalOutR];
midR -= bassR;
//end KalmanMR
//begin KalmanSL
temp = bassL;
kalS[prevSlewL3] += kalS[prevSampL3] - kalS[prevSampL2]; kalS[prevSlewL3] *= 0.5;
@ -345,44 +502,100 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
bassL -= subL;
//end KalmanSL
//begin KalmanSR
temp = bassR;
kalS[prevSlewR3] += kalS[prevSampR3] - kalS[prevSampR2]; kalS[prevSlewR3] *= 0.5;
kalS[prevSlewR2] += kalS[prevSampR2] - kalS[prevSampR1]; kalS[prevSlewR2] *= 0.5;
kalS[prevSlewR1] += kalS[prevSampR1] - bassR; kalS[prevSlewR1] *= 0.5;
//make slews from each set of samples used
kalS[accSlewR2] += kalS[prevSlewR3] - kalS[prevSlewR2]; kalS[accSlewR2] *= 0.5;
kalS[accSlewR1] += kalS[prevSlewR2] - kalS[prevSlewR1]; kalS[accSlewR1] *= 0.5;
//differences between slews: rate of change of rate of change
kalS[accSlewR3] += (kalS[accSlewR2] - kalS[accSlewR1]); kalS[accSlewR3] *= 0.5;
//entering the abyss, what even is this
kalS[kalOutR] += kalS[prevSampR1] + kalS[prevSlewR2] + kalS[accSlewR3]; kalS[kalOutR] *= 0.5;
//resynthesizing predicted result (all iir smoothed)
kalS[kalGainR] += fabs(temp-kalS[kalOutR])*kalSub*8.0; kalS[kalGainR] *= 0.5;
//madness takes its toll. Kalman Gain: how much dry to retain
if (kalS[kalGainR] > kalSub*0.5) kalS[kalGainR] = kalSub*0.5;
//attempts to avoid explosions
kalS[kalOutR] += (temp*(1.0-(0.68+(kalSub*0.157))));
//this is for tuning a really complete cancellation up around Nyquist
kalS[prevSampR3] = kalS[prevSampR2]; kalS[prevSampR2] = kalS[prevSampR1];
kalS[prevSampR1] = (kalS[kalGainR] * kalS[kalOutR]) + ((1.0-kalS[kalGainR])*temp);
//feed the chain of previous samples
long double subR = (kalS[kalOutR]+kalS[kalAvgR])*0.5;
kalS[kalAvgR] = kalS[kalOutR];
bassR -= subR;
//end KalmanSR
inputSampleL = (subL*subGain);
inputSampleL += (bassL*bassGain);
inputSampleL += (midL*midGain);
inputSampleL += (trebleL*trebleGain);
inputSampleR = (subR*subGain);
inputSampleR += (bassR*bassGain);
inputSampleR += (midR*midGain);
inputSampleR += (trebleR*trebleGain);
for (int count = 0; count < zoomStages; count++) {
if (zoom > 0.0) {
long double closer = inputSampleL * 1.57079633;
double closer = inputSampleL * 1.57079633;
if (closer > 1.57079633) closer = 1.57079633;
if (closer < -1.57079633) closer = -1.57079633;
inputSampleL = (inputSampleL*(1.0-zoom))+(sin(closer)*zoom);
closer = inputSampleR * 1.57079633;
if (closer > 1.57079633) closer = 1.57079633;
if (closer < -1.57079633) closer = -1.57079633;
inputSampleR = (inputSampleR*(1.0-zoom))+(sin(closer)*zoom);
} //zooming in will make the body of the sound louder: it's just Density
if (zoom < 0.0) {
long double farther = fabs(inputSampleL) * 1.57079633;
double farther = fabs(inputSampleL) * 1.57079633;
if (farther > 1.57079633) farther = 1.0;
else farther = 1.0-cos(farther);
if (inputSampleL > 0.0) inputSampleL = (inputSampleL*(1.0+zoom))-(farther*zoom*1.57079633);
if (inputSampleL < 0.0) inputSampleL = (inputSampleL*(1.0+zoom))+(farther*zoom*1.57079633);
farther = fabs(inputSampleR) * 1.57079633;
if (farther > 1.57079633) farther = 1.0;
else farther = 1.0-cos(farther);
if (inputSampleR > 0.0) inputSampleR = (inputSampleR*(1.0+zoom))-(farther*zoom*1.57079633);
if (inputSampleR < 0.0) inputSampleR = (inputSampleR*(1.0+zoom))+(farther*zoom*1.57079633);
} //zooming out boosts the hottest peaks but cuts back softer stuff
}
//begin ClipOnly2 as a little, compressed chunk that can be dropped into code
//begin ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
if (inputSampleL > 4.0) inputSampleL = 4.0; if (inputSampleL < -4.0) inputSampleL = -4.0;
if (wasPosClip == true) { //current will be over
if (inputSampleL<lastSample) lastSample=0.7058208+(inputSampleL*0.2609148);
else lastSample = 0.2491717+(lastSample*0.7390851);
} wasPosClip = false;
if (inputSampleL>0.9549925859) {wasPosClip=true;inputSampleL=0.7058208+(lastSample*0.2609148);}
if (wasNegClip == true) { //current will be -over
if (inputSampleL > lastSample) lastSample=-0.7058208+(inputSampleL*0.2609148);
else lastSample=-0.2491717+(lastSample*0.7390851);
} wasNegClip = false;
if (inputSampleL<-0.9549925859) {wasNegClip=true;inputSampleL=-0.7058208+(lastSample*0.2609148);}
intermediate[spacing] = inputSampleL;
inputSampleL = lastSample; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediate[x-1] = intermediate[x];
lastSample = intermediate[0]; //run a little buffer to handle this
//end ClipOnly2 as a little, compressed chunk that can be dropped into code
if (wasPosClipL == true) { //current will be over
if (inputSampleL<lastSampleL) lastSampleL=0.7058208+(inputSampleL*0.2609148);
else lastSampleL = 0.2491717+(lastSampleL*0.7390851);
} wasPosClipL = false;
if (inputSampleL>0.9549925859) {wasPosClipL=true;inputSampleL=0.7058208+(lastSampleL*0.2609148);}
if (wasNegClipL == true) { //current will be -over
if (inputSampleL > lastSampleL) lastSampleL=-0.7058208+(inputSampleL*0.2609148);
else lastSampleL=-0.2491717+(lastSampleL*0.7390851);
} wasNegClipL = false;
if (inputSampleL<-0.9549925859) {wasNegClipL=true;inputSampleL=-0.7058208+(lastSampleL*0.2609148);}
intermediateL[spacing] = inputSampleL;
inputSampleL = lastSampleL; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediateL[x-1] = intermediateL[x];
lastSampleL = intermediateL[0]; //run a little buffer to handle this
if (inputSampleR > 4.0) inputSampleR = 4.0; if (inputSampleR < -4.0) inputSampleR = -4.0;
if (wasPosClipR == true) { //current will be over
if (inputSampleR<lastSampleR) lastSampleR=0.7058208+(inputSampleR*0.2609148);
else lastSampleR = 0.2491717+(lastSampleR*0.7390851);
} wasPosClipR = false;
if (inputSampleR>0.9549925859) {wasPosClipR=true;inputSampleR=0.7058208+(lastSampleR*0.2609148);}
if (wasNegClipR == true) { //current will be -over
if (inputSampleR > lastSampleR) lastSampleR=-0.7058208+(inputSampleR*0.2609148);
else lastSampleR=-0.2491717+(lastSampleR*0.7390851);
} wasNegClipR = false;
if (inputSampleR<-0.9549925859) {wasNegClipR=true;inputSampleR=-0.7058208+(lastSampleR*0.2609148);}
intermediateR[spacing] = inputSampleR;
inputSampleR = lastSampleR; //Latency is however many samples equals one 44.1k sample
for (int x = spacing; x > 0; x--) intermediateR[x-1] = intermediateR[x];
lastSampleR = intermediateR[0]; //run a little buffer to handle this
//end ClipOnly2 stereo as a little, compressed chunk that can be dropped into code
temp = inputSampleL;
long double sinew = threshSinew * cos(lastSinewL*lastSinewL);
@ -390,17 +603,405 @@ void Mastering::MasteringKernel::Process( const Float32 *inSourceP,
if (-(inputSampleL - lastSinewL) > sinew) temp = lastSinewL - sinew;
lastSinewL = temp;
inputSampleL = (inputSampleL * (1.0-depthSinew))+(lastSinewL*depthSinew);
temp = inputSampleR;
sinew = threshSinew * cos(lastSinewR*lastSinewR);
if (inputSampleR - lastSinewR > sinew) temp = lastSinewR + sinew;
if (-(inputSampleR - lastSinewR) > sinew) temp = lastSinewR - sinew;
lastSinewR = temp;
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpd ^= fpd << 13; fpd ^= fpd >> 17; fpd ^= fpd << 5;
inputSampleL += ((double(fpd)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*destP = inputSampleL;
*outputL = inputSampleL;
*outputR = inputSampleR;
//direct stereo out
sourceP += inNumChannels; destP += inNumChannels;
inputL += 1;
inputR += 1;
outputL += 1;
outputR += 1;
}
return noErr;
}

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*
@ -63,6 +63,20 @@ static const float kDefaultValue_ParamF = 0.5;
static const float kDefaultValue_ParamG = 0.5;
static const float kDefaultValue_ParamH = 0.5;
static const float kDefaultValue_ParamI = 0.0;
static const int kDark = 1;
static const int kTenNines = 2;
static const int kTPDFWide = 3;
static const int kPaulWide = 4;
static const int kNJAD = 5;
static const int kBypass = 6;
static const int kDefaultValue_ParamJ = kBypass;
static CFStringRef kMenuItem_Dark = CFSTR ("Dark");
static CFStringRef kMenuItem_TenNines = CFSTR ("Ten Nines");
static CFStringRef kMenuItem_TPDFWide = CFSTR ("TPDFWide");
static CFStringRef kMenuItem_PaulWide = CFSTR ("PaulWide");
static CFStringRef kMenuItem_NJAD = CFSTR ("NJAD");
static CFStringRef kMenuItem_Bypass = CFSTR ("Bypass");
static CFStringRef kParameterAName = CFSTR("Air");
static CFStringRef kParameterBName = CFSTR("Mid");
@ -73,6 +87,7 @@ static CFStringRef kParameterFName = CFSTR("XvL-S");
static CFStringRef kParameterGName = CFSTR("Zoom");
static CFStringRef kParameterHName = CFSTR("DarkF");
static CFStringRef kParameterIName = CFSTR("Ratio");
static CFStringRef kParameterJName = CFSTR("Dither");
enum {
kParam_A =0,
@ -84,8 +99,9 @@ enum {
kParam_G =6,
kParam_H =7,
kParam_I =8,
kParam_J =9,
//Add your parameters here...
kNumberOfParameters=9
kNumberOfParameters=10
};
#pragma mark ____Mastering
@ -97,8 +113,13 @@ public:
virtual ~Mastering () { delete mDebugDispatcher; }
#endif
virtual AUKernelBase * NewKernel() { return new MasteringKernel(this); }
virtual ComponentResult Reset(AudioUnitScope inScope, AudioUnitElement inElement);
virtual OSStatus ProcessBufferLists(AudioUnitRenderActionFlags & ioActionFlags,
const AudioBufferList & inBuffer, AudioBufferList & outBuffer,
UInt32 inFramesToProcess);
virtual UInt32 SupportedNumChannels(const AUChannelInfo ** outInfo);
virtual ComponentResult GetParameterValueStrings(AudioUnitScope inScope,
AudioUnitParameterID inParameterID,
CFArrayRef * outStrings);
@ -117,7 +138,7 @@ public:
AudioUnitScope inScope,
AudioUnitElement inElement,
void * outData);
virtual ComponentResult Initialize();
virtual bool SupportsTail () { return true; }
virtual Float64 GetTailTime() {return (1.0/GetSampleRate())*0.0;} //in SECONDS! gsr * a number = in samples
@ -126,78 +147,126 @@ public:
/*! @method Version */
virtual ComponentResult Version() { return kMasteringVersion; }
private:
protected:
class MasteringKernel : public AUKernelBase // most of the real work happens here
{
public:
MasteringKernel(AUEffectBase *inAudioUnit )
: AUKernelBase(inAudioUnit)
{
}
// *Required* overides for the process method for this effect
// processes one channel of interleaved samples
virtual void Process( const Float32 *inSourceP,
Float32 *inDestP,
UInt32 inFramesToProcess,
UInt32 inNumChannels,
bool &ioSilence);
virtual void Reset();
private:
enum {
pvAL1,
pvSL1,
accSL1,
acc2SL1,
pvAL2,
pvSL2,
accSL2,
acc2SL2,
pvAL3,
pvSL3,
accSL3,
pvAL4,
pvSL4,
gndavgL,
outAL,
gainAL,
air_total
};
double air[air_total];
enum {
prevSampL1,
prevSlewL1,
accSlewL1,
prevSampL2,
prevSlewL2,
accSlewL2,
prevSampL3,
prevSlewL3,
accSlewL3,
kalGainL,
kalOutL,
kalAvgL,
kal_total
};
double kalM[kal_total];
double kalS[kal_total];
long double lastSinewL;
//this is overkill, used to run both Zoom and Sinew stages as they are after
//the summing in StoneFire, which sums three doubles to a long double.
double lastSample; //this doesn't touch the audio unless it's clipping
double intermediate[16];
bool wasPosClip;
bool wasNegClip;
uint32_t fpd;
enum {
pvAL1,
pvSL1,
accSL1,
acc2SL1,
pvAL2,
pvSL2,
accSL2,
acc2SL2,
pvAL3,
pvSL3,
accSL3,
pvAL4,
pvSL4,
gndavgL,
outAL,
gainAL,
pvAR1,
pvSR1,
accSR1,
acc2SR1,
pvAR2,
pvSR2,
accSR2,
acc2SR2,
pvAR3,
pvSR3,
accSR3,
pvAR4,
pvSR4,
gndavgR,
outAR,
gainAR,
air_total
};
double air[air_total];
enum {
prevSampL1,
prevSlewL1,
accSlewL1,
prevSampL2,
prevSlewL2,
accSlewL2,
prevSampL3,
prevSlewL3,
accSlewL3,
kalGainL,
kalOutL,
kalAvgL,
prevSampR1,
prevSlewR1,
accSlewR1,
prevSampR2,
prevSlewR2,
accSlewR2,
prevSampR3,
prevSlewR3,
accSlewR3,
kalGainR,
kalOutR,
kalAvgR,
kal_total
};
double kalM[kal_total];
double kalS[kal_total];
long double lastSinewL;
long double lastSinewR;
//this is overkill, used to run both Zoom and Sinew stages as they are after
//the summing in StoneFire, which sums three doubles to a long double.
double lastSampleL;
double intermediateL[16];
bool wasPosClipL;
bool wasNegClipL;
double lastSampleR;
double intermediateR[16];
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
};
//~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*

View file

@ -251,7 +251,7 @@
<dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array>
<real>186</real>
<real>299</real>
</array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array>
@ -264,19 +264,22 @@
<array>
<string>089C166AFE841209C02AAC07</string>
<string>08FB77ADFE841716C02AAC07</string>
<string>8BA05AEB0720742700365D66</string>
<string>8BA05A7D072073D200365D66</string>
<string>8BA05A7E072073D200365D66</string>
<string>1C37FBAC04509CD000000102</string>
<string>1C37FABC05509CD000000102</string>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
<array>
<integer>20</integer>
<integer>19</integer>
<integer>6</integer>
<integer>5</integer>
<integer>4</integer>
<integer>1</integer>
<integer>0</integer>
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 0}, {186, 445}}</string>
<string>{{0, 0}, {299, 445}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -288,19 +291,19 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {203, 463}}</string>
<string>{{0, 0}, {316, 463}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>186</real>
<real>299</real>
</array>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
<key>Proportion</key>
<string>203pt</string>
<string>316pt</string>
</dict>
<dict>
<key>Dock</key>
@ -311,15 +314,13 @@
<key>PBXProjectModuleGUID</key>
<string>1CE0B20306471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>MyNewFile14.java</string>
<string>&lt;No Editor&gt;</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>1CE0B20406471E060097A5F4</string>
<key>PBXProjectModuleLabel</key>
<string>MyNewFile14.java</string>
</dict>
<key>SplitCount</key>
<string>1</string>
@ -330,14 +331,14 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {580, 269}}</string>
<string>{{0, 0}, {467, 0}}</string>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>269pt</string>
<string>0pt</string>
</dict>
<dict>
<key>ContentConfiguration</key>
@ -350,18 +351,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 274}, {580, 189}}</string>
<string>{{0, 5}, {467, 458}}</string>
<key>RubberWindowFrame</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
<key>Proportion</key>
<string>189pt</string>
<string>458pt</string>
</dict>
</array>
<key>Proportion</key>
<string>580pt</string>
<string>467pt</string>
</dict>
</array>
<key>Name</key>
@ -376,9 +377,9 @@
</array>
<key>TableOfContents</key>
<array>
<string>8B563EC9161B5E170067FE32</string>
<string>8BDD47AA1A48BB8900FB2F61</string>
<string>1CE0B1FE06471DED0097A5F4</string>
<string>8B563ECA161B5E170067FE32</string>
<string>8BDD47AB1A48BB8900FB2F61</string>
<string>1CE0B20306471E060097A5F4</string>
<string>1CE0B20506471E060097A5F4</string>
</array>
@ -517,10 +518,10 @@
<key>WindowOrderList</key>
<array>
<string>8BD3CCBD148831C90062E48C</string>
<string>/Developer/Library/Xcode/Project Templates/System Plug-in/Audio Unit Effect/Audio Unit Effect/StarterAU.xcodeproj</string>
<string>/Developer/Library/Xcode/Project Templates/System Plug-in/Audio Unit Effect/Audio Unit Effect with Cocoa View/StarterAU.xcodeproj</string>
</array>
<key>WindowString</key>
<string>203 321 788 504 0 0 1440 878 </string>
<string>18 337 788 504 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>
@ -597,7 +598,7 @@
<key>TableOfContents</key>
<array>
<string>8BD3CCBD148831C90062E48C</string>
<string>8B563ECB161B5E170067FE32</string>
<string>8BDD47AC1A48BB8900FB2F61</string>
<string>1CD0528F0623707200166675</string>
<string>XCMainBuildResultsModuleGUID</string>
</array>

View file

@ -10,7 +10,7 @@
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
292,
364,
20,
48,
43,
@ -32,7 +32,7 @@
PBXFileTableDataSourceColumnSortingKey = PBXFileDataSource_Filename_ColumnID;
PBXFileTableDataSourceColumnWidthsKey = (
20,
252,
188,
60,
20,
48,
@ -49,14 +49,12 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 750255310;
PBXWorkspaceStateSaveDate = 750255310;
PBXPerProjectTemplateStateSaveDate = 751290936;
PBXWorkspaceStateSaveDate = 751290936;
};
perUserProjectItems = {
8BA3DC492CB5EC1900B899C2 /* PlistBookmark */ = 8BA3DC492CB5EC1900B899C2 /* PlistBookmark */;
8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */ = 8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */;
8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */ = 8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */;
8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */ = 8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */;
8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */ = 8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */;
8BC437832CC7CCED0098AE55 /* PBXTextBookmark */ = 8BC437832CC7CCED0098AE55 /* PBXTextBookmark */;
};
sourceControlManager = 8BD3CCB8148830B20062E48C /* Source Control */;
userBuildSettings = {
@ -64,38 +62,53 @@
};
8BA05A660720730100365D66 /* Mastering.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {822, 7380}}";
sepNavSelRange = "{17032, 0}";
sepNavVisRange = "{15387, 90}";
sepNavWindowFrame = "{{12, 53}, {1040, 821}}";
sepNavIntBoundsRect = "{{0, 0}, {849, 18270}}";
sepNavSelRange = "{31815, 0}";
sepNavVisRange = "{31575, 221}";
sepNavWindowFrame = "{{8, 49}, {1061, 821}}";
};
};
8BA05A690720730100365D66 /* MasteringVersion.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1056, 1062}}";
sepNavSelRange = "{2906, 0}";
sepNavVisRange = "{1069, 1900}";
sepNavWindowFrame = "{{15, 52}, {1040, 821}}";
sepNavSelRange = "{2907, 0}";
sepNavVisRange = "{1070, 1900}";
sepNavWindowFrame = "{{15, 52}, {1061, 821}}";
};
};
8BA3DC492CB5EC1900B899C2 /* PlistBookmark */ = {
isa = PlistBookmark;
fRef = 8D01CCD10486CAD60068D4B7 /* Info.plist */;
fallbackIsa = PBXBookmark;
isK = 0;
kPath = (
CFBundleName,
);
name = /Users/christopherjohnson/Desktop/Mastering/Info.plist;
8BA05A7F072073D200365D66 /* AUBase.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {516, 23430}}";
sepNavSelRange = "{0, 0}";
sepNavVisRange = "{0, 1336}";
};
};
8BC4371D2CC70EE00098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 693";
rLen = 0;
rLoc = 9223372036854775808;
rLoc = 31815;
rType = 0;
vrLen = 252;
vrLoc = 31544;
};
8BC437832CC7CCED0098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 693";
rLen = 0;
rLoc = 31815;
rType = 0;
vrLen = 221;
vrLoc = 31575;
};
8BC6025B073B072D006C4272 /* Mastering.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1056, 3132}}";
sepNavSelRange = "{3665, 0}";
sepNavVisRange = "{2605, 1167}";
sepNavWindowFrame = "{{38, 57}, {1040, 821}}";
sepNavIntBoundsRect = "{{0, 0}, {1146, 4950}}";
sepNavSelRange = "{7725, 0}";
sepNavVisRange = "{7429, 835}";
sepNavWindowFrame = "{{26, 47}, {1061, 821}}";
};
};
8BD3CCB8148830B20062E48C /* Source Control */ = {
@ -112,36 +125,6 @@
isa = PBXCodeSenseManager;
indexTemplatePath = "";
};
8BF17B272CB7FB4400FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 347";
rLen = 0;
rLoc = 17032;
rType = 0;
vrLen = 38;
vrLoc = 15492;
};
8BF17B702CB7FF3300FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BC6025B073B072D006C4272 /* Mastering.h */;
name = "Mastering.h: 65";
rLen = 0;
rLoc = 3252;
rType = 0;
vrLen = 52;
vrLoc = 3253;
};
8BF17B712CB7FF3300FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 8BA05A660720730100365D66 /* Mastering.cpp */;
name = "Mastering.cpp: 347";
rLen = 0;
rLoc = 17032;
rType = 0;
vrLen = 90;
vrLoc = 15387;
};
8D01CCC60486CAD60068D4B7 /* Mastering */ = {
activeExec = 0;
};

View file

@ -178,7 +178,7 @@
<key>FavBarConfig</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274F1D46E5A5000176F0</string>
<string>8BC435772CC6F8650098AE55</string>
<key>XCBarModuleItemNames</key>
<dict/>
<key>XCBarModuleItems</key>
@ -225,8 +225,8 @@
<array/>
<key>PerspectiveWidths</key>
<array>
<integer>841</integer>
<integer>841</integer>
<integer>810</integer>
<integer>810</integer>
</array>
<key>Perspectives</key>
<array>
@ -282,7 +282,7 @@
<dict>
<key>PBXSmartGroupTreeModuleColumnWidthsKey</key>
<array>
<real>288</real>
<real>185</real>
</array>
<key>PBXSmartGroupTreeModuleColumnsKey_v4</key>
<array>
@ -296,8 +296,6 @@
<string>089C166AFE841209C02AAC07</string>
<string>08FB77ADFE841716C02AAC07</string>
<string>8BA05A56072072A900365D66</string>
<string>089C167CFE841241C02AAC07</string>
<string>1C37FBAC04509CD000000102</string>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateSelectionKey</key>
<array>
@ -309,7 +307,7 @@
</array>
</array>
<key>PBXSmartGroupTreeModuleOutlineStateVisibleRectKey</key>
<string>{{0, 0}, {288, 595}}</string>
<string>{{0, 0}, {185, 428}}</string>
</dict>
<key>PBXTopSmartGroupGIDs</key>
<array/>
@ -319,19 +317,19 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {305, 613}}</string>
<string>{{0, 0}, {202, 446}}</string>
<key>GroupTreeTableConfiguration</key>
<array>
<string>MainColumn</string>
<real>288</real>
<real>185</real>
</array>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
<key>Proportion</key>
<string>305pt</string>
<string>202pt</string>
</dict>
<dict>
<key>Dock</key>
@ -340,7 +338,7 @@
<key>ContentConfiguration</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274A1D46E5A5000176F0</string>
<string>8BC435722CC6F8650098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>Mastering.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
@ -348,18 +346,16 @@
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BD7274B1D46E5A5000176F0</string>
<string>8BC435732CC6F8650098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>Mastering.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BF17B712CB7FF3300FAAF3F</string>
<string>8BC437832CC7CCED0098AE55</string>
<key>history</key>
<array>
<string>8BA3DC492CB5EC1900B899C2</string>
<string>8BF17B702CB7FF3300FAAF3F</string>
<string>8BF17B272CB7FB4400FAAF3F</string>
<string>8BC4371D2CC70EE00098AE55</string>
</array>
</dict>
<key>SplitCount</key>
@ -373,18 +369,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {531, 56}}</string>
<string>{{0, 0}, {603, 86}}</string>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>56pt</string>
<string>86pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>552pt</string>
<string>355pt</string>
<key>Tabs</key>
<array>
<dict>
@ -398,9 +394,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {531, 525}}</string>
<string>{{10, 27}, {603, 328}}</string>
<key>RubberWindowFrame</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -454,7 +450,7 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {531, 507}}</string>
<string>{{10, 27}, {603, 282}}</string>
</dict>
<key>Module</key>
<string>PBXBuildResultsModule</string>
@ -463,7 +459,7 @@
</dict>
</array>
<key>Proportion</key>
<string>531pt</string>
<string>603pt</string>
</dict>
</array>
<key>Name</key>
@ -482,11 +478,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>8BF17B722CB7FF3300FAAF3F</string>
<string>8BC437842CC7CCED0098AE55</string>
<string>1CA23ED40692098700951B8B</string>
<string>8BF17B732CB7FF3300FAAF3F</string>
<string>8BD7274A1D46E5A5000176F0</string>
<string>8BF17B742CB7FF3300FAAF3F</string>
<string>8BC437852CC7CCED0098AE55</string>
<string>8BC435722CC6F8650098AE55</string>
<string>8BC437862CC7CCED0098AE55</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -523,7 +519,7 @@
<key>Identifier</key>
<string>perspective.debug</string>
<key>IsVertical</key>
<true/>
<integer>1</integer>
<key>Layout</key>
<array>
<dict>
@ -542,7 +538,7 @@
<key>Module</key>
<string>PBXDebugCLIModule</string>
<key>Proportion</key>
<string>0pt</string>
<string>0%</string>
</dict>
<dict>
<key>ContentConfiguration</key>
@ -561,8 +557,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {395, 214}}</string>
<string>{{395, 0}, {415, 214}}</string>
<string>{{0, 0}, {395, 213}}</string>
<string>{{395, 0}, {415, 213}}</string>
</array>
</dict>
<key>VerticalSplitView</key>
@ -577,8 +573,8 @@
<string>yes</string>
<key>sizes</key>
<array>
<string>{{0, 0}, {810, 214}}</string>
<string>{{0, 214}, {810, 227}}</string>
<string>{{0, 0}, {810, 213}}</string>
<string>{{0, 213}, {810, 225}}</string>
</array>
</dict>
</dict>
@ -591,6 +587,8 @@
</dict>
<key>GeometryConfiguration</key>
<dict>
<key>DebugConsoleDrawerSize</key>
<string>{100, 120}</string>
<key>DebugConsoleVisible</key>
<string>None</string>
<key>DebugConsoleWindowFrame</key>
@ -598,54 +596,32 @@
<key>DebugSTDIOWindowFrame</key>
<string>{{200, 200}, {500, 300}}</string>
<key>Frame</key>
<string>{{0, 5}, {810, 441}}</string>
<key>PBXDebugSessionStackFrameViewKey</key>
<dict>
<key>DebugVariablesTableConfiguration</key>
<array>
<string>Name</string>
<real>120</real>
<string>Value</string>
<real>85</real>
<string>Summary</string>
<real>185</real>
</array>
<key>Frame</key>
<string>{{395, 0}, {415, 214}}</string>
</dict>
<string>{{0, 7}, {810, 438}}</string>
</dict>
<key>Module</key>
<string>PBXDebugSessionModule</string>
<key>Proportion</key>
<string>441pt</string>
<string>443pt</string>
</dict>
</array>
<key>Name</key>
<string>Debug</string>
<key>ServiceClasses</key>
<array>
<string>XCModuleDock</string>
<string>XCModuleDock</string>
<string>PBXDebugCLIModule</string>
<string>PBXDebugSessionModule</string>
<string>PBXDebugProcessAndThreadModule</string>
<string>PBXDebugProcessViewModule</string>
<string>PBXDebugThreadViewModule</string>
<string>PBXDebugStackFrameViewModule</string>
<string>PBXNavigatorGroup</string>
<string>XCConsole</string>
</array>
<key>TableOfContents</key>
<array>
<string>8BD727EC1D46ECF1000176F0</string>
<string>1CC8E6A5069209BD00BB180A</string>
<string>1CC8E6A6069209BD00BB180A</string>
<string>1CCC7628064C1048000F2A68</string>
<string>1CCC7629064C1048000F2A68</string>
<string>8BD727ED1D46ECF1000176F0</string>
<string>8BD727EE1D46ECF1000176F0</string>
<string>8BD727EF1D46ECF1000176F0</string>
<string>8BD727F01D46ECF1000176F0</string>
<string>8BD727E71D46ECD9000176F0</string>
<string>1CC8E6A7069209BD00BB180A</string>
</array>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarConfiguration</key>
<string>xcode.toolbar.config.debugV3</string>
</dict>
@ -659,7 +635,7 @@
<key>StatusbarIsVisible</key>
<true/>
<key>TimeStamp</key>
<real>750255923.53302801</real>
<real>751291629.93373895</real>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarDisplayMode</key>
@ -676,11 +652,11 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>8BF17B752CB7FF3300FAAF3F</string>
<string>8BC437872CC7CCED0098AE55</string>
<string>/Users/christopherjohnson/Desktop/airwindows/plugins/MacAU/Mastering/Mastering.xcodeproj</string>
</array>
<key>WindowString</key>
<string>8 177 841 654 0 0 1440 878 </string>
<string>0 299 810 487 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View file

@ -3,7 +3,7 @@
*
* Version: 1.0
*
* Created: 10/8/24
* Created: 10/21/24
*
* Copyright: Copyright © 2024 Airwindows, Airwindows uses the MIT license
*

View file

@ -0,0 +1,5 @@
//
// Prefix header for all source files of the '«PROJECTNAMEASIDENTIFIER»' target in the '«PROJECTNAMEASIDENTIFIER»' project.
//
#include <CoreServices/CoreServices.h>

View file

@ -51,13 +51,16 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 750255314;
PBXWorkspaceStateSaveDate = 750255314;
PBXPerProjectTemplateStateSaveDate = 751291914;
PBXWorkspaceStateSaveDate = 751291914;
};
perUserProjectItems = {
8BC437242CC70EF00098AE55 /* PBXTextBookmark */ = 8BC437242CC70EF00098AE55 /* PBXTextBookmark */;
8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */ = 8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */;
8BC437962CC7CE130098AE55 /* PBXBookmark */ = 8BC437962CC7CE130098AE55 /* PBXBookmark */;
8BC437A32CC7CE520098AE55 /* PBXTextBookmark */ = 8BC437A32CC7CE520098AE55 /* PBXTextBookmark */;
8BC437A92CC7CE520098AE55 /* PBXTextBookmark */ = 8BC437A92CC7CE520098AE55 /* PBXTextBookmark */;
8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */ = 8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */;
8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */ = 8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */;
8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */ = 8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */;
};
sourceControlManager = 8B02375E1D42B1C400E1E8C8 /* Source Control */;
userBuildSettings = {
@ -65,17 +68,17 @@
};
2407DEB6089929BA00EB68BF /* Mastering.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {848, 3330}}";
sepNavSelRange = "{5220, 0}";
sepNavVisRange = "{5828, 1821}";
sepNavWindowFrame = "{{702, 47}, {895, 831}}";
sepNavIntBoundsRect = "{{0, 0}, {948, 4860}}";
sepNavSelRange = "{7531, 13}";
sepNavVisRange = "{739, 942}";
sepNavWindowFrame = "{{545, 47}, {895, 831}}";
};
};
245463B80991757100464AD3 /* Mastering.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1110, 2880}}";
sepNavSelRange = "{3289, 0}";
sepNavVisRange = "{3111, 702}";
sepNavIntBoundsRect = "{{0, 0}, {554, 3600}}";
sepNavSelRange = "{528, 0}";
sepNavVisRange = "{0, 0}";
sepNavWindowFrame = "{{545, 47}, {895, 831}}";
};
};
@ -89,9 +92,9 @@
};
24D8286F09A914000093AEF8 /* MasteringProc.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {714, 10530}}";
sepNavSelRange = "{16048, 0}";
sepNavVisRange = "{15306, 97}";
sepNavIntBoundsRect = "{{0, 0}, {1056, 23598}}";
sepNavSelRange = "{31210, 0}";
sepNavVisRange = "{803, 1981}";
sepNavWindowFrame = "{{543, 47}, {895, 831}}";
};
};
@ -109,36 +112,60 @@
isa = PBXCodeSenseManager;
indexTemplatePath = "";
};
8BC437242CC70EF00098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 31418;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 245463B80991757100464AD3 /* Mastering.h */;
name = "Mastering.h: 29";
rLen = 0;
rLoc = 528;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC437962CC7CE130098AE55 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
};
8BC437A32CC7CE520098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 245463B80991757100464AD3 /* Mastering.h */;
name = "Mastering.h: 29";
rLen = 0;
rLoc = 528;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC437A92CC7CE520098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 699";
rLen = 0;
rLoc = 31210;
rType = 0;
vrLen = 1981;
vrLoc = 803;
};
8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 2407DEB6089929BA00EB68BF /* Mastering.cpp */;
name = "Mastering.cpp: 29";
rLen = 0;
rLoc = 707;
rLoc = 717;
rType = 0;
vrLen = 356;
vrLoc = 5826;
};
8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 16048;
rType = 0;
vrLen = 126;
vrLoc = 15253;
};
8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 16048;
rType = 0;
vrLen = 97;
vrLoc = 15306;
};
8D01CCC60486CAD60068D4B7 /* Mastering */ = {
activeExec = 0;
};

View file

@ -222,7 +222,48 @@
</dict>
</array>
<key>OpenEditors</key>
<array/>
<array>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BC437A72CC7CE520098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BC437A82CC7CE520098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BC437A92CC7CE520098AE55</string>
<key>history</key>
<array>
<string>8BC437962CC7CE130098AE55</string>
</array>
</dict>
<key>SplitCount</key>
<string>1</string>
</dict>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {895, 734}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>543 103 895 775 0 0 1440 878 </string>
</dict>
</dict>
</array>
<key>PerspectiveWidths</key>
<array>
<integer>810</integer>
@ -323,7 +364,7 @@
<real>185</real>
</array>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
@ -339,7 +380,7 @@
<key>PBXProjectModuleGUID</key>
<string>8B0237581D42B1C400E1E8C8</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<string>Mastering.h</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
@ -347,15 +388,16 @@
<key>PBXProjectModuleGUID</key>
<string>8B0237591D42B1C400E1E8C8</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<string>Mastering.h</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BF17B6B2CB7FF3200FAAF3F</string>
<string>8BC437A32CC7CE520098AE55</string>
<key>history</key>
<array>
<string>8BF17AF32CB7F7B000FAAF3F</string>
<string>8BF17B6A2CB7FF3200FAAF3F</string>
<string>8BC437242CC70EF00098AE55</string>
<string>8BC4377F2CC7CCEC0098AE55</string>
</array>
</dict>
<key>SplitCount</key>
@ -369,18 +411,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {603, 86}}</string>
<string>{{0, 0}, {603, 0}}</string>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>86pt</string>
<string>0pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>355pt</string>
<string>441pt</string>
<key>Tabs</key>
<array>
<dict>
@ -394,9 +436,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {603, 328}}</string>
<string>{{10, 27}, {603, 414}}</string>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -478,11 +520,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>8BF17B6C2CB7FF3200FAAF3F</string>
<string>8BC437A42CC7CE520098AE55</string>
<string>1CA23ED40692098700951B8B</string>
<string>8BF17B6D2CB7FF3200FAAF3F</string>
<string>8BC437A52CC7CE520098AE55</string>
<string>8B0237581D42B1C400E1E8C8</string>
<string>8BF17B6E2CB7FF3200FAAF3F</string>
<string>8BC437A62CC7CE520098AE55</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -655,7 +697,7 @@
<key>StatusbarIsVisible</key>
<true/>
<key>TimeStamp</key>
<real>750255922.06214201</real>
<real>751291986.86297703</real>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarDisplayMode</key>
@ -672,11 +714,11 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>8BF17B6F2CB7FF3200FAAF3F</string>
<string>/Users/christopherjohnson/Desktop/airwindows/plugins/MacVST/Mastering/Mastering.xcodeproj</string>
<string>8BC437A72CC7CE520098AE55</string>
</array>
<key>WindowString</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View file

@ -12,15 +12,15 @@
24CFB70407E7A0220081BD57 /* PkgInfo in Resources */ = {isa = PBXBuildFile; fileRef = 24CFB70307E7A0220081BD57 /* PkgInfo */; };
24D8287009A914000093AEF8 /* MasteringProc.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */; };
24D8287F09A9164A0093AEF8 /* xcode_vst_prefix.h in Headers */ = {isa = PBXBuildFile; fileRef = 24D8287E09A9164A0093AEF8 /* xcode_vst_prefix.h */; };
8B5A01292CB8542B00E1C37C /* vstfxstore.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A011D2CB8542B00E1C37C /* vstfxstore.h */; };
8B5A012A2CB8542B00E1C37C /* aeffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A011E2CB8542B00E1C37C /* aeffect.h */; };
8B5A012B2CB8542B00E1C37C /* aeffectx.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A011F2CB8542B00E1C37C /* aeffectx.h */; };
8B5A012C2CB8542B00E1C37C /* audioeffectx.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A01232CB8542B00E1C37C /* audioeffectx.h */; };
8B5A012D2CB8542B00E1C37C /* audioeffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B5A01242CB8542B00E1C37C /* audioeffect.cpp */; };
8B5A012E2CB8542B00E1C37C /* audioeffectx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B5A01252CB8542B00E1C37C /* audioeffectx.cpp */; };
8B5A012F2CB8542B00E1C37C /* aeffeditor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A01262CB8542B00E1C37C /* aeffeditor.h */; };
8B5A01302CB8542B00E1C37C /* vstplugmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B5A01272CB8542B00E1C37C /* vstplugmain.cpp */; };
8B5A01312CB8542B00E1C37C /* audioeffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B5A01282CB8542B00E1C37C /* audioeffect.h */; };
8B0FB94A2CC849930015BC09 /* vstfxstore.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB93E2CC849930015BC09 /* vstfxstore.h */; };
8B0FB94B2CC849930015BC09 /* aeffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB93F2CC849930015BC09 /* aeffect.h */; };
8B0FB94C2CC849930015BC09 /* aeffectx.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB9402CC849930015BC09 /* aeffectx.h */; };
8B0FB94D2CC849930015BC09 /* audioeffectx.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB9442CC849930015BC09 /* audioeffectx.h */; };
8B0FB94E2CC849930015BC09 /* audioeffect.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B0FB9452CC849930015BC09 /* audioeffect.cpp */; };
8B0FB94F2CC849930015BC09 /* audioeffectx.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B0FB9462CC849930015BC09 /* audioeffectx.cpp */; };
8B0FB9502CC849930015BC09 /* aeffeditor.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB9472CC849930015BC09 /* aeffeditor.h */; };
8B0FB9512CC849930015BC09 /* vstplugmain.cpp in Sources */ = {isa = PBXBuildFile; fileRef = 8B0FB9482CC849930015BC09 /* vstplugmain.cpp */; };
8B0FB9522CC849930015BC09 /* audioeffect.h in Headers */ = {isa = PBXBuildFile; fileRef = 8B0FB9492CC849930015BC09 /* audioeffect.h */; };
/* End PBXBuildFile section */
/* Begin PBXFileReference section */
@ -30,15 +30,15 @@
24CFB70307E7A0220081BD57 /* PkgInfo */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text; name = PkgInfo; path = mac/PkgInfo; sourceTree = "<group>"; };
24D8286F09A914000093AEF8 /* MasteringProc.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; name = MasteringProc.cpp; path = source/MasteringProc.cpp; sourceTree = "<group>"; };
24D8287E09A9164A0093AEF8 /* xcode_vst_prefix.h */ = {isa = PBXFileReference; fileEncoding = 30; lastKnownFileType = sourcecode.c.h; name = xcode_vst_prefix.h; path = mac/xcode_vst_prefix.h; sourceTree = SOURCE_ROOT; };
8B5A011D2CB8542B00E1C37C /* vstfxstore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vstfxstore.h; sourceTree = "<group>"; };
8B5A011E2CB8542B00E1C37C /* aeffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffect.h; sourceTree = "<group>"; };
8B5A011F2CB8542B00E1C37C /* aeffectx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffectx.h; sourceTree = "<group>"; };
8B5A01232CB8542B00E1C37C /* audioeffectx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audioeffectx.h; sourceTree = "<group>"; };
8B5A01242CB8542B00E1C37C /* audioeffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audioeffect.cpp; sourceTree = "<group>"; };
8B5A01252CB8542B00E1C37C /* audioeffectx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audioeffectx.cpp; sourceTree = "<group>"; };
8B5A01262CB8542B00E1C37C /* aeffeditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffeditor.h; sourceTree = "<group>"; };
8B5A01272CB8542B00E1C37C /* vstplugmain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vstplugmain.cpp; sourceTree = "<group>"; };
8B5A01282CB8542B00E1C37C /* audioeffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audioeffect.h; sourceTree = "<group>"; };
8B0FB93E2CC849930015BC09 /* vstfxstore.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = vstfxstore.h; sourceTree = "<group>"; };
8B0FB93F2CC849930015BC09 /* aeffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffect.h; sourceTree = "<group>"; };
8B0FB9402CC849930015BC09 /* aeffectx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffectx.h; sourceTree = "<group>"; };
8B0FB9442CC849930015BC09 /* audioeffectx.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audioeffectx.h; sourceTree = "<group>"; };
8B0FB9452CC849930015BC09 /* audioeffect.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audioeffect.cpp; sourceTree = "<group>"; };
8B0FB9462CC849930015BC09 /* audioeffectx.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = audioeffectx.cpp; sourceTree = "<group>"; };
8B0FB9472CC849930015BC09 /* aeffeditor.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = aeffeditor.h; sourceTree = "<group>"; };
8B0FB9482CC849930015BC09 /* vstplugmain.cpp */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.cpp.cpp; path = vstplugmain.cpp; sourceTree = "<group>"; };
8B0FB9492CC849930015BC09 /* audioeffect.h */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = sourcecode.c.h; path = audioeffect.h; sourceTree = "<group>"; };
8D01CCD10486CAD60068D4B7 /* Info.plist */ = {isa = PBXFileReference; fileEncoding = 4; lastKnownFileType = text.plist.xml; name = Info.plist; path = mac/Info.plist; sourceTree = "<group>"; };
/* End PBXFileReference section */
@ -66,7 +66,7 @@
08FB77ADFE841716C02AAC07 /* Source */ = {
isa = PBXGroup;
children = (
8B5A011A2CB8542B00E1C37C /* vstsdk2.4 */,
8B0FB93B2CC849930015BC09 /* vstsdk2.4 */,
2407DEB6089929BA00EB68BF /* Mastering.cpp */,
24D8286F09A914000093AEF8 /* MasteringProc.cpp */,
245463B80991757100464AD3 /* Mastering.h */,
@ -82,59 +82,59 @@
name = Products;
sourceTree = "<group>";
};
8B5A011A2CB8542B00E1C37C /* vstsdk2.4 */ = {
8B0FB93B2CC849930015BC09 /* vstsdk2.4 */ = {
isa = PBXGroup;
children = (
8B5A011B2CB8542B00E1C37C /* pluginterfaces */,
8B5A01202CB8542B00E1C37C /* public.sdk */,
8B0FB93C2CC849930015BC09 /* pluginterfaces */,
8B0FB9412CC849930015BC09 /* public.sdk */,
);
name = vstsdk2.4;
path = ../../../../vstsdk2.4;
sourceTree = "<group>";
};
8B5A011B2CB8542B00E1C37C /* pluginterfaces */ = {
8B0FB93C2CC849930015BC09 /* pluginterfaces */ = {
isa = PBXGroup;
children = (
8B5A011C2CB8542B00E1C37C /* vst2.x */,
8B0FB93D2CC849930015BC09 /* vst2.x */,
);
path = pluginterfaces;
sourceTree = "<group>";
};
8B5A011C2CB8542B00E1C37C /* vst2.x */ = {
8B0FB93D2CC849930015BC09 /* vst2.x */ = {
isa = PBXGroup;
children = (
8B5A011D2CB8542B00E1C37C /* vstfxstore.h */,
8B5A011E2CB8542B00E1C37C /* aeffect.h */,
8B5A011F2CB8542B00E1C37C /* aeffectx.h */,
8B0FB93E2CC849930015BC09 /* vstfxstore.h */,
8B0FB93F2CC849930015BC09 /* aeffect.h */,
8B0FB9402CC849930015BC09 /* aeffectx.h */,
);
path = vst2.x;
sourceTree = "<group>";
};
8B5A01202CB8542B00E1C37C /* public.sdk */ = {
8B0FB9412CC849930015BC09 /* public.sdk */ = {
isa = PBXGroup;
children = (
8B5A01212CB8542B00E1C37C /* source */,
8B0FB9422CC849930015BC09 /* source */,
);
path = public.sdk;
sourceTree = "<group>";
};
8B5A01212CB8542B00E1C37C /* source */ = {
8B0FB9422CC849930015BC09 /* source */ = {
isa = PBXGroup;
children = (
8B5A01222CB8542B00E1C37C /* vst2.x */,
8B0FB9432CC849930015BC09 /* vst2.x */,
);
path = source;
sourceTree = "<group>";
};
8B5A01222CB8542B00E1C37C /* vst2.x */ = {
8B0FB9432CC849930015BC09 /* vst2.x */ = {
isa = PBXGroup;
children = (
8B5A01232CB8542B00E1C37C /* audioeffectx.h */,
8B5A01242CB8542B00E1C37C /* audioeffect.cpp */,
8B5A01252CB8542B00E1C37C /* audioeffectx.cpp */,
8B5A01262CB8542B00E1C37C /* aeffeditor.h */,
8B5A01272CB8542B00E1C37C /* vstplugmain.cpp */,
8B5A01282CB8542B00E1C37C /* audioeffect.h */,
8B0FB9442CC849930015BC09 /* audioeffectx.h */,
8B0FB9452CC849930015BC09 /* audioeffect.cpp */,
8B0FB9462CC849930015BC09 /* audioeffectx.cpp */,
8B0FB9472CC849930015BC09 /* aeffeditor.h */,
8B0FB9482CC849930015BC09 /* vstplugmain.cpp */,
8B0FB9492CC849930015BC09 /* audioeffect.h */,
);
path = vst2.x;
sourceTree = "<group>";
@ -146,14 +146,14 @@
isa = PBXHeadersBuildPhase;
buildActionMask = 2147483647;
files = (
8B5A012F2CB8542B00E1C37C /* aeffeditor.h in Headers */,
8B0FB9502CC849930015BC09 /* aeffeditor.h in Headers */,
245463B90991757100464AD3 /* Mastering.h in Headers */,
8B5A01312CB8542B00E1C37C /* audioeffect.h in Headers */,
8B5A012A2CB8542B00E1C37C /* aeffect.h in Headers */,
8B0FB9522CC849930015BC09 /* audioeffect.h in Headers */,
8B0FB94B2CC849930015BC09 /* aeffect.h in Headers */,
24D8287F09A9164A0093AEF8 /* xcode_vst_prefix.h in Headers */,
8B5A012C2CB8542B00E1C37C /* audioeffectx.h in Headers */,
8B5A01292CB8542B00E1C37C /* vstfxstore.h in Headers */,
8B5A012B2CB8542B00E1C37C /* aeffectx.h in Headers */,
8B0FB94D2CC849930015BC09 /* audioeffectx.h in Headers */,
8B0FB94A2CC849930015BC09 /* vstfxstore.h in Headers */,
8B0FB94C2CC849930015BC09 /* aeffectx.h in Headers */,
);
runOnlyForDeploymentPostprocessing = 0;
};
@ -193,9 +193,9 @@
hasScannedForEncodings = 1;
knownRegions = (
Base,
en,
fr,
de,
en,
ja,
);
mainGroup = 089C166AFE841209C02AAC07 /* FM-Chopper */;
@ -240,10 +240,10 @@
isa = PBXSourcesBuildPhase;
buildActionMask = 2147483647;
files = (
8B5A012E2CB8542B00E1C37C /* audioeffectx.cpp in Sources */,
8B0FB94F2CC849930015BC09 /* audioeffectx.cpp in Sources */,
2407DEB9089929BA00EB68BF /* Mastering.cpp in Sources */,
8B5A012D2CB8542B00E1C37C /* audioeffect.cpp in Sources */,
8B5A01302CB8542B00E1C37C /* vstplugmain.cpp in Sources */,
8B0FB94E2CC849930015BC09 /* audioeffect.cpp in Sources */,
8B0FB9512CC849930015BC09 /* vstplugmain.cpp in Sources */,
24D8287009A914000093AEF8 /* MasteringProc.cpp in Sources */,
);
runOnlyForDeploymentPostprocessing = 0;

View file

@ -21,6 +21,7 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
G = 0.5;
H = 0.5;
I = 0.0;
J = 1.0;
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
@ -36,6 +37,62 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
//this is reset: values being initialized only once. Startup values, whatever they are.
@ -78,6 +135,7 @@ VstInt32 Mastering::getChunk (void** data, bool isPreset)
chunkData[6] = G;
chunkData[7] = H;
chunkData[8] = I;
chunkData[9] = J;
/* 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. */
@ -98,6 +156,7 @@ VstInt32 Mastering::setChunk (void* data, VstInt32 byteSize, bool isPreset)
G = pinParameter(chunkData[6]);
H = pinParameter(chunkData[7]);
I = pinParameter(chunkData[8]);
J = pinParameter(chunkData[9]);
/* We're ignoring byteSize as we found it to be a filthy liar */
/* calculate any other fields you need here - you could copy in
@ -116,6 +175,7 @@ void Mastering::setParameter(VstInt32 index, float value) {
case kParamG: G = value; break;
case kParamH: H = value; break;
case kParamI: I = value; break;
case kParamJ: J = value; break;
default: throw; // unknown parameter, shouldn't happen!
}
}
@ -131,6 +191,7 @@ float Mastering::getParameter(VstInt32 index) {
case kParamG: return G; break;
case kParamH: return H; break;
case kParamI: return I; break;
case kParamJ: return J; break;
default: break; // unknown parameter, shouldn't happen!
} return 0.0; //we only need to update the relevant name, this is simple to manage
}
@ -146,6 +207,7 @@ void Mastering::getParameterName(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "Zoom", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "DarkF", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "Ratio", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "Dither", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} //this is our labels for displaying in the VST host
}
@ -161,6 +223,15 @@ void Mastering::getParameterDisplay(VstInt32 index, char *text) {
case kParamG: float2string (G, text, kVstMaxParamStrLen); break;
case kParamH: float2string (H, text, kVstMaxParamStrLen); break;
case kParamI: float2string (I, text, kVstMaxParamStrLen); break;
case kParamJ: switch((VstInt32)( J * 5.999 )) //0 to almost edge of # of params
{ case 0: vst_strncpy (text, "Dark", kVstMaxParamStrLen); break;
case 1: vst_strncpy (text, "TenNines", kVstMaxParamStrLen); break;
case 2: vst_strncpy (text, "TPDFWde", kVstMaxParamStrLen); break;
case 3: vst_strncpy (text, "PaulWde", kVstMaxParamStrLen); break;
case 4: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break;
case 5: vst_strncpy (text, "Bypass", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} break; //completed consoletype 'popup' parameter, exit
default: break; // unknown parameter, shouldn't happen!
} //this displays the values and handles 'popups' where it's discrete choices
}
@ -176,6 +247,7 @@ void Mastering::getParameterLabel(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
}
}

View file

@ -25,7 +25,8 @@ enum {
kParamG =6,
kParamH =7,
kParamI =8,
kNumParameters = 9
kParamJ =9,
kNumParameters = 10
}; //
const int kNumPrograms = 0;
@ -69,6 +70,7 @@ private:
float G;
float H;
float I;
float J;
enum {
pvAL1,
@ -151,6 +153,41 @@ private:
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
//default stuff

View file

@ -36,6 +36,10 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
@ -270,14 +274,388 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit stereo floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;
@ -318,7 +696,11 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
double inputSampleL = *in1;
@ -552,14 +934,388 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 64 bit stereo floating point dither
int expon; frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 64 bit stereo floating point dither
frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;

View file

@ -51,13 +51,16 @@
PBXFileDataSource_Warnings_ColumnID,
);
};
PBXPerProjectTemplateStateSaveDate = 750255314;
PBXWorkspaceStateSaveDate = 750255314;
PBXPerProjectTemplateStateSaveDate = 751291914;
PBXWorkspaceStateSaveDate = 751291914;
};
perUserProjectItems = {
8BC437242CC70EF00098AE55 /* PBXTextBookmark */ = 8BC437242CC70EF00098AE55 /* PBXTextBookmark */;
8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */ = 8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */;
8BC437962CC7CE130098AE55 /* PBXBookmark */ = 8BC437962CC7CE130098AE55 /* PBXBookmark */;
8BC437A32CC7CE520098AE55 /* PBXTextBookmark */ = 8BC437A32CC7CE520098AE55 /* PBXTextBookmark */;
8BC437A92CC7CE520098AE55 /* PBXTextBookmark */ = 8BC437A92CC7CE520098AE55 /* PBXTextBookmark */;
8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */ = 8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */;
8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */ = 8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */;
8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */ = 8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */;
};
sourceControlManager = 8B02375E1D42B1C400E1E8C8 /* Source Control */;
userBuildSettings = {
@ -65,17 +68,17 @@
};
2407DEB6089929BA00EB68BF /* Mastering.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {848, 3330}}";
sepNavSelRange = "{5220, 0}";
sepNavVisRange = "{5828, 1821}";
sepNavWindowFrame = "{{702, 47}, {895, 831}}";
sepNavIntBoundsRect = "{{0, 0}, {948, 4860}}";
sepNavSelRange = "{7531, 13}";
sepNavVisRange = "{739, 942}";
sepNavWindowFrame = "{{545, 47}, {895, 831}}";
};
};
245463B80991757100464AD3 /* Mastering.h */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {1110, 2880}}";
sepNavSelRange = "{3289, 0}";
sepNavVisRange = "{3111, 702}";
sepNavIntBoundsRect = "{{0, 0}, {554, 3600}}";
sepNavSelRange = "{528, 0}";
sepNavVisRange = "{0, 0}";
sepNavWindowFrame = "{{545, 47}, {895, 831}}";
};
};
@ -89,9 +92,9 @@
};
24D8286F09A914000093AEF8 /* MasteringProc.cpp */ = {
uiCtxt = {
sepNavIntBoundsRect = "{{0, 0}, {714, 10530}}";
sepNavSelRange = "{16048, 0}";
sepNavVisRange = "{15306, 97}";
sepNavIntBoundsRect = "{{0, 0}, {1056, 23598}}";
sepNavSelRange = "{31210, 0}";
sepNavVisRange = "{803, 1981}";
sepNavWindowFrame = "{{543, 47}, {895, 831}}";
};
};
@ -109,36 +112,60 @@
isa = PBXCodeSenseManager;
indexTemplatePath = "";
};
8BC437242CC70EF00098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 31418;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC4377F2CC7CCEC0098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 245463B80991757100464AD3 /* Mastering.h */;
name = "Mastering.h: 29";
rLen = 0;
rLoc = 528;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC437962CC7CE130098AE55 /* PBXBookmark */ = {
isa = PBXBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
};
8BC437A32CC7CE520098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 245463B80991757100464AD3 /* Mastering.h */;
name = "Mastering.h: 29";
rLen = 0;
rLoc = 528;
rType = 0;
vrLen = 0;
vrLoc = 0;
};
8BC437A92CC7CE520098AE55 /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 699";
rLen = 0;
rLoc = 31210;
rType = 0;
vrLen = 1981;
vrLoc = 803;
};
8BF17AF32CB7F7B000FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 2407DEB6089929BA00EB68BF /* Mastering.cpp */;
name = "Mastering.cpp: 29";
rLen = 0;
rLoc = 707;
rLoc = 717;
rType = 0;
vrLen = 356;
vrLoc = 5826;
};
8BF17B6A2CB7FF3200FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 16048;
rType = 0;
vrLen = 126;
vrLoc = 15253;
};
8BF17B6B2CB7FF3200FAAF3F /* PBXTextBookmark */ = {
isa = PBXTextBookmark;
fRef = 24D8286F09A914000093AEF8 /* MasteringProc.cpp */;
name = "MasteringProc.cpp: 325";
rLen = 0;
rLoc = 16048;
rType = 0;
vrLen = 97;
vrLoc = 15306;
};
8D01CCC60486CAD60068D4B7 /* Mastering */ = {
activeExec = 0;
};

View file

@ -222,7 +222,48 @@
</dict>
</array>
<key>OpenEditors</key>
<array/>
<array>
<dict>
<key>Content</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BC437A72CC7CE520098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
<dict>
<key>PBXProjectModuleGUID</key>
<string>8BC437A82CC7CE520098AE55</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BC437A92CC7CE520098AE55</string>
<key>history</key>
<array>
<string>8BC437962CC7CE130098AE55</string>
</array>
</dict>
<key>SplitCount</key>
<string>1</string>
</dict>
<key>StatusBarVisibility</key>
<true/>
</dict>
<key>Geometry</key>
<dict>
<key>Frame</key>
<string>{{0, 20}, {895, 734}}</string>
<key>PBXModuleWindowStatusBarHidden2</key>
<false/>
<key>RubberWindowFrame</key>
<string>543 103 895 775 0 0 1440 878 </string>
</dict>
</dict>
</array>
<key>PerspectiveWidths</key>
<array>
<integer>810</integer>
@ -323,7 +364,7 @@
<real>185</real>
</array>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXSmartGroupTreeModule</string>
@ -339,7 +380,7 @@
<key>PBXProjectModuleGUID</key>
<string>8B0237581D42B1C400E1E8C8</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<string>Mastering.h</string>
<key>PBXSplitModuleInNavigatorKey</key>
<dict>
<key>Split0</key>
@ -347,15 +388,16 @@
<key>PBXProjectModuleGUID</key>
<string>8B0237591D42B1C400E1E8C8</string>
<key>PBXProjectModuleLabel</key>
<string>MasteringProc.cpp</string>
<string>Mastering.h</string>
<key>_historyCapacity</key>
<integer>0</integer>
<key>bookmark</key>
<string>8BF17B6B2CB7FF3200FAAF3F</string>
<string>8BC437A32CC7CE520098AE55</string>
<key>history</key>
<array>
<string>8BF17AF32CB7F7B000FAAF3F</string>
<string>8BF17B6A2CB7FF3200FAAF3F</string>
<string>8BC437242CC70EF00098AE55</string>
<string>8BC4377F2CC7CCEC0098AE55</string>
</array>
</dict>
<key>SplitCount</key>
@ -369,18 +411,18 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{0, 0}, {603, 86}}</string>
<string>{{0, 0}, {603, 0}}</string>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>PBXNavigatorGroup</string>
<key>Proportion</key>
<string>86pt</string>
<string>0pt</string>
</dict>
<dict>
<key>Proportion</key>
<string>355pt</string>
<string>441pt</string>
<key>Tabs</key>
<array>
<dict>
@ -394,9 +436,9 @@
<key>GeometryConfiguration</key>
<dict>
<key>Frame</key>
<string>{{10, 27}, {603, 328}}</string>
<string>{{10, 27}, {603, 414}}</string>
<key>RubberWindowFrame</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
</dict>
<key>Module</key>
<string>XCDetailModule</string>
@ -478,11 +520,11 @@
</array>
<key>TableOfContents</key>
<array>
<string>8BF17B6C2CB7FF3200FAAF3F</string>
<string>8BC437A42CC7CE520098AE55</string>
<string>1CA23ED40692098700951B8B</string>
<string>8BF17B6D2CB7FF3200FAAF3F</string>
<string>8BC437A52CC7CE520098AE55</string>
<string>8B0237581D42B1C400E1E8C8</string>
<string>8BF17B6E2CB7FF3200FAAF3F</string>
<string>8BC437A62CC7CE520098AE55</string>
<string>1CA23EDF0692099D00951B8B</string>
<string>1CA23EE00692099D00951B8B</string>
<string>1CA23EE10692099D00951B8B</string>
@ -655,7 +697,7 @@
<key>StatusbarIsVisible</key>
<true/>
<key>TimeStamp</key>
<real>750255922.06214201</real>
<real>751291986.86297703</real>
<key>ToolbarConfigUserDefaultsMinorVersion</key>
<string>2</string>
<key>ToolbarDisplayMode</key>
@ -672,11 +714,11 @@
<integer>5</integer>
<key>WindowOrderList</key>
<array>
<string>8BF17B6F2CB7FF3200FAAF3F</string>
<string>/Users/christopherjohnson/Desktop/airwindows/plugins/MacVST/Mastering/Mastering.xcodeproj</string>
<string>8BC437A72CC7CE520098AE55</string>
</array>
<key>WindowString</key>
<string>579 290 810 487 0 0 1440 878 </string>
<string>620 297 810 487 0 0 1440 878 </string>
<key>WindowToolsV3</key>
<array>
<dict>

View file

@ -21,6 +21,7 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
G = 0.5;
H = 0.5;
I = 0.0;
J = 1.0;
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
@ -36,6 +37,62 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
//this is reset: values being initialized only once. Startup values, whatever they are.
@ -78,6 +135,7 @@ VstInt32 Mastering::getChunk (void** data, bool isPreset)
chunkData[6] = G;
chunkData[7] = H;
chunkData[8] = I;
chunkData[9] = J;
/* 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. */
@ -98,6 +156,7 @@ VstInt32 Mastering::setChunk (void* data, VstInt32 byteSize, bool isPreset)
G = pinParameter(chunkData[6]);
H = pinParameter(chunkData[7]);
I = pinParameter(chunkData[8]);
J = pinParameter(chunkData[9]);
/* We're ignoring byteSize as we found it to be a filthy liar */
/* calculate any other fields you need here - you could copy in
@ -116,6 +175,7 @@ void Mastering::setParameter(VstInt32 index, float value) {
case kParamG: G = value; break;
case kParamH: H = value; break;
case kParamI: I = value; break;
case kParamJ: J = value; break;
default: throw; // unknown parameter, shouldn't happen!
}
}
@ -131,6 +191,7 @@ float Mastering::getParameter(VstInt32 index) {
case kParamG: return G; break;
case kParamH: return H; break;
case kParamI: return I; break;
case kParamJ: return J; break;
default: break; // unknown parameter, shouldn't happen!
} return 0.0; //we only need to update the relevant name, this is simple to manage
}
@ -146,6 +207,7 @@ void Mastering::getParameterName(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "Zoom", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "DarkF", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "Ratio", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "Dither", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} //this is our labels for displaying in the VST host
}
@ -161,6 +223,15 @@ void Mastering::getParameterDisplay(VstInt32 index, char *text) {
case kParamG: float2string (G, text, kVstMaxParamStrLen); break;
case kParamH: float2string (H, text, kVstMaxParamStrLen); break;
case kParamI: float2string (I, text, kVstMaxParamStrLen); break;
case kParamJ: switch((VstInt32)( J * 5.999 )) //0 to almost edge of # of params
{ case 0: vst_strncpy (text, "Dark", kVstMaxParamStrLen); break;
case 1: vst_strncpy (text, "TenNines", kVstMaxParamStrLen); break;
case 2: vst_strncpy (text, "TPDFWde", kVstMaxParamStrLen); break;
case 3: vst_strncpy (text, "PaulWde", kVstMaxParamStrLen); break;
case 4: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break;
case 5: vst_strncpy (text, "Bypass", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} break; //completed consoletype 'popup' parameter, exit
default: break; // unknown parameter, shouldn't happen!
} //this displays the values and handles 'popups' where it's discrete choices
}
@ -176,6 +247,7 @@ void Mastering::getParameterLabel(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
}
}

View file

@ -25,7 +25,8 @@ enum {
kParamG =6,
kParamH =7,
kParamI =8,
kNumParameters = 9
kParamJ =9,
kNumParameters = 10
}; //
const int kNumPrograms = 0;
@ -69,6 +70,7 @@ private:
float G;
float H;
float I;
float J;
enum {
pvAL1,
@ -151,6 +153,41 @@ private:
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
//default stuff

View file

@ -36,6 +36,10 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
@ -270,14 +274,388 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit stereo floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;
@ -318,7 +696,11 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
double inputSampleL = *in1;
@ -552,14 +934,388 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 64 bit stereo floating point dither
int expon; frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 64 bit stereo floating point dither
frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;

View file

@ -21,6 +21,7 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
G = 0.5;
H = 0.5;
I = 0.0;
J = 1.0;
for (int x = 0; x < air_total; x++) air[x] = 0.0;
for (int x = 0; x < kal_total; x++) {kalM[x] = 0.0;kalS[x] = 0.0;}
@ -36,6 +37,62 @@ Mastering::Mastering(audioMasterCallback audioMaster) :
wasNegClipR = false;
for (int x = 0; x < 16; x++) {intermediateL[x] = 0.0; intermediateR[x] = 0.0;}
quantA = 0;
quantB = 1;
expectedSlew = 0.0;
testA = 0.0;
testB = 0.0;
correction = 0.0;
shapedSampleL = 0.0;
shapedSampleR = 0.0;
currentDither = 0.0;
ditherL = 0.0;
ditherR = 0.0;
cutbinsL = false;
cutbinsR = false;
hotbinA = 0;
hotbinB = 0;
benfordize = 0.0;
totalA = 0.0;
totalB = 0.0;
outputSample = 0.0;
expon = 0; //internal dither variables
//these didn't like to be defined inside a case statement
NSOddL = 0.0; NSEvenL = 0.0; prevShapeL = 0.0;
NSOddR = 0.0; NSEvenR = 0.0; prevShapeR = 0.0;
flip = true; //Ten Nines
for(int count = 0; count < 99; count++) {
darkSampleL[count] = 0;
darkSampleR[count] = 0;
} //Dark
previousDitherL = 0.0;
previousDitherR = 0.0; //PaulWide
bynL[0] = 1000.0;
bynL[1] = 301.0;
bynL[2] = 176.0;
bynL[3] = 125.0;
bynL[4] = 97.0;
bynL[5] = 79.0;
bynL[6] = 67.0;
bynL[7] = 58.0;
bynL[8] = 51.0;
bynL[9] = 46.0;
bynL[10] = 1000.0;
noiseShapingL = 0.0;
bynR[0] = 1000.0;
bynR[1] = 301.0;
bynR[2] = 176.0;
bynR[3] = 125.0;
bynR[4] = 97.0;
bynR[5] = 79.0;
bynR[6] = 67.0;
bynR[7] = 58.0;
bynR[8] = 51.0;
bynR[9] = 46.0;
bynR[10] = 1000.0;
noiseShapingR = 0.0; //NJAD
fpdL = 1.0; while (fpdL < 16386) fpdL = rand()*UINT32_MAX;
fpdR = 1.0; while (fpdR < 16386) fpdR = rand()*UINT32_MAX;
//this is reset: values being initialized only once. Startup values, whatever they are.
@ -78,6 +135,7 @@ VstInt32 Mastering::getChunk (void** data, bool isPreset)
chunkData[6] = G;
chunkData[7] = H;
chunkData[8] = I;
chunkData[9] = J;
/* 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. */
@ -98,6 +156,7 @@ VstInt32 Mastering::setChunk (void* data, VstInt32 byteSize, bool isPreset)
G = pinParameter(chunkData[6]);
H = pinParameter(chunkData[7]);
I = pinParameter(chunkData[8]);
J = pinParameter(chunkData[9]);
/* We're ignoring byteSize as we found it to be a filthy liar */
/* calculate any other fields you need here - you could copy in
@ -116,6 +175,7 @@ void Mastering::setParameter(VstInt32 index, float value) {
case kParamG: G = value; break;
case kParamH: H = value; break;
case kParamI: I = value; break;
case kParamJ: J = value; break;
default: throw; // unknown parameter, shouldn't happen!
}
}
@ -131,6 +191,7 @@ float Mastering::getParameter(VstInt32 index) {
case kParamG: return G; break;
case kParamH: return H; break;
case kParamI: return I; break;
case kParamJ: return J; break;
default: break; // unknown parameter, shouldn't happen!
} return 0.0; //we only need to update the relevant name, this is simple to manage
}
@ -146,6 +207,7 @@ void Mastering::getParameterName(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "Zoom", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "DarkF", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "Ratio", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "Dither", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} //this is our labels for displaying in the VST host
}
@ -161,6 +223,15 @@ void Mastering::getParameterDisplay(VstInt32 index, char *text) {
case kParamG: float2string (G, text, kVstMaxParamStrLen); break;
case kParamH: float2string (H, text, kVstMaxParamStrLen); break;
case kParamI: float2string (I, text, kVstMaxParamStrLen); break;
case kParamJ: switch((VstInt32)( J * 5.999 )) //0 to almost edge of # of params
{ case 0: vst_strncpy (text, "Dark", kVstMaxParamStrLen); break;
case 1: vst_strncpy (text, "TenNines", kVstMaxParamStrLen); break;
case 2: vst_strncpy (text, "TPDFWde", kVstMaxParamStrLen); break;
case 3: vst_strncpy (text, "PaulWde", kVstMaxParamStrLen); break;
case 4: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break;
case 5: vst_strncpy (text, "Bypass", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
} break; //completed consoletype 'popup' parameter, exit
default: break; // unknown parameter, shouldn't happen!
} //this displays the values and handles 'popups' where it's discrete choices
}
@ -176,6 +247,7 @@ void Mastering::getParameterLabel(VstInt32 index, char *text) {
case kParamG: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamH: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamI: vst_strncpy (text, "", kVstMaxParamStrLen); break;
case kParamJ: vst_strncpy (text, "", kVstMaxParamStrLen); break;
default: break; // unknown parameter, shouldn't happen!
}
}

View file

@ -25,7 +25,8 @@ enum {
kParamG =6,
kParamH =7,
kParamI =8,
kNumParameters = 9
kParamJ =9,
kNumParameters = 10
}; //
const int kNumPrograms = 0;
@ -69,6 +70,7 @@ private:
float G;
float H;
float I;
float J;
enum {
pvAL1,
@ -151,6 +153,41 @@ private:
bool wasPosClipR;
bool wasNegClipR; //Stereo ClipOnly2
int quantA;
int quantB;
float expectedSlew;
float testA;
float testB;
double correction;
double shapedSampleL;
double shapedSampleR;
double currentDither;
double ditherL;
double ditherR;
bool cutbinsL;
bool cutbinsR;
int hotbinA;
int hotbinB;
double benfordize;
double totalA;
double totalB;
double outputSample;
int expon; //internal dither variables
double NSOddL; //dither section!
double NSEvenL;
double prevShapeL;
double NSOddR;
double NSEvenR;
double prevShapeR;
bool flip; //VinylDither
double darkSampleL[100];
double darkSampleR[100]; //Dark
double previousDitherL;
double previousDitherR; //PaulWide
double bynL[13], bynR[13];
double noiseShapingL, noiseShapingR; //NJAD
uint32_t fpdL;
uint32_t fpdR;
//default stuff

View file

@ -36,6 +36,10 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
@ -270,14 +274,388 @@ void Mastering::processReplacing(float **inputs, float **outputs, VstInt32 sampl
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 32 bit stereo floating point dither
int expon; frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 32 bit stereo floating point dither
frexpf((float)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
frexpf((float)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 5.5e-36l * pow(2,expon+62));
//end 32 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;
@ -318,7 +696,11 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
double depthSinew = I;
int spacing = floor(overallscale); //should give us working basic scaling, usually 2 or 4
if (spacing < 1) spacing = 1; if (spacing > 16) spacing = 16;
int dither = (int) ( J * 5.999 )+1;
int depth = (int)(17.0*overallscale);
if (depth < 3) depth = 3;
if (depth > 98) depth = 98; //for Dark
while (--sampleFrames >= 0)
{
double inputSampleL = *in1;
@ -552,14 +934,388 @@ void Mastering::processDoubleReplacing(double **inputs, double **outputs, VstInt
inputSampleR = (inputSampleR * (1.0-depthSinew))+(lastSinewR*depthSinew);
//run Sinew to stop excess slews, but run a dry/wet to allow a range of brights
//begin 64 bit stereo floating point dither
int expon; frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
switch (dither) {
case 1:
//begin Dark
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin left
quantA = floor(inputSampleL);
quantB = floor(inputSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark left
//begin right
quantA = floor(inputSampleR);
quantB = floor(inputSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark right
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Dark (Monitoring2)
case 2:
//begin Dark for Ten Nines
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0; //we will apply the 24 bit Dark
//We are doing it first Left, then Right, because the loops may run faster if
//they aren't too jammed full of variables. This means re-running code.
//begin L
correction = 0;
if (flip) {
NSOddL = (NSOddL * 0.9999999999) + prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) - prevShapeL;
correction = NSOddL;
} else {
NSOddL = (NSOddL * 0.9999999999) - prevShapeL;
NSEvenL = (NSEvenL * 0.9999999999) + prevShapeL;
correction = NSEvenL;
}
shapedSampleL = inputSampleL+correction;
//end Ten Nines L
//begin Dark L
quantA = floor(shapedSampleL);
quantB = floor(shapedSampleL+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleL[x+1] - darkSampleL[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleL[0] - quantA) - expectedSlew);
testB = fabs((darkSampleL[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleL = quantA;
else inputSampleL = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleL[x+1] = darkSampleL[x];
}
darkSampleL[0] = inputSampleL;
//end Dark L
prevShapeL = (floor(shapedSampleL) - inputSampleL)*0.9999999999;
//end Ten Nines L
//begin R
correction = 0;
if (flip) {
NSOddR = (NSOddR * 0.9999999999) + prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) - prevShapeR;
correction = NSOddR;
} else {
NSOddR = (NSOddR * 0.9999999999) - prevShapeR;
NSEvenR = (NSEvenR * 0.9999999999) + prevShapeR;
correction = NSEvenR;
}
shapedSampleR = inputSampleR+correction;
//end Ten Nines R
//begin Dark R
quantA = floor(shapedSampleR);
quantB = floor(shapedSampleR+1.0);
//to do this style of dither, we quantize in either direction and then
//do a reconstruction of what the result will be for each choice.
//We then evaluate which one we like, and keep a history of what we previously had
expectedSlew = 0;
for(int x = 0; x < depth; x++) {
expectedSlew += (darkSampleR[x+1] - darkSampleR[x]);
}
expectedSlew /= depth; //we have an average of all recent slews
//we are doing that to voice the thing down into the upper mids a bit
//it mustn't just soften the brightest treble, it must smooth high mids too
testA = fabs((darkSampleR[0] - quantA) - expectedSlew);
testB = fabs((darkSampleR[0] - quantB) - expectedSlew);
if (testA < testB) inputSampleR = quantA;
else inputSampleR = quantB;
//select whichever one departs LEAST from the vector of averaged
//reconstructed previous final samples. This will force a kind of dithering
//as it'll make the output end up as smooth as possible
for(int x = depth; x >=0; x--) {
darkSampleR[x+1] = darkSampleR[x];
}
darkSampleR[0] = inputSampleR;
//end Dark R
prevShapeR = (floor(shapedSampleR) - inputSampleR)*0.9999999999;
//end Ten Nines
flip = !flip;
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //Ten Nines (which goes into Dark in Monitoring3)
case 3:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
//TPDF: two 0-1 random noises
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherR = -1.0;
ditherR += (double(fpdR)/UINT32_MAX);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
ditherR += (double(fpdR)/UINT32_MAX);
}
if (fabs(ditherL-ditherR) < 0.5) {
ditherL = -1.0;
ditherL += (double(fpdL)/UINT32_MAX);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
ditherL += (double(fpdL)/UINT32_MAX);
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //TPDFWide (a good neutral with the width enhancement)
case 4:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
//Paul Frindle: It's true that the dither itself can sound different
//if it's given a different freq response and you get to hear it.
//The one we use most is triangular single pole high pass dither.
//It's not freq bent enough to sound odd, but is slightly less audible than
//flat dither. It can also be easily made by taking one sample of dither
//away from the previous one - this gives you the triangular PDF and the
//filtering in one go :-)
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
//TPDF: two 0-1 random noises
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
//TPDF: two 0-1 random noises
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
currentDither = (double(fpdR)/UINT32_MAX);
ditherR = currentDither;
ditherR -= previousDitherR;
previousDitherR = currentDither;
}
if (fabs(ditherL-ditherR) < 0.5) {
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
currentDither = (double(fpdL)/UINT32_MAX);
ditherL = currentDither;
ditherL -= previousDitherL;
previousDitherL = currentDither;
}
inputSampleL = floor(inputSampleL+ditherL);
inputSampleR = floor(inputSampleR+ditherR);
inputSampleL /= 8388608.0;
inputSampleR /= 8388608.0;
break; //PaulWide (brighter neutral that's still TPDF and wide)
case 5:
inputSampleL *= 8388608.0;
inputSampleR *= 8388608.0;
cutbinsL = false;
cutbinsR = false;
drySampleL = inputSampleL;//re-using in NJAD
inputSampleL -= noiseShapingL;
//NJAD L
benfordize = floor(inputSampleL);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynL[hotbinA] += 1; if (bynL[hotbinA] > 982) cutbinsL = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynL[hotbinB] += 1; if (bynL[hotbinB] > 982) cutbinsL = true;
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; outputSample = floor(inputSampleL);}
else {bynL[hotbinB] += 1; outputSample = floor(inputSampleL+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsL) {
bynL[1] *= 0.99; bynL[2] *= 0.99; bynL[3] *= 0.99; bynL[4] *= 0.99; bynL[5] *= 0.99;
bynL[6] *= 0.99; bynL[7] *= 0.99; bynL[8] *= 0.99; bynL[9] *= 0.99; bynL[10] *= 0.99;
}
noiseShapingL += outputSample - drySampleL;
if (noiseShapingL > fabs(inputSampleL)) noiseShapingL = fabs(inputSampleL);
if (noiseShapingL < -fabs(inputSampleL)) noiseShapingL = -fabs(inputSampleL);
inputSampleL /= 8388608.0;
if (inputSampleL > 1.0) inputSampleL = 1.0;
if (inputSampleL < -1.0) inputSampleL = -1.0;
//finished NJAD L
//NJAD R
drySampleR = inputSampleR;
inputSampleR -= noiseShapingR;
benfordize = floor(inputSampleR);
while (benfordize >= 1.0) benfordize /= 10;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinA = floor(benfordize);
//hotbin becomes the Benford bin value for this number floored
totalA = 0.0;
if ((hotbinA > 0) && (hotbinA < 10))
{
bynR[hotbinA] += 1; if (bynR[hotbinA] > 982) cutbinsR = true;
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;
while (benfordize < 1.0 && benfordize > 0.0000001) benfordize *= 10;
hotbinB = floor(benfordize);
//hotbin becomes the Benford bin value for this number ceiled
totalB = 0.0;
if ((hotbinB > 0) && (hotbinB < 10))
{
bynR[hotbinB] += 1; if (bynR[hotbinB] > 982) cutbinsR = true;
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; outputSample = floor(inputSampleR);}
else {bynR[hotbinB] += 1; outputSample = floor(inputSampleR+1);}
//assign the relevant one to the delay line
//and floor/ceil signal accordingly
if (cutbinsR) {
bynR[1] *= 0.99; bynR[2] *= 0.99; bynR[3] *= 0.99; bynR[4] *= 0.99; bynR[5] *= 0.99;
bynR[6] *= 0.99; bynR[7] *= 0.99; bynR[8] *= 0.99; bynR[9] *= 0.99; bynR[10] *= 0.99;
}
noiseShapingR += outputSample - drySampleR;
if (noiseShapingR > fabs(inputSampleR)) noiseShapingR = fabs(inputSampleR);
if (noiseShapingR < -fabs(inputSampleR)) noiseShapingR = -fabs(inputSampleR);
inputSampleR /= 8388608.0;
if (inputSampleR > 1.0) inputSampleR = 1.0;
if (inputSampleR < -1.0) inputSampleR = -1.0;
break; //NJAD (Monitoring. Brightest)
case 6:
//begin 64 bit stereo floating point dither
frexp((double)inputSampleL, &expon);
fpdL ^= fpdL << 13; fpdL ^= fpdL >> 17; fpdL ^= fpdL << 5;
inputSampleL += ((double(fpdL)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
frexp((double)inputSampleR, &expon);
fpdR ^= fpdR << 13; fpdR ^= fpdR >> 17; fpdR ^= fpdR << 5;
inputSampleR += ((double(fpdR)-uint32_t(0x7fffffff)) * 1.1e-44l * pow(2,expon+62));
//end 64 bit stereo floating point dither
break; //Bypass for saving floating point files directly
}
*out1 = inputSampleL;
*out2 = inputSampleR;

View file

@ -331,7 +331,8 @@ SpatializeDither is a high-performance clarity and accuracy dither.[coll=]
Spiral is the new best smoothest distortion algorithm.[coll=]
Spiral2 is Spiral with controls including Presence.[coll=Latest]
Srsly is a psychoacoustic stereo processor.[coll=Recommended]
Srsly2 is a revisit of Srsly, to make the stereo widening more extreme.[coll=Basic,Recommended,Latest]
Srsly2 is a revisit of Srsly, to make the stereo widening more extreme.[coll=]
Srsly3 is Srsly2, with a Nonlin control to analogify the filters.[coll=Basic,Recommended,Latest]
StarChild is a weird digital ambience/echo plugin.[coll=]
StarChild2 is a weird digital ambience/echo plugin adapted to high sample rates.[coll=Latest]
StereoChorus is a nice basic stereo chorus.[coll=Latest]