// 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 "boost-fix.h" #define NOMINMAX #define NOSERVICE #define NOMCX #define NOIMM #define WIN32_LEAN_AND_MEAN #include #include #include #include #include #include "../common/logging.h" #include "editor.h" /** * 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 PluginBridge { 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. */ 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*, int, int, intptr_t, void*, float); /** * With the `audioMasterGetTime` host callback the plugin expects the return * value from the calblack to be a pointer to a VstTimeInfo struct. */ VstTimeInfo time_info; private: /** * A wrapper around `plugin->dispatcher` that handles the opening and * closing of GUIs. */ intptr_t dispatch_wrapper(AEffect* plugin, int opcode, int index, intptr_t value, void* data, float option); /** * 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; boost::asio::local::stream_protocol::socket vst_host_callback; /** * Used for both `getParameter` and `setParameter` since they mostly * overlap. */ boost::asio::local::stream_protocol::socket host_vst_parameters; boost::asio::local::stream_protocol::socket host_vst_process_replacing; /** * This socket only handles updates of the `AEffect` struct instead of * passing through function calls. It's also used during initialization to * 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; /** * The thread that responds to `getParameter` and `setParameter` requests. */ std::thread parameters_handler; /** * The thread that handles calls to `processReplacing` (and `process`). */ std::thread process_replacing_handler; /** * A binary semaphore to prevent race conditions from the host callback * function being called by two threads at once. See `send_event()` for more * information. */ std::mutex host_callback_semaphore; /** * A scratch buffer for sending and receiving data during `process` and * `processReplacing` calls. */ std::vector process_buffer; Editor editor; };