Dithering in C++

Hello everyone,

I know this forum isn’t meant to help with DIY builds, but this is more of a curious questions about customizing firmware, I hope it’s OK.

Could anyone here help me out with simple audio dithering in C++?

I’ve just watched this very good video on the subject of dithering in audio.

I’ve looked at the 12 bit Braids eurorack module’s DAC.h function. To convert from 16 to 12 bits, the code just bitshifts the output values 4 bits to the right to truncate them.

Simple, but now my kicks have a weird tail… So, as I understand, I just need to add a random value to my 16 bit value before bitshifting.

My questions are:

  1. How many bits of noise do I need before truncating? I’m guessing 5 bits.
  2. How can I implement Triangular Probability Density Function? Should I create two 4 bit random values and add them?

For this, I’ve included the stmlib/utils/random.h file from Stages, to use Random::GetSample(), which returns a fixed width 16 bit random value.

Here’s my current code:

int16_t dit1 = Random::GetSample() >> 12;
int16_t dit2 = Random::GetSample() >> 12;
int16_t noise = dit1 + dit2 - 15;
value = value + noise;
value = value >> 4;

This doesn’t give me the wanted results. It’s just adding noise, and not helping with the quantization errors I think I’m hearing.

Any help appreciated, even if just to tell me this is a futile pursuit :smiley:

Interesting topic, wondering how effective dithering will be on the Braids DAC, but anyway the musicdsp.org archive contains several dithering ideas so you might be able find something useful there

Thanks for the nudge in the right direction :smiley: I did indeed stumble across musicdsp.org and it’s example with floats. I’m still a beginner so I’m taking time to figure out how to apply it to unsigned integers but I think it’s the right path. I also found this old post from Mutable themselves. It’s for signed integers so it also needs a bit of adapting but it might be more suited to my needs.

As far as I understand, the dithering should round to zero on any input value that is already quantized to the output bit depth.
The simple test: set your dither noise to the maximum value it can be and add it to an input of e.g. 0, then bitshift/quantize. The output should also be 0. The dithering should only have an effect on input values between two output values.

At first glance, your code looks correct but maybe trying the simple test can help you debug the problem?

The other thing to understand is that dithering cannot artificially increase the SNR of the output signal. All it does is to spread the quantization noise across a wider spectrum. Maybe the noise you hear is that spread-out residual noise?
Again on a quantized input, there should be no residual noise if the dithering is implemented correctly.

1 Like

Hello, thank you for responding,

I think the dither adds noise even when the original input value is already at a exact quantized value. It heightens the noise floor, but it reduce quantization “glitches”. So I think there should be residual noise, like how it looks at at 3:45 in the video I linked.