In the same way as 50c25c1cf0 did it for
VST2 plugins. Input and output audio data is now stored in a shared
memory buffer instead of being sent over the sockets. This reduces the
bridging overhead to a minimum since copying data was the most expensive
operation we were doing and we now only need to copy the entire buffer
once per processing cycle.
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).
Apparently the destructor for C++17/20 conditional initializers are only
run after the else branch, so this would keep the mutex locked while
executing `do_call()`.
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.
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.
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.
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.