Current state of bypass management

Hi guys,

I’m trying to deal with the situation where hosts are not calling processBlockBypassed when a plugin gets bypassed via the host bypass buttons. I’ve read several threads, some of them dated almost 10 years ago, and the situation looks basically unsolved.

I know about getBypassParameter method, but I don’t think that’s a reliable solution. Most hosts looks like to just not calling processBlock any longer, when their bypass is on, so there’s no way (afaik) to reliably detect the bypass state and clear buffers (or do anything we need to do when the plugin is bypassed). EDIT: looks like getBypassParameter is not getting called at all. I tried overriding the method and it’s never called.

Right now, I’m trying with a bare boolean to detect if processBlock is working

isProcessing = true;     //first processBlock row
//--- my processing code ---
//isProcessing = false;  //last processBlock row

Then I can check the state of this bool in getStateInformation, since it’s seems to be called when the bypass button on the host is clicked. That works but it’s obviously useless if you need to do buffer operations, so I’m back to square one.

I also tried to check if the processor gets suspended, but looks like it is not… so, basically, there are hosts (like Live, Reaper, maybe Logic Pro) which are simply not calling processBlock or entirely skipping the plugin in the chain.

Has anyone found a viable workaround to this?

Thanks,
Luca

Hi,

Some hosts allow disabling the plugin entirely in addition to bypassing it. It’s also not uncommon that the plugin is suspended (e.g. no processing is ever called) to save CPU, Logic is very aggressive with that. There is also no rule that forces a host to support the soft bypass of your plugin in addition to its own bypass mechanics.

Long story short: Neither can you rely on processBlockBypassed being used, nor can you reliably detect if the plugin is suspended.
The best workaround for “plugin is inactive” detection I have found so far is storing a timestamp in my process callback and having the UI test how long ago that was. If it’s more than X (few hundred ms), I use this to fade out some audio engine visual feedback. I’m also making sure that everything works from a usability perspective without any audio processing ever happening. This is important for cases like “offline processing” in Cubase, for example.

I’d also recommend not making any assumptions on when exactly getStateInformation will be called. Host behavior is wildly different when it comes to that. I’ve even seen situations where hosts call setStateInformation during a process callback (which should never ever happen - but it does). Best play it as safe as possible, and assume that hosts will interpret the plugin interfaces creatively to the point of ignoring specifications.

3 Likes

that was my assumption too after struggling with this :smiley: Thanks for your feedback, @jcomusic. Your timestamp suggestion could be a fine workaround.

Luca

Thanks @jcomusic. I used a similar workaround, but stored in processBlock.

Basically I store, at the end of processBlock, the value of Time::getMillisecondsCounter()
At the very beginning of processBlock, I get another call to getMillisecondsCounter and compare it with the previously store. If the difference between the two is over a predefined threshold, I call the methods I need to clear my buffers. Works flawlessly.

And how does that work in offline rendering then? The timings must be vastly different I assume…

1 Like

You can (and should) check for offline/non-realtime rendering. I’d only use the timestamp trick for non-critical stuff like disabling visualizers in the UI and the like. I’ve had good experience with thresholds in the range of “no update during the last 250ms”. Offline rendering has a high probability of running faster than realtime, so it could even be a good idea to throttle down things like UI feedback for that case. It depends, it could just as well be blocking for a long time between process calls because some plugin needs to do a blocking load of sample data during offline rendering.

I’d definitely not rely on the timestamp heuristic for anything affecting audio processing. Transitions between offline and non-offline can be detected quite well without it, and they can be used to clear history buffers (reverb or delay tails, filter state, etc). Not all DAWs behave the same way when it comes to reset and prepare calls. But that’s a different rabbit hole.

3 Likes

Yep that is what I was thinking. We want to clear buffers / effect tails / meters etc. also when bypassing and then un-bypassing, not just when switching between non realtime and realtime rendering. So we implemented the timer based thing also for audio stuff. Of course that only works in realtime mode but hey - it’s something. For offline rendering we have to rely on processBlockBypassed() or the bypass parameter so there will be a known issue regarding offline rendering in Logic, Reaper and possibly other more exotic DAWs. I’m curious whether that all goes through release qualification… :sweat_smile:

