mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Implement CLAP plugin initialization
This commit is contained in:
@@ -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 << "<none>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool ClapLogger::log_request(bool is_host_plugin,
|
bool ClapLogger::log_request(bool is_host_plugin,
|
||||||
const clap::plugin::Destroy& request) {
|
const clap::plugin::Destroy& request) {
|
||||||
return log_request_base(is_host_plugin, [&](auto& message) {
|
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 << "<none>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
void ClapLogger::log_response(bool is_host_plugin, const Configuration&) {
|
void ClapLogger::log_response(bool is_host_plugin, const Configuration&) {
|
||||||
log_response_base(is_host_plugin,
|
log_response_base(is_host_plugin,
|
||||||
[&](auto& message) { message << "<Configuration>"; });
|
[&](auto& message) { message << "<Configuration>"; });
|
||||||
|
|||||||
@@ -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::List&);
|
||||||
bool log_request(bool is_host_plugin, const clap::plugin_factory::Create&);
|
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&);
|
bool log_request(bool is_host_plugin, const clap::plugin::Destroy&);
|
||||||
|
|
||||||
// TODO: Audio thread requests
|
// TODO: Audio thread requests
|
||||||
@@ -60,6 +61,7 @@ class ClapLogger {
|
|||||||
const clap::plugin_factory::ListResponse&);
|
const clap::plugin_factory::ListResponse&);
|
||||||
void log_response(bool is_host_plugin,
|
void log_response(bool is_host_plugin,
|
||||||
const clap::plugin_factory::CreateResponse&);
|
const clap::plugin_factory::CreateResponse&);
|
||||||
|
void log_response(bool is_host_plugin, const clap::plugin::InitResponse&);
|
||||||
|
|
||||||
// TODO: Audio thread responses
|
// TODO: Audio thread responses
|
||||||
// void log_response(bool is_host_plugin,
|
// void log_response(bool is_host_plugin,
|
||||||
|
|||||||
@@ -42,6 +42,7 @@
|
|||||||
using ClapMainThreadControlRequest = std::variant<WantsConfiguration,
|
using ClapMainThreadControlRequest = std::variant<WantsConfiguration,
|
||||||
clap::plugin_factory::List,
|
clap::plugin_factory::List,
|
||||||
clap::plugin_factory::Create,
|
clap::plugin_factory::Create,
|
||||||
|
clap::plugin::Init,
|
||||||
clap::plugin::Destroy>;
|
clap::plugin::Destroy>;
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
@@ -92,7 +93,7 @@ struct ClapAudioThreadControlRequest {
|
|||||||
// // deserializing we'll deserialize into the persistent and
|
// // deserializing we'll deserialize into the persistent and
|
||||||
// // thread local `process_request` object (see
|
// // thread local `process_request` object (see
|
||||||
// // `ClapSockets::add_audio_processor_and_listen`) and then
|
// // `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,
|
// s.ext(request_ref,
|
||||||
// bitsery::ext::MessageReference(process_request_));
|
// bitsery::ext::MessageReference(process_request_));
|
||||||
// },
|
// },
|
||||||
|
|||||||
@@ -155,7 +155,7 @@ struct Init {
|
|||||||
template <typename S>
|
template <typename S>
|
||||||
void serialize(S& s) {
|
void serialize(S& s) {
|
||||||
s.value8b(instance_id);
|
s.value8b(instance_id);
|
||||||
s.boject(supported_host_extensions);
|
s.object(supported_host_extensions);
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|||||||
@@ -205,7 +205,7 @@ struct Vst3AudioProcessorRequest {
|
|||||||
// deserializing we'll deserialize into the persistent and
|
// deserializing we'll deserialize into the persistent and
|
||||||
// thread local `process_request` object (see
|
// thread local `process_request` object (see
|
||||||
// `Vst3Sockets::add_audio_processor_and_listen`) and then
|
// `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,
|
s.ext(request_ref,
|
||||||
bitsery::ext::MessageReference(process_request_));
|
bitsery::ext::MessageReference(process_request_));
|
||||||
},
|
},
|
||||||
|
|||||||
@@ -25,7 +25,6 @@ clap_plugin_proxy::clap_plugin_proxy(ClapPluginBridge& bridge,
|
|||||||
: bridge_(bridge),
|
: bridge_(bridge),
|
||||||
instance_id_(instance_id),
|
instance_id_(instance_id),
|
||||||
descriptor_(std::move(descriptor)),
|
descriptor_(std::move(descriptor)),
|
||||||
host_(host),
|
|
||||||
plugin_vtable_(clap_plugin_t{
|
plugin_vtable_(clap_plugin_t{
|
||||||
.desc = descriptor_.get(),
|
.desc = descriptor_.get(),
|
||||||
.plugin_data = this,
|
.plugin_data = this,
|
||||||
@@ -39,14 +38,23 @@ clap_plugin_proxy::clap_plugin_proxy(ClapPluginBridge& bridge,
|
|||||||
.process = plugin_process,
|
.process = plugin_process,
|
||||||
.get_extension = plugin_get_extension,
|
.get_extension = plugin_get_extension,
|
||||||
.on_main_thread = plugin_on_main_thread,
|
.on_main_thread = plugin_on_main_thread,
|
||||||
}) {}
|
}),
|
||||||
|
host_(host) {}
|
||||||
|
|
||||||
bool CLAP_ABI clap_plugin_proxy::plugin_init(const struct clap_plugin* plugin) {
|
bool CLAP_ABI clap_plugin_proxy::plugin_init(const struct clap_plugin* plugin) {
|
||||||
assert(plugin && plugin->plugin_data);
|
assert(plugin && plugin->plugin_data);
|
||||||
auto self = static_cast<const clap_plugin_proxy*>(plugin->plugin_data);
|
auto self = static_cast<clap_plugin_proxy*>(plugin->plugin_data);
|
||||||
|
|
||||||
// TODO: Implement
|
const clap::plugin::InitResponse response =
|
||||||
return false;
|
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
|
void CLAP_ABI
|
||||||
|
|||||||
@@ -83,16 +83,23 @@ class clap_plugin_proxy {
|
|||||||
size_t instance_id_;
|
size_t instance_id_;
|
||||||
clap::plugin::Descriptor descriptor_;
|
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
|
* 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
|
* 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*`.
|
* the start of the struct and directly casting the `clap_plugin_t*`.
|
||||||
*/
|
*/
|
||||||
const clap_plugin_t plugin_vtable_;
|
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_;
|
||||||
};
|
};
|
||||||
|
|||||||
@@ -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_process(const struct clap_host* host);
|
||||||
static void CLAP_ABI host_request_callback(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:
|
private:
|
||||||
ClapBridge& bridge_;
|
ClapBridge& bridge_;
|
||||||
size_t owner_instance_id_;
|
size_t owner_instance_id_;
|
||||||
|
|||||||
@@ -147,7 +147,7 @@ void ClapBridge::run() {
|
|||||||
.run_in_context([&]() {
|
.run_in_context([&]() {
|
||||||
plugin_factory_ =
|
plugin_factory_ =
|
||||||
static_cast<const clap_plugin_factory_t*>(
|
static_cast<const clap_plugin_factory_t*>(
|
||||||
(entry_->get_factory)(CLAP_PLUGIN_FACTORY_ID));
|
entry_->get_factory(CLAP_PLUGIN_FACTORY_ID));
|
||||||
if (!plugin_factory_) {
|
if (!plugin_factory_) {
|
||||||
return clap::plugin_factory::ListResponse{
|
return clap::plugin_factory::ListResponse{
|
||||||
.descriptors = std::nullopt};
|
.descriptors = std::nullopt};
|
||||||
@@ -155,11 +155,10 @@ void ClapBridge::run() {
|
|||||||
|
|
||||||
std::vector<clap::plugin::Descriptor> descriptors;
|
std::vector<clap::plugin::Descriptor> descriptors;
|
||||||
const uint32_t num_plugins =
|
const uint32_t num_plugins =
|
||||||
(plugin_factory_->get_plugin_count)(
|
plugin_factory_->get_plugin_count(plugin_factory_);
|
||||||
plugin_factory_);
|
|
||||||
for (uint32_t i = 0; i < num_plugins; i++) {
|
for (uint32_t i = 0; i < num_plugins; i++) {
|
||||||
const clap_plugin_descriptor_t* descriptor =
|
const clap_plugin_descriptor_t* descriptor =
|
||||||
(plugin_factory_->get_plugin_descriptor)(
|
plugin_factory_->get_plugin_descriptor(
|
||||||
plugin_factory_, i);
|
plugin_factory_, i);
|
||||||
if (!descriptor) {
|
if (!descriptor) {
|
||||||
std::cerr << "Plugin returned a null pointer "
|
std::cerr << "Plugin returned a null pointer "
|
||||||
@@ -209,6 +208,37 @@ void ClapBridge::run() {
|
|||||||
})
|
})
|
||||||
.get();
|
.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& request)
|
||||||
-> clap::plugin::Destroy::Response {
|
-> clap::plugin::Destroy::Response {
|
||||||
return main_context_
|
return main_context_
|
||||||
|
|||||||
@@ -78,9 +78,12 @@ struct ClapPluginInstance {
|
|||||||
* A proxy for the native CLAP host. Stored using an `std::unique_ptr`
|
* 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
|
* because it must be created before creating the plugin instance, and the
|
||||||
* object cannot move after being created because of the vtable.
|
* 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<clap_host_proxy> host_proxy;
|
std::unique_ptr<clap_host_proxy> host_proxy;
|
||||||
// TODO: Proxies for host extension objects
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A dedicated thread for handling incoming audio thread function calls.
|
* A dedicated thread for handling incoming audio thread function calls.
|
||||||
|
|||||||
Reference in New Issue
Block a user