View Single Post
Old 08-29-2018, 12:48 PM   #5
earlevel
Human being with feelings
 
Join Date: Dec 2015
Posts: 331
Default

You're on the right track. A little explanation first, if you don't already know (or for the benefit of future thread readers).

Floating point processors try to keep number in a normalized state, which means everything is of of the form of signed 1.xxxxx times 2^n, to take full advantage of the mantissa bits (and 1 is discarded to gain a bit). Even through that allows for tiny numbers, processors go a step further and allow numbers to be de-normallized. So if the smallest normalized number is 1.00000 x 2^-127, denormalization allows 0.00001 x 2^-127. This trick allows greater precision for values close to zero. But there's a hug performance penalty. modern processors have means of flushing to zero or treating denormals as zero, another topic.

In plugins, you may have a recursive lowpass filter. Everything's fine while you're putting audio through it, but maybe when you stop playback, the host continues to send you empty buffers. So, you have zero into the filter, and decaying what's in the filter memory—eventually into denormals, which in turn propagate to your next DSP elements.

But again you were on the right track. Another way to get rid of denormals is to add a small DC offset to the signal. 1E-15 is a nice number, because it's -300 dB—even with substantial gain, it will never get close to your 24-bit DAC output, or 32-bit float files. Yet, it's relatively large compared to denormals (hundreds of dB for float, thousands for double)—even if your DSP chain reduced it by a high margin, it's still big enough to wipe denormals. A highpass filter in the chain could take it out, but you can either re-add it after such key points in your chain, better yet just alternate it plus and minus periodically (like, reverse it each time you get a buffer to process).

If you are truly paranoid about adding values hundreds of dB down, you can add the small value then subtract it. The nature of floating point is that adding very small numbers to relative large number results in no change to the large number. So, adding 1E-15 to 1.2345E-3 results in 1.2345E-3—no change. And if you subtract 1E-15 from that, you still end up with 1.2345E-3—again no change. But adding 1E-15 to denormalized 0.0001E-127 yields 1E-15. Then if you subtract 1E-15 from that you get 0.0000—you just flushed any denormalized number to zero, while having no effect at all on larger numbers. But practically, just adding the tiny value does the trick.
earlevel is offline   Reply With Quote