This should fix#118 without breaking our _other_ workaround from
yabridge 3.4.0 to fix the issue where a plugin would freeze if it would
try to resize itself while at the same time it sent parameter changes
from the audio thread. (and both of these issues of course are caused by
the same JUCE bug)
This is super difficult to trigger on purpose, but I did run into it at
least once just now so it seems like a good idea to at least make sure
that this doesn't happen.
JUCE incorrectly calls `IComponentHandler::performEdit()` from the audio
thread instead of using the output parameter changes queue, so this
would also cause GUI resizes to be handled from the audio thread if they
come in at the same time as such a parameter change.
Seems weird to need this specifically so we can use the map overload
that creates a new instance when the key doesn't exist in the map. This
seems safer.
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.