Work around thread safety issue in Melda plugins

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.
This commit is contained in:
Robbert van der Helm
2021-07-15 15:45:15 +02:00
parent 6b3f593bdb
commit 5f7fb2e2c3
3 changed files with 38 additions and 6 deletions
+3
View File
@@ -80,6 +80,9 @@ Versioning](https://semver.org/spec/v2.0.0.html).
tries to use REAPER's [host function tries to use REAPER's [host function
API](https://www.reaper.fm/sdk/vst/vst_ext.php#vst_host). This currently isn't API](https://www.reaper.fm/sdk/vst/vst_ext.php#vst_host). This currently isn't
supported by yabridge. We now explicitly ignore these requests. supported by yabridge. We now explicitly ignore these requests.
- Worked around a rare thread safety issue in _MeldaProduction_ VST3 plugins
where the plugin would deadlock when the host asks for the editor's size while
plugin is also being initialized form the audio thread.
- Fixed JUCE VST3 plugins like Tokyo Dawn Records' _SlickEQ M_ causing the host - Fixed JUCE VST3 plugins like Tokyo Dawn Records' _SlickEQ M_ causing the host
to freeze when they send a parameter change from the audio thread using the to freeze when they send a parameter change from the audio thread using the
wrong VST3 API while the plugin is also trying to resize the window from the wrong VST3 API while the plugin is also trying to resize the window from the
+22 -6
View File
@@ -800,13 +800,20 @@ void Vst3Bridge::run() {
.get(); .get();
}, },
[&](YaPlugView::GetSize& request) -> YaPlugView::GetSize::Response { [&](YaPlugView::GetSize& request) -> YaPlugView::GetSize::Response {
Vst3PluginInstance& instance =
object_instances.at(request.owner_instance_id);
// Melda plugins will refuse to open dialogs of this function is // Melda plugins will refuse to open dialogs of this function is
// not run from the GUI thread // not run from the GUI thread. Oh and they also deadlock if
// audio processing gets initialized at the same time as this
// function, not sure why.
std::lock_guard lock(instance.get_size_mutex);
Steinberg::ViewRect size{}; Steinberg::ViewRect size{};
const tresult result = const tresult result =
do_mutual_recursion_on_gui_thread([&]() -> tresult { do_mutual_recursion_on_gui_thread([&]() -> tresult {
return object_instances.at(request.owner_instance_id) return instance.plug_view_instance->plug_view->getSize(
.plug_view_instance->plug_view->getSize(&size); &size);
}); });
return YaPlugView::GetSizeResponse{.result = result, return YaPlugView::GetSizeResponse{.result = result,
@@ -1419,9 +1426,18 @@ size_t Vst3Bridge::register_object_instance(
}, },
[&](const YaAudioProcessor::SetProcessing& request) [&](const YaAudioProcessor::SetProcessing& request)
-> YaAudioProcessor::SetProcessing::Response { -> YaAudioProcessor::SetProcessing::Response {
return object_instances.at(request.instance_id) Vst3PluginInstance& instance =
.interfaces.audio_processor->setProcessing( object_instances.at(request.instance_id);
request.state);
// HACK: MeldaProduction plugins for some reason cannot
// handle it if this function is called from the
// audio thread while at the same time
// `IPlugView::getSize()` is being called from the
// GUI thread
std::lock_guard lock(instance.get_size_mutex);
return instance.interfaces.audio_processor
->setProcessing(request.state);
}, },
[&](MessageReference<YaAudioProcessor::Process>& [&](MessageReference<YaAudioProcessor::Process>&
request_ref) request_ref)
+13
View File
@@ -216,6 +216,19 @@ struct Vst3PluginInstance {
*/ */
std::optional<Vst3PlugViewInterfaces> plug_view_instance; std::optional<Vst3PlugViewInterfaces> plug_view_instance;
/**
* Used to make sure that `IPlugView::getSize()` can never be called at the
* same time as `IAudioProcessor::setProcessing()`.
*
* HACK: This really shouldn't be needed, but MeldaProduction plugins seem
* to deadlock when this happens. It's pretty tricky to reproduce the
* timing for making this happen (since opening the GUI also needs to
* be delayed slightly, like when opening a plugin from Bitwig's popup
* browser), but it seems like a good idea to make sure that this
* doesn't cause any freezes.
*/
std::mutex get_size_mutex;
/** /**
* This contains smart pointers to all VST3 plugin interfaces that can be * This contains smart pointers to all VST3 plugin interfaces that can be
* casted from `object`. * casted from `object`.