diff --git a/CHANGELOG.md b/CHANGELOG.md index 17202753..4a36d6c1 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -8,6 +8,15 @@ Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- Added a new [compatibility + option](https://github.com/robbert-vdh/yabridge#compatibility-options) to hide + the name of the DAW you're using for a plugin. This can be useful with plugins + that have undesirable or broken DAW-specific behaviour. See the [known + issues](https://github.com/robbert-vdh/yabridge#runtime-dependencies-and-known-issues) + section of the readme for more information on when this may be useful. + ### Changed - When building the package from source, the targetted Wine version gets printed diff --git a/README.md b/README.md index a9536751..7855d9d8 100644 --- a/README.md +++ b/README.md @@ -297,6 +297,7 @@ plugin._ | `editor_force_dnd` | `{true,false}` | This option forcefully enables drag-and-drop support in _REAPER_. Because REAPER's FX window supports drag-and-drop itself, dragging a file onto a plugin editor will cause the drop to be intercepted by the FX window. This makes it impossible to drag files onto plugins in REAPER under normal circumstances. Setting this option to `true` will strip drag-and-drop support from the FX window, thus allowing files to be dragged onto the plugin again. Defaults to `false`. | | `editor_xembed` | `{true,false}` | Use Wine's XEmbed implementation instead of yabridge's normal window embedding method. Some plugins will have redrawing issues when using XEmbed and editor resizing won't always work properly with it, but it could be useful in certain setups. You may need to use [this Wine patch](https://github.com/psycha0s/airwave/blob/master/fix-xembed-wine-windows.patch) if you're getting blank editor windows. Defaults to `false`. | | `frame_rate` | `` | The rate at which Win32 events are being handled and usually also the refresh rate of a plugin's editor GUI. When using plugin groups all plugins share the same event handling loop, so in those the last loaded plugin will set the refresh rate. Defaults to `60`. | +| `hide_daw` | `{true,false}` | Don't report the name of the actual DAW to the plugin. See the [known issues](#runtime-dependencies-and-known-issues) section for a list of situations where this may be useful. This affects both VST2 and VST3 plugins. Defaults to `false`. | | `vst3_no_scaling` | `{true,false}` | Disable HiDPI scaling for VST3 plugins. Wine currently does not have proper fractional HiDPI support, so you might have to enable this option if you're using a HiDPI display. In most cases setting the font DPI in `winecfg`'s graphics tab to 192 will cause plugins to scale correctly at 200% size. Defaults to `false`. | | `vst3_prefer_32bit` | `{true,false}` | Use the 32-bit version of a VST3 plugin instead the 64-bit version if both are installed and they're in the same VST3 bundle inside of `~/.vst3/yabridge`. You likely won't need this. | @@ -329,6 +330,9 @@ editor_double_embed = true ["Analog Lab 3.so"] editor_xembed = true +["Chromaphone 3.so"] +hide_daw = true + ["SWAM Cello 64bit.so"] cache_time_info = true @@ -367,6 +371,9 @@ deep within in, like this: group = "fabfilter" vst3_no_scaling = true +["Chromaphone 3.vst3"] +hide_daw = true + ["Misstortion2.vst3"] vst3_no_scaling = true diff --git a/src/common/configuration.cpp b/src/common/configuration.cpp index 8bdd6d53..919b1157 100644 --- a/src/common/configuration.cpp +++ b/src/common/configuration.cpp @@ -119,6 +119,12 @@ Configuration::Configuration(const fs::path& config_path, } else { invalid_options.push_back(key); } + } else if (key == "hide_daw") { + if (const auto parsed_value = value.as_boolean()) { + hide_daw = parsed_value->get(); + } else { + invalid_options.push_back(key); + } } else if (key == "vst3_no_scaling") { if (const auto parsed_value = value.as_boolean()) { vst3_no_scaling = parsed_value->get(); diff --git a/src/common/configuration.h b/src/common/configuration.h index 66a4c95b..5d07bc15 100644 --- a/src/common/configuration.h +++ b/src/common/configuration.h @@ -138,6 +138,15 @@ class Configuration { */ std::optional frame_rate; + /** + * When this option is enabled, we'll report some random other string + * instead of the actual name of the host when the plugin queries it. This + * can sometimes be useful when a plugin has undesirable host-specific + * behaviour. See the readme for some examples of where this might be + * useful. + */ + bool hide_daw = false; + /** * Disable `IPlugViewContentScaleSupport::setContentScaleFactor()`. Wine * does not properly implement fractional DPI scaling, so without this @@ -198,6 +207,7 @@ class Configuration { s.value1b(editor_xembed); s.ext(frame_rate, bitsery::ext::StdOptional(), [](S& s, auto& v) { s.value4b(v); }); + s.value1b(hide_daw); s.value1b(vst3_no_scaling); s.value1b(vst3_prefer_32bit); diff --git a/src/common/utils.h b/src/common/utils.h index daafac4a..f99b0505 100644 --- a/src/common/utils.h +++ b/src/common/utils.h @@ -31,6 +31,20 @@ */ constexpr time_t audio_thread_priority_synchronization_interval = 10; +/** + * When the `hide_daw` compatibility option is enabled, we'll report this + * instead of the actual DAW's name. This can be useful when plugins are + * hardcoded to behave differently in certain DAWs, and when that different + * behaviour causes issues under Wine. Examples of this are Melodyne 5 under + * REAPER, and AAS Chromaphone 3 under Bitwig. + */ +constexpr char product_name_override[] = "Get yabridge'd"; +/** + * When the `hide_daw` compatibility option is enabled, we'll report this + * instead of the actual vendor's name in a VST2 plugin. + */ +constexpr char vendor_name_override[] = "yabridge"; + // The cannonical overloading template for `std::visitor`, not sure why this // isn't part of the standard library template diff --git a/src/plugin/bridges/common.h b/src/plugin/bridges/common.h index 9ac41461..2c91dc9f 100644 --- a/src/plugin/bridges/common.h +++ b/src/plugin/bridges/common.h @@ -193,6 +193,9 @@ class PluginBridge { << *config.frame_rate << " fps"; other_options.push_back(option.str()); } + if (config.hide_daw) { + other_options.push_back("hack: hide DAW name"); + } if (config.vst3_no_scaling) { other_options.push_back("vst3: no GUI scaling"); } diff --git a/src/plugin/bridges/vst2.cpp b/src/plugin/bridges/vst2.cpp index de2d49b5..f2e9bd7a 100644 --- a/src/plugin/bridges/vst2.cpp +++ b/src/plugin/bridges/vst2.cpp @@ -90,11 +90,10 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback) incoming_midi_events.push_back( std::get(event.payload)); - EventResult response{.return_value = 1, - .payload = nullptr, - .value_payload = std::nullopt}; - return response; + return EventResult{.return_value = 1, + .payload = nullptr, + .value_payload = std::nullopt}; } break; // REAPER requires that `audioMasterSizeWindow()` calls are // handled from the GUI thread, which is the thread that @@ -105,16 +104,50 @@ Vst2PluginBridge::Vst2PluginBridge(audioMasterCallback host_callback) std::lock_guard lock(incoming_resize_mutex); incoming_resize = std::pair(event.index, event.value); - EventResult response{.return_value = 1, - .payload = nullptr, - .value_payload = std::nullopt}; - return response; + return EventResult{.return_value = 1, + .payload = nullptr, + .value_payload = std::nullopt}; + } break; + // HACK: Certain plugins may have undesirable DAW-specific + // behaviour. Chromaphone 3 for instance has broken + // text input dialogs when using Bitwig. We can work + // around these issues by reporting we're running + // under some other host. We need to do this on the + // plugin side instead of one the Wine side because + // the plugin will likely do this callback during + // initialization, and at that point we will not yet + // have sent the configuration to the plugin. + case audioMasterGetProductString: { + if (config.hide_daw) { + logger.log("The plugin asked for the host's name."); + logger.log("Reporting \"" + + std::string(product_name_override) + + "\" instead of the actual host's name."); + + return EventResult{.return_value = 1, + .payload = product_name_override, + .value_payload = std::nullopt}; + } + } break; + case audioMasterGetVendorString: { + if (config.hide_daw) { + logger.log( + "The plugin asked for the host's vendor."); + logger.log( + "Reporting \"" + + std::string(vendor_name_override) + + "\" instead of the actual host's vendor."); + + return EventResult{.return_value = 1, + .payload = vendor_name_override, + .value_payload = std::nullopt}; + } } break; - default: - return passthrough_event(&plugin, - host_callback_function, event); } + + return passthrough_event(&plugin, host_callback_function, + event); }); });