mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Implement Wine side for creating plugin instances
This commit is contained in:
@@ -29,6 +29,15 @@ bool ClapLogger::log_request(bool is_host_plugin,
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
bool ClapLogger::log_request(bool is_host_plugin,
|
||||||
|
const clap::plugin_factory::Create& request) {
|
||||||
|
return log_request_base(is_host_plugin, [&](auto& message) {
|
||||||
|
message << "clap_plugin_factory::create(host = <clap_host_t*>, "
|
||||||
|
"plugin_id = \""
|
||||||
|
<< request.plugin_id << "\")";
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
bool ClapLogger::log_request(bool is_host_plugin, const WantsConfiguration&) {
|
bool ClapLogger::log_request(bool is_host_plugin, const WantsConfiguration&) {
|
||||||
return log_request_base(is_host_plugin, [&](auto& message) {
|
return log_request_base(is_host_plugin, [&](auto& message) {
|
||||||
message << "Requesting <Configuration>";
|
message << "Requesting <Configuration>";
|
||||||
@@ -40,10 +49,10 @@ bool ClapLogger::log_request(bool is_host_plugin, const WantsConfiguration&) {
|
|||||||
// });
|
// });
|
||||||
// }
|
// }
|
||||||
|
|
||||||
bool ClapLogger::log_response(
|
void ClapLogger::log_response(
|
||||||
bool is_host_plugin,
|
bool is_host_plugin,
|
||||||
const clap::plugin_factory::ListResponse& response) {
|
const clap::plugin_factory::ListResponse& response) {
|
||||||
return log_request_base(is_host_plugin, [&](auto& message) {
|
return log_response_base(is_host_plugin, [&](auto& message) {
|
||||||
if (response.descriptors) {
|
if (response.descriptors) {
|
||||||
message << "<clap_plugin_factory containing "
|
message << "<clap_plugin_factory containing "
|
||||||
<< response.descriptors->size() << " plugin descriptors>";
|
<< response.descriptors->size() << " plugin descriptors>";
|
||||||
@@ -53,6 +62,19 @@ bool ClapLogger::log_response(
|
|||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void ClapLogger::log_response(
|
||||||
|
bool is_host_plugin,
|
||||||
|
const clap::plugin_factory::CreateResponse& response) {
|
||||||
|
return log_response_base(is_host_plugin, [&](auto& message) {
|
||||||
|
if (response.instance_id) {
|
||||||
|
message << "<clap_plugin_t* with instance ID "
|
||||||
|
<< *response.instance_id << ">";
|
||||||
|
} else {
|
||||||
|
message << "<nullptr*>";
|
||||||
|
}
|
||||||
|
});
|
||||||
|
}
|
||||||
|
|
||||||
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>"; });
|
||||||
|
|||||||
@@ -46,6 +46,7 @@ class ClapLogger {
|
|||||||
// log message for the response together with the request.
|
// log message for the response together with the request.
|
||||||
|
|
||||||
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&);
|
||||||
|
|
||||||
// TODO: Audio thread requests
|
// TODO: Audio thread requests
|
||||||
// bool log_request(bool is_host_plugin,
|
// bool log_request(bool is_host_plugin,
|
||||||
@@ -54,8 +55,10 @@ class ClapLogger {
|
|||||||
bool log_request(bool is_host_plugin, const WantsConfiguration&);
|
bool log_request(bool is_host_plugin, const WantsConfiguration&);
|
||||||
|
|
||||||
// void log_response(bool is_host_plugin, const Ack&);
|
// void log_response(bool is_host_plugin, const Ack&);
|
||||||
bool log_response(bool is_host_plugin,
|
void log_response(bool is_host_plugin,
|
||||||
const clap::plugin_factory::ListResponse&);
|
const clap::plugin_factory::ListResponse&);
|
||||||
|
void log_response(bool is_host_plugin,
|
||||||
|
const clap::plugin_factory::CreateResponse&);
|
||||||
|
|
||||||
// TODO: Audio thread responses
|
// TODO: Audio thread responses
|
||||||
// void log_response(bool is_host_plugin,
|
// void log_response(bool is_host_plugin,
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
|
|
||||||
#include "../bitsery/ext/message-reference.h"
|
#include "../bitsery/ext/message-reference.h"
|
||||||
#include "../utils.h"
|
#include "../utils.h"
|
||||||
|
#include "clap/host.h"
|
||||||
#include "clap/plugin-factory.h"
|
#include "clap/plugin-factory.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
@@ -38,8 +39,9 @@
|
|||||||
*/
|
*/
|
||||||
// FIXME: Remove the `WantsConfiguration`. For some reason bitsery just won't
|
// FIXME: Remove the `WantsConfiguration`. For some reason bitsery just won't
|
||||||
// serialize this without it.
|
// serialize this without it.
|
||||||
using ClapMainThreadControlRequest =
|
using ClapMainThreadControlRequest = std::variant<WantsConfiguration,
|
||||||
std::variant<WantsConfiguration, clap::plugin_factory::List>;
|
clap::plugin_factory::List,
|
||||||
|
clap::plugin_factory::Create>;
|
||||||
|
|
||||||
template <typename S>
|
template <typename S>
|
||||||
void serialize(S& s, ClapMainThreadControlRequest& payload) {
|
void serialize(S& s, ClapMainThreadControlRequest& payload) {
|
||||||
|
|||||||
@@ -49,6 +49,10 @@ class clap_host_proxy {
|
|||||||
* Get a `clap_host` vtable that can be passed to the plugin.
|
* Get a `clap_host` vtable that can be passed to the plugin.
|
||||||
*/
|
*/
|
||||||
inline const clap_host_t* host_vtable() const { return &host_vtable_; }
|
inline const clap_host_t* host_vtable() const { return &host_vtable_; }
|
||||||
|
/**
|
||||||
|
* The instance ID of the plugin instance this proxy belongs to.
|
||||||
|
*/
|
||||||
|
inline size_t owner_isntance_id() const { return owner_instance_id_; }
|
||||||
|
|
||||||
static const void* CLAP_ABI host_get_extension(const struct clap_host* host,
|
static const void* CLAP_ABI host_get_extension(const struct clap_host* host,
|
||||||
const char* extension_id);
|
const char* extension_id);
|
||||||
|
|||||||
@@ -30,8 +30,12 @@ namespace fs = ghc::filesystem;
|
|||||||
ClapPluginExtensions::ClapPluginExtensions(const clap_plugin& plugin) noexcept {
|
ClapPluginExtensions::ClapPluginExtensions(const clap_plugin& plugin) noexcept {
|
||||||
}
|
}
|
||||||
|
|
||||||
ClapPluginInstance::ClapPluginInstance(const clap_plugin* plugin) noexcept
|
ClapPluginInstance::ClapPluginInstance(
|
||||||
: plugin((assert(plugin), plugin), plugin->destroy), extensions(*plugin) {}
|
const clap_plugin* plugin,
|
||||||
|
std::unique_ptr<clap_host_proxy> host_proxy) noexcept
|
||||||
|
: host_proxy(std::move(host_proxy)),
|
||||||
|
plugin((assert(plugin), plugin), plugin->destroy),
|
||||||
|
extensions(*plugin) {}
|
||||||
|
|
||||||
ClapBridge::ClapBridge(MainContext& main_context,
|
ClapBridge::ClapBridge(MainContext& main_context,
|
||||||
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
// NOLINTNEXTLINE(bugprone-easily-swappable-parameters)
|
||||||
@@ -141,20 +145,22 @@ void ClapBridge::run() {
|
|||||||
-> clap::plugin_factory::List::Response {
|
-> clap::plugin_factory::List::Response {
|
||||||
return main_context_
|
return main_context_
|
||||||
.run_in_context([&]() {
|
.run_in_context([&]() {
|
||||||
const clap_plugin_factory_t* 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 (!factory) {
|
if (!plugin_factory_) {
|
||||||
return clap::plugin_factory::ListResponse{
|
return clap::plugin_factory::ListResponse{
|
||||||
.descriptors = std::nullopt};
|
.descriptors = std::nullopt};
|
||||||
}
|
}
|
||||||
|
|
||||||
std::vector<clap::plugin::Descriptor> descriptors;
|
std::vector<clap::plugin::Descriptor> descriptors;
|
||||||
const uint32_t num_plugins =
|
const uint32_t num_plugins =
|
||||||
(factory->get_plugin_count)(factory);
|
(plugin_factory_->get_plugin_count)(
|
||||||
|
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 =
|
||||||
(factory->get_plugin_descriptor)(factory, i);
|
(plugin_factory_->get_plugin_descriptor)(
|
||||||
|
plugin_factory_, i);
|
||||||
if (!descriptor) {
|
if (!descriptor) {
|
||||||
std::cerr << "Plugin returned a null pointer "
|
std::cerr << "Plugin returned a null pointer "
|
||||||
"for plugin index "
|
"for plugin index "
|
||||||
@@ -172,6 +178,37 @@ void ClapBridge::run() {
|
|||||||
})
|
})
|
||||||
.get();
|
.get();
|
||||||
},
|
},
|
||||||
|
[&](clap::plugin_factory::Create& request)
|
||||||
|
-> clap::plugin_factory::Create::Response {
|
||||||
|
return main_context_
|
||||||
|
.run_in_context([&]() {
|
||||||
|
// This assertion should never be hit, but you can never
|
||||||
|
// be too sure!
|
||||||
|
assert(plugin_factory_);
|
||||||
|
|
||||||
|
// We need the instance ID before the instance exists.
|
||||||
|
// If creating the plugin fails then that's no problem
|
||||||
|
// since we're using sparse hash maps anyways.
|
||||||
|
const size_t instance_id = generate_instance_id();
|
||||||
|
auto host_proxy = std::make_unique<clap_host_proxy>(
|
||||||
|
*this, instance_id, std::move(request.host));
|
||||||
|
|
||||||
|
const clap_plugin_t* plugin =
|
||||||
|
plugin_factory_->create_plugin(
|
||||||
|
plugin_factory_, host_proxy->host_vtable(),
|
||||||
|
request.plugin_id.c_str());
|
||||||
|
if (plugin) {
|
||||||
|
register_plugin_instance(plugin,
|
||||||
|
std::move(host_proxy));
|
||||||
|
return clap::plugin_factory::CreateResponse{
|
||||||
|
.instance_id = instance_id};
|
||||||
|
} else {
|
||||||
|
return clap::plugin_factory::CreateResponse{
|
||||||
|
.instance_id = std::nullopt};
|
||||||
|
}
|
||||||
|
})
|
||||||
|
.get();
|
||||||
|
},
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -359,15 +396,19 @@ ClapBridge::get_instance(size_t instance_id) noexcept {
|
|||||||
// return buffer_config;
|
// return buffer_config;
|
||||||
// }
|
// }
|
||||||
|
|
||||||
size_t ClapBridge::register_plugin_instance(const clap_plugin* plugin) {
|
void ClapBridge::register_plugin_instance(
|
||||||
|
const clap_plugin* plugin,
|
||||||
|
std::unique_ptr<clap_host_proxy> host_proxy) {
|
||||||
std::unique_lock lock(object_instances_mutex_);
|
std::unique_lock lock(object_instances_mutex_);
|
||||||
|
|
||||||
if (!plugin) {
|
assert(plugin);
|
||||||
throw std::invalid_argument("The plugin pointer cannot be null");
|
assert(host_proxy);
|
||||||
}
|
|
||||||
|
|
||||||
const size_t instance_id = generate_instance_id();
|
// This instance ID has already been generated because the host proxy has to
|
||||||
object_instances_.emplace(instance_id, plugin);
|
// be created before the plugin instance
|
||||||
|
const size_t instance_id = host_proxy->owner_isntance_id();
|
||||||
|
object_instances_.emplace(
|
||||||
|
instance_id, ClapPluginInstance(plugin, std::move(host_proxy)));
|
||||||
|
|
||||||
// Every plugin instance gets its own audio thread
|
// Every plugin instance gets its own audio thread
|
||||||
std::promise<void> socket_listening_latch;
|
std::promise<void> socket_listening_latch;
|
||||||
@@ -413,8 +454,6 @@ size_t ClapBridge::register_plugin_instance(const clap_plugin* plugin) {
|
|||||||
// the native plugin may try to connect to it before our thread is up and
|
// the native plugin may try to connect to it before our thread is up and
|
||||||
// running.
|
// running.
|
||||||
socket_listening_latch.get_future().wait();
|
socket_listening_latch.get_future().wait();
|
||||||
|
|
||||||
return instance_id;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void ClapBridge::unregister_object_instance(size_t instance_id) {
|
void ClapBridge::unregister_object_instance(size_t instance_id) {
|
||||||
|
|||||||
@@ -22,6 +22,7 @@
|
|||||||
#include <string>
|
#include <string>
|
||||||
|
|
||||||
#include <clap/entry.h>
|
#include <clap/entry.h>
|
||||||
|
#include <clap/plugin-factory.h>
|
||||||
#include <clap/plugin.h>
|
#include <clap/plugin.h>
|
||||||
|
|
||||||
#include "../../common/audio-shm.h"
|
#include "../../common/audio-shm.h"
|
||||||
@@ -29,6 +30,7 @@
|
|||||||
#include "../../common/configuration.h"
|
#include "../../common/configuration.h"
|
||||||
#include "../../common/mutual-recursion.h"
|
#include "../../common/mutual-recursion.h"
|
||||||
#include "../editor.h"
|
#include "../editor.h"
|
||||||
|
#include "clap-impls/host-proxy.h"
|
||||||
#include "common.h"
|
#include "common.h"
|
||||||
|
|
||||||
/**
|
/**
|
||||||
@@ -62,16 +64,23 @@ struct ClapPluginInstance {
|
|||||||
* Bind a CLAP plugin pointer to this plugin instance object. This can only
|
* Bind a CLAP plugin pointer to this plugin instance object. This can only
|
||||||
* be done once per plugin pointer. The pointer must be non-null.
|
* be done once per plugin pointer. The pointer must be non-null.
|
||||||
*/
|
*/
|
||||||
ClapPluginInstance(const clap_plugin* plugin) noexcept;
|
ClapPluginInstance(const clap_plugin* plugin,
|
||||||
|
std::unique_ptr<clap_host_proxy> host_proxy) noexcept;
|
||||||
|
|
||||||
public:
|
public:
|
||||||
|
/**
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
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.
|
||||||
*/
|
*/
|
||||||
Win32Thread audio_thread_handler;
|
Win32Thread audio_thread_handler;
|
||||||
|
|
||||||
// TODO: Proxies for host extension objects
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* A shared memory object we'll write the input audio buffers to on the
|
* A shared memory object we'll write the input audio buffers to on the
|
||||||
* native plugin side. We'll then let the plugin write its outputs here on
|
* native plugin side. We'll then let the plugin write its outputs here on
|
||||||
@@ -331,11 +340,13 @@ class ClapBridge : public HostBridge {
|
|||||||
size_t instance_id);
|
size_t instance_id);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Assign a unique identifier to an object and add it to
|
* Add a plugin and its host to it to `object_instances_`. The plugin's
|
||||||
* `object_instances_`. This will also set up an audio thread socket
|
* identifier is taken from the host proxy since this host proxy is already
|
||||||
* listener for the plugin instance.
|
* needed when constructing the plugin. This will also set up an audio
|
||||||
|
* thread socket listener for the plugin instance.
|
||||||
*/
|
*/
|
||||||
size_t register_plugin_instance(const clap_plugin* plugin);
|
void register_plugin_instance(const clap_plugin* plugin,
|
||||||
|
std::unique_ptr<clap_host_proxy> host_proxy);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Remove an object from `object_instances_`. Will also tear down the
|
* Remove an object from `object_instances_`. Will also tear down the
|
||||||
@@ -363,6 +374,12 @@ class ClapBridge : public HostBridge {
|
|||||||
*/
|
*/
|
||||||
std::unique_ptr<clap_plugin_entry, void (*)(clap_plugin_entry*)> entry_;
|
std::unique_ptr<clap_plugin_entry, void (*)(clap_plugin_entry*)> entry_;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The plugin's factory, initialized when the host requests the plugin
|
||||||
|
* factory.
|
||||||
|
*/
|
||||||
|
const clap_plugin_factory_t* plugin_factory_ = nullptr;
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* All sockets used for communicating with this specific plugin.
|
* All sockets used for communicating with this specific plugin.
|
||||||
*
|
*
|
||||||
|
|||||||
Reference in New Issue
Block a user