From 5ace761ce906975595c3c9dd786a7a601ad38357 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 1 Mar 2020 01:06:35 +0100 Subject: [PATCH] Pass callbacks back through to the host Instead of using std::thread this can be done cleaner using recursive async read functions. Everything withing those functions should of course still remain synchronous. --- src/plugin/bridge.cpp | 22 +++++++++++++++++++--- src/plugin/bridge.h | 21 ++++++++++++++++++++- src/plugin/plugin.cpp | 8 +++++--- src/wine-host/bridge.cpp | 11 +++++++---- src/wine-host/bridge.h | 1 + 5 files changed, 52 insertions(+), 11 deletions(-) diff --git a/src/plugin/bridge.cpp b/src/plugin/bridge.cpp index bf42911d..0252d932 100644 --- a/src/plugin/bridge.cpp +++ b/src/plugin/bridge.cpp @@ -51,20 +51,27 @@ bp::environment set_wineprefix(); // TODO: When adding debug information, print both the path to the VST host and // the chosen wineprefix -Bridge::Bridge() +Bridge::Bridge(AEffect* plugin, audioMasterCallback host_callback) : io_context(), socket_endpoint(generate_endpoint_name().string()), socket_acceptor(io_context, socket_endpoint), host_vst_dispatch(io_context), + vst_host_callback(io_context), + host_callback_function(host_callback), vst_host(find_wine_vst_host(), - // The Wine VST host needs to know which plugin to load and which - // Unix domain socket to connect to + // The Wine VST host needs to know which plugin to load and + // which Unix domain socket to connect to find_vst_plugin(), socket_endpoint.path(), bp::env = set_wineprefix()) { // It's very important that these sockets are connected to in the same order // in the Wine VST host socket_acceptor.accept(host_vst_dispatch); + socket_acceptor.accept(vst_host_callback); + + // TODO: REmove + // After accepting the sockets + removeme = std::thread([&]() { return host_callback_loop(plugin); }); } /** @@ -213,6 +220,15 @@ 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 Bridge::host_callback_loop(AEffect* plugin) { + 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/bridge.h b/src/plugin/bridge.h index dbdcaaca..a6bff524 100644 --- a/src/plugin/bridge.h +++ b/src/plugin/bridge.h @@ -21,6 +21,8 @@ #include #include #include +// TODO: Remove +#include /** * This handles the communication between the Linux native VST plugin and the @@ -36,10 +38,14 @@ class Bridge { * TODO: Figure out whether shared memory gives us better throughput and/or * lower overhead than using a Unix domain socket would. * + * @param host_callback The callback function passed to the VST plugin by + * the host. + * * @throw std::runtime_error Thrown when the VST host could not be found, or * if it could not locate and load a VST .dll file. */ - Bridge(); + // TODO: The plugin struct should be created here, not passed in + Bridge(AEffect* plugin, audioMasterCallback host_callback); // The four below functions are the handlers from the VST2 API. They are // called through proxy functions in `plugin.cpp`. @@ -61,6 +67,9 @@ class Bridge { 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(AEffect* plugin); + private: boost::asio::io_context io_context; boost::asio::local::stream_protocol::endpoint socket_endpoint; @@ -71,6 +80,16 @@ class Bridge { // `AEffect.dispatch()` calls from the native VST host to the Windows VST // plugin (through the Wine VST host). boost::asio::local::stream_protocol::socket host_vst_dispatch; + boost::asio::local::stream_protocol::socket vst_host_callback; + /** + * 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. + */ boost::process::child vst_host; }; diff --git a/src/plugin/plugin.cpp b/src/plugin/plugin.cpp index 7e2d4f7f..21e50d49 100644 --- a/src/plugin/plugin.cpp +++ b/src/plugin/plugin.cpp @@ -61,11 +61,13 @@ Bridge& get_bridge_instance(const AEffect& plugin) { * manual memory management. Clean up is done when we receive the `effClose` * opcode from the VST host (i.e. opcode 1).` */ -VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback /*audioMaster*/) { +VST_EXPORT AEffect* VSTPluginMain(audioMasterCallback host_callback) { try { - Bridge* bridge = new Bridge(); - + // TODO: Create the plugin instance in the bridge based on the received + // parameters. We can then also use a smart pointer so we only + // have to manually delete the bridge instance. AEffect* plugin = new AEffect(); + Bridge* bridge = new Bridge(plugin, host_callback); plugin->ptr3 = bridge; plugin->dispatcher = dispatch_proxy; diff --git a/src/wine-host/bridge.cpp b/src/wine-host/bridge.cpp index a34d8400..b1b3ea77 100644 --- a/src/wine-host/bridge.cpp +++ b/src/wine-host/bridge.cpp @@ -38,7 +38,8 @@ Bridge::Bridge(std::string plugin_dll_path, std::string socket_endpoint_path) : plugin_handle(LoadLibrary(plugin_dll_path.c_str()), &FreeLibrary), io_context(), socket_endpoint(socket_endpoint_path), - host_vst_dispatch(io_context) { + host_vst_dispatch(io_context), + vst_host_callback(io_context) { // Got to love these C APIs if (plugin_handle == nullptr) { throw std::runtime_error("Could not load a shared library at '" + @@ -63,7 +64,10 @@ Bridge::Bridge(std::string plugin_dll_path, std::string socket_endpoint_path) "'."); } + // It's very important that these sockets are accepted to in the same order + // in the Linus plugin host_vst_dispatch.connect(socket_endpoint); + vst_host_callback.connect(socket_endpoint); // Initialize after communication has been set up We'll try to do the same // `get_bridge_isntance` trick as in `plugin/plugin.cpp`, but since the @@ -90,14 +94,13 @@ void Bridge::dispatch_loop() { } } -intptr_t Bridge::host_callback(AEffect* plugin, +intptr_t Bridge::host_callback(AEffect* /*plugin*/, int32_t opcode, int32_t index, intptr_t value, void* data, float option) { - // TODO - return 1; + return send_event(vst_host_callback, opcode, index, value, data, option); } intptr_t VST_CALL_CONV host_callback_proxy(AEffect* effect, diff --git a/src/wine-host/bridge.h b/src/wine-host/bridge.h index 51e6ee49..6034cd6d 100644 --- a/src/wine-host/bridge.h +++ b/src/wine-host/bridge.h @@ -74,4 +74,5 @@ class Bridge { // `AEffect.dispatch()` calls from the native VST host to the Windows VST // plugin (through the Wine VST host). boost::asio::local::stream_protocol::socket host_vst_dispatch; + boost::asio::local::stream_protocol::socket vst_host_callback; };