diff --git a/src/common/serialization/vst3/plugin/audio-processor.h b/src/common/serialization/vst3/plugin/audio-processor.h index 8a2e0d1e..d504dc14 100644 --- a/src/common/serialization/vst3/plugin/audio-processor.h +++ b/src/common/serialization/vst3/plugin/audio-processor.h @@ -250,10 +250,22 @@ class YaAudioProcessor : public Steinberg::Vst::IAudioProcessor { YaProcessData data; + /** + * We'll periodically synchronize the realtime priority setting of the + * host's audio thread with the Wine plugin host. We'll do this + * approximately every ten seconds, as doing this getting and setting + * scheduler information has a non trivial amount of overhead (even if + * it's only a single microsoecond). + */ + std::optional new_realtime_priority; + template void serialize(S& s) { s.value8b(instance_id); s.object(data); + + s.ext(new_realtime_priority, bitsery::ext::StdOptional{}, + [](S& s, int& priority) { s.value4b(priority); }); } }; diff --git a/src/common/utils.h b/src/common/utils.h index 31ccd4a1..8066e92a 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -21,6 +21,14 @@ #endif #include +/** + * The interval in seconds between synchronizing the Wine plugin host's audio + * thread scheduling priority with the host's audio thread. + * + * @relates Vst2Bridge::last_audio_thread_priority_synchronization + */ +constexpr time_t audio_thread_priority_synchronization_interval = 10; + // The cannonical overloading template for `std::visitor`, not sure why this // isn't part of the standard library template diff --git a/src/plugin/bridges/vst2.cpp b/src/plugin/bridges/vst2.cpp index 6153d615..4895c894 100644 --- a/src/plugin/bridges/vst2.cpp +++ b/src/plugin/bridges/vst2.cpp @@ -19,14 +19,6 @@ #include "../../common/communication/vst2.h" #include "../utils.h" -/** - * The interval in seconds between synchronizing the Wine plugin host's audio - * thread scheduling priority with the host's audio thread. - * - * @relates Vst2Bridge::last_audio_thread_priority_synchronization - */ -constexpr time_t audio_thread_priority_synchronization_interval = 10; - intptr_t dispatch_proxy(AEffect*, int, int, intptr_t, void*, float); void process_proxy(AEffect*, float**, float**, int); void process_replacing_proxy(AEffect*, float**, float**, int); diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index 4eed113d..5e9ae518 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -141,10 +141,23 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setProcessing(TBool state) { tresult PLUGIN_API Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) { + // We'll synchronize the scheduling priority of the audio thread on the Wine + // plugin host with that of the host's audio thread every once in a while + std::optional new_realtime_priority = std::nullopt; + time_t now = std::time(nullptr); + if (now > last_audio_thread_priority_synchronization + + audio_thread_priority_synchronization_interval) { + new_realtime_priority = get_realtime_priority(); + last_audio_thread_priority_synchronization = now; + } + // TODO: Check whether reusing a `YaProcessData` object make a difference in // terms of performance - ProcessResponse response = bridge.send_audio_processor_message( - YaAudioProcessor::Process{.instance_id = instance_id(), .data = data}); + ProcessResponse response = + bridge.send_audio_processor_message(YaAudioProcessor::Process{ + .instance_id = instance_id(), + .data = data, + .new_realtime_priority = new_realtime_priority}); response.output_data.write_back_outputs(data); diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index 1b5869e5..9c11c33b 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -375,6 +375,13 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { */ Steinberg::IPtr host_context; + /** + * We'll periodically synchronize the Wine host's audio thread priority with + * that of the host. Since the overhead from doing so does add up, we'll + * only do this every once in a while. + */ + time_t last_audio_thread_priority_synchronization = 0; + /** * Used to assign unique identifiers to context menus created by * `IComponentHandler3::CreateContextMenu`. diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index e0465a0a..f691d278 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -1129,6 +1129,14 @@ size_t Vst3Bridge::register_object_instance( }, [&](YaAudioProcessor::Process& request) -> YaAudioProcessor::Process::Response { + // As suggested by Jack Winter, we'll synchronize this + // thread's audio processing priority with that of the + // host's audio thread every once in a while + if (request.new_realtime_priority) { + set_realtime_priority( + true, *request.new_realtime_priority); + } + const tresult result = object_instances[request.instance_id] .audio_processor->process(request.data.get());