diff --git a/README.md b/README.md index 27783b27..e15c3cf5 100644 --- a/README.md +++ b/README.md @@ -84,9 +84,9 @@ follows: 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 sockets rather than shared memory to avoid having to do manual - synchronization and because it makes it easy to handle different kinds of - events asynchronously. Since the Wine VST host can't access the Linux VST - host's memory we would have to copy audio buffers in either case. + synchronization and because they have very low overhead. Since the Wine VST + host can't access the Linux VST host's memory we would have to copy audio + buffers in either case. 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 domain socket that was just created. diff --git a/src/plugin/host-bridge.cpp b/src/plugin/host-bridge.cpp index c350008c..17bc113c 100644 --- a/src/plugin/host-bridge.cpp +++ b/src/plugin/host-bridge.cpp @@ -95,10 +95,15 @@ HostBridge::HostBridge(audioMasterCallback host_callback) plugin.getParameter = getParameter_proxy; plugin.processReplacing = process_replacing_proxy; - // TODO: Replace manual thread creation with an async_read loop - // Start accepting host callbacks after we've set up our sockets and basic - // `AEffect` struct. - removeme = std::thread([&]() { return host_callback_loop(); }); + // For our communication we use simple threads and blocking operations + // instead of asynchronous IO since communication has to be handled in + // lockstep anyway + 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 // done after we started accepting host callbacks as the plugin might do @@ -261,15 +266,6 @@ fs::path generate_endpoint_name() { 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. * This way it's also possible to run .dll files outside of a wineprefix using diff --git a/src/plugin/host-bridge.h b/src/plugin/host-bridge.h index b84db621..7156dbc3 100644 --- a/src/plugin/host-bridge.h +++ b/src/plugin/host-bridge.h @@ -21,7 +21,6 @@ #include #include #include -// TODO: Remove #include /** @@ -67,9 +66,6 @@ class HostBridge { void set_parameter(AEffect* plugin, int32_t index, float value); 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 * 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; + /** + * The thread that handles host callbacks. + */ + std::thread host_callback_handler; + /** * The callback function passed by the host to the VST plugin instance. */ audioMasterCallback host_callback_function; - // TODO: Remove - std::thread removeme; /** * The Wine process hosting the Windows VST plugin. */ diff --git a/src/wine-host/plugin-bridge.cpp b/src/wine-host/plugin-bridge.cpp index cdeaa7ce..b2886d43 100644 --- a/src/wine-host/plugin-bridge.cpp +++ b/src/wine-host/plugin-bridge.cpp @@ -108,15 +108,19 @@ PluginBridge::PluginBridge(std::string plugin_dll_path, // We only needed this little hack during initialization current_bridge_isntance = nullptr; 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 -// sockets. Also extract this functionality somewhere since the host event -// callback needs to do exactly the same thing. -void PluginBridge::dispatch_loop() { - while (true) { - passthrough_event(host_vst_dispatch, plugin, plugin->dispatcher); - } +void PluginBridge::wait() { + dispatch_handler.join(); } intptr_t PluginBridge::host_callback(AEffect* /*plugin*/, diff --git a/src/wine-host/plugin-bridge.h b/src/wine-host/plugin-bridge.h index f2493a4e..040d0334 100644 --- a/src/wine-host/plugin-bridge.h +++ b/src/wine-host/plugin-bridge.h @@ -24,6 +24,8 @@ #include #include +#include + /** * 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 @@ -45,13 +47,13 @@ class PluginBridge { */ 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); - // TODO: Remove debug loop - void dispatch_loop(); - - // TODO: Set up all callback handlers - private: /** * 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. */ 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 }; diff --git a/src/wine-host/vst-host.cpp b/src/wine-host/vst-host.cpp index 4ac3115f..83787c28 100644 --- a/src/wine-host/vst-host.cpp +++ b/src/wine-host/vst-host.cpp @@ -33,10 +33,10 @@ int main(int argc, char* argv[]) { const std::string socket_endpoint_path(argv[2]); try { - PluginBridge Pluginbridge(plugin_dll_path, socket_endpoint_path); + PluginBridge bridge(plugin_dll_path, socket_endpoint_path); - // TODO: Remove debug - Pluginbridge.dispatch_loop(); + // Block the main thread until the plugin shuts down + bridge.wait(); } catch (const std::runtime_error& error) { std::cerr << "Error while initializing plugin:" << std::endl; std::cerr << error.what() << std::endl;