From 5c88140c5477f2ece4cd07e9e87fcb3d5dbe9b07 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 2 May 2021 00:38:14 +0200 Subject: [PATCH] Also use mutual recursion for program list changes 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. --- CHANGELOG.md | 2 ++ .../bridges/vst3-impls/component-handler-proxy.cpp | 12 ++++++++---- src/wine-host/bridges/vst3.cpp | 12 +++++++++--- 3 files changed, 19 insertions(+), 7 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 94abec1c..77605ebf 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -93,6 +93,8 @@ Versioning](https://semver.org/spec/v2.0.0.html). open. - Fixed VST3 plugins freezing in **Ardour** and **Mixbus** when the plugin tries to automate a parameter while loading a preset. +- Fixed _Voxengo_ VST3 plugins freezing in **Ardour** and **Mixbus** when + loading a project or when duplicating the plugin instances. - Fixed potential X11 errors resulting in assertion failures and crashes in **Ardour** and **Mixbus** by ignoring X11 events after those hosts hides the editor window. diff --git a/src/wine-host/bridges/vst3-impls/component-handler-proxy.cpp b/src/wine-host/bridges/vst3-impls/component-handler-proxy.cpp index 227082e9..c8300c6d 100644 --- a/src/wine-host/bridges/vst3-impls/component-handler-proxy.cpp +++ b/src/wine-host/bridges/vst3-impls/component-handler-proxy.cpp @@ -175,10 +175,14 @@ tresult PLUGIN_API Vst3ComponentHandlerProxyImpl::notifyUnitSelection( tresult PLUGIN_API Vst3ComponentHandlerProxyImpl::notifyProgramListChange( Steinberg::Vst::ProgramListID listId, int32 programIndex) { - return bridge.send_message(YaUnitHandler::NotifyProgramListChange{ - .owner_instance_id = owner_instance_id(), - .list_id = listId, - .program_index = programIndex}); + // NOTE: When a plugin calls this, Ardour will fetch the new program names + // with `IUnitInfo::getProgramName()`. TEOTE requires this to be + // called from the same thread. + return bridge.send_mutually_recursive_message( + YaUnitHandler::NotifyProgramListChange{ + .owner_instance_id = owner_instance_id(), + .list_id = listId, + .program_index = programIndex}); } tresult PLUGIN_API Vst3ComponentHandlerProxyImpl::notifyUnitByBusChange() { diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 1f482269..abb8f3c7 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -1037,10 +1037,16 @@ void Vst3Bridge::run() { [&](const YaUnitInfo::GetProgramName& request) -> YaUnitInfo::GetProgramName::Response { Steinberg::Vst::String128 name{0}; + // NOTE: This will likely be requested in response to + // `IUnitHandler::notifyProgramListChange`, but some + // plugins (like TEOTE) require this to be called from the + // same thread when that happens. const tresult result = - object_instances[request.instance_id] - .unit_info->getProgramName(request.list_id, - request.program_index, name); + do_mutual_recursion_on_off_thread([&]() { + return object_instances[request.instance_id] + .unit_info->getProgramName( + request.list_id, request.program_index, name); + }); return YaUnitInfo::GetProgramNameResponse{ .result = result, .name = tchar_pointer_to_u16string(name)};