diff --git a/src/common/logging/clap.cpp b/src/common/logging/clap.cpp index 5ed8c96e..51d54ae1 100644 --- a/src/common/logging/clap.cpp +++ b/src/common/logging/clap.cpp @@ -38,6 +38,34 @@ bool ClapLogger::log_request(bool is_host_plugin, }); } +bool ClapLogger::log_request(bool is_host_plugin, + const clap::plugin::Init& request) { + return log_request_base(is_host_plugin, [&](auto& message) { + message << request.instance_id + << ": clap_plugin::init(), supported host extensions: "; + + // TODO: Log supported extensions + bool first = true; + // for (const auto& [supported, extension_name] : {}) { + // if (!supported) { + // continue; + // } + + // if (first) { + // message << extension_name; + // } else { + // message << ", " << extension_name; + // } + + // first = false; + // } + + if (first) { + message << ""; + } + }); +} + bool ClapLogger::log_request(bool is_host_plugin, const clap::plugin::Destroy& request) { return log_request_base(is_host_plugin, [&](auto& message) { @@ -81,6 +109,34 @@ void ClapLogger::log_response( }); } +void ClapLogger::log_response(bool is_host_plugin, + const clap::plugin::InitResponse& response) { + return log_response_base(is_host_plugin, [&](auto& message) { + message << (response.result ? "true" : "false") + << ", supported plugin extensions: "; + + // TODO: Log supported extensions + bool first = true; + // for (const auto& [supported, extension_name] : {}) { + // if (!supported) { + // continue; + // } + + // if (first) { + // message << extension_name; + // } else { + // message << ", " << extension_name; + // } + + // first = false; + // } + + if (first) { + message << ""; + } + }); +} + void ClapLogger::log_response(bool is_host_plugin, const Configuration&) { log_response_base(is_host_plugin, [&](auto& message) { message << ""; }); diff --git a/src/common/logging/clap.h b/src/common/logging/clap.h index e7b25c3e..429cc138 100644 --- a/src/common/logging/clap.h +++ b/src/common/logging/clap.h @@ -47,6 +47,7 @@ class ClapLogger { bool log_request(bool is_host_plugin, const clap::plugin_factory::List&); bool log_request(bool is_host_plugin, const clap::plugin_factory::Create&); + bool log_request(bool is_host_plugin, const clap::plugin::Init&); bool log_request(bool is_host_plugin, const clap::plugin::Destroy&); // TODO: Audio thread requests @@ -60,6 +61,7 @@ class ClapLogger { const clap::plugin_factory::ListResponse&); void log_response(bool is_host_plugin, const clap::plugin_factory::CreateResponse&); + void log_response(bool is_host_plugin, const clap::plugin::InitResponse&); // TODO: Audio thread responses // void log_response(bool is_host_plugin, diff --git a/src/common/serialization/clap.h b/src/common/serialization/clap.h index be75d6dc..7594436a 100644 --- a/src/common/serialization/clap.h +++ b/src/common/serialization/clap.h @@ -42,6 +42,7 @@ using ClapMainThreadControlRequest = std::variant; template @@ -92,7 +93,7 @@ struct ClapAudioThreadControlRequest { // // deserializing we'll deserialize into the persistent and // // thread local `process_request` object (see // // `ClapSockets::add_audio_processor_and_listen`) and then - // // reassign the reference to point to that boject. + // // reassign the reference to point to that object. // s.ext(request_ref, // bitsery::ext::MessageReference(process_request_)); // }, diff --git a/src/common/serialization/clap/plugin.h b/src/common/serialization/clap/plugin.h index 645afde1..75f209e0 100644 --- a/src/common/serialization/clap/plugin.h +++ b/src/common/serialization/clap/plugin.h @@ -155,7 +155,7 @@ struct Init { template void serialize(S& s) { s.value8b(instance_id); - s.boject(supported_host_extensions); + s.object(supported_host_extensions); } }; diff --git a/src/common/serialization/vst3.h b/src/common/serialization/vst3.h index f073b09d..de199678 100644 --- a/src/common/serialization/vst3.h +++ b/src/common/serialization/vst3.h @@ -205,7 +205,7 @@ struct Vst3AudioProcessorRequest { // deserializing we'll deserialize into the persistent and // thread local `process_request` object (see // `Vst3Sockets::add_audio_processor_and_listen`) and then - // reassign the reference to point to that boject. + // reassign the reference to point to that object. s.ext(request_ref, bitsery::ext::MessageReference(process_request_)); }, diff --git a/src/plugin/bridges/clap-impls/plugin-proxy.cpp b/src/plugin/bridges/clap-impls/plugin-proxy.cpp index b3f4a7da..3dee36fe 100644 --- a/src/plugin/bridges/clap-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/clap-impls/plugin-proxy.cpp @@ -25,7 +25,6 @@ clap_plugin_proxy::clap_plugin_proxy(ClapPluginBridge& bridge, : bridge_(bridge), instance_id_(instance_id), descriptor_(std::move(descriptor)), - host_(host), plugin_vtable_(clap_plugin_t{ .desc = descriptor_.get(), .plugin_data = this, @@ -39,14 +38,23 @@ clap_plugin_proxy::clap_plugin_proxy(ClapPluginBridge& bridge, .process = plugin_process, .get_extension = plugin_get_extension, .on_main_thread = plugin_on_main_thread, - }) {} + }), + host_(host) {} bool CLAP_ABI clap_plugin_proxy::plugin_init(const struct clap_plugin* plugin) { assert(plugin && plugin->plugin_data); - auto self = static_cast(plugin->plugin_data); + auto self = static_cast(plugin->plugin_data); - // TODO: Implement - return false; + const clap::plugin::InitResponse response = + self->bridge_.send_main_thread_message( + clap::plugin::Init{.instance_id = self->instance_id(), + .supported_host_extensions = *self->host_}); + + // This determines which extensions the host is allowed to query in + // `clap_plugin::get_extension()` + self->supported_extensions_ = response.supported_plugin_extensions; + + return response.result; } void CLAP_ABI diff --git a/src/plugin/bridges/clap-impls/plugin-proxy.h b/src/plugin/bridges/clap-impls/plugin-proxy.h index df0c64cb..ec234d9f 100644 --- a/src/plugin/bridges/clap-impls/plugin-proxy.h +++ b/src/plugin/bridges/clap-impls/plugin-proxy.h @@ -83,16 +83,23 @@ class clap_plugin_proxy { size_t instance_id_; clap::plugin::Descriptor descriptor_; - /** - * The `clap_host_t*` passed when creating the instance. Any callbacks made - * by the proxied plugin instance must go through ere. - */ - const clap_host_t* host_; - /** * The vtable for `clap_plugin`, requires that this object is never moved or * copied. We'll use the host data pointer instead of placing this vtable at * the start of the struct and directly casting the `clap_plugin_t*`. */ const clap_plugin_t plugin_vtable_; + + /** + * The extensions supported by the bridged plugin. Set after a successful + * `clap_plugin::init()` call. We'll allow the host to query these same + * extensions from our plugin proxy. + */ + clap::plugin::SupportedPluginExtensions supported_extensions_; + + /** + * The `clap_host_t*` passed when creating the instance. Any callbacks made + * by the proxied plugin instance must go through ere. + */ + const clap_host_t* host_; }; diff --git a/src/wine-host/bridges/clap-impls/host-proxy.h b/src/wine-host/bridges/clap-impls/host-proxy.h index dc9dd796..7832eea9 100644 --- a/src/wine-host/bridges/clap-impls/host-proxy.h +++ b/src/wine-host/bridges/clap-impls/host-proxy.h @@ -60,6 +60,13 @@ class clap_host_proxy { static void CLAP_ABI host_request_process(const struct clap_host* host); static void CLAP_ABI host_request_callback(const struct clap_host* host); + /** + * The extensions supported by the host, set just before calling + * `clap_plugin::init()` on the bridged plugin. We'll allow the plugin to + * query these extensions through `clap_host::get_extension()`. + */ + clap::host::SupportedHostExtensions supported_extensions_; + private: ClapBridge& bridge_; size_t owner_instance_id_; diff --git a/src/wine-host/bridges/clap.cpp b/src/wine-host/bridges/clap.cpp index be8f69e0..2ab0ca8a 100644 --- a/src/wine-host/bridges/clap.cpp +++ b/src/wine-host/bridges/clap.cpp @@ -147,7 +147,7 @@ void ClapBridge::run() { .run_in_context([&]() { plugin_factory_ = static_cast( - (entry_->get_factory)(CLAP_PLUGIN_FACTORY_ID)); + entry_->get_factory(CLAP_PLUGIN_FACTORY_ID)); if (!plugin_factory_) { return clap::plugin_factory::ListResponse{ .descriptors = std::nullopt}; @@ -155,11 +155,10 @@ void ClapBridge::run() { std::vector descriptors; const uint32_t num_plugins = - (plugin_factory_->get_plugin_count)( - plugin_factory_); + plugin_factory_->get_plugin_count(plugin_factory_); for (uint32_t i = 0; i < num_plugins; i++) { const clap_plugin_descriptor_t* descriptor = - (plugin_factory_->get_plugin_descriptor)( + plugin_factory_->get_plugin_descriptor( plugin_factory_, i); if (!descriptor) { std::cerr << "Plugin returned a null pointer " @@ -209,6 +208,37 @@ void ClapBridge::run() { }) .get(); }, + [&](clap::plugin::Init& request) -> clap::plugin::Init::Response { + return main_context_ + .run_in_context([&]() { + const auto& [instance, _] = + get_instance(request.instance_id); + + // The plugin is allowed to query the same set of + // extensions from our host proxy that the native host + // supports + instance.host_proxy->supported_extensions_ = + request.supported_host_extensions; + + const bool result = + instance.plugin->init(instance.plugin.get()); + if (result) { + // This mimics the same behavior we had to implement + // for VST2 and VST3. The Win32 message loop is + // completely blocked while a plugin instance has + // been created but not yet initialized. + instance.is_initialized = true; + } + + return clap::plugin::InitResponse{ + .result = result, + // Similarly, we'll make the plugin's supported + // extensions available to the host + .supported_plugin_extensions = *instance.plugin}; + }) + .get(); + }, + [&](clap::plugin::Destroy& request) -> clap::plugin::Destroy::Response { return main_context_ diff --git a/src/wine-host/bridges/clap.h b/src/wine-host/bridges/clap.h index 35279423..9ec20583 100644 --- a/src/wine-host/bridges/clap.h +++ b/src/wine-host/bridges/clap.h @@ -78,9 +78,12 @@ struct ClapPluginInstance { * A proxy for the native CLAP host. Stored using an `std::unique_ptr` * because it must be created before creating the plugin instance, and the * object cannot move after being created because of the vtable. + * + * Contains a `clap::host::SupportedHostExtensions` set just before + * `clap_plugin::init()` that allows the plugin to query host extensions + * also supported by the native host. */ std::unique_ptr host_proxy; - // TODO: Proxies for host extension objects /** * A dedicated thread for handling incoming audio thread function calls.