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.