This prevents reinitializing `std::variant`s when the variant we want to
deserialize is already active. We store audio buffers in variants, so
reinitializing them results in a lot of unnecessary memory frees,
allocations and writes during every processing cycle.
I blindly assumed the original implementation also did this, but this
version `std::variant<Ts...>` objects from being reinitialized if we're
deserializing a variant that's also currently active in the object we're
deserializing into. For simple structs this won't make any difference,
but in yabridge we often use variants to differentiate between things
like single precision and double precision audio buffers. Those buffers
are allocated on the heap, so recreating the objects every time we
deserialize them adds a lot of unnecessary overhead.
We did a ton of work earlier to make sure we can reuse these objects,
but `auto` implies the type is never a reference type, and we were thus
unnecessarily creating copies every iteration, kind of defeating the
purpose of doing all of this in the first place. We could do some
template trickery here, but it's also safe to just make the persistent
object thread local since the actual objects aren't that large.
We don't need any special handling for this since our default argument
detection will handle strings, but it might be useful for log output if
a host ever uses this. At the moment there don't seem to be any hosts on
Linux that use this.
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).
As it turns out, we'll sadly also need this for VST2 plugins on the Wine
side, so we should probably finally encapsulate this instead of
duplicating it a third time.
For some reason ujam plugins (and other plugins made with the Gorilla
Engine, like the LoopCloud plugins) will throw a `JS_EXEC_FAILED` error
when trying to load the plugin while either of the STDOUT or STDERR
streams is pointing to a pipe. Simply redirecting the output to a file
fixes this. By default we'll write the output to
`<temporary_directory>/yabridge-plugin-output.log`, but you can also set
the new `disable_pipes` option to `"/dev/null"` to completely throw away
all output.
This addresses #47.
This may also fix some weird cases where everything appeared to work
fine, but where the file descriptors weren't actually assigned
correctly. Not sure what that happened, but it with carla-single the
Wine host's STDOUT and STDERR would still point to the orignal pty even
though everything still went through the pipes.
With `vfork()` the child process inherits the parents process image and
prevents copying them, but if it outlives its parent then the file
descriptors will still remain open. Manually closing all file
descriptors is the only solution here.
This was only an issue with Ardour since they don't open all of their
files with `FD_CLOEXEC`. Last update's watchdog timer somewhat mitigated
the issue, but Ardour should now no longer freeze when reopening because
of this. The watchdog timer is still necessary, since hanging Wine
processes will still prevent the Wine server from shutting down.
This makes much more sense, since all plugin instances will be sharing a
single GUI thread. What would happen was that resize calls from one
instance and GUI thread function calls from another instance would
collide. Using a single shared mutual recursion mechanism (just like on
the Wine side) fixes this.
This was causing a timing issue with DMG plugins where the plugins would
try to resize after receiving new state (and not during the call), while
REAPER at the same time would try to set channel context information on
the plugin (which also has to be handled on the GUI thread).
This was removed in 4a92034620 after the
VST2 callback prefetching from yabridge 3.2.0. Now with the recent VST3
optimizations, VST3 plugins always outperform VST2 plugins on my system
even when using plugin groups for the VST2 version (and not having to
use plugin groups is of course another good reason to prefer VST3).
Apparently this can actually make a difference in some cases, and the
C++ Core Guideliens recommend doing this on all default constructors,
destructors, and all functions that can not throw (and thus also don't
allocate).