This does what we did for a few functions in the last few commits for
every function. We now use either the `std::invocable` concept or our
own `invocable_returning` concept wherever possible to make sure we pass
function types to these template functions, since constraint errors are
a lot more readable than template deduction errors. And instead of
having to specify the return type as a template argument, we now just
use `std::invoke_result_t<F>` instead. The VST3 message handling
functions are still using the good old `typename F` since those are
overloaded polymorphic functions. This was also a good moment to modify
`AdHocSocketHandler::send()` to allow functions returning void (this got
rid of an old fixme where we had to return some dummy value from a
function instead of just not returning anything).
This is very ugly so hopefully I can think of a neater way, but now the
response object is just a set of pointers, so we can avoid all copies
and moves on the Wine side.
We do this by using this new `MessageReference<T>` type to avoid copying
our `YaAudioProcessor::Process` struct and the contained `YaProcessData`
object. This is only part of the work, but this redesign lets us keep
the these objects alive on both the plugin and the host side. On the
plugin side, we'll simply serialize the data from the referred to object
without copying it. On the Wine side, we'll write the data to a
persistent thread local object, and then reassign the
`MessageReference<T>` to point to that object. This lets us serialize
'references', thus avoiding potentially expensive allocations. With
these last few changes alone VST3 plugins are already at the same
performance level as our optimized VST2 plugin groups.
The VST3 version of Voxengo TEOTE would deadlock in Ardour when Ardour
calls `IEditController::setState()`, the plugin calls
`IUnitHandler::notifyProgramListChange()` in response, and then when
Ardour calls `IUnitInfo::getProgramName()` while handling that callback.
All of these functions have to be called from the same thread in Voxengo
plugins.
Those DAWs would immediately call `IEditController::performEdit()` with
the same parameter change the plugin has just announced, which would
result in a deadlock. Hopefully this helps with #100.
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.
I haven't seen this cause any issues this way, and I could imagine that
this could cause some hangs when initializing a second instance of a
plugin while you're interacting with the GUI of the first instance.
This reverts commit a495f1a67f.
This ended up not being an issue. What we _do_ have to do, sadly, is to
have a mutual recursion context stack per plugin. Otherwise multiple
plugin instances can deadlock eachother.
This works around a bug in the VST3 version of W. A. Production
Imperfect as mentioned in #97. Even if it's a synth and numInputs is 0,
the plugin will still try to read the input arrangement.
After a quick round of testing it seems like REAPER doesn't always
enable this on the audio thread, but Bitwig, Ardour, Carla and Renoise
do. So it should be safe to just get rid of the option and to leave this
enabled all the time.
This prevents Kush Audio REDDI from taking down the DAW when the host
passes it denormalized audio to process. I've discovered that the issue
with this plugin had to do with denormals in the issue linked below, but
I didn't realize that we can just enable the FTZ flag for plugins that
don't already do so.
https://github.com/osxmidi/LinVst/issues/174
So far only PSPaudioware InfiniStrip needed this. but it may be a good
idea to make this visible since it's probably an issue with the
plugin (even if most Windows hosts will have COM initialized).
The `LoadLibrary()` call for PSPaudioware InfiniStrip would fail because
the plugin would always expect COM to be initialized. Now if loading a
VST2 or VST3 module fails, we'll initialize COM and try again before
throwing an error. This may fix#94.
Or technically, two, since the group bridge also does the same loop. We
no longer need special handling for VST2 and VST3 plugins, so we can
simplify things a bit here.
Ever since 0bed2b7bc0 REAPER will randomly
not play back one or more audio channels for plugins that support
IPlugViewContentScaleSuport. If you return `kNotImplemented` then this
bug doesn't occur. REAPER should definitely fix this soon. With
`kResultFalse` this issue still occurs, hence this change so you can use
`vst3_no_scale` to work around this REAPER bug.
FabFilter plugins will exchange messages that have to be handled from
the GUI thread, or they'll get stuck waiting on a synchronisation
object. This probably hurts GUI performance significantly but luckily it
only affects Ardour.
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.
It's pretty hard to find a solution that checks all of the boxes. I want
something that:
- Closes instantly when you close the editor, and in REAPER you should
be able to instantly switch between docked and floating modes
- Where there should not be a delay in user interaction when quickly
reopening the editor (or doing that switching thing in REAPER since that's
the same thing)
- Where the window manager should not try to reparent the window during
the losing process as that can cause some jarring flickering
- And, of course, there should be no weird Wine X11Drv crashes
And it should do all of that in Bitwig, REAPER, Carla, Ardour and
Renoise. Apparently it's quite the task to find an approach that checks
all the boxes there.