Add a holder for component contexts and pointers

When implementing the other component interfaces we want to be able to
store the `FUnknownPtrs`.
This commit is contained in:
Robbert van der Helm
2020-12-13 21:31:59 +01:00
parent 6adeb1987d
commit 583645bb46
2 changed files with 61 additions and 45 deletions
+32 -28
View File
@@ -22,6 +22,12 @@
#include "vst3-impls/host-application.h" #include "vst3-impls/host-application.h"
ComponentInstance::ComponentInstance() {}
ComponentInstance::ComponentInstance(
Steinberg::IPtr<Steinberg::Vst::IComponent> component)
: component(component) {}
Vst3Bridge::Vst3Bridge(MainContext& main_context, Vst3Bridge::Vst3Bridge(MainContext& main_context,
std::string plugin_dll_path, std::string plugin_dll_path,
std::string endpoint_base_dir) std::string endpoint_base_dir)
@@ -44,6 +50,11 @@ Vst3Bridge::Vst3Bridge(MainContext& main_context,
} }
void Vst3Bridge::run() { void Vst3Bridge::run() {
// XXX: In theory all of thise should be safe assuming the host doesn't do
// anything weird. We're using mutexes when inserting and removing
// things, but for correctness we should have a multiple-readers
// single-writer style lock since concurrent reads and writes can also
// be unsafe.
sockets.host_vst_control.receive_messages( sockets.host_vst_control.receive_messages(
std::nullopt, std::nullopt,
overload{ overload{
@@ -61,7 +72,8 @@ void Vst3Bridge::run() {
component_instances[instance_id] = std::move(component); component_instances[instance_id] = std::move(component);
return YaComponent::ConstructArgs( return YaComponent::ConstructArgs(
component_instances[instance_id], instance_id); component_instances[instance_id].component,
instance_id);
} else { } else {
// The actual result is lost here // The actual result is lost here
return UniversalTResult(Steinberg::kNotImplemented); return UniversalTResult(Steinberg::kNotImplemented);
@@ -69,15 +81,8 @@ void Vst3Bridge::run() {
}, },
[&](const YaComponent::Destruct& request) [&](const YaComponent::Destruct& request)
-> YaComponent::Destruct::Response { -> YaComponent::Destruct::Response {
std::scoped_lock lock( std::lock_guard lock(component_instances_mutex);
component_instances_mutex,
component_host_application_context_instance_mutex);
component_instances.erase(request.instance_id); 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{}; return Ack{};
}, },
@@ -88,40 +93,39 @@ void Vst3Bridge::run() {
// be cleaned up again during `YaComponent::Destruct`. // be cleaned up again during `YaComponent::Destruct`.
Steinberg::FUnknown* context = nullptr; Steinberg::FUnknown* context = nullptr;
if (request.host_application_context_args) { if (request.host_application_context_args) {
// TODO: Is this safe? These Steinberg smart pointers are component_instances[request.instance_id]
// scary .hsot_application_context =
component_host_application_context_instances Steinberg::owned(new YaHostApplicationHostImpl(
[request.instance_id] = *this,
Steinberg::owned(new YaHostApplicationHostImpl( std::move(*request.host_application_context_args)));
*this, context = component_instances[request.instance_id]
std::move( .hsot_application_context;
*request.host_application_context_args)));
context = component_host_application_context_instances
[request.instance_id];
} }
return component_instances[request.instance_id]->initialize( return component_instances[request.instance_id]
context); .component->initialize(context);
}, },
[&](const YaComponent::Terminate& request) [&](const YaComponent::Terminate& request)
-> YaComponent::Terminate::Response { -> YaComponent::Terminate::Response {
return component_instances[request.instance_id]->terminate(); return component_instances[request.instance_id]
.component->terminate();
}, },
[&](const YaComponent::SetIoMode& request) [&](const YaComponent::SetIoMode& request)
-> YaComponent::SetIoMode::Response { -> YaComponent::SetIoMode::Response {
return component_instances[request.instance_id]->setIoMode( return component_instances[request.instance_id]
request.mode); .component->setIoMode(request.mode);
}, },
[&](const YaComponent::GetBusCount& request) [&](const YaComponent::GetBusCount& request)
-> YaComponent::GetBusCount::Response { -> YaComponent::GetBusCount::Response {
return component_instances[request.instance_id]->getBusCount( return component_instances[request.instance_id]
request.type, request.dir); .component->getBusCount(request.type, request.dir);
}, },
[&](YaComponent::GetBusInfo& request) [&](YaComponent::GetBusInfo& request)
-> YaComponent::GetBusInfo::Response { -> YaComponent::GetBusInfo::Response {
const tresult result = const tresult result =
component_instances[request.instance_id]->getBusInfo( component_instances[request.instance_id]
request.type, request.dir, request.index, request.bus); .component->getBusInfo(request.type, request.dir,
request.index, request.bus);
return YaComponent::GetBusInfoResponse{ return YaComponent::GetBusInfoResponse{
.result = result, .updated_bus = request.bus}; .result = result, .updated_bus = request.bus};
+29 -17
View File
@@ -24,6 +24,34 @@
#include "../../common/configuration.h" #include "../../common/configuration.h"
#include "common.h" #include "common.h"
/**
* A holder for an `IComponent` instance created from the factory along with any
* host context proxy objects belonging to it, and several predefined
* `FUnknownPtrs` so we don't have to do these dynamic casts all the times..
*/
struct ComponentInstance {
ComponentInstance();
ComponentInstance(Steinberg::IPtr<Steinberg::Vst::IComponent> component);
/**
* If the host passes an `IHostApplication` during
* `IPluginBase::initialize()`, we'll store a proxy object here and then
* pass it to `component->initialize()`.
*/
Steinberg::IPtr<YaHostApplication> hsot_application_context;
/**
* The `IComponent` instance we created.
*/
Steinberg::IPtr<Steinberg::Vst::IComponent> component;
// All smart pointers below are created from `component`. They will be null
// pointers if `component` did not implement the interface.
// TODO: Implement things like `IConnectionPoint` and `IAudioProcessor`
};
/** /**
* This hosts a Windows VST3 plugin, forwards messages sent by the Linux VST * This hosts a Windows VST3 plugin, forwards messages sent by the Linux VST
* plugin and provides host callback function for the plugin to talk back. * plugin and provides host callback function for the plugin to talk back.
@@ -112,22 +140,6 @@ class Vst3Bridge : public HostBridge {
// instances. The mutexes are used for operations that insert or remove // instances. The mutexes are used for operations that insert or remove
// items, and not for regular access. // items, and not for regular access.
std::map<size_t, Steinberg::IPtr<Steinberg::Vst::IComponent>> std::map<size_t, ComponentInstance> component_instances;
component_instances;
std::mutex component_instances_mutex; 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<size_t, Steinberg::IPtr<YaHostApplication>>
component_host_application_context_instances;
std::mutex component_host_application_context_instance_mutex;
}; };