As part of the implementation I did some research on which DAW does what to implement bypass that I think could be handy for others should they find themselves in the position of having to “fix” the bypass handling of their plugins.

Cubase 13

Deactivating by clicking the Activate button

Stops calling processBlock() and does not call processBlockBypassed()

Activating by clicking the Activate button

Calls perpareToPlay()

Bypassing by clicking the Bypass button

Without getBypassParameter() overridden

Calls processBlockBypassed()

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 1.0

Un-Bypassing by clicking the Bypass button

Without getBypassParameter() overridden

Starts calling processBlock() again

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 0.0

Differences between VST2 & 3

Could not check as Steinberg is the only DAW manufacturer not supporting VST2 on an M2 Mac

Pro Tools Ultimate 23.09

Bypassing by clicking the Bypass button in the plugin window frame

Without getBypassParameter() overridden

Calls processBlockBypassed()

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 1.0

Un-Bypassing by clicking the Bypass button in the plugin window frame

Without getBypassParameter() overridden

Starts calling processBlock() again

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 0.0

Logic Pro X

Bypassing and unbypassing using the on/off button in the plugin window frame or channel strip

Stops & resumes calling processBlock()

You cannot really get logs very well from Logic now that they’re sandboxing plugins in AUHostingService. So the behaviour is my best guess for the symptoms I saw.

Studio One 6

Deactivating by clicking the Activate button

Stops calling processBlock() and does not call processBlockBypassed()

Activating by clicking the Activate button

Calls perpareToPlay()

Bypassing by clicking the Bypass button

Without getBypassParameter() overridden

Calls processBlockBypassed()

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 1.0

Un-Bypassing by clicking the Bypass button

Without getBypassParameter() overridden

Starts calling processBlock() again

With getBypassParameter() overridden

Continues to call processBlock() with bypass parameter set to 0.0

Differences between VST2, VST3 & AU

None

Live

Deactivating by clicking the Device Activator button

Stops calling processBlock()

VST2: Activating by clicking the Device Activator button

Calls perpareToPlay()

AU & VST3: Activating by clicking the Device Activator button

Starts calling processBlock() again

Reaper

Deactivating the plugin by unchecking the checkbox

Stops calling processBlock() and does not call processBlockBypassed()

Activating the plugin by unchecking the checkbox

Starts calling processBlock() again

Differences between VST2, VST3 & AU

None

Adding a dedicated bypass parameter and returning it to JUCE wrappers by overriding getBypassParameter()

Three of the tested DAWs change their behaviour:

Cubase 13

Pro Tools Ultimate 23.09

Studio One 6

all continue to call processBlock() with the bypass parameter set to 1 instead of 0 when bypassed.

Studio One and Cubase have the additional “Activate” button which behaves the same no matter whether there is a bypass parameter or not.

Difference between effect and instrument plugins

The difference I found is that Pro Tools and Reaper stop calling the processing callback when there is silence in the channel for longer than approximately 15 seconds or so.

10 Likes

Note that Cubase also has a Preference to stop calling the plugin when there is no audio.

1 Like

Hey! Thanks for sharing the info about the behaviour you observed. It might be relevant to also take “reset” calls into consideration that DAWs can use to explicitly notify a plugin that it should probably clear its buffers.
Reaper also wins the “anything is possible” competition by letting the user configure how and what of the plugin API to call in various combinations.

1 Like

Thank you so much for providing this info it would have taken days to figure out

Do you recall which host(s) that occurred ? Also was it only setStateInformation or any other AudioProcessor functions that you have seen called during a processBlock ? I have never seen a pliugin code example which has any code in the PluginProcessor which does additional logic to deal with situation like that. If anyone has please reply here want to look at an exmaple.

How do we do detect transition between offline and non-offline processing?