What does "sample-accurate bypass" mean?

The documentation for what I should actually do with my “bypass” parameter is hard to find.
I first tried to implement it as “copy input to output unless the pointers are the same,” but that actually crashes in the validator, which passes in nullptr for the buffers in the bypass test.
So, now I just return, doing nothing, when bypass is set. But that makes bypass only automated on a per-block level, not with per-sample accuracy.

What should I do in my plugin when I receive “sample accurate” automation for the kIsBypass parameter?

Although the validator may do that for a test you shouldn’t assume that the host will pass a null buffer all the time when bypassed.
The host bypass param should be treated like any other automation param. If a non null buffer is provided then use the timestamped parameter changes provided in inputParameterChanges via the process data. If you use the sampleOffset for the bypass parameter you can then pass through the input audio from the buffer for the bypassed portion of the block and process the remaining partial block.
Of course if the buffer provided is a null pointer then just treat it at the block level like what you are doing.

What the SDK does not make clear is how host bypass should be handled in the case of plugins that have delay.
i.e simply bypassing and unbypassing by muting buffers isn’t enough to handle delay when the plugin is bypassed or unbypassed, since the plugin has already processed lookahead buffers.

Yes, I was processing buffers – the problem was actually that the validator did NOT provide buffers, whereas I was assuming they would be there.
Now I skip processing if inputs or outputs are null, or if numsamples is 0, no matter whether bypassing or not.

There are also at least two different interepretations of “bypass,” as you suggest.

One is:
“immediately start copying over input data, keeping old pre-computed state; when bypass goes away, re-use old precomputed state for whatever data comes next.”
This is approximately what you’d get if you “copy and spliced” a chunk of sample data in the middle of a stream, and the plugin essentially was “unaware” of this.

The other is:
“play out any precomputed state/tail you have, but do not feed the input to your algorithm. When the bypass goes away, start feeding the input again.”
This is approximately what you get if your effect lives on a send bus, and “bypass” temporarily mutes the send to my effect.


The SDK actually says in once place that I’m supposed to “copy input data while applying whatever input delay I have.”

I very seldom use bypass myself, although I can think of cases where it would be useful to audition subtle before/after changes. Then again, for the most subtle audition, my “bypass” should actually fade in/out over 100 samples or so, to give a softer turn-on/turn-off transient. Else the transient of on/off will “poison” my ears to the subtle differences that would be there.
Anyway, if someone uses “bypass” for audition, it’s totally OK to apply it only at processing buffer boundaries, and sample accurate automation isn’t needed.

Is anyone doing sample-accurate automation of bypass to generate some kind of dope glitchstep beats? I kinda doubt it …

The SDK actually says in once place that I’m supposed to “copy input data while applying whatever input delay I have.”

Where do you see that? Can you quote the section from the SDK?
That implies that the plug-in should be handling its delay internally even when it is bypassed. Its an important distinction since it implies that the host does not need do anything special in response to the bypass parameter other than continuing to stream to the plug-in even when bypassed. Maybe Yvan Grabit can shed some light on this. Today we (Cakewalk) don’t do anything special i.e if the plugin doesn’t manage its delay internally when bypassed, it will cause audio to go out of sync when the user toggles the bypass state.
Also its not as simple as copying input data - when you bypass a plugin that has input delay the plugin needs to internally keep discarding data from its delay buffers to emulate what it does during normal processing. When unbypassed it will initially start emitting unprocessed audio that is queued (while it was bypassed). There isn’t any way to avoid that but at least the audio will be in sync.

I very seldom use bypass myself, although I can think of cases where it would be useful to audition subtle before/after changes. Then again, for the most subtle audition, my “bypass” should actually fade in/out over 100 samples or so, to give a softer turn-on/turn-off transient. Else the transient of on/off will “poison” my ears to the subtle differences that would be there.
Anyway, if someone uses “bypass” for audition, it’s totally OK to apply it only at processing buffer boundaries, and sample accurate automation isn’t needed.

Is anyone doing sample-accurate automation of bypass to generate some kind of dope glitchstep beats? I kinda doubt it …

Sample accurate bypass may not be a common use case but there are cases in some genres where someone may want to apply a very steep filter to the sound at a specific section of the audio. If the user is running at a large buffer size the result would be unpredictable if it is aligned to the buffer start.
BTW I expect that when a plugin is bypassed it immediately stops generating processed audio with no lag…

The reason I started asking was that I had used fast/steep filter automation in FL Studio, and tried to do it in CuBase, and it didn’t work too well, because the default Strip EQ doesn’t respond fast enough at all – seemed to be per-buffer.

I also tried the Monark filter from Reaktor, but while it seemed to respond a little better, I could still hear it opening pretty sluggishly; it seemed to apply some internal rate limiting (maybe for stability?)

Having done DSP a long time ago, I chased down the VST 3 SDK, and I ended up writing my own sample accurate filter plugin, which in turn caused this question! (I also have a sample accurate gain fader now, because that, too, wasn’t too hot in the default Cubase strip.)

Trying to re-google the bypass specification that I read (it said something about “the minimum implementation is copying input to output, applying whatever internal delay the plugin has.”) It’s not here: https://steinbergmedia.github.io/vst3_doc/vstsdk/faq.html#faqProcessing1

Maybe it’s this part, in the VST docs themselves, on disk, the file vst3_doc/vstsdk/faq.html has this to say:

vst3_doc\vstsdk\faq.html
209:<p>In order to implement audio process bypassing, the plug-in can export a parameter which is additionally and exclusively flagged as having the attribute kIsBypass. When the user activates the plug-in bypass in the host, like all parameter changes, this is sent as part of the parameter data passed to the Vst::Steinberg::IAudioProcessor::process method.</p>
210:<p>The implementation of the bypass feature is entirely the responsibility of the plug-in:</p>
211:<p>The IAudioProcessor::process method will continue to be called. The plug-in must take care of artifact-free switching (ramping, parallel processing or algorithm changes) and must also provide a delayed action if your plug-in has a latency. Note: The plug-in needs to save in its state the bypass parameter like any other parameters.</p>

Specifically:

and must also provide a delayed action if your plug-in has a latency

Please have a look at the FAQ about bypass processing/parameter:

Log In - Steinberg Developer Help?

Cheers

Thanks Yvan that’s a much clearer explanation. I had not noticed that in the SDK myself. Perhaps link it to the actual bypass parameter documentation.
It makes sense that this is a plugin function to handle delay. We are expecting this in our implementation as well.

It would be great if there was one canonical place where the latest docs were collected, and all the other places (github, SDK install directory, etc) just linked there.
I can tell that the same paragraph has gone through multiple iterations of updating, depending on where I find it when browsing around the docs, in different places (process / automation / kIsBypass) in different places (headers, github, SDK docs, Steinberg docs, …)

1 Like