diff --git a/README.md b/README.md index 4a3f0937..be611af7 100644 --- a/README.md +++ b/README.md @@ -18,7 +18,7 @@ imcomplete list of things that still have to be done before this can be used: - Left to implement: - `YaHostApplicationHostImpl::createComponent`. - `IPluginFactory3::setHostContext()` using the same host application context proxy method. - - The rest of `IComponent`'s functions after implementing `intialize()` + - The rest of `IComponent`'s functions - `IPluginFactory3::setHostContext()` - All other mandatory interfaces - All other optional interfaces diff --git a/src/common/communication/vst3.h b/src/common/communication/vst3.h index 24601100..3f73f95a 100644 --- a/src/common/communication/vst3.h +++ b/src/common/communication/vst3.h @@ -180,7 +180,7 @@ class Vst3MessageHandler : public AdHocSocketHandler { // always know for sure that the function returns the correct // type, and we can scrap a lot of boilerplate elsewhere. std::visit( - [&](const T object) { + [&](T object) { typename T::Response response = callback(object); if (logging) { diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index ffd0e29d..1696a6d8 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -20,6 +20,8 @@ #include +#include "vst3-impls/host-application.h" + Vst3Bridge::Vst3Bridge(MainContext& main_context, std::string plugin_dll_path, std::string endpoint_base_dir) @@ -67,18 +69,39 @@ void Vst3Bridge::run() { }, [&](const YaComponent::Destruct& request) -> YaComponent::Destruct::Response { - std::lock_guard lock(component_instances_mutex); + std::scoped_lock lock( + component_instances_mutex, + component_host_application_context_instance_mutex); component_instances.erase(request.instance_id); + if (component_host_application_context_instances.contains( + request.instance_id)) { + component_host_application_context_instances.erase( + request.instance_id); + } return Ack{}; }, - [&](const YaComponent::Initialize& request) + [&](YaComponent::Initialize& request) -> YaComponent::Initialize::Response { - // TODO: If `request.host_context_args` has a value, we should - // initialize a proxy object and pass a pointer to that - // instead + // If we got passed a host context, we'll create a proxy object + // and pass that to the initialize function. This object should + // be cleaned up again during `YaComponent::Destruct`. + Steinberg::FUnknown* context = nullptr; + if (request.host_application_context_args) { + // TODO: Is this safe? These Steinberg smart pointers are + // scary + component_host_application_context_instances + [request.instance_id] = + Steinberg::owned(new YaHostApplicationHostImpl( + *this, + std::move( + *request.host_application_context_args))); + context = component_host_application_context_instances + [request.instance_id]; + } + return component_instances[request.instance_id]->initialize( - nullptr); + context); }, [&](const YaComponent::Terminate& request) -> YaComponent::Terminate::Response { diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index 7c638e88..9bfd01e4 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -108,4 +108,19 @@ class Vst3Bridge : public HostBridge { std::map> component_instances; std::mutex component_instances_mutex; + + /** + * If an `IHostApplication` was passed during + * `{IPluginBase,IComponent}::initialize()`, then we'll store a proxy object + * here. The instance ID is the same as the corresponding instance ID in + * `component_instances`. When an instance gets removed from + * `component_instances`, it should also be removed from here. + * + * XXX: If it turns out we need to keep track of more of these kinds of + * objects, then we should create a wrapper so that everything can stay + * in `component_instances` + */ + std::map> + component_host_application_context_instances; + std::mutex component_host_application_context_instance_mutex; };