mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Use a thread for dispatch events
This commit is contained in:
@@ -84,9 +84,9 @@ follows:
|
|||||||
3. The plugin then sets up a Unix domain socket endpoint to communicate with the
|
3. The plugin then sets up a Unix domain socket endpoint to communicate with the
|
||||||
Wine VST host somewhere in a temporary directory. I chose to use Unix domain
|
Wine VST host somewhere in a temporary directory. I chose to use Unix domain
|
||||||
sockets rather than shared memory to avoid having to do manual
|
sockets rather than shared memory to avoid having to do manual
|
||||||
synchronization and because it makes it easy to handle different kinds of
|
synchronization and because they have very low overhead. Since the Wine VST
|
||||||
events asynchronously. Since the Wine VST host can't access the Linux VST
|
host can't access the Linux VST host's memory we would have to copy audio
|
||||||
host's memory we would have to copy audio buffers in either case.
|
buffers in either case.
|
||||||
4. The plugin launches the Wine VST host in the detected wine prefix, passing
|
4. The plugin launches the Wine VST host in the detected wine prefix, passing
|
||||||
the name of the `.dll` file it should be loading and the path to the Unix
|
the name of the `.dll` file it should be loading and the path to the Unix
|
||||||
domain socket that was just created.
|
domain socket that was just created.
|
||||||
|
|||||||
@@ -95,10 +95,15 @@ HostBridge::HostBridge(audioMasterCallback host_callback)
|
|||||||
plugin.getParameter = getParameter_proxy;
|
plugin.getParameter = getParameter_proxy;
|
||||||
plugin.processReplacing = process_replacing_proxy;
|
plugin.processReplacing = process_replacing_proxy;
|
||||||
|
|
||||||
// TODO: Replace manual thread creation with an async_read loop
|
// For our communication we use simple threads and blocking operations
|
||||||
// Start accepting host callbacks after we've set up our sockets and basic
|
// instead of asynchronous IO since communication has to be handled in
|
||||||
// `AEffect` struct.
|
// lockstep anyway
|
||||||
removeme = std::thread([&]() { return host_callback_loop(); });
|
host_callback_handler = std::thread([&]() {
|
||||||
|
while (true) {
|
||||||
|
passthrough_event(vst_host_callback, &plugin,
|
||||||
|
host_callback_function);
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
// Read the plugin's information from the Wine process. This can only be
|
// Read the plugin's information from the Wine process. This can only be
|
||||||
// done after we started accepting host callbacks as the plugin might do
|
// done after we started accepting host callbacks as the plugin might do
|
||||||
@@ -261,15 +266,6 @@ fs::path generate_endpoint_name() {
|
|||||||
return candidate_endpoint;
|
return candidate_endpoint;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace blocking loop with async readers or threads for all of the
|
|
||||||
// sockets. Also extract this functionality somewhere since the host event
|
|
||||||
// callback needs to do exactly the same thing.
|
|
||||||
void HostBridge::host_callback_loop() {
|
|
||||||
while (true) {
|
|
||||||
passthrough_event(vst_host_callback, &plugin, host_callback_function);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Locate the wineprefix and set the `WINEPREFIX` environment variable if found.
|
* Locate the wineprefix and set the `WINEPREFIX` environment variable if found.
|
||||||
* This way it's also possible to run .dll files outside of a wineprefix using
|
* This way it's also possible to run .dll files outside of a wineprefix using
|
||||||
|
|||||||
@@ -21,7 +21,6 @@
|
|||||||
#include <boost/asio/io_context.hpp>
|
#include <boost/asio/io_context.hpp>
|
||||||
#include <boost/asio/local/stream_protocol.hpp>
|
#include <boost/asio/local/stream_protocol.hpp>
|
||||||
#include <boost/process/child.hpp>
|
#include <boost/process/child.hpp>
|
||||||
// TODO: Remove
|
|
||||||
#include <thread>
|
#include <thread>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -67,9 +66,6 @@ class HostBridge {
|
|||||||
void set_parameter(AEffect* plugin, int32_t index, float value);
|
void set_parameter(AEffect* plugin, int32_t index, float value);
|
||||||
float get_parameter(AEffect* plugin, int32_t index);
|
float get_parameter(AEffect* plugin, int32_t index);
|
||||||
|
|
||||||
// TODO: Remove debug loop
|
|
||||||
void host_callback_loop();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This AEffect struct will be populated using the data passed by the Wine
|
* This AEffect struct will be populated using the data passed by the Wine
|
||||||
* VST host during initialization and then passed as a pointer to the Linux
|
* VST host during initialization and then passed as a pointer to the Linux
|
||||||
@@ -96,12 +92,15 @@ class HostBridge {
|
|||||||
*/
|
*/
|
||||||
boost::asio::local::stream_protocol::socket vst_host_aeffect;
|
boost::asio::local::stream_protocol::socket vst_host_aeffect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thread that handles host callbacks.
|
||||||
|
*/
|
||||||
|
std::thread host_callback_handler;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* The callback function passed by the host to the VST plugin instance.
|
* The callback function passed by the host to the VST plugin instance.
|
||||||
*/
|
*/
|
||||||
audioMasterCallback host_callback_function;
|
audioMasterCallback host_callback_function;
|
||||||
// TODO: Remove
|
|
||||||
std::thread removeme;
|
|
||||||
/**
|
/**
|
||||||
* The Wine process hosting the Windows VST plugin.
|
* The Wine process hosting the Windows VST plugin.
|
||||||
*/
|
*/
|
||||||
|
|||||||
@@ -108,15 +108,19 @@ PluginBridge::PluginBridge(std::string plugin_dll_path,
|
|||||||
// We only needed this little hack during initialization
|
// We only needed this little hack during initialization
|
||||||
current_bridge_isntance = nullptr;
|
current_bridge_isntance = nullptr;
|
||||||
plugin->ptr1 = this;
|
plugin->ptr1 = this;
|
||||||
|
|
||||||
|
// For our communication we use simple threads and blocking operations
|
||||||
|
// instead of asynchronous IO since communication has to be handled in
|
||||||
|
// lockstep anyway
|
||||||
|
dispatch_handler = std::thread([&]() {
|
||||||
|
while (true) {
|
||||||
|
passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher);
|
||||||
|
}
|
||||||
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Replace blocking loop with async readers or threads for all of the
|
void PluginBridge::wait() {
|
||||||
// sockets. Also extract this functionality somewhere since the host event
|
dispatch_handler.join();
|
||||||
// callback needs to do exactly the same thing.
|
|
||||||
void PluginBridge::dispatch_loop() {
|
|
||||||
while (true) {
|
|
||||||
passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
|
intptr_t PluginBridge::host_callback(AEffect* /*plugin*/,
|
||||||
|
|||||||
@@ -24,6 +24,8 @@
|
|||||||
#include <vestige/aeffect.h>
|
#include <vestige/aeffect.h>
|
||||||
#include <windows.h>
|
#include <windows.h>
|
||||||
|
|
||||||
|
#include <thread>
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* This handles the communication between the Linux native VST plugin and the
|
* This handles the communication between the Linux native VST plugin and the
|
||||||
* Wine VST host. The functions below should be used as callback functions in an
|
* Wine VST host. The functions below should be used as callback functions in an
|
||||||
@@ -45,13 +47,13 @@ class PluginBridge {
|
|||||||
*/
|
*/
|
||||||
PluginBridge(std::string plugin_dll_path, std::string socket_endpoint_path);
|
PluginBridge(std::string plugin_dll_path, std::string socket_endpoint_path);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Block the main thread until the plugin shuts down.
|
||||||
|
*/
|
||||||
|
void wait();
|
||||||
|
|
||||||
intptr_t host_callback(AEffect*, int32_t, int32_t, intptr_t, void*, float);
|
intptr_t host_callback(AEffect*, int32_t, int32_t, intptr_t, void*, float);
|
||||||
|
|
||||||
// TODO: Remove debug loop
|
|
||||||
void dispatch_loop();
|
|
||||||
|
|
||||||
// TODO: Set up all callback handlers
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
/**
|
||||||
* The shared library handle of the VST plugin. I sadly could not get
|
* The shared library handle of the VST plugin. I sadly could not get
|
||||||
@@ -82,4 +84,11 @@ class PluginBridge {
|
|||||||
* pass the Wine plugin's information to the host.
|
* pass the Wine plugin's information to the host.
|
||||||
*/
|
*/
|
||||||
boost::asio::local::stream_protocol::socket vst_host_aeffect;
|
boost::asio::local::stream_protocol::socket vst_host_aeffect;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The thread that handles dispatch events from the host.
|
||||||
|
*/
|
||||||
|
std::thread dispatch_handler;
|
||||||
|
|
||||||
|
// TODO: Set up all other callback handlers
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -33,10 +33,10 @@ int main(int argc, char* argv[]) {
|
|||||||
const std::string socket_endpoint_path(argv[2]);
|
const std::string socket_endpoint_path(argv[2]);
|
||||||
|
|
||||||
try {
|
try {
|
||||||
PluginBridge Pluginbridge(plugin_dll_path, socket_endpoint_path);
|
PluginBridge bridge(plugin_dll_path, socket_endpoint_path);
|
||||||
|
|
||||||
// TODO: Remove debug
|
// Block the main thread until the plugin shuts down
|
||||||
Pluginbridge.dispatch_loop();
|
bridge.wait();
|
||||||
} catch (const std::runtime_error& error) {
|
} catch (const std::runtime_error& error) {
|
||||||
std::cerr << "Error while initializing plugin:" << std::endl;
|
std::cerr << "Error while initializing plugin:" << std::endl;
|
||||||
std::cerr << error.what() << std::endl;
|
std::cerr << error.what() << std::endl;
|
||||||
|
|||||||
Reference in New Issue
Block a user