// 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 . #include #include // Generated inside of the build directory #include #include #include "../common/utils.h" #include "bridges/vst2.h" #ifdef WITH_VST3 #include "bridges/vst3.h" #endif /** * This is the default plugin host application. It will load the specified * plugin plugin, and then connect back to the `libyabridge-{vst2,vst3}.so` * instance that spawned this over the socket. * * The explicit calling convention is needed to work around a bug introduced in * Wine 5.7: https://bugs.winehq.org/show_bug.cgi?id=49138 */ int __cdecl __attribute__((visibility("default"))) main(int argc, char* argv[]) { set_realtime_priority(); // We pass plugin format, the name of the VST2 plugin .dll file or VST3 // bundle to load, and the base directory for the Unix domain socket // endpoints to connect to as the first two arguments of this process in // `src/plugin/host-process.cpp` if (argc < 4) { std::cerr << "Usage: " #ifdef __i386__ << yabridge_individual_host_name_32bit #else << yabridge_individual_host_name #endif << " " << std::endl; return 1; } const std::string plugin_type_str(argv[1]); const PluginType plugin_type = plugin_type_from_string(plugin_type_str); const std::string plugin_location(argv[2]); const std::string socket_endpoint_path(argv[3]); std::cout << "Initializing yabridge host version " << yabridge_git_version #ifdef __i386__ << " (32-bit compatibility mode)" #endif << std::endl; std::cout << "Preparing to load " << plugin_type_to_string(plugin_type) << " plugin at '" << plugin_location << "'" << std::endl; // As explained in `Vst2Bridge`, the plugin has to be initialized in the // same thread as the one that calls `io_context.run()`. This setup is // slightly more convoluted than it has to be, but doing it this way we // don't need to differentiate between individually hosted plugins and // plugin groups when it comes to event handling. MainContext main_context{}; std::unique_ptr bridge; try { switch (plugin_type) { case PluginType::vst2: bridge = std::make_unique( main_context, plugin_location, socket_endpoint_path); break; case PluginType::vst3: #ifdef WITH_VST3 justdewit(plugin_location); std::cerr << "TODO: Not yet implemented" << std::endl; return 1; #else std::cerr << "This version of yabridge has not been compiled " "with VST3 support" << std::endl; return 1; #endif break; case PluginType::unknown: std::cerr << "Unknown plugin type '" << plugin_type_str << "'" << std::endl; return 1; break; }; } catch (const std::runtime_error& error) { std::cerr << "Error while initializing the Wine plugin host:" << std::endl; std::cerr << error.what() << std::endl; return 1; } // Let the plugin receive and handle its events on its own thread. Some // potentially unsafe events that should always be run from the UI thread // will be posted to `main_context`. Win32Thread worker_thread([&]() { bridge->run(); // When the sockets get closed, this application should // terminate gracefully main_context.stop(); }); std::cout << "Finished initializing '" << plugin_location << "'" << std::endl; // Handle Win32 messages and X11 events on a timer, just like in // `GroupBridge::async_handle_events()`` main_context.async_handle_events([&]() { bridge->handle_x11_events(); bridge->handle_win32_events(); }); main_context.run(); }