Audio signal lost for very low signal

Hi,

I noticed that JUCE gates-out all very-low-signal, lower than exactly -100 (dB).

I’ve built the simplest buffer_in to buffer_out plug-in and tested it:
With a -99db input the output is -99dB.
With a -101db input the output is -INFdB. Gone.

For a specific task, I need extremely low signals, like -110/-120 dB.

How can I bypass this in-built gate ?

Using JUCE 7.0.5 for building windows based apps. currently testing on Ableton 10.

Are you using decibelsToGain() or gainToDecibels() anywhere? they both take a second argument minusInfinityDb which by default is -100dB.

Thanks for the answer but not using the mentioned functions.

Are you sure it’s a Juce issue and not something happening in Ableton Live itself?

Thanks, but when I bypass the plug-in, ableton passes even lower than -100 db signals.

I have just tried one of my saturation plugins (built with JUCE 7.0.10) in Reaper. And I put the following things on a track:

  • a -12dB pink noise generator
  • a -100dB volume adjustment
  • the saturation plugin
  • a +100dB volume adjustment

And I can hear the pink noise, i.e., it is not -INF. Perhaps you can verify whether it is actual muted in ableton?


Not sure whether it is windows-related :melting_face: I am on mac

The fact that it’s -100dB makes me suspicious that decibelsToGain() or gainToDecibels() are being used somewhere, maybe indirectly. For example are you using a juce::dsp::Gain object? or any other juce::dsp classes?

When you say you’ve built a simple buffer in to buffer out plugin, could you share the processBlock? are you really doing absolutely nothing? for example if you create a brand new juce plugin and do nothing do you have the same issue?

1 Like

thanks for all the answers. I’ll check and update.

I released this free plugin, that can display signals as low as -190 dB:

(To get it to read down that far, set it for 20 LEDs, and 10 dB per LED)

So I can tell you that JUCE definitely does not automatically gate signals under -100 dB.

The Simple Meter plugin may also be useful for your testing efforts.

FYI you can also pass -INFINITY instead of the default of -100. I’m using this for all my plug-ins and have never run into any issues. You do need to be aware that negative infinities will occur, which will also lead to NaNs if you’re not careful. But if you’re rigorous about handling those cases, it’s all good.

Same here.
I’ve just exported an empty new plugin project straight out of the Projucer with default settings (no special dependencies) and compiled to a VST3 using VS2022. No use of the aforementioned Decibels class.
Here is what I’ve found.
Tried running inside Ableton, Reaper and MaxMSP, all gives 0 at input values under 0.00001 (-100dB).
It seems that Juce itself can read the samples (comparisons, addition and multiplication works). Only the output gets snapped to zero. (also: I tried disabling FloatVectorOperations SNAP_TO_ZERO and other denormals macros - even though I assumed it wouldn’t change anything here).
float UnitTest also passes without issues.
Furthermore, one of the tools I used to analyze the output is also made with juce:
Bitbucket which obviously don’t show this behavior - but gets snapped to zero around -140dB due to FloatVectorOperation’s

#ifndef JUCE_SNAP_TO_ZERO
 #if JUCE_INTEL
  #define JUCE_SNAP_TO_ZERO(n)    if (! (n < -1.0e-8f || n > 1.0e-8f)) n = 0;

which kind of makes sense. because of precision loss in float.

Anyway, I can’t trace any other clampings or zero-snapping anywhere on the code. Not in JUCE.

Strange

It would be helpful if you could describe, as precisely as possible, the steps you followed before arriving at this conclusion. Where are you noticing that the signal is “gated”? Inside the plugin, or at the plugin’s output?

As a very quick test, I tried putting a blank JUCE plugin on a track in Reaper 7.11, and adding a -100dB gain before and a +100dB gain after the blank plugin. Audio played on the track is audible at its original level, which suggests JUCE is not doing any gating.

Then I tried doing the same thing in Live 11 with a non-JUCE plugin (bx_cleansweep v2) and a blank JUCE plugin. In both cases, I noticed that when the output of the third-party VST3 was very quiet, it seemed to be clamped to 0.

If this is the same issue that you saw, then it appears to affect non-JUCE plugins, and isn’t present in other hosts, so it’s probably a behaviour of Ableton Live. I’d recommend contacting their support to find out more if you need to support this use-case in Live.

I guess “gated” means clamped, although gating is a special case when the entire signal (or envelope) falls under -100dB. But the issue also occurs for ANY sample that is less than 0.00001.
To illustrate this, here are the results on an oscilloscope (zoomed in):


Where the input is very close to -100dB and a very low frequency sinewave, so the effect can be clearly observed. You can clearly see the 0 clamping when the signal falls under -100dB.
When the plugin is off it’s a pure sinewave. Again: The VST3 plugin was made using JUCE (basically exported a blank new plugin project out of the projucer), where the processBlock function is equivalent to being empty!
This is also not unique to Ableton Live. tested on Protools, as well as MaxMSP and Reaper.

I’m sure this is not a “global” JUCE issue, as you can find plenty of plugins made with JUCE that don’t show this behavior. But in the case of using the Projucer “basic plugin” as a template, which is how I tend to start, this occurs. But I can’t seem to find the reason WHY this is happening.

Are there any other “starting points” to a new project other than the Projucer you can recommend? I’m very familiar with JUCE and used it a lot in the past, but always on an existing project (as part of my job) and never started from scratch (I assumed that with the Projucer it would be easy and without pitfalls, but I guess I was wrong(?)).

P.S
I also eliminated the VST3’s “silence flags” as the cause, because this behavior also occurs when exporting VST2.

Denormal to zero stuff ?
check for ScopedNoDenormals

Already checked. UnitTest passes with flying colors even with numeric_limits()::min() (and also ::denorm_min()!)
Also, commenting out the juce::ScopedNoDenormals noDenormals; in the plugin code did not change anything.
But it was a longshot anyway because 1e-05 is far from being denormalized…

I just attempted to reproduce the issue with the CMake AudioPlugin VST3 example. The source for this matches the template code generated by the Projucer for a new plugin project.

I don’t see drop-outs in Reaper (tone generator @ -120dB → JUCE example → oscilloscope).

I also don’t see drop-outs in Max 8 (sine osc @ -100dB → JUCE example → oscilloscope).

So far, I’ve only seen evidence of this behaviour affecting Live 11.3.

If you’re seeing this behaviour in other hosts, then please:

  • Provide the exact versions of the hosts, and the OS version you’re using for testing, and
  • List the exact steps, signal-chain etc. that you’re using to demonstrate the issue.

Hi reuk.
Thank you so much for your effort!

First of all, I wasn’t aware of the cmake examples. This is so much fun. Thank you!

Now to the point.
I’m a secular Jewish but oh my god, “All my sins, I now detest them…” :slight_smile:
While I was testing other DAWs Ableton was still open in the background, and being out of office I used the troublemaker asio4all. So somehow a clash in the bus made other programs also be affected (who knows why).
So after some self reconciling and a further re-examination I can now confirm that this only happens in Ableton Live (tested both on v.11 and v.10). <Would you have a suggestion why Live and not others?>

Anyways, still, the remaining question is why does it happen on some VSTs but not in others (either made with JUCE or not), and, more crucially, does it mean every VST made using the Projucer/CMake template suffer from this (effectively bit crushing the signal)?
But I guess this is a question I should address to the guys from Ableton. I will send them a bug report ASAP and hopefully come back here with some answers.

Thanks again
Ronen