mirror of
https://github.com/airwindows/airwindows.git
synced 2026-05-21 06:46:21 -06:00
505 lines
No EOL
15 KiB
C++
Executable file
505 lines
No EOL
15 KiB
C++
Executable file
/* ========================================
|
|
* NotJustAnotherDither - NotJustAnotherDither.h
|
|
* Copyright (c) 2016 airwindows, All rights reserved
|
|
* ======================================== */
|
|
|
|
#ifndef __NotJustAnotherDither_H
|
|
#include "NotJustAnotherDither.h"
|
|
#endif
|
|
|
|
void NotJustAnotherDither::processReplacing(float **inputs, float **outputs, VstInt32 sampleFrames)
|
|
{
|
|
float* in1 = inputs[0];
|
|
float* in2 = inputs[1];
|
|
float* out1 = outputs[0];
|
|
float* out2 = outputs[1];
|
|
|
|
long double inputSampleL;
|
|
long double inputSampleR;
|
|
|
|
double benfordize;
|
|
int hotbinA;
|
|
int hotbinB;
|
|
double totalA;
|
|
double totalB;
|
|
float drySampleL;
|
|
float drySampleR;
|
|
|
|
while (--sampleFrames >= 0)
|
|
{
|
|
inputSampleL = *in1;
|
|
inputSampleR = *in2;
|
|
if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
|
|
static int noisesource = 0;
|
|
//this declares a variable before anything else is compiled. It won't keep assigning
|
|
//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
|
|
//but it lets me add this denormalization fix in a single place rather than updating
|
|
//it in three different locations. The variable isn't thread-safe but this is only
|
|
//a random seed and we can share it with whatever.
|
|
noisesource = noisesource % 1700021; noisesource++;
|
|
int residue = noisesource * noisesource;
|
|
residue = residue % 170003; residue *= residue;
|
|
residue = residue % 17011; residue *= residue;
|
|
residue = residue % 1709; residue *= residue;
|
|
residue = residue % 173; residue *= residue;
|
|
residue = residue % 17;
|
|
double applyresidue = residue;
|
|
applyresidue *= 0.00000001;
|
|
applyresidue *= 0.00000001;
|
|
inputSampleL = applyresidue;
|
|
}
|
|
if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
|
|
static int noisesource = 0;
|
|
noisesource = noisesource % 1700021; noisesource++;
|
|
int residue = noisesource * noisesource;
|
|
residue = residue % 170003; residue *= residue;
|
|
residue = residue % 17011; residue *= residue;
|
|
residue = residue % 1709; residue *= residue;
|
|
residue = residue % 173; residue *= residue;
|
|
residue = residue % 17;
|
|
double applyresidue = residue;
|
|
applyresidue *= 0.00000001;
|
|
applyresidue *= 0.00000001;
|
|
inputSampleR = applyresidue;
|
|
//this denormalization routine produces a white noise at -300 dB which the noise
|
|
//shaping will interact with to produce a bipolar output, but the noise is actually
|
|
//all positive. That should stop any variables from going denormal, and the routine
|
|
//only kicks in if digital black is input. As a final touch, if you save to 24-bit
|
|
//the silence will return to being digital black again.
|
|
}
|
|
drySampleL = inputSampleL;
|
|
drySampleR = inputSampleR;
|
|
|
|
inputSampleL -= noiseShapingL;
|
|
inputSampleR -= noiseShapingR;
|
|
|
|
inputSampleL *= 8388608.0;
|
|
inputSampleR *= 8388608.0;
|
|
//0-1 is now one bit, now we dither
|
|
|
|
//begin L
|
|
benfordize = floor(inputSampleL);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinA = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number floored
|
|
totalA = 0;
|
|
if ((hotbinA > 0) && (hotbinA < 10))
|
|
{
|
|
bynL[hotbinA] += 1;
|
|
totalA += (301-bynL[1]);
|
|
totalA += (176-bynL[2]);
|
|
totalA += (125-bynL[3]);
|
|
totalA += (97-bynL[4]);
|
|
totalA += (79-bynL[5]);
|
|
totalA += (67-bynL[6]);
|
|
totalA += (58-bynL[7]);
|
|
totalA += (51-bynL[8]);
|
|
totalA += (46-bynL[9]);
|
|
bynL[hotbinA] -= 1;
|
|
} else {hotbinA = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
benfordize = ceil(inputSampleL);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinB = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number ceiled
|
|
totalB = 0;
|
|
if ((hotbinB > 0) && (hotbinB < 10))
|
|
{
|
|
bynL[hotbinB] += 1;
|
|
totalB += (301-bynL[1]);
|
|
totalB += (176-bynL[2]);
|
|
totalB += (125-bynL[3]);
|
|
totalB += (97-bynL[4]);
|
|
totalB += (79-bynL[5]);
|
|
totalB += (67-bynL[6]);
|
|
totalB += (58-bynL[7]);
|
|
totalB += (51-bynL[8]);
|
|
totalB += (46-bynL[9]);
|
|
bynL[hotbinB] -= 1;
|
|
} else {hotbinB = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
if (totalA < totalB)
|
|
{
|
|
bynL[hotbinA] += 1;
|
|
inputSampleL = floor(inputSampleL);
|
|
}
|
|
else
|
|
{
|
|
bynL[hotbinB] += 1;
|
|
inputSampleL = ceil(inputSampleL);
|
|
}
|
|
//assign the relevant one to the delay line
|
|
//and floor/ceil signal accordingly
|
|
|
|
totalA = bynL[1] + bynL[2] + bynL[3] + bynL[4] + bynL[5] + bynL[6] + bynL[7] + bynL[8] + bynL[9];
|
|
totalA /= 1000;
|
|
if (totalA = 0) totalA = 1;
|
|
bynL[1] /= totalA;
|
|
bynL[2] /= totalA;
|
|
bynL[3] /= totalA;
|
|
bynL[4] /= totalA;
|
|
bynL[5] /= totalA;
|
|
bynL[6] /= totalA;
|
|
bynL[7] /= totalA;
|
|
bynL[8] /= totalA;
|
|
bynL[9] /= totalA;
|
|
bynL[10] /= 2; //catchall for garbage data
|
|
//end L
|
|
|
|
//begin R
|
|
benfordize = floor(inputSampleR);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinA = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number floored
|
|
totalA = 0;
|
|
if ((hotbinA > 0) && (hotbinA < 10))
|
|
{
|
|
bynR[hotbinA] += 1;
|
|
totalA += (301-bynR[1]);
|
|
totalA += (176-bynR[2]);
|
|
totalA += (125-bynR[3]);
|
|
totalA += (97-bynR[4]);
|
|
totalA += (79-bynR[5]);
|
|
totalA += (67-bynR[6]);
|
|
totalA += (58-bynR[7]);
|
|
totalA += (51-bynR[8]);
|
|
totalA += (46-bynR[9]);
|
|
bynR[hotbinA] -= 1;
|
|
} else {hotbinA = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
benfordize = ceil(inputSampleR);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinB = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number ceiled
|
|
totalB = 0;
|
|
if ((hotbinB > 0) && (hotbinB < 10))
|
|
{
|
|
bynR[hotbinB] += 1;
|
|
totalB += (301-bynR[1]);
|
|
totalB += (176-bynR[2]);
|
|
totalB += (125-bynR[3]);
|
|
totalB += (97-bynR[4]);
|
|
totalB += (79-bynR[5]);
|
|
totalB += (67-bynR[6]);
|
|
totalB += (58-bynR[7]);
|
|
totalB += (51-bynR[8]);
|
|
totalB += (46-bynR[9]);
|
|
bynR[hotbinB] -= 1;
|
|
} else {hotbinB = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
if (totalA < totalB)
|
|
{
|
|
bynR[hotbinA] += 1;
|
|
inputSampleR = floor(inputSampleR);
|
|
}
|
|
else
|
|
{
|
|
bynR[hotbinB] += 1;
|
|
inputSampleR = ceil(inputSampleR);
|
|
}
|
|
//assign the relevant one to the delay line
|
|
//and floor/ceil signal accordingly
|
|
|
|
totalA = bynR[1] + bynR[2] + bynR[3] + bynR[4] + bynR[5] + bynR[6] + bynR[7] + bynR[8] + bynR[9];
|
|
totalA /= 1000;
|
|
if (totalA = 0) totalA = 1;
|
|
bynR[1] /= totalA;
|
|
bynR[2] /= totalA;
|
|
bynR[3] /= totalA;
|
|
bynR[4] /= totalA;
|
|
bynR[5] /= totalA;
|
|
bynR[6] /= totalA;
|
|
bynR[7] /= totalA;
|
|
bynR[8] /= totalA;
|
|
bynR[9] /= totalA;
|
|
bynR[10] /= 2; //catchall for garbage data
|
|
//end R
|
|
|
|
inputSampleL /= 8388608.0;
|
|
inputSampleR /= 8388608.0;
|
|
|
|
noiseShapingL += inputSampleL - drySampleL;
|
|
noiseShapingR += inputSampleR - drySampleR;
|
|
|
|
*out1 = inputSampleL;
|
|
*out2 = inputSampleR;
|
|
|
|
*in1++;
|
|
*in2++;
|
|
*out1++;
|
|
*out2++;
|
|
}
|
|
}
|
|
|
|
void NotJustAnotherDither::processDoubleReplacing(double **inputs, double **outputs, VstInt32 sampleFrames)
|
|
{
|
|
double* in1 = inputs[0];
|
|
double* in2 = inputs[1];
|
|
double* out1 = outputs[0];
|
|
double* out2 = outputs[1];
|
|
|
|
|
|
long double inputSampleL;
|
|
long double inputSampleR;
|
|
|
|
double benfordize;
|
|
int hotbinA;
|
|
int hotbinB;
|
|
double totalA;
|
|
double totalB;
|
|
double drySampleL;
|
|
double drySampleR;
|
|
|
|
while (--sampleFrames >= 0)
|
|
{
|
|
inputSampleL = *in1;
|
|
inputSampleR = *in2;
|
|
if (inputSampleL<1.2e-38 && -inputSampleL<1.2e-38) {
|
|
static int noisesource = 0;
|
|
//this declares a variable before anything else is compiled. It won't keep assigning
|
|
//it to 0 for every sample, it's as if the declaration doesn't exist in this context,
|
|
//but it lets me add this denormalization fix in a single place rather than updating
|
|
//it in three different locations. The variable isn't thread-safe but this is only
|
|
//a random seed and we can share it with whatever.
|
|
noisesource = noisesource % 1700021; noisesource++;
|
|
int residue = noisesource * noisesource;
|
|
residue = residue % 170003; residue *= residue;
|
|
residue = residue % 17011; residue *= residue;
|
|
residue = residue % 1709; residue *= residue;
|
|
residue = residue % 173; residue *= residue;
|
|
residue = residue % 17;
|
|
double applyresidue = residue;
|
|
applyresidue *= 0.00000001;
|
|
applyresidue *= 0.00000001;
|
|
inputSampleL = applyresidue;
|
|
}
|
|
if (inputSampleR<1.2e-38 && -inputSampleR<1.2e-38) {
|
|
static int noisesource = 0;
|
|
noisesource = noisesource % 1700021; noisesource++;
|
|
int residue = noisesource * noisesource;
|
|
residue = residue % 170003; residue *= residue;
|
|
residue = residue % 17011; residue *= residue;
|
|
residue = residue % 1709; residue *= residue;
|
|
residue = residue % 173; residue *= residue;
|
|
residue = residue % 17;
|
|
double applyresidue = residue;
|
|
applyresidue *= 0.00000001;
|
|
applyresidue *= 0.00000001;
|
|
inputSampleR = applyresidue;
|
|
//this denormalization routine produces a white noise at -300 dB which the noise
|
|
//shaping will interact with to produce a bipolar output, but the noise is actually
|
|
//all positive. That should stop any variables from going denormal, and the routine
|
|
//only kicks in if digital black is input. As a final touch, if you save to 24-bit
|
|
//the silence will return to being digital black again.
|
|
}
|
|
drySampleL = inputSampleL;
|
|
drySampleR = inputSampleR;
|
|
|
|
inputSampleL -= noiseShapingL;
|
|
inputSampleR -= noiseShapingR;
|
|
|
|
inputSampleL *= 8388608.0;
|
|
inputSampleR *= 8388608.0;
|
|
//0-1 is now one bit, now we dither
|
|
|
|
//begin L
|
|
benfordize = floor(inputSampleL);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinA = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number floored
|
|
totalA = 0;
|
|
if ((hotbinA > 0) && (hotbinA < 10))
|
|
{
|
|
bynL[hotbinA] += 1;
|
|
totalA += (301-bynL[1]);
|
|
totalA += (176-bynL[2]);
|
|
totalA += (125-bynL[3]);
|
|
totalA += (97-bynL[4]);
|
|
totalA += (79-bynL[5]);
|
|
totalA += (67-bynL[6]);
|
|
totalA += (58-bynL[7]);
|
|
totalA += (51-bynL[8]);
|
|
totalA += (46-bynL[9]);
|
|
bynL[hotbinA] -= 1;
|
|
} else {hotbinA = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
benfordize = ceil(inputSampleL);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinB = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number ceiled
|
|
totalB = 0;
|
|
if ((hotbinB > 0) && (hotbinB < 10))
|
|
{
|
|
bynL[hotbinB] += 1;
|
|
totalB += (301-bynL[1]);
|
|
totalB += (176-bynL[2]);
|
|
totalB += (125-bynL[3]);
|
|
totalB += (97-bynL[4]);
|
|
totalB += (79-bynL[5]);
|
|
totalB += (67-bynL[6]);
|
|
totalB += (58-bynL[7]);
|
|
totalB += (51-bynL[8]);
|
|
totalB += (46-bynL[9]);
|
|
bynL[hotbinB] -= 1;
|
|
} else {hotbinB = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
if (totalA < totalB)
|
|
{
|
|
bynL[hotbinA] += 1;
|
|
inputSampleL = floor(inputSampleL);
|
|
}
|
|
else
|
|
{
|
|
bynL[hotbinB] += 1;
|
|
inputSampleL = ceil(inputSampleL);
|
|
}
|
|
//assign the relevant one to the delay line
|
|
//and floor/ceil signal accordingly
|
|
|
|
totalA = bynL[1] + bynL[2] + bynL[3] + bynL[4] + bynL[5] + bynL[6] + bynL[7] + bynL[8] + bynL[9];
|
|
totalA /= 1000;
|
|
if (totalA = 0) totalA = 1;
|
|
bynL[1] /= totalA;
|
|
bynL[2] /= totalA;
|
|
bynL[3] /= totalA;
|
|
bynL[4] /= totalA;
|
|
bynL[5] /= totalA;
|
|
bynL[6] /= totalA;
|
|
bynL[7] /= totalA;
|
|
bynL[8] /= totalA;
|
|
bynL[9] /= totalA;
|
|
bynL[10] /= 2; //catchall for garbage data
|
|
//end L
|
|
|
|
//begin R
|
|
benfordize = floor(inputSampleR);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinA = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number floored
|
|
totalA = 0;
|
|
if ((hotbinA > 0) && (hotbinA < 10))
|
|
{
|
|
bynR[hotbinA] += 1;
|
|
totalA += (301-bynR[1]);
|
|
totalA += (176-bynR[2]);
|
|
totalA += (125-bynR[3]);
|
|
totalA += (97-bynR[4]);
|
|
totalA += (79-bynR[5]);
|
|
totalA += (67-bynR[6]);
|
|
totalA += (58-bynR[7]);
|
|
totalA += (51-bynR[8]);
|
|
totalA += (46-bynR[9]);
|
|
bynR[hotbinA] -= 1;
|
|
} else {hotbinA = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
benfordize = ceil(inputSampleR);
|
|
while (benfordize >= 1.0) {benfordize /= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
if (benfordize < 1.0) {benfordize *= 10;}
|
|
hotbinB = floor(benfordize);
|
|
//hotbin becomes the Benford bin value for this number ceiled
|
|
totalB = 0;
|
|
if ((hotbinB > 0) && (hotbinB < 10))
|
|
{
|
|
bynR[hotbinB] += 1;
|
|
totalB += (301-bynR[1]);
|
|
totalB += (176-bynR[2]);
|
|
totalB += (125-bynR[3]);
|
|
totalB += (97-bynR[4]);
|
|
totalB += (79-bynR[5]);
|
|
totalB += (67-bynR[6]);
|
|
totalB += (58-bynR[7]);
|
|
totalB += (51-bynR[8]);
|
|
totalB += (46-bynR[9]);
|
|
bynR[hotbinB] -= 1;
|
|
} else {hotbinB = 10;}
|
|
//produce total number- smaller is closer to Benford real
|
|
|
|
if (totalA < totalB)
|
|
{
|
|
bynR[hotbinA] += 1;
|
|
inputSampleR = floor(inputSampleR);
|
|
}
|
|
else
|
|
{
|
|
bynR[hotbinB] += 1;
|
|
inputSampleR = ceil(inputSampleR);
|
|
}
|
|
//assign the relevant one to the delay line
|
|
//and floor/ceil signal accordingly
|
|
|
|
totalA = bynR[1] + bynR[2] + bynR[3] + bynR[4] + bynR[5] + bynR[6] + bynR[7] + bynR[8] + bynR[9];
|
|
totalA /= 1000;
|
|
if (totalA = 0) totalA = 1;
|
|
bynR[1] /= totalA;
|
|
bynR[2] /= totalA;
|
|
bynR[3] /= totalA;
|
|
bynR[4] /= totalA;
|
|
bynR[5] /= totalA;
|
|
bynR[6] /= totalA;
|
|
bynR[7] /= totalA;
|
|
bynR[8] /= totalA;
|
|
bynR[9] /= totalA;
|
|
bynR[10] /= 2; //catchall for garbage data
|
|
//end R
|
|
|
|
inputSampleL /= 8388608.0;
|
|
inputSampleR /= 8388608.0;
|
|
|
|
noiseShapingL += inputSampleL - drySampleL;
|
|
noiseShapingR += inputSampleR - drySampleR;
|
|
|
|
*out1 = inputSampleL;
|
|
*out2 = inputSampleR;
|
|
|
|
*in1++;
|
|
*in2++;
|
|
*out1++;
|
|
*out2++;
|
|
}
|
|
} |