Pass plugin path around instead of redetecting

This is now set only once at the top level. This is needed for the
chainloading to work because we'll need to set the path when we create
the bridge.
This commit is contained in:
Robbert van der Helm
2022-04-16 14:21:24 +02:00
parent 1fec4c8860
commit fde90d7bc3
11 changed files with 78 additions and 36 deletions
+3 -1
View File
@@ -20,7 +20,9 @@
#include <dlfcn.h>
std::string get_this_file_location() {
namespace fs = ghc::filesystem;
fs::path get_this_file_location() {
// We'll try to find the library this function was defined in. When called
// from a copy of `libyabridge-*.so` this will return that library. Because
// the chainloader libraries load the plugin libraries from fixed locations,
+2 -2
View File
@@ -19,7 +19,7 @@
// This header is completely standalone so the chainloading libraries can
// retrieve their file path without pulling in a lot of additional dependencies
#include <string>
#include <ghc/filesystem.hpp>
/**
* Return a path to this `.so` file. This can be used to find out from where
@@ -29,4 +29,4 @@
* library using the provided exported functions since they can't detect the
* path themselves.
*/
std::string get_this_file_location();
ghc::filesystem::path get_this_file_location();
+14 -11
View File
@@ -66,23 +66,26 @@ class PluginBridge {
* `connect_sockets_guarded()` themselves after their initialization list.
*
* @param plugin_type The type of the plugin we're handling.
* @param plugin_path The path to the plugin. For VST2 plugins this is the
* path to the `.dll` file, and for VST3 plugins this is the path to the
* module (either a `.vst3` DLL file or a bundle).
* @param plugin_path The path to the **native** plugin library `.so` file.
* This is used to determine the path to the Windows plugin library we
* should load.
* @param create_socket_instance A function to create a socket instance.
* Using a lambda here feels wrong, but I can't think of a better
* solution right now.
*
* @throw std::runtime_error Thrown when the Wine plugin host could not be
* found, or if it could not locate and load a VST3 module.
* found, or if it could not locate and load a corresponding Windows
* plugin library.
*/
template <
invocable_returning<TSockets, asio::io_context&, const PluginInfo&> F>
PluginBridge(PluginType plugin_type, F&& create_socket_instance)
PluginBridge(PluginType plugin_type,
const ghc::filesystem::path& plugin_path,
F&& create_socket_instance)
// This is still correct for VST3 plugins because we can configure an
// entire directory (the module's bundle) at once
: config_(load_config_for(get_this_file_location())),
info_(plugin_type, config_.vst3_prefer_32bit),
: config_(load_config_for(plugin_path)),
info_(plugin_type, plugin_path, config_.vst3_prefer_32bit),
io_context_(),
sockets_(create_socket_instance(io_context_, info_)),
generic_logger_(Logger::create_from_environment(
@@ -179,7 +182,7 @@ class PluginBridge {
"recommended to set up proper realtime privileges "
"for your user. Check the readme for "
"instructions on how to do that.",
false);
std::nullopt);
} else {
init_msg << "'yes'" << std::endl;
}
@@ -222,7 +225,7 @@ class PluginBridge {
"realtime privileges for your user, and some plugins "
"may cause your DAW to crash until you fix this. Check "
"the readme for instructions on how to do that.",
false);
std::nullopt);
}
} else {
init_msg
@@ -390,7 +393,7 @@ class PluginBridge {
"went wrong. You may need to rerun your DAW from a "
"terminal and restart the plugin scanning process to "
"see the error.",
true);
info_.native_library_path_);
std::terminate();
}
@@ -426,7 +429,7 @@ class PluginBridge {
"Version mismatch",
"If you just updated yabridge, then you may need "
"to rerun 'yabridgectl sync' first to update your plugins.",
true);
info_.native_library_path_);
}
}
+3 -1
View File
@@ -35,9 +35,11 @@ Vst2PluginBridge& get_bridge_instance(const AEffect& plugin) noexcept {
return *static_cast<Vst2PluginBridge*>(plugin.ptr3);
}
Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback)
Vst2PluginBridge::Vst2PluginBridge(const ghc::filesystem::path& plugin_path,
audioMasterCallback host_callback)
: PluginBridge(
PluginType::vst2,
plugin_path,
[](asio::io_context& io_context, const PluginInfo& info) {
return Vst2Sockets<std::jthread>(
io_context,
+7 -1
View File
@@ -40,13 +40,19 @@ class Vst2PluginBridge : PluginBridge<Vst2Sockets<std::jthread>> {
* Initializes the Wine plugin bridge. This sets up the sockets for event
* handling.
*
* @param plugin_path The path to the **native** plugin library `.so` file.
* This is used to determine the path to the Windows plugin library we
* should load. For directly loaded bridges this should be
* `get_this_file_location()`. Chainloaded plugins should use the path of
* the chainloader copy instead.
* @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.
*/
Vst2PluginBridge(audioMasterCallback host_callback);
Vst2PluginBridge(const ghc::filesystem::path& plugin_path,
audioMasterCallback host_callback);
/**
* Terminate the Wine plugin host process and drop all work when the module
+2 -1
View File
@@ -24,9 +24,10 @@
using namespace std::literals::string_literals;
Vst3PluginBridge::Vst3PluginBridge()
Vst3PluginBridge::Vst3PluginBridge(const ghc::filesystem::path& plugin_path)
: PluginBridge(
PluginType::vst3,
plugin_path,
[](asio::io_context& io_context, const PluginInfo& info) {
return Vst3Sockets<std::jthread>(
io_context,
+7 -1
View File
@@ -52,10 +52,16 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
* Initializes the VST3 module by starting and setting up communicating with
* the Wine plugin host.
*
* @param plugin_path The path to the **native** plugin library `.so` file.
* This is used to determine the path to the Windows plugin library we
* should load. For directly loaded bridges this should be
* `get_this_file_location()`. Chainloaded plugins should use the path of
* the chainloader copy instead.
*
* @throw std::runtime_error Thrown when the Wine plugin host could not be
* found, or if it could not locate and load a VST3 module.
*/
explicit Vst3PluginBridge();
explicit Vst3PluginBridge(const ghc::filesystem::path& plugin_path);
/**
* Terminate the Wine plugin host process and drop all work when the module
+13 -10
View File
@@ -43,9 +43,11 @@ fs::path normalize_plugin_path(const fs::path& windows_library_path,
std::variant<OverridenWinePrefix, fs::path, DefaultWinePrefix> find_wine_prefix(
fs::path windows_plugin_path);
PluginInfo::PluginInfo(PluginType plugin_type, bool prefer_32bit_vst3)
PluginInfo::PluginInfo(PluginType plugin_type,
const ghc::filesystem::path& plugin_path,
bool prefer_32bit_vst3)
: plugin_type_(plugin_type),
native_library_path_(get_this_file_location()),
native_library_path_(plugin_path),
// As explained in the docstring, this is the actual Windows library. For
// VST3 plugins that come in a module we should be loading that module
// instead of the `.vst3` file within in, which is where
@@ -423,23 +425,24 @@ Configuration load_config_for(const fs::path& yabridge_path) {
bool send_notification(const std::string& title,
const std::string body,
bool append_origin) {
std::optional<ghc::filesystem::path> origin) {
// I think there's a zero chance that we're going to call this function with
// anything that even somewhat resembles HTML, but we should still do a
// basic XML escape anyways.
std::ostringstream formatted_body;
formatted_body << xml_escape(body);
// If possible, append the path to this library file to the message.
if (append_origin) {
// If the path to the current library file is provided, then we'll append
// the path to that library file to the message. In earlier versions we
// would detect the library path right here, but that will not work with
// chainloaded plugins as they will load the actual plugin libraries from
// fixed locations.
if (origin) {
try {
const fs::path this_library = get_this_file_location();
formatted_body << "\n"
<< "Source: <a href=\"file://"
<< url_encode_path(
this_library.parent_path().string())
<< "\">"
<< xml_escape(this_library.filename().string())
<< url_encode_path(origin->parent_path().string())
<< "\">" << xml_escape(origin->filename().string())
<< "</a>";
} catch (const std::system_error&) {
// I don't think this can fail in the way we're using it, but the
+10 -4
View File
@@ -58,6 +58,9 @@ struct PluginInfo {
*
* @param plugin_type The type of the plugin we're going to load. The
* detection works slightly differently depending on the plugin type.
* @param plugin_path The path to the **native** plugin library `.so` file.
* This is used to determine the path to the Windows plugin library we
* should load.
* @param prefer_32bit_vst3 If there's both a 64-bit and a 32-bit Windows
* VST3 module in the same bundle, then setting this to true will cause
* the 32-bit version to be used instead of the 64-bit version.
@@ -66,7 +69,9 @@ struct PluginInfo {
* plugin. The error message contains a human readable description of what
* went wrong.
*/
PluginInfo(PluginType plugin_type, bool prefer_32bit_vst3 = false);
PluginInfo(PluginType plugin_type,
const ghc::filesystem::path& plugin_path,
bool prefer_32bit_vst3 = false);
/**
* Create the environment for the plugin host based on `wine_prefix_`. If
@@ -267,15 +272,16 @@ Configuration load_config_for(const ghc::filesystem::path& yabridge_path);
* @param body The message to display. This can contain line feeds, and it any
* HTML tags and XML escape sequences will be automatically escaped. The
* message can also be empty.
* @param Whether to append 'Source: <XXX.so>' to the body, where `<XXX.so>` is
* a hyperlink to the directory this library is placed in.
* @param origin If this is set to the current plugin's path, then the
* notification will append a 'Source: <XXX.so>' hyperlink to the body so the
* user can more easily navigate to the plugin's path.
*
* @return Whether the notification was sent. This will be false if
* `notify-send` is not available.
*/
bool send_notification(const std::string& title,
const std::string body,
bool append_origin);
std::optional<ghc::filesystem::path> origin);
/**
* Starting from the starting file or directory, go up in the directory
+8 -2
View File
@@ -24,6 +24,8 @@
using namespace std::literals::string_literals;
namespace fs = ghc::filesystem;
// The main entry point for VST2 plugins should be called `VSTPluginMain``. The
// other one exist for legacy reasons since some old hosts might still use them
// (EnergyXT being the only known host on Linux that uses the `main` entry
@@ -40,11 +42,15 @@ using namespace std::literals::string_literals;
*/
extern "C" YABRIDGE_EXPORT AEffect* VSTPluginMain(
audioMasterCallback host_callback) {
// FIXME: Update this for the chainloading
const fs::path plugin_path = get_this_file_location();
try {
// This is the only place where we have to use manual memory management.
// The bridge's destructor is called when the `effClose` opcode is
// received.
Vst2PluginBridge* bridge = new Vst2PluginBridge(host_callback);
Vst2PluginBridge* bridge =
new Vst2PluginBridge(plugin_path, host_callback);
return &bridge->plugin_;
} catch (const std::exception& error) {
@@ -62,7 +68,7 @@ extern "C" YABRIDGE_EXPORT AEffect* VSTPluginMain(
error.what() +
"\nIf you just updated yabridge, then you may need to rerun "
"'yabridgectl sync' first to update your plugins."s,
true);
plugin_path);
return nullptr;
}
+9 -2
View File
@@ -29,6 +29,10 @@ using namespace std::literals::string_literals;
// NOLINTNEXTLINE(bugprone-suspicious-include)
#include <public.sdk/source/main/linuxmain.cpp>
using namespace std::literals::string_literals;
namespace fs = ghc::filesystem;
// Because VST3 plugins consist of completely independent components that have
// to be initialized and connected by the host, hosting a VST3 plugin through
// yabridge works very differently from hosting VST2 plugin. Even with
@@ -48,8 +52,11 @@ std::unique_ptr<Vst3PluginBridge> bridge;
bool InitModule() {
assert(!bridge);
// FIXME: Update this for the chainloading
const fs::path plugin_path = get_this_file_location();
try {
bridge = std::make_unique<Vst3PluginBridge>();
bridge = std::make_unique<Vst3PluginBridge>(plugin_path);
return true;
} catch (const std::exception& error) {
@@ -67,7 +74,7 @@ bool InitModule() {
error.what() +
"\nIf you just updated yabridge, then you may need to rerun "
"'yabridgectl sync' first to update your plugins."s,
true);
plugin_path);
return false;
}