DitherFloat

TL;DW: Look down. Look up. Your plugins are now dithered to 32 bit floating point :D

DitherFloat

This began as a challenge. A forum poster said you couldn’t dither floating point outputs, and posted a link to a study explaining why.

Floating point (including the kind that fits between every plugin in a mix on MacOS or 32-bit bussed VST) has fixed point math of the kind one needs to dither, in a part of the number called the mantissa. (64-bit VST has it too, just more finely grained.) It’s not all that hard to work out how to apply dither to this part. You scale it up or down according to the part of the number called the exponent.

The trouble is (a) it’s hard enough getting people to dither to 16-bit CDs, and (b) the argument is that the amplitude of the dither would fluctuate madly, making it unhelpful and incorrect. This is kind of like how flat dither isn’t correct: with only one noise source what happens is, the noise floor fluctuates according to the waveform causing a kind of distortion. If you have a low sine wave you’ll hear the ripple effect of flat dither, and the argument is that dithering floating point is like that only more so (and so, nobody ever tried).

DitherFloat demonstrates this, and it’s not true. You can TPDF dither (even PaulDither, like I’m using here) floating point. The noise doesn’t fluctuate according to the waveform represented in the mantissa. It fluctuates according to the value in the EXPONENT, because it has to, because the quantization noise also fluctuates wildly in volume. And if you get it right, you end up with no truncation distortion at all, just like using TPDF to fixed point.

The video explains more and shows it working. It’s practically impossible to hear ONE stage of 32 bit truncation (may be literally impossible, I think) but you can cheat and hear it as obviously as you like. You just add a huge offset to the number, convert it to float, and then subtract the offset again: and that’s what DitherFloat does. It’s a demo. It shows you there’s still truncation in floats, and it shows you the way TPDF dither completely removes the truncation distortion. It linearizes the signal so that no trace of the truncation is present (that’s how correct dither works).

You can’t add DitherFloat after existing plugins to fix them: even though you can use it (with zero offset) to export a 64 bit buss to 32 bit float and dither it, by itself DitherFloat can’t fix existing plugins. You would have to put the code for the dithering, into every single plugin that outputs 32 bit floats. Every MacOS plugin, every singlereplacing VST (every older VST implementation before they implemented 64 bit buss). For the Airwindows library that would involve personally revising every plugin I’ve released under the VST/Patreon years, many hundreds of plugins.

So I did. :D

See the video, and to update everything you have, download NewUpdates.zip to drag and drop the whole collection (or whatever subset of it you use) to your plugins folder. Each individual plugin package has also been updated for people who download them one at a time, or find them through search. The only exceptions are plugins that are already dithers, or things like DCOffset and BitShiftGain that are meant to work with the direct sample values (BitShiftGain is purer than even 32 bit dithering: it literally changes only the exponent and leaves the mantissa always exactly as it was, only at a different gain scale, so it’s cleaner than even PurestGain). (if you need to roll back for any reason, BeforeFPDither.zip is the previous version, untouched)

It’s free. Go ahead and use all this. I don’t have to put any barrier in your way. Update the plugins for free, read the source code on my github page, and the new code is this, intentionally dual licensed in addition to my MIT license.

//This is free and unencumbered software released into the public domain.
uint32_t fpd; //this goes where fpNShape went, but it's an unsigned int used for the random generator
fpd = 17; //the random generator is xorshift32 which can't start off with zero.
//then in the actual processing code:
int expon; frexpf((float)inputSample, &expon);
fpd ^= fpd<<13; fpd ^= fpd>>17; fpd ^= fpd<<5;
inputSample += (fpd*3.4e-36l*pow(2,expon+62));
//Anyone is free to copy, modify, publish, use, compile, sell, or
//distribute this software, either in source code form or as a compiled
//binary, for any purpose, commercial or non-commercial, and by any
//means.
//In jurisdictions that recognize copyright laws, the author or authors
//of this software dedicate any and all copyright interest in the
//software to the public domain. We make this dedication for the benefit
//of the public at large and to the detriment of our heirs and
//successors. We intend this dedication to be an overt act of
//relinquishment in perpetuity of all present and future rights to this
//software under copyright law.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
//OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.

64 bit version for hilarious overkill is almost identical but with small changes in frexp() and the constants. This is now a sort of mad community effort, so that becomes public domain too:

//This is free and unencumbered software released into the public domain.
uint32_t fpd; //this goes where fpNShape went, but it's an unsigned int used for the random generator
fpd = 17; //the random generator is xorshift32 which can't start off with zero.
//then in the actual processing code:
int expon; frexp((double)inputSample, &expon);
fpd ^= fpd<<13; fpd ^= fpd>>17; fpd ^= fpd<<5;
inputSample += (fpd*6.4e-45l*pow(2,expon+62));
//Anyone is free to copy, modify, publish, use, compile, sell, or
//distribute this software, either in source code form or as a compiled
//binary, for any purpose, commercial or non-commercial, and by any
//means.
//In jurisdictions that recognize copyright laws, the author or authors
//of this software dedicate any and all copyright interest in the
//software to the public domain. We make this dedication for the benefit
//of the public at large and to the detriment of our heirs and
//successors. We intend this dedication to be an overt act of
//relinquishment in perpetuity of all present and future rights to this
//software under copyright law.
//THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
//EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
//MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
//IN NO EVENT SHALL THE AUTHORS BE LIABLE FOR ANY CLAIM, DAMAGES OR
//OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE,
//ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR
//OTHER DEALINGS IN THE SOFTWARE.

It’s not complicated but it’s my own code and it’ll work: it’s even pretty easy to drop into other plugins. If anyone’s game to do that and shout out that they did, I’d love to hear about it.

If they don’t, they will just continue adding a little truncation with every single plugin, every single calculation, and now none of MY plugins do that :)

If you like me being able to discover something like this, becoming determined to explore it, discovering that it’s a huge upgrade and implementing it into every (relevant) plugin I make, and then giving it to the world even more than I usually do, please support my Patreon. I like days like this. I like helping the industry (to the extent it’s willing to be helped, which is always a question) and advancing the science of digital audio, and I especially like making demos where it’s plain to hear what’s being done under the hood. And I wouldn’t be able to do it if not for Patreon, which doesn’t make as much money as commercial work (I’m still very poor) but it’s steadier, and it lets me give these tools to ALL the musicians whether they’re broke or not :)

Thank you and good night. Next up is Pafnuty, next week.