From e598d7c1338c0174c6c99cdcb68ff6b16566b602 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Thu, 27 Feb 2020 13:55:19 +0100 Subject: [PATCH] Add a bridge for the Wine host to connect back This is equivalent to plugin/bridge.h but for communicating between the native Linus VST plugin and the Windows VST plugin. --- meson.build | 1 + src/wine-host/bridge.cpp | 53 ++++++++++++++++++++++++++++ src/wine-host/bridge.h | 72 ++++++++++++++++++++++++++++++++++++++ src/wine-host/vst-host.cpp | 1 + 4 files changed, 127 insertions(+) create mode 100644 src/wine-host/bridge.cpp create mode 100644 src/wine-host/bridge.h diff --git a/meson.build b/meson.build index 4ebb254c..41503024 100644 --- a/meson.build +++ b/meson.build @@ -43,6 +43,7 @@ shared_library( executable( 'yabridge-host', [ + 'src/wine-host/bridge.cpp', 'src/wine-host/vst-host.cpp', ], native : false, diff --git a/src/wine-host/bridge.cpp b/src/wine-host/bridge.cpp new file mode 100644 index 00000000..f0d129a2 --- /dev/null +++ b/src/wine-host/bridge.cpp @@ -0,0 +1,53 @@ +#include "bridge.h" + +/** + * A function pointer to what should be the entry point of a VST plugin. + */ +using VstEntryPoint = AEffect*(VST_CALL_CONV*)(audioMasterCallback); + +intptr_t VST_CALL_CONV +host_callback(AEffect*, int32_t, int32_t, intptr_t, void*, float); + +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) { + // Got to love these C APIs + + // VST plugin entry point functions should be called `VSTPluginMain`, but + // there are some older deprecated names that legacy plugins may still use + VstEntryPoint vst_entry_point = nullptr; + for (auto name : {"VSTPluginMain", "MAIN", "main_plugin"}) { + vst_entry_point = + reinterpret_cast(reinterpret_cast( + GetProcAddress(plugin_handle.get(), name))); + + if (name != nullptr) { + break; + } + } + if (vst_entry_point == nullptr) { + throw std::runtime_error( + "Could not find a valid VST entry point for '" + plugin_dll_path + + "'."); + } + + plugin = vst_entry_point(host_callback); + if (plugin == nullptr) { + throw std::runtime_error("VST plugin at '" + plugin_dll_path + + "' failed to initialize."); + } + + host_vst_dispatch.connect(socket_endpoint); +} + +// // TODO: Placeholder +// intptr_t VST_CALL_CONV host_callback(AEffect* plugin, +// int32_t opcode, +// int32_t index, +// intptr_t value, +// void* data, +// float option) { +// return 1; +// } diff --git a/src/wine-host/bridge.h b/src/wine-host/bridge.h new file mode 100644 index 00000000..648ae95f --- /dev/null +++ b/src/wine-host/bridge.h @@ -0,0 +1,72 @@ +// 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 + +#include "native-includes.h" + +// `native-includes.h` has to be included before any other files as otherwise we +// might get the wrong version of certain libraries +#define WIN32_LEAN_AND_MEAN +#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 + * `AEffect` object. + */ +class Bridge { + public: + /** + * Initializes the Windows VST plugin and set up communication with the + * native Linux VST plugin. + * + * @param plugin_dll_path A (Unix style) path to the VST plugin .dll file to + * load. + * @param socket_endpoint_path A (Unix style) path to the Unix socket + * endpoint the native VST plugin created to communicate over. + * + * @throw std::runtime_error Thrown when the VST plugin could not be loaded, + * or if communication could not be set up. + */ + Bridge(std::string plugin_dll_path, std::string socket_endpoint_path); + + // TODO: Set up all callback handlers + + private: + /** + * The shared library handle of the VST plugin. I sadly could not get + * Boost.DLL to work here, so we'll just load the VST plugisn by hand. + */ + std::unique_ptr, decltype(&FreeLibrary)> + plugin_handle; + + /** + * The loaded plugin's `AEffect` struct, obtained using the above library + * handle. + */ + AEffect* plugin; + + boost::asio::io_context io_context; + boost::asio::local::stream_protocol::endpoint socket_endpoint; + + // The naming convention for these sockets is `__`. For + // instance the socket named `host_vst_dispatch` forwards + // `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; +}; diff --git a/src/wine-host/vst-host.cpp b/src/wine-host/vst-host.cpp index d4e40200..24159f12 100644 --- a/src/wine-host/vst-host.cpp +++ b/src/wine-host/vst-host.cpp @@ -25,6 +25,7 @@ #include #include "../common/communication.h" +#include "bridge.h" /** * A function pointer to what should be the entry point of a VST plugin.