From 3dd30d920a374ba31994f784fadd5ee130752247 Mon Sep 17 00:00:00 2001 From: Chris Johnson Date: Mon, 3 Sep 2018 16:35:36 -0400 Subject: Ditherbox update --- .../Ditherbox.xcodeproj/christopherjohnson.pbxuser | 61 +++-- .../christopherjohnson.perspectivev3 | 37 +-- plugins/MacVST/Ditherbox/source/Ditherbox.cpp | 62 +++-- plugins/MacVST/Ditherbox/source/Ditherbox.h | 2 + plugins/MacVST/Ditherbox/source/DitherboxProc.cpp | 295 +++++++++++++++++++-- 5 files changed, 368 insertions(+), 89 deletions(-) (limited to 'plugins/MacVST/Ditherbox') diff --git a/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.pbxuser b/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.pbxuser index b36856e..fafb484 100755 --- a/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.pbxuser +++ b/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.pbxuser @@ -49,12 +49,13 @@ PBXFileDataSource_Warnings_ColumnID, ); }; - PBXPerProjectTemplateStateSaveDate = 557543533; - PBXWorkspaceStateSaveDate = 557543533; + PBXPerProjectTemplateStateSaveDate = 557697507; + PBXWorkspaceStateSaveDate = 557697507; }; perUserProjectItems = { - 8B39A1A1213B713000112CCA /* PBXTextBookmark */ = 8B39A1A1213B713000112CCA /* PBXTextBookmark */; - 8B39A1A2213B713000112CCA /* PBXTextBookmark */ = 8B39A1A2213B713000112CCA /* PBXTextBookmark */; + 8B913F89213DBC2200BA6EEC /* PBXTextBookmark */ = 8B913F89213DBC2200BA6EEC /* PBXTextBookmark */; + 8B914093213DCA1600BA6EEC /* PBXTextBookmark */ = 8B914093213DCA1600BA6EEC /* PBXTextBookmark */; + 8B914094213DCA1600BA6EEC /* PBXTextBookmark */ = 8B914094213DCA1600BA6EEC /* PBXTextBookmark */; }; sourceControlManager = 8B02375E1D42B1C400E1E8C8 /* Source Control */; userBuildSettings = { @@ -62,17 +63,17 @@ }; 2407DEB6089929BA00EB68BF /* Ditherbox.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {733, 3107}}"; - sepNavSelRange = "{5938, 0}"; - sepNavVisRange = "{6518, 428}"; + sepNavIntBoundsRect = "{{0, 0}, {558, 3757}}"; + sepNavSelRange = "{6184, 0}"; + sepNavVisRange = "{6556, 137}"; sepNavWindowFrame = "{{13, 47}, {895, 831}}"; }; }; 245463B80991757100464AD3 /* Ditherbox.h */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {866, 1716}}"; - sepNavSelRange = "{2755, 0}"; - sepNavVisRange = "{1597, 1663}"; + sepNavIntBoundsRect = "{{0, 0}, {866, 1573}}"; + sepNavSelRange = "{2576, 0}"; + sepNavVisRange = "{1102, 2059}"; sepNavWindowFrame = "{{17, 44}, {895, 831}}"; }; }; @@ -86,10 +87,10 @@ }; 24D8286F09A914000093AEF8 /* DitherboxProc.cpp */ = { uiCtxt = { - sepNavIntBoundsRect = "{{0, 0}, {848, 23439}}"; - sepNavSelRange = "{72139, 0}"; - sepNavVisRange = "{37029, 1848}"; - sepNavWindowFrame = "{{32, 38}, {895, 831}}"; + sepNavIntBoundsRect = "{{0, 0}, {565, 26065}}"; + sepNavSelRange = "{81896, 0}"; + sepNavVisRange = "{39186, 42}"; + sepNavWindowFrame = "{{516, 47}, {895, 831}}"; }; }; 8B02375E1D42B1C400E1E8C8 /* Source Control */ = { @@ -106,25 +107,35 @@ isa = PBXCodeSenseManager; indexTemplatePath = ""; }; - 8B39A1A1213B713000112CCA /* PBXTextBookmark */ = { + 8B913F89213DBC2200BA6EEC /* PBXTextBookmark */ = { isa = PBXTextBookmark; - fRef = 2407DEB6089929BA00EB68BF /* Ditherbox.cpp */; - name = "Ditherbox.cpp: 223"; + fRef = 24D8286F09A914000093AEF8 /* DitherboxProc.cpp */; + name = "DitherboxProc.cpp: 1829"; rLen = 0; - rLoc = 5938; + rLoc = 81896; rType = 0; - vrLen = 428; - vrLoc = 6518; + vrLen = 246; + vrLoc = 38973; }; - 8B39A1A2213B713000112CCA /* PBXTextBookmark */ = { + 8B914093213DCA1600BA6EEC /* PBXTextBookmark */ = { isa = PBXTextBookmark; fRef = 2407DEB6089929BA00EB68BF /* Ditherbox.cpp */; - name = "Ditherbox.cpp: 223"; + name = "Ditherbox.cpp: 228"; + rLen = 0; + rLoc = 6184; + rType = 0; + vrLen = 137; + vrLoc = 6556; + }; + 8B914094213DCA1600BA6EEC /* PBXTextBookmark */ = { + isa = PBXTextBookmark; + fRef = 24D8286F09A914000093AEF8 /* DitherboxProc.cpp */; + name = "DitherboxProc.cpp: 2008"; rLen = 0; - rLoc = 5938; + rLoc = 81896; rType = 0; - vrLen = 428; - vrLoc = 6518; + vrLen = 42; + vrLoc = 39186; }; 8D01CCC60486CAD60068D4B7 /* Ditherbox */ = { activeExec = 0; diff --git a/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.perspectivev3 b/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.perspectivev3 index 4c6b162..b9f897f 100755 --- a/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.perspectivev3 +++ b/plugins/MacVST/Ditherbox/Ditherbox.xcodeproj/christopherjohnson.perspectivev3 @@ -323,7 +323,7 @@ 185 RubberWindowFrame - 44 351 810 487 0 0 1440 878 + 34 315 810 487 0 0 1440 878 Module PBXSmartGroupTreeModule @@ -339,7 +339,7 @@ PBXProjectModuleGUID 8B0237581D42B1C400E1E8C8 PBXProjectModuleLabel - Ditherbox.cpp + DitherboxProc.cpp PBXSplitModuleInNavigatorKey Split0 @@ -347,14 +347,15 @@ PBXProjectModuleGUID 8B0237591D42B1C400E1E8C8 PBXProjectModuleLabel - Ditherbox.cpp + DitherboxProc.cpp _historyCapacity 0 bookmark - 8B39A1A2213B713000112CCA + 8B914094213DCA1600BA6EEC history - 8B39A1A1213B713000112CCA + 8B914093213DCA1600BA6EEC + 8B913F89213DBC2200BA6EEC SplitCount @@ -368,18 +369,18 @@ GeometryConfiguration Frame - {{0, 0}, {603, 132}} + {{0, 0}, {603, 51}} RubberWindowFrame - 44 351 810 487 0 0 1440 878 + 34 315 810 487 0 0 1440 878 Module PBXNavigatorGroup Proportion - 132pt + 51pt Proportion - 309pt + 390pt Tabs @@ -393,9 +394,9 @@ GeometryConfiguration Frame - {{10, 27}, {603, 282}} + {{10, 27}, {603, 363}} RubberWindowFrame - 44 351 810 487 0 0 1440 878 + 34 315 810 487 0 0 1440 878 Module XCDetailModule @@ -449,7 +450,7 @@ GeometryConfiguration Frame - {{10, 27}, {603, 414}} + {{10, 27}, {603, 297}} Module PBXBuildResultsModule @@ -477,11 +478,11 @@ TableOfContents - 8B39A1A3213B713000112CCA + 8B914095213DCA1600BA6EEC 1CA23ED40692098700951B8B - 8B39A1A4213B713000112CCA + 8B914096213DCA1600BA6EEC 8B0237581D42B1C400E1E8C8 - 8B39A1A5213B713000112CCA + 8B914097213DCA1600BA6EEC 1CA23EDF0692099D00951B8B 1CA23EE00692099D00951B8B 1CA23EE10692099D00951B8B @@ -634,7 +635,7 @@ StatusbarIsVisible TimeStamp - 557543728.63115299 + 557697558.29189706 ToolbarConfigUserDefaultsMinorVersion 2 ToolbarDisplayMode @@ -651,11 +652,11 @@ 5 WindowOrderList - 8B39A1A6213B713000112CCA + 8B914098213DCA1600BA6EEC /Users/christopherjohnson/Desktop/MacVST/Ditherbox/Ditherbox.xcodeproj WindowString - 44 351 810 487 0 0 1440 878 + 34 315 810 487 0 0 1440 878 WindowToolsV3 diff --git a/plugins/MacVST/Ditherbox/source/Ditherbox.cpp b/plugins/MacVST/Ditherbox/source/Ditherbox.cpp index 7e57c49..0d3822f 100755 --- a/plugins/MacVST/Ditherbox/source/Ditherbox.cpp +++ b/plugins/MacVST/Ditherbox/source/Ditherbox.cpp @@ -12,11 +12,13 @@ AudioEffect* createEffectInstance(audioMasterCallback audioMaster) {return new D Ditherbox::Ditherbox(audioMasterCallback audioMaster) : AudioEffectX(audioMaster, kNumPrograms, kNumParameters) { - A = 0.825; + A = 0.86; Position = 99999999; contingentErrL = 0.0; contingentErrR = 0.0; + currentDitherL = 0.0; + currentDitherR = 0.0; bynL[0] = 1000; bynL[1] = 301; bynL[2] = 176; @@ -211,27 +213,33 @@ void Ditherbox::getParameterName(VstInt32 index, char *text) { void Ditherbox::getParameterDisplay(VstInt32 index, char *text) { switch (index) { - case kParamA: switch((VstInt32)( A * 19.999 )) //0 to almost edge of # of params + case kParamA: switch((VstInt32)( A * 24.999 )) //0 to almost edge of # of params { case 0: vst_strncpy (text, "Trunc", kVstMaxParamStrLen); break; case 1: vst_strncpy (text, "Flat", kVstMaxParamStrLen); break; case 2: vst_strncpy (text, "TPDF", kVstMaxParamStrLen); break; - case 4: vst_strncpy (text, "HiGloss", kVstMaxParamStrLen); break; - case 5: vst_strncpy (text, "Vinyl", kVstMaxParamStrLen); break; - case 6: vst_strncpy (text, "Spatial", kVstMaxParamStrLen); break; - case 7: vst_strncpy (text, "Natural", kVstMaxParamStrLen); break; - case 8: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break; - case 9: vst_strncpy (text, "Trunc", kVstMaxParamStrLen); break; - case 10: vst_strncpy (text, "Flat", kVstMaxParamStrLen); break; - case 11: vst_strncpy (text, "TPDF", kVstMaxParamStrLen); break; - case 12: vst_strncpy (text, "HiGloss", kVstMaxParamStrLen); break; - case 13: vst_strncpy (text, "Vinyl", kVstMaxParamStrLen); break; - case 14: vst_strncpy (text, "Spatial", kVstMaxParamStrLen); break; - case 15: vst_strncpy (text, "Natural", kVstMaxParamStrLen); break; - case 16: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break; - case 17: vst_strncpy (text, "SlewOnl", kVstMaxParamStrLen); break; - case 18: vst_strncpy (text, "SubsOnl", kVstMaxParamStrLen); break; - case 19: vst_strncpy (text, "Silhoue", kVstMaxParamStrLen); break; + case 3: vst_strncpy (text, "Paul", kVstMaxParamStrLen); break; + case 4: vst_strncpy (text, "DbPaul", kVstMaxParamStrLen); break; + case 5: vst_strncpy (text, "Tape", kVstMaxParamStrLen); break; + case 6: vst_strncpy (text, "HiGloss", kVstMaxParamStrLen); break; + case 7: vst_strncpy (text, "Vinyl", kVstMaxParamStrLen); break; + case 8: vst_strncpy (text, "Spatial", kVstMaxParamStrLen); break; + case 9: vst_strncpy (text, "Natural", kVstMaxParamStrLen); break; + case 10: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break; + case 11: vst_strncpy (text, "Trunc", kVstMaxParamStrLen); break; + case 12: vst_strncpy (text, "Flat", kVstMaxParamStrLen); break; + case 13: vst_strncpy (text, "TPDF", kVstMaxParamStrLen); break; + case 14: vst_strncpy (text, "Paul", kVstMaxParamStrLen); break; + case 15: vst_strncpy (text, "DbPaul", kVstMaxParamStrLen); break; + case 16: vst_strncpy (text, "Tape", kVstMaxParamStrLen); break; + case 17: vst_strncpy (text, "HiGloss", kVstMaxParamStrLen); break; + case 18: vst_strncpy (text, "Vinyl", kVstMaxParamStrLen); break; + case 19: vst_strncpy (text, "Spatial", kVstMaxParamStrLen); break; + case 20: vst_strncpy (text, "Natural", kVstMaxParamStrLen); break; + case 21: vst_strncpy (text, "NJAD", kVstMaxParamStrLen); break; + case 22: vst_strncpy (text, "SlewOnl", kVstMaxParamStrLen); break; + case 23: vst_strncpy (text, "SubsOnl", kVstMaxParamStrLen); break; + case 24: vst_strncpy (text, "Silhoue", kVstMaxParamStrLen); break; default: break; // unknown parameter, shouldn't happen! } break; default: break; // unknown parameter, shouldn't happen! @@ -240,27 +248,33 @@ void Ditherbox::getParameterDisplay(VstInt32 index, char *text) { void Ditherbox::getParameterLabel(VstInt32 index, char *text) { switch (index) { - case kParamA: switch((VstInt32)( A * 19.999 )) //0 to almost edge of # of params + case kParamA: switch((VstInt32)( A * 24.999 )) //0 to almost edge of # of params { case 0: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 1: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 2: vst_strncpy (text, "16", kVstMaxParamStrLen); break; + case 3: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 4: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 5: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 6: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 7: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 8: vst_strncpy (text, "16", kVstMaxParamStrLen); break; - case 9: vst_strncpy (text, "24", kVstMaxParamStrLen); break; - case 10: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 9: vst_strncpy (text, "16", kVstMaxParamStrLen); break; + case 10: vst_strncpy (text, "16", kVstMaxParamStrLen); break; case 11: vst_strncpy (text, "24", kVstMaxParamStrLen); break; case 12: vst_strncpy (text, "24", kVstMaxParamStrLen); break; case 13: vst_strncpy (text, "24", kVstMaxParamStrLen); break; case 14: vst_strncpy (text, "24", kVstMaxParamStrLen); break; case 15: vst_strncpy (text, "24", kVstMaxParamStrLen); break; case 16: vst_strncpy (text, "24", kVstMaxParamStrLen); break; - case 17: vst_strncpy (text, "y", kVstMaxParamStrLen); break; - case 18: vst_strncpy (text, "y", kVstMaxParamStrLen); break; - case 19: vst_strncpy (text, "tte", kVstMaxParamStrLen); break; + case 17: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 18: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 19: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 20: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 21: vst_strncpy (text, "24", kVstMaxParamStrLen); break; + case 22: vst_strncpy (text, "y", kVstMaxParamStrLen); break; + case 23: vst_strncpy (text, "y", kVstMaxParamStrLen); break; + case 24: vst_strncpy (text, "tte", kVstMaxParamStrLen); break; default: break; // unknown parameter, shouldn't happen! } break; default: break; // unknown parameter, shouldn't happen! diff --git a/plugins/MacVST/Ditherbox/source/Ditherbox.h b/plugins/MacVST/Ditherbox/source/Ditherbox.h index baf5bb1..fa54082 100755 --- a/plugins/MacVST/Ditherbox/source/Ditherbox.h +++ b/plugins/MacVST/Ditherbox/source/Ditherbox.h @@ -58,6 +58,8 @@ private: long double noiseShapingR; double contingentErrL; double contingentErrR; + double currentDitherL; + double currentDitherR; int Position; bool flip; double NSOddL; diff --git a/plugins/MacVST/Ditherbox/source/DitherboxProc.cpp b/plugins/MacVST/Ditherbox/source/DitherboxProc.cpp index feb5874..4115687 100755 --- a/plugins/MacVST/Ditherbox/source/DitherboxProc.cpp +++ b/plugins/MacVST/Ditherbox/source/DitherboxProc.cpp @@ -14,7 +14,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl float* out1 = outputs[0]; float* out2 = outputs[1]; - int dtype = (int)(A * 19.999); // +1 for Reaper bug workaround + int dtype = (int)(A * 24.999)+1; // +1 for Reaper bug workaround long double overallscale = 1.0; overallscale /= 44100.0; overallscale *= getSampleRate(); @@ -42,14 +42,52 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl long double trim = 2.302585092994045684017991; //natural logarithm of 10 bool highRes = false; bool dithering = true; - if (dtype > 8){highRes = true; dtype -= 8;} - if (dtype > 8){dithering = false; highRes = false;} + if (dtype > 11){highRes = true; dtype -= 11;} + if (dtype > 11){dithering = false; highRes = false;} //follow up by switching high res back off for the monitoring while (--sampleFrames >= 0) { long double inputSampleL = *in1; long double inputSampleR = *in2; + if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) { + static int noisesource = 0; + //this declares a variable before anything else is compiled. It won't keep assigning + //it to 0 for every sample, it's as if the declaration doesn't exist in this context, + //but it lets me add this denormalization fix in a single place rather than updating + //it in three different locations. The variable isn't thread-safe but this is only + //a random seed and we can share it with whatever. + noisesource = noisesource % 1700021; noisesource++; + int residue = noisesource * noisesource; + residue = residue % 170003; residue *= residue; + residue = residue % 17011; residue *= residue; + residue = residue % 1709; residue *= residue; + residue = residue % 173; residue *= residue; + residue = residue % 17; + double applyresidue = residue; + applyresidue *= 0.00000001; + applyresidue *= 0.00000001; + inputSampleL = applyresidue; + } + if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) { + static int noisesource = 0; + noisesource = noisesource % 1700021; noisesource++; + int residue = noisesource * noisesource; + residue = residue % 170003; residue *= residue; + residue = residue % 17011; residue *= residue; + residue = residue % 1709; residue *= residue; + residue = residue % 173; residue *= residue; + residue = residue % 17; + double applyresidue = residue; + applyresidue *= 0.00000001; + applyresidue *= 0.00000001; + inputSampleR = applyresidue; + //this denormalization routine produces a white noise at -300 dB which the noise + //shaping will interact with to produce a bipolar output, but the noise is actually + //all positive. That should stop any variables from going denormal, and the routine + //only kicks in if digital black is input. As a final touch, if you save to 24-bit + //the silence will return to being digital black again. + } float drySampleL = inputSampleL; float drySampleR = inputSampleR; @@ -89,7 +127,95 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //TPDF dither break; - case 4: + case 4: + currentDitherL = (rand()/(double)RAND_MAX); + inputSampleL += currentDitherL; + inputSampleL -= lastSampleL; + inputSampleL = floor(inputSampleL); + lastSampleL = currentDitherL; + currentDitherR = (rand()/(double)RAND_MAX); + inputSampleR += currentDitherR; + inputSampleR -= lastSampleR; + inputSampleR = floor(inputSampleR); + lastSampleR = currentDitherR; + //Paul dither + break; + + case 5: + nsL[9] = nsL[8]; nsL[8] = nsL[7]; nsL[7] = nsL[6]; nsL[6] = nsL[5]; + nsL[5] = nsL[4]; nsL[4] = nsL[3]; nsL[3] = nsL[2]; nsL[2] = nsL[1]; + nsL[1] = nsL[0]; nsL[0] = (rand()/(double)RAND_MAX); + + currentDitherL = (nsL[0] * 0.061); + currentDitherL -= (nsL[1] * 0.11); + currentDitherL += (nsL[8] * 0.126); + currentDitherL -= (nsL[7] * 0.23); + currentDitherL += (nsL[2] * 0.25); + currentDitherL -= (nsL[3] * 0.43); + currentDitherL += (nsL[6] * 0.5); + currentDitherL -= nsL[5]; + currentDitherL += nsL[4]; + //this sounds different from doing it in order of sample position + //cumulative tiny errors seem to build up even at this buss depth + //considerably more pronounced at 32 bit float. + //Therefore we add the most significant components LAST. + //trying to keep values on like exponents of the floating point value. + inputSampleL += currentDitherL; + + inputSampleL = floor(inputSampleL); + //done with L + + nsR[9] = nsR[8]; nsR[8] = nsR[7]; nsR[7] = nsR[6]; nsR[6] = nsR[5]; + nsR[5] = nsR[4]; nsR[4] = nsR[3]; nsR[3] = nsR[2]; nsR[2] = nsR[1]; + nsR[1] = nsR[0]; nsR[0] = (rand()/(double)RAND_MAX); + + currentDitherR = (nsR[0] * 0.061); + currentDitherR -= (nsR[1] * 0.11); + currentDitherR += (nsR[8] * 0.126); + currentDitherR -= (nsR[7] * 0.23); + currentDitherR += (nsR[2] * 0.25); + currentDitherR -= (nsR[3] * 0.43); + currentDitherR += (nsR[6] * 0.5); + currentDitherR -= nsR[5]; + currentDitherR += nsR[4]; + //this sounds different from doing it in order of sample position + //cumulative tiny errors seem to build up even at this buss depth + //considerably more pronounced at 32 bit float. + //Therefore we add the most significant components LAST. + //trying to keep values on like exponents of the floating point value. + inputSampleR += currentDitherR; + + inputSampleR = floor(inputSampleR); + //done with R + + //DoublePaul dither + break; + + case 6: + currentDitherL = (rand()/(double)RAND_MAX); + currentDitherR = (rand()/(double)RAND_MAX); + + inputSampleL += currentDitherL; + inputSampleR += currentDitherR; + inputSampleL -= nsL[4]; + inputSampleR -= nsR[4]; + + inputSampleL = floor(inputSampleL); + inputSampleR = floor(inputSampleR); + + nsL[4] = nsL[3]; + nsL[3] = nsL[2]; + nsL[2] = nsL[1]; + nsL[1] = currentDitherL; + + nsR[4] = nsR[3]; + nsR[3] = nsR[2]; + nsR[2] = nsR[1]; + nsR[1] = currentDitherR; + //Tape dither + break; + + case 7: Position += 1; //Note- uses integer overflow as a 'mod' operator hotbinA = Position * Position; @@ -111,7 +237,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //Quadratic dither break; - case 5: + case 8: absSample = ((rand()/(double)RAND_MAX) - 0.5); nsL[0] += absSample; nsL[0] /= 2; absSample -= nsL[0]; absSample += ((rand()/(double)RAND_MAX) - 0.5); @@ -206,7 +332,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //TenNines dither R break; - case 6: + case 9: if (inputSampleL > 0) inputSampleL += 0.383; if (inputSampleL < 0) inputSampleL -= 0.383; if (inputSampleR > 0) inputSampleR += 0.383; @@ -246,7 +372,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //and does a teeny parallel-compression thing when almost at digital black. break; - case 7: //this one is the original Naturalize + case 10: //this one is the original Naturalize if (inputSampleL > 0) inputSampleL += (0.3333333333); if (inputSampleL < 0) inputSampleL -= (0.3333333333); inputSampleL += (rand()/(double)RAND_MAX)*0.6666666666; @@ -406,7 +532,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //end R break; - case 8: //this one is the Not Just Another Dither + case 11: //this one is the Not Just Another Dither //begin L benfordize = floor(inputSampleL); @@ -571,7 +697,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl //end R break; - case 9: + case 12: //slew only outputSampleL = (inputSampleL - lastSampleL)*trim; outputSampleR = (inputSampleR - lastSampleR)*trim; @@ -585,7 +711,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl inputSampleR = outputSampleR; break; - case 10: + case 13: //subs only gain = gaintarget; @@ -801,7 +927,7 @@ void Ditherbox::processReplacing(float **inputs, float **outputs, VstInt32 sampl if (inputSampleR < -1.0) inputSampleR = -1.0; break; - case 11: + case 14: //silhouette //begin L bridgerectifier = fabs(inputSampleL)*1.57079633; @@ -893,7 +1019,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt double* out1 = outputs[0]; double* out2 = outputs[1]; - int dtype = (int)(A * 19.999); // +1 for Reaper bug workaround + int dtype = (int)(A * 24.999)+1; // +1 for Reaper bug workaround long double overallscale = 1.0; overallscale /= 44100.0; overallscale *= getSampleRate(); @@ -921,14 +1047,52 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt long double trim = 2.302585092994045684017991; //natural logarithm of 10 bool highRes = false; bool dithering = true; - if (dtype > 8){highRes = true; dtype -= 8;} - if (dtype > 8){dithering = false; highRes = false;} + if (dtype > 11){highRes = true; dtype -= 11;} + if (dtype > 11){dithering = false; highRes = false;} //follow up by switching high res back off for the monitoring while (--sampleFrames >= 0) { long double inputSampleL = *in1; long double inputSampleR = *in2; + if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) { + static int noisesource = 0; + //this declares a variable before anything else is compiled. It won't keep assigning + //it to 0 for every sample, it's as if the declaration doesn't exist in this context, + //but it lets me add this denormalization fix in a single place rather than updating + //it in three different locations. The variable isn't thread-safe but this is only + //a random seed and we can share it with whatever. + noisesource = noisesource % 1700021; noisesource++; + int residue = noisesource * noisesource; + residue = residue % 170003; residue *= residue; + residue = residue % 17011; residue *= residue; + residue = residue % 1709; residue *= residue; + residue = residue % 173; residue *= residue; + residue = residue % 17; + double applyresidue = residue; + applyresidue *= 0.00000001; + applyresidue *= 0.00000001; + inputSampleL = applyresidue; + } + if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) { + static int noisesource = 0; + noisesource = noisesource % 1700021; noisesource++; + int residue = noisesource * noisesource; + residue = residue % 170003; residue *= residue; + residue = residue % 17011; residue *= residue; + residue = residue % 1709; residue *= residue; + residue = residue % 173; residue *= residue; + residue = residue % 17; + double applyresidue = residue; + applyresidue *= 0.00000001; + applyresidue *= 0.00000001; + inputSampleR = applyresidue; + //this denormalization routine produces a white noise at -300 dB which the noise + //shaping will interact with to produce a bipolar output, but the noise is actually + //all positive. That should stop any variables from going denormal, and the routine + //only kicks in if digital black is input. As a final touch, if you save to 24-bit + //the silence will return to being digital black again. + } double drySampleL = inputSampleL; double drySampleR = inputSampleR; @@ -968,7 +1132,94 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //TPDF dither break; - case 4: + case 4: + currentDitherL = (rand()/(double)RAND_MAX); + inputSampleL += currentDitherL; + inputSampleL -= lastSampleL; + inputSampleL = floor(inputSampleL); + lastSampleL = currentDitherL; + currentDitherR = (rand()/(double)RAND_MAX); + inputSampleR += currentDitherR; + inputSampleR -= lastSampleR; + inputSampleR = floor(inputSampleR); + lastSampleR = currentDitherR; + //Paul dither + break; + + case 5: + nsL[9] = nsL[8]; nsL[8] = nsL[7]; nsL[7] = nsL[6]; nsL[6] = nsL[5]; + nsL[5] = nsL[4]; nsL[4] = nsL[3]; nsL[3] = nsL[2]; nsL[2] = nsL[1]; + nsL[1] = nsL[0]; nsL[0] = (rand()/(double)RAND_MAX); + + currentDitherL = (nsL[0] * 0.061); + currentDitherL -= (nsL[1] * 0.11); + currentDitherL += (nsL[8] * 0.126); + currentDitherL -= (nsL[7] * 0.23); + currentDitherL += (nsL[2] * 0.25); + currentDitherL -= (nsL[3] * 0.43); + currentDitherL += (nsL[6] * 0.5); + currentDitherL -= nsL[5]; + currentDitherL += nsL[4]; + //this sounds different from doing it in order of sample position + //cumulative tiny errors seem to build up even at this buss depth + //considerably more pronounced at 32 bit float. + //Therefore we add the most significant components LAST. + //trying to keep values on like exponents of the floating point value. + inputSampleL += currentDitherL; + + inputSampleL = floor(inputSampleL); + //done with L + + nsR[9] = nsR[8]; nsR[8] = nsR[7]; nsR[7] = nsR[6]; nsR[6] = nsR[5]; + nsR[5] = nsR[4]; nsR[4] = nsR[3]; nsR[3] = nsR[2]; nsR[2] = nsR[1]; + nsR[1] = nsR[0]; nsR[0] = (rand()/(double)RAND_MAX); + + currentDitherR = (nsR[0] * 0.061); + currentDitherR -= (nsR[1] * 0.11); + currentDitherR += (nsR[8] * 0.126); + currentDitherR -= (nsR[7] * 0.23); + currentDitherR += (nsR[2] * 0.25); + currentDitherR -= (nsR[3] * 0.43); + currentDitherR += (nsR[6] * 0.5); + currentDitherR -= nsR[5]; + currentDitherR += nsR[4]; + //this sounds different from doing it in order of sample position + //cumulative tiny errors seem to build up even at this buss depth + //considerably more pronounced at 32 bit float. + //Therefore we add the most significant components LAST. + //trying to keep values on like exponents of the floating point value. + inputSampleR += currentDitherR; + + inputSampleR = floor(inputSampleR); + //done with R + //DoublePaul dither + break; + + case 6: + currentDitherL = (rand()/(double)RAND_MAX); + currentDitherR = (rand()/(double)RAND_MAX); + + inputSampleL += currentDitherL; + inputSampleR += currentDitherR; + inputSampleL -= nsL[4]; + inputSampleR -= nsR[4]; + + inputSampleL = floor(inputSampleL); + inputSampleR = floor(inputSampleR); + + nsL[4] = nsL[3]; + nsL[3] = nsL[2]; + nsL[2] = nsL[1]; + nsL[1] = currentDitherL; + + nsR[4] = nsR[3]; + nsR[3] = nsR[2]; + nsR[2] = nsR[1]; + nsR[1] = currentDitherR; + //Tape dither + break; + + case 7: Position += 1; //Note- uses integer overflow as a 'mod' operator hotbinA = Position * Position; @@ -990,7 +1241,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //Quadratic dither break; - case 5: + case 8: absSample = ((rand()/(double)RAND_MAX) - 0.5); nsL[0] += absSample; nsL[0] /= 2; absSample -= nsL[0]; absSample += ((rand()/(double)RAND_MAX) - 0.5); @@ -1085,7 +1336,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //TenNines dither R break; - case 6: + case 9: if (inputSampleL > 0) inputSampleL += 0.383; if (inputSampleL < 0) inputSampleL -= 0.383; if (inputSampleR > 0) inputSampleR += 0.383; @@ -1125,7 +1376,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //and does a teeny parallel-compression thing when almost at digital black. break; - case 7: //this one is the original Naturalize + case 10: //this one is the original Naturalize if (inputSampleL > 0) inputSampleL += (0.3333333333); if (inputSampleL < 0) inputSampleL -= (0.3333333333); inputSampleL += (rand()/(double)RAND_MAX)*0.6666666666; @@ -1285,7 +1536,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //end R break; - case 8: //this one is the Not Just Another Dither + case 11: //this one is the Not Just Another Dither //begin L benfordize = floor(inputSampleL); @@ -1450,7 +1701,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt //end R break; - case 9: + case 12: //slew only outputSampleL = (inputSampleL - lastSampleL)*trim; outputSampleR = (inputSampleR - lastSampleR)*trim; @@ -1464,7 +1715,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt inputSampleR = outputSampleR; break; - case 10: + case 13: //subs only gain = gaintarget; @@ -1680,7 +1931,7 @@ void Ditherbox::processDoubleReplacing(double **inputs, double **outputs, VstInt if (inputSampleR < -1.0) inputSampleR = -1.0; break; - case 11: + case 14: //silhouette //begin L bridgerectifier = fabs(inputSampleL)*1.57079633; -- cgit v1.2.3