diff --git a/CHANGELOG.md b/CHANGELOG.md index d28ca66d..e2cd52e9 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -17,6 +17,14 @@ Versioning](https://semver.org/spec/v2.0.0.html). [readme](https://github.com/robbert-vdh/yabridge#editor-hosting-modes) for more details. +### Changed + +- Both parts of yabridge will now run with realtime priority if available. This + can significantly reduce overall latency and spikes. Wine itself will still + run with a normal scheduling policy by default, since running wineserver with + realtime priority can increase the audio processing latency although it does + greatly reduce the amount of latency spikes even further. + ### Fixed - Fixed rare plugin location detection issue related to the plugin and host diff --git a/meson.build b/meson.build index 6d18f3b7..2ac02d9c 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ shared_library( 'src/common/configuration.cpp', 'src/common/logging.cpp', 'src/common/serialization.cpp', + 'src/common/utils.cpp', 'src/plugin/host-process.cpp', 'src/plugin/plugin.cpp', 'src/plugin/plugin-bridge.cpp', @@ -115,6 +116,7 @@ host_sources = [ 'src/common/configuration.cpp', 'src/common/logging.cpp', 'src/common/serialization.cpp', + 'src/common/utils.cpp', 'src/wine-host/bridges/vst2.cpp', 'src/wine-host/editor.cpp', 'src/wine-host/editor.cpp', diff --git a/src/common/utils.cpp b/src/common/utils.cpp new file mode 100644 index 00000000..d17a91a6 --- /dev/null +++ b/src/common/utils.cpp @@ -0,0 +1,24 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "utils.h" + +#include + +bool set_realtime_priority() { + sched_param params{.sched_priority = 10}; + return sched_setscheduler(0, SCHED_FIFO, ¶ms) == 0; +} diff --git a/src/common/utils.h b/src/common/utils.h new file mode 100644 index 00000000..7543294e --- /dev/null +++ b/src/common/utils.h @@ -0,0 +1,27 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +/** + * Set the scheduling policy to `SCHED_FIFO` with priority 10 for this process. + * We explicitly don't do this for wineserver itself since from my testing that + * can actually increase latencies. + * + * @return Whether the operation was successful or not. This will fail if the + * user does not have the privileges to set realtime priorities. + */ +bool set_realtime_priority(); diff --git a/src/plugin/plugin-bridge.cpp b/src/plugin/plugin-bridge.cpp index 0298960e..e695b1c7 100644 --- a/src/plugin/plugin-bridge.cpp +++ b/src/plugin/plugin-bridge.cpp @@ -16,12 +16,13 @@ #include "plugin-bridge.h" -// Generated inside of build directory +// Generated inside of the build directory #include #include #include "../common/communication.h" #include "../common/events.h" +#include "../common/utils.h" #include "utils.h" namespace bp = boost::process; @@ -78,6 +79,7 @@ PluginBridge::PluginBridge(audioMasterCallback host_callback) logger, vst_plugin_path, socket_endpoint.path()))), + has_realtime_priority(set_realtime_priority()), wine_io_handler([&]() { io_context.run(); }) { log_init_message(); @@ -598,6 +600,8 @@ void PluginBridge::log_init_message() { << std::endl; init_msg << "plugin: '" << vst_plugin_path.string() << "'" << std::endl; + init_msg << "realtime: '" << (has_realtime_priority ? "yes" : "no") + << "'" << std::endl; init_msg << "socket: '" << socket_endpoint.path() << "'" << std::endl; init_msg << "wine prefix: '"; diff --git a/src/plugin/plugin-bridge.h b/src/plugin/plugin-bridge.h index ed908f4e..77166ad8 100644 --- a/src/plugin/plugin-bridge.h +++ b/src/plugin/plugin-bridge.h @@ -183,6 +183,14 @@ class PluginBridge { * @see launch_vst_host */ std::unique_ptr vst_host; + + /** + * Whether this process runs with realtime priority. We'll set this _after_ + * spawning the Wine process because from my testing running wineserver with + * realtime priority can actually increase latency. + */ + bool has_realtime_priority; + /** * Runs the Boost.Asio `io_context` thread for logging the Wine process * STDOUT and STDERR messages. diff --git a/src/plugin/utils.cpp b/src/plugin/utils.cpp index 614cb2de..cd043cf9 100644 --- a/src/plugin/utils.cpp +++ b/src/plugin/utils.cpp @@ -25,7 +25,7 @@ #include #include -// Generated inside of build directory +// Generated inside of the build directory #include #include "../common/configuration.h" diff --git a/src/wine-host/group-host.cpp b/src/wine-host/group-host.cpp index abc72e95..b19e3b4a 100644 --- a/src/wine-host/group-host.cpp +++ b/src/wine-host/group-host.cpp @@ -18,10 +18,11 @@ #include -// Generated inside of build directory +// Generated inside of the build directory #include #include +#include "../common/utils.h" #include "bridges/group.h" #include "bridges/vst2.h" @@ -39,6 +40,8 @@ * Wine 5.7: https://bugs.winehq.org/show_bug.cgi?id=49138 */ int __cdecl main(int argc, char* argv[]) { + set_realtime_priority(); + // Instead of directly hosting a plugin, this process will receive a UNIX // domain socket endpoint path that it should listen on to allow yabridge // instances to spawn plugins in this process. diff --git a/src/wine-host/individual-host.cpp b/src/wine-host/individual-host.cpp index 592f411b..48e4f847 100644 --- a/src/wine-host/individual-host.cpp +++ b/src/wine-host/individual-host.cpp @@ -17,10 +17,11 @@ #include #include -// Generated inside of build directory +// Generated inside of the build directory #include #include +#include "../common/utils.h" #include "bridges/vst2.h" using namespace std::literals::chrono_literals; @@ -45,6 +46,8 @@ void async_handle_events(boost::asio::steady_timer& timer, Vst2Bridge& bridge); * Wine 5.7: https://bugs.winehq.org/show_bug.cgi?id=49138 */ int __cdecl main(int argc, char* argv[]) { + set_realtime_priority(); + // We pass the name of the VST plugin .dll file to load and the Unix domain // socket to connect to in plugin/bridge.cpp as the first two arguments of // this process.