/*
Dither

Range of dither types for word-length reduction.

Bits		Output word length 8 - 24 bits
Dither Type	OFF	- Truncation
		TRI	- Triangular PDF dither
		HP-TRI	- High-pass Triangular PDF dither (a good general purpose dither)
		N-SHAPE	- Second-order noise-shaped dither (for final mastering to 8 or 16 bits)
Dither Level	Is at optimum level but can be turned down to reduce background hiss
		at the expense of dither level "pumping" caused by the input signal type and level
DC Trim		Fine tune DC offset - can help get best dither sound for silent or very quiet inputs
Zoom		Allows the signal to be faded into the noise floor at a clearly audible level so dither settings can be "auditioned"
		Note that some (perceptual) properties of dither will change when listened to in this way

Technical notes:

When a waveform is rounded to the nearest 16 (or whatever)-bit value this causes distortion.
Dither allows you to exchange this rough sounding signal-dependant distortion for a smooth background hiss.

Some sort of dither should always be used when reducing the word length of digital audio,
such as from 24-bit to 16-bit. In many cases the background noise in a recording will act as dither,
but dither will still be required on fades and on very clean recordings such as purely synthetic sources.

Noise shaping makes the background hiss of dither sound quieter,
but adds more high-frequency noise than 'ordinary' dither.
This high frequency noise can be a problem if a recording is later processed in any way
(including gain changes) especially if noise shaping is applied a second time.

If you are producing an absolutely final master at 16 bits or less, use noise shaped dither.
In all other situations use a non-noise-shaped dither such as high-pass-triangular.
When mastering for MP3 or other compressed formats be aware that noise shaping
may take some of the encoder's 'attention' away from the real signal at high frequencies.

No gain changes should be applied after this plug-in.
Make sure any master output fader is set to 0.0 dB in the host application.
*/

slider1:16<8,24,8>bits
slider2:3<0,3,1{OFF,TRI,HP-TRI,N-SHAPE}>dither type
slider3:0.5<0,1,0.01>dither level
slider4:0.5<0,1,0.01>dc trim
slider5:0<0,1,0.01>zoom

in_pin:L in
in_pin:R in
out_pin:L out
out_pin:R out

@init
ext_nodenorm = 1;

sh1 = sh2 = sh3 = sh4 = 0;
r1 = r2 = 0;

@slider
fParam0 = slider1; //resolution/word length/bits
fParam1 = slider2; //dither type
fParam2 = slider3; //dither level
fParam3 = slider4; //dc trim
fParam4 = slider5; //zoom

gain = 1;

(fParam4>0.1) ? (
wlen = 32;
gain = (1 - fParam4);
gain *= gain;
):
wlen = pow(2, fParam0 - 1);
wi = 1/wlen;

offs = (4 * fParam3 - 1.5);
dith = 4 * fParam2;
shap = 0;

(fParam1==3) ? shap = 0.5;

@sample
a = spl0 * gain + shap * (sh1+sh1-sh2);
b = spl1 * gain + shap * (sh3+sh3-sh4);

fParam1 == 2 ? r2 = r1 : r2 = 0;
fParam1 > 0 ? r1 = (rand(10000)+rand(10000))/10000 - 1 : r1 = 0;

noise = (r1-r2) * dith + offs;

spl0 = max(min((floor(a*wlen + noise))*wi,1),-1);
spl1 = max(min((floor(b*wlen + noise))*wi,1),-1);

sh2 = sh1;
sh4 = sh3;

sh1 = a - spl0;
sh3 = b - spl1;

@gfx 0 80
gfx_r=0; gfx_g=0.9; gfx_b=0; gfx_a=1;
gfx_setfont(1,"Arial", 16);

gfx_x =20; gfx_y =10;  gfx_printf("%.2f",(4 * fParam2) );
gfx_x =70; gfx_y =10;  gfx_printf("lsb");
gfx_x =110; gfx_y =10;  gfx_printf("Dither Level");

gfx_x =20; gfx_y =30;  gfx_printf("%.2f",(4 * fParam3 - 2) );
gfx_x =70; gfx_y =30;  gfx_printf("lsb");
gfx_x =110; gfx_y =30;  gfx_printf("DC Trim");

(fParam4>0.1) ? (
(gain<0.0001) ? (
gfx_x =20; gfx_y =50;  gfx_printf("-80");
gfx_x =70; gfx_y =50;  gfx_printf("dB");
):(
gfx_x =20; gfx_y =50;  gfx_printf("%.1f",(20 * log10(gain)));
gfx_x =70; gfx_y =50;  gfx_printf("dB");
);
):(
gfx_x =20; gfx_y =50;  gfx_printf("OFF");
);
gfx_x =110; gfx_y =50;  gfx_printf("Zoom");
