VST3 plugins could freeze in REAPER when the plugin sends
`IComponentHandler::performEdit()` followed by
`IPlugFrame::resizeView()` when REAPER simultaneously tries to call
`*::getState()`. Here `*::getState()` gets called from the GUI thread,
while `IPlugFrame::resizeView()` has to be handled on REAPER's GUI
thread, resulting in a deadlock unless we use the plugin-side mutual
recursion mechanism.
I've seen this cause issues with PSPaudioware InfiniStrip.
When setting the state on the audio processor, it can happen that plugin
triggers a resize from the edit controller. We should also be able to
handle that situation.
With this we should be able to handle `setState()`s that try to resize
the currently open editor. This could pop up when using the preset
browser in REAPER with plugins that recall their old size when loading a
preset.
This greatly improves compatibility with VST3 plugins in Ardour and
Mixbus. Most notably the FabFilter plugins would previously freeze when
having the GUI open while duplicating or inserting new instances.
Even though the interface ID is passed as an FIDString and there is a
function to compare FIDStrings obviously doesn't mean that you're
supposed to use them! Duh.
Since the restart will always be called from another thread, and when a
plugin asks for a restart during initialization this can quickly lead to
issues.
This is in some cases needed to get decent performance in REAPER, as
REAPER seems to query this information (which cannot change without the
plugin requesting a restart) four times per second.
This works around an issue with REAPER. During every processing cycle
REAPER would query how many input and output busses we have, and it
would then enumerate over all of those busses. This meant that if a VST3
plugin has 32 output busses, then REAPER will do 34 extra function calls
before processing audio.
This is a breaking change. Old projects containing VST3 plugins running
through yabridge will no longer work without modifications. I'll write
some scripts to convert the class IDs stored in those project files soon
a migration path.
The UIDs reported by the plugin were apparently wrong, which meant that
the native Linux VST3 version of plugin X and the normal Windows VST3
version of plugin X used different class ideas than the Windows VST3
version of plugin X running through yabridge. Those things are supposed
to be compatible, so we sadly needed to make this change at some point.
This prevents REAPER from crashing when removing the last instance of a
plugin and then readding it. REAPER doesn't unload the module even after
it removes its last plugin factory instance. This means that before this
the plugin factory would be freed but we still had a seemingly valid
pointer to it that we would try to access.
By directly stopping the IO context there was a chance that a task would
get cancelled outright if all stars aligned in the wrong way. Stopping
the IO context could happen between posting the task to the context and
waiting for it. This approach is much safer as we cannot drop any work
this way.
This would cause crashes in Bitwig, as `RunLoopTasks`' destructor would
not be run after the event handler has been unregistered, and we
unregister the event handler in that destructor.
I've never seen this happen, but now this too would support deeply
nested mutual recursion just like we implemented in
`Vst3PlugViewProxyImpl`. Better safe than sorry.
This was a bit of a tricky one because it requires simulating mutual
recursion, but it's needed for REAPER as otherwide calls to
`IPlugFrame::resizeView()` and `IContextMenu::popup()` might cause
REAPER to segfault because its GUI is not thread safe.