When are input/output buffer pointers permitted to be equal to each other?

I was reading the AGain example in the SDK. In the process() method, in the cases where the silent flag or bypass flag is set, the example checks to make sure that the input and output buffer pointers are not equal to each other before performing a memset or memcpy. Is it actually allowed for a host to pass the same pointer for input and output buffers? I was not able to find anything in the SDK documentation suggesting this to be the case, so I would be very surprised to encounter a host doing this. I’d like to know to for sure whether this is allowed, and if so, when, because I do not like the idea of my plugin’s DSP code unknowingly writing to an input buffer that it is also reading from.

There’s something else that wasn’t entirely clear to me: The documentation for ProcessData states, “The number of channels (numChannels) must always match the current bus arrangement. It could be set to value ‘0’ when the host wants to flush the parameters (when the plug-in is not processed).” Obviously, if the current bus arrangement has more than 0 channels, having numChannels set to 0 means it does not match the current bus arrangement. So, should I interpret this to mean that numChannels will either match the current bus arrangement, or it will be set to 0 in in order to flush parameters?

Here is my current working understanding of correct behavior regarding ProcessData. I would appreciate a correction if any aspect is incorrect:

  • inputs must point to a valid array of AudioBusBuffers with a length equal to the return value of IComponent::getBusCount(kAudio, kInput). Likewise, outputs must point to a valid array of AudioBusBuffers with a length equal to the return value of IComponent::getBusCount(kAudio, kOutput).
  • Inside a given AudioBusBuffers, numChannels must either be equal to either the current number of channels of the corresponding bus (as specified by IComponent::getBusInfo), or equal to 0, in the case where the host simply wants to flush parameter changes.
  • Inside a given AudioBusBuffers, channelBuffers32/channelBuffers64 must point to a valid array of Sample32 */Sample64 * with a length equal to numChannels.
  • If the corresponding bus is active, the pointers in the channelBuffers32/channelBuffers64 array must point to a valid array of Sample32/Sample64 with length equal to numSamples. If the bus is not active, these pointers are not required to point to a valid array and the plugin should not read from or write to them.
  • For an input bus, the plugin can read from the arrays of Sample32/Sample64 but not write to them. For an output bus, the plugin can write to the arrays of Sample32/Sample64.
  • An array of Sample32/Sample64 for an active output bus should not overlap with (alias) another such array for any other input or output bus.

This last assumption seems completely reasonable to me, but as I mentioned, the AGain example threw some doubt on it for me. I would appreciate any clarification on this. Thanks!

If I remember correctly, I think the only time input can be equal to output is in processReplacing(). Now, that may be old news – maybe things have changed in the latest versions – but that’s what that function was for back when it was added.

It seems that Arne has confirmed in a different thread that input and output buffers can be the same: [Solved] FX plugin wrapped for VST2 receives its audio input in the output buffer - #4 by Arne_Scheffler

It looks like JUCE checks for this as well: JUCE/juce_VST3_Wrapper.cpp at 90e8da0cfb54ac593cdbed74c3d0c9b09bad3a9f · juce-framework/JUCE · GitHub

It would certainly be nice if this were mentioned somewhere in the VST3 documentation.