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.
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.
This change reshuffles the way that parameter updates and notifications
work for hosted VST3 plugins.
Previously:
- Parameter::setValue would update the processor and editor, but not the
host
- Parameter::setValueFromEditor would update the processor and host, but
not the editor
- MIDI CC events would be converted to events and added to the
processor's input event list, but were not forwarded to the
IEditController.
Now:
- Parameter::setValue updates the host's cachedParamValues, which is the
host's source of truth for parameter values. On each process callback,
changes will be added to the input parameter list. Then, for each item
in the parameter list, an update will be dispatched back to the
editor.
- Parameter::setValueFromEditor is removed. All parameter changes will
be sent back to the editor, even if they originated from the editor.
setValueNotifyingHost can be used to notify listeners that one of the
host's JUCE parameters has changed, e.g. in the host context's
performEdit.
- MIDI CC events trigger calls to setValueNotifyingHost on any mapped
parameters. The flow is very similar to a parameter change from the
editor: the cachedParamValues are updated immediately, and host
parameter listeners are notified. Then, for each changed
cachedParamValue an entry is added to the inputParameterChanges
(updating the processor), then for each item in the
inputParameterChanges an update is sent to the editor.
Previously, preparing an AudioProcessorGraph containing hosted LV2
plugins would recreate the plugins and then set their state. For plugins
without threadsafe restore, setting the state would take the
callbackLock to avoid races with processBlock. This meant that
- During prepare, the graph would take the processorLock, then the
processor would take its own callbackLock.
- During playback, the graph would take the processor's callbackLock,
and then would take the node's processorLock.
This is probably benign (prepare shouldn't be called concurrently with
processBlock at all), but to be on the safe side we now avoid taking the
callbackLock when setting new plugin state during prepareToPlay.