mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Fix mutual recursion with latency in Ardour/Mixbus
This would cause Ardour and Mixbus to freeze when inserting a latency introducing (JUCE based) VST3 plugin. As mentioned in #98.
This commit is contained in:
@@ -61,6 +61,9 @@ Versioning](https://semver.org/spec/v2.0.0.html).
|
||||
plugins. We now explicitly reparent the window to back the root window first
|
||||
before deferring the window closing. This should work around the issue, while
|
||||
still keeping editor closing nice and snappy.
|
||||
- Prevented latency introducing plugins from causing **Ardour** and **Mixbus**
|
||||
to freeze. This for example prevents _Neural DSP Darkglass_ from freezing when
|
||||
used under those DAWs.
|
||||
- _PSPaudioware InifniStrip_ would fail to initialize because the plugin expects
|
||||
the host to always be using Microsoft COM and it won't initialize it by
|
||||
itself. InfiniStrip loads as expected now.
|
||||
|
||||
@@ -61,8 +61,9 @@ Vst3ComponentHandlerProxyImpl::endEdit(Steinberg::Vst::ParamID id) {
|
||||
|
||||
tresult PLUGIN_API
|
||||
Vst3ComponentHandlerProxyImpl::restartComponent(int32 flags) {
|
||||
return bridge.send_message(YaComponentHandler::RestartComponent{
|
||||
.owner_instance_id = owner_instance_id(), .flags = flags});
|
||||
return bridge.send_mutually_recursive_message(
|
||||
YaComponentHandler::RestartComponent{
|
||||
.owner_instance_id = owner_instance_id(), .flags = flags});
|
||||
}
|
||||
|
||||
tresult PLUGIN_API Vst3ComponentHandlerProxyImpl::setDirty(TBool state) {
|
||||
|
||||
@@ -1300,8 +1300,22 @@ size_t Vst3Bridge::register_object_instance(
|
||||
},
|
||||
[&](const YaComponent::SetActive& request)
|
||||
-> YaComponent::SetActive::Response {
|
||||
return object_instances[request.instance_id]
|
||||
.component->setActive(request.state);
|
||||
// NOTE: Ardour/Mixbus will immediately call this
|
||||
// function in response to a latency change
|
||||
// announced through
|
||||
// `IComponentHandler::restartComponent()`. We
|
||||
// need to make sure that these two functions are
|
||||
// handled from the same thread to prevent
|
||||
// deadlocks caused by mutually recursive function
|
||||
// calls.
|
||||
// TODO: Check if this causes any issues when activating
|
||||
// plugins while simultaneously resizing another
|
||||
// instance of the same plugin
|
||||
return do_mutual_recursion_or_handle_in_main_context<
|
||||
tresult>([&]() {
|
||||
return object_instances[request.instance_id]
|
||||
.component->setActive(request.state);
|
||||
});
|
||||
},
|
||||
[&](const YaPrefetchableSupport::GetPrefetchableSupport&
|
||||
request)
|
||||
|
||||
@@ -256,6 +256,11 @@ class Vst3Bridge : public HostBridge {
|
||||
* but in this sequence that thread is being blocked by a call to
|
||||
* `IPlugFrame::resizeView()`.
|
||||
*
|
||||
* We also need to use this for when a plugin calls
|
||||
* `IComponentHandler::restartComponent()` to change the latency, and when
|
||||
* the host then calls `IAudioProcessor::setActive()` in response to that to
|
||||
* restart the plugin. Otherwise this will lead to an infinite loop.
|
||||
*
|
||||
* The hacky solution here is to send the message from another thread, and
|
||||
* to then allow this thread to execute other functions submitted to an IO
|
||||
* context.
|
||||
@@ -346,6 +351,28 @@ class Vst3Bridge : public HostBridge {
|
||||
return do_call_response.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* The same as the above function, but we'll just execute the function on
|
||||
* this thread when the mutual recursion context is not active.
|
||||
*
|
||||
* @see Vst3Bridge::do_mutual_recursion_or_handle_in_main_context
|
||||
*/
|
||||
template <typename T, typename F>
|
||||
T do_mutual_recursion(F f) {
|
||||
std::packaged_task<T()> do_call(std::move(f));
|
||||
std::future<T> do_call_response = do_call.get_future();
|
||||
|
||||
if (std::lock_guard lock(mutual_recursion_contexts_mutex);
|
||||
!mutual_recursion_contexts.empty()) {
|
||||
boost::asio::dispatch(*mutual_recursion_contexts.back(),
|
||||
std::move(do_call));
|
||||
} else {
|
||||
do_call();
|
||||
}
|
||||
|
||||
return do_call_response.get();
|
||||
}
|
||||
|
||||
/**
|
||||
* Register a context with with `context_menu`'s ID and owner in
|
||||
* `object_instances`. This will be called during the constructor of
|
||||
|
||||
Reference in New Issue
Block a user