Previously, the bus layout was considered invalid if the host provided
an unexpected number of channels on a disabled bus. Specifically,
Acoustica 7 would prepare sidechain input buses with a non-zero number
of channels, but provide a zero-channel bus during processing.
Given that the plug-in doesn't attempt to read from disabled buses, it
should be safe to process as normal in this scenario.
According to the VST3 spec, activateBus and setBusArrangements shall not
be called when a plugin is in the 'activated' state.
Previously, if prepareToPlay was called twice in a row on a hosted VST3
plugin, during the second call the plug-in would already be activated,
but its bus layout would still be adjusted. Now, we always ensure that
the plugin is inactive before the bus properties are adjusted.
This avoids repeating the 'fallback' values in the case that the
AudioPlayHead or PositionInfo is not available.
As a side-effect of this change, when an AudioPlayHead is available but
does not supply a valid BPM value, a fallback of 120 will be used,
instead of 0. This fixes an issue where the Microtonic sequencer failed
to play in the AudioPluginHost.
The X42 stepseq.lv2 has an input atom port without the "control"
designation, but that still supports time:Position events. In order to
support this plugin, JUCE hosts will now send position info to any input
atom port that is marked as supporting this event type.
The host sync feature in stepseq.lv2 also requires the bar count to be
included in the position information.
Previously, activateBus would fail if the new BusesLayout wasn't
supported, as reported by isBusesLayoutSupported. However, according to
the VST3 docs, a host is allowed to enable and disable buses in any
combination, and the plugin should be able to handle this gracefully.
The ability to enable/disable individual buses without failure is
particularly important because there's no VST3 API to set a complete bus
layout in one go. That is, the only way to set all buses active or all
buses inactive is to set the appropriate state on each bus individually,
which in turn means that at some point, some buses will be active and
some will be inactive. Disallowing such 'intermediate' states may
prevent the host from putting the plugin into other (valid) states.
To ensure that the VST3 wrapper always accepts activateBus calls, it now
keeps track of the activation state of each bus as requested by the
host. When the host tries to change the activation state, the wrapper
will try to set the host's "ideal" bus layout on the AudioProcessor. If
this fails, the AudioProcessor will retain its previous bus layout.
The buffer remapping inside the process callback has been made more
robust, to handle cases where the host and the AudioProcessor disagree
about the activation state of each bus:
For input buses:
- If the host has activated the bus, but the AudioProcessor decided to
keep the bus inactive, the host's input will be ignored.
- If the host deactivated the bus, but the AudioProcessor wanted to keep
the bus active, the AudioProcessor will be provided with silence on
that bus.
For output buses:
- If the host has activated the bus, but the AudioProcessor decided to
keep the bus inactive, the wrapper will clear the host's output
bus buffers.
- If the host deactivated the bus, but the AudioProcessor wanted to keep
the bus active, the AudioProcessor's output on that bus will be
ignored.
The AudioBuffer passed to the wrapped AudioProcessor will no longer
contain any pointers from the host's ProcessData. Instead, the host's
inputs will be copied (in JUCE channel order) to a temporary buffer,
and this temporary buffer will be passed to
AudioProcessor::processBlock. After processBlock, the buffer contents
will be copied to the host's output buffers.
This change is intended to avoid a potential issue when reordering
channels into JUCE order, which may necessitate copying a host input
channel to a different host output channel. In the case that the host is
using the same buffers for both inputs and outputs, copying an input to
an output channel may end up overwriting another input channel, breaking
the plugin's inputs.