Replace ComponentInstance with a generic variant

This allows casting to supported interface from an FUnknown.
This commit is contained in:
Robbert van der Helm
2020-12-17 13:47:43 +01:00
parent d0e96da21a
commit a5834cd438
2 changed files with 66 additions and 59 deletions
+42 -39
View File
@@ -22,13 +22,13 @@
#include "vst3-impls/host-application.h" #include "vst3-impls/host-application.h"
ComponentInstance::ComponentInstance() {} PluginObject::PluginObject() {}
ComponentInstance::ComponentInstance( PluginObject::PluginObject(Steinberg::IPtr<Steinberg::FUnknown> object)
Steinberg::IPtr<Steinberg::Vst::IComponent> component) : object(object),
: component(component), audio_processor(object),
plugin_base(component), component(object),
audio_processor(component) {} plugin_base(object) {}
Vst3Bridge::Vst3Bridge(MainContext& main_context, Vst3Bridge::Vst3Bridge(MainContext& main_context,
std::string plugin_dll_path, std::string plugin_dll_path,
@@ -64,33 +64,36 @@ void Vst3Bridge::run() {
-> Vst3PluginProxy::Construct::Response { -> Vst3PluginProxy::Construct::Response {
Steinberg::TUID cid; Steinberg::TUID cid;
std::copy(args.cid.begin(), args.cid.end(), cid); std::copy(args.cid.begin(), args.cid.end(), cid);
Steinberg::IPtr<Steinberg::Vst::IComponent> component = // TODO: Change this to allow creating different tyeps of
// objects
Steinberg::IPtr<Steinberg::FUnknown> object =
module->getFactory() module->getFactory()
.createInstance<Steinberg::Vst::IComponent>(cid); .createInstance<Steinberg::Vst::IComponent>(cid);
if (component) { if (object) {
std::lock_guard lock(component_instances_mutex); std::lock_guard lock(object_instances_mutex);
const size_t instance_id = generate_instance_id(); const size_t instance_id = generate_instance_id();
component_instances[instance_id] = std::move(component); object_instances[instance_id] = std::move(object);
// This is where the magic happens. Here we deduce which
// interfaces are supported by this object so we can create
// a one-to-one proxy of it.
return Vst3PluginProxy::ConstructArgs( return Vst3PluginProxy::ConstructArgs(
component_instances[instance_id].component, object_instances[instance_id].object, instance_id);
instance_id);
} else { } else {
// The actual result is lost here return UniversalTResult(Steinberg::kResultFalse);
return UniversalTResult(Steinberg::kNotImplemented);
} }
}, },
[&](const Vst3PluginProxy::Destruct& request) [&](const Vst3PluginProxy::Destruct& request)
-> Vst3PluginProxy::Destruct::Response { -> Vst3PluginProxy::Destruct::Response {
std::lock_guard lock(component_instances_mutex); std::lock_guard lock(object_instances_mutex);
component_instances.erase(request.instance_id); object_instances.erase(request.instance_id);
return Ack{}; return Ack{};
}, },
[&](YaAudioProcessor::SetBusArrangements& request) [&](YaAudioProcessor::SetBusArrangements& request)
-> YaAudioProcessor::SetBusArrangements::Response { -> YaAudioProcessor::SetBusArrangements::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->setBusArrangements( .audio_processor->setBusArrangements(
request.inputs.data(), request.num_ins, request.inputs.data(), request.num_ins,
request.outputs.data(), request.num_outs); request.outputs.data(), request.num_outs);
@@ -98,7 +101,7 @@ void Vst3Bridge::run() {
[&](YaAudioProcessor::GetBusArrangement& request) [&](YaAudioProcessor::GetBusArrangement& request)
-> YaAudioProcessor::GetBusArrangement::Response { -> YaAudioProcessor::GetBusArrangement::Response {
const tresult result = const tresult result =
component_instances[request.instance_id] object_instances[request.instance_id]
.audio_processor->getBusArrangement( .audio_processor->getBusArrangement(
request.dir, request.index, request.arr); request.dir, request.index, request.arr);
@@ -107,29 +110,29 @@ void Vst3Bridge::run() {
}, },
[&](const YaAudioProcessor::CanProcessSampleSize& request) [&](const YaAudioProcessor::CanProcessSampleSize& request)
-> YaAudioProcessor::CanProcessSampleSize::Response { -> YaAudioProcessor::CanProcessSampleSize::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->canProcessSampleSize( .audio_processor->canProcessSampleSize(
request.symbolic_sample_size); request.symbolic_sample_size);
}, },
[&](const YaAudioProcessor::GetLatencySamples& request) [&](const YaAudioProcessor::GetLatencySamples& request)
-> YaAudioProcessor::GetLatencySamples::Response { -> YaAudioProcessor::GetLatencySamples::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->getLatencySamples(); .audio_processor->getLatencySamples();
}, },
[&](YaAudioProcessor::SetupProcessing& request) [&](YaAudioProcessor::SetupProcessing& request)
-> YaAudioProcessor::SetupProcessing::Response { -> YaAudioProcessor::SetupProcessing::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->setupProcessing(request.setup); .audio_processor->setupProcessing(request.setup);
}, },
[&](const YaAudioProcessor::SetProcessing& request) [&](const YaAudioProcessor::SetProcessing& request)
-> YaAudioProcessor::SetProcessing::Response { -> YaAudioProcessor::SetProcessing::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->setProcessing(request.state); .audio_processor->setProcessing(request.state);
}, },
[&](YaAudioProcessor::Process& request) [&](YaAudioProcessor::Process& request)
-> YaAudioProcessor::Process::Response { -> YaAudioProcessor::Process::Response {
const tresult result = const tresult result =
component_instances[request.instance_id] object_instances[request.instance_id]
.audio_processor->process(request.data.get()); .audio_processor->process(request.data.get());
return YaAudioProcessor::ProcessResponse{ return YaAudioProcessor::ProcessResponse{
@@ -138,25 +141,24 @@ void Vst3Bridge::run() {
}, },
[&](const YaAudioProcessor::GetTailSamples& request) [&](const YaAudioProcessor::GetTailSamples& request)
-> YaAudioProcessor::GetTailSamples::Response { -> YaAudioProcessor::GetTailSamples::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.audio_processor->getTailSamples(); .audio_processor->getTailSamples();
}, },
[&](const YaComponent::SetIoMode& request) [&](const YaComponent::SetIoMode& request)
-> YaComponent::SetIoMode::Response { -> YaComponent::SetIoMode::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.component->setIoMode(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] return object_instances[request.instance_id]
.component->getBusCount(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] object_instances[request.instance_id].component->getBusInfo(
.component->getBusInfo(request.type, request.dir, request.type, request.dir, request.index, request.bus);
request.index, request.bus);
return YaComponent::GetBusInfoResponse{ return YaComponent::GetBusInfoResponse{
.result = result, .updated_bus = request.bus}; .result = result, .updated_bus = request.bus};
@@ -164,7 +166,7 @@ void Vst3Bridge::run() {
[&](YaComponent::GetRoutingInfo& request) [&](YaComponent::GetRoutingInfo& request)
-> YaComponent::GetRoutingInfo::Response { -> YaComponent::GetRoutingInfo::Response {
const tresult result = const tresult result =
component_instances[request.instance_id] object_instances[request.instance_id]
.component->getRoutingInfo(request.in_info, .component->getRoutingInfo(request.in_info,
request.out_info); request.out_info);
@@ -175,25 +177,26 @@ void Vst3Bridge::run() {
}, },
[&](const YaComponent::ActivateBus& request) [&](const YaComponent::ActivateBus& request)
-> YaComponent::ActivateBus::Response { -> YaComponent::ActivateBus::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.component->activateBus(request.type, request.dir, .component->activateBus(request.type, request.dir,
request.index, request.state); request.index, request.state);
}, },
[&](const YaComponent::SetActive& request) [&](const YaComponent::SetActive& request)
-> YaComponent::SetActive::Response { -> YaComponent::SetActive::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.component->setActive(request.state); .component->setActive(request.state);
}, },
[&](YaComponent::SetState& request) [&](YaComponent::SetState& request)
-> YaComponent::SetState::Response { -> YaComponent::SetState::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.component->setState(&request.state); .component->setState(&request.state);
}, },
[&](YaComponent::GetState& request) [&](YaComponent::GetState& request)
-> YaComponent::GetState::Response { -> YaComponent::GetState::Response {
VectorStream stream; VectorStream stream;
const tresult result = component_instances[request.instance_id] const tresult result =
.component->getState(&stream); object_instances[request.instance_id].component->getState(
&stream);
return YaComponent::GetStateResponse{ return YaComponent::GetStateResponse{
.result = result, .updated_state = std::move(stream)}; .result = result, .updated_state = std::move(stream)};
@@ -206,21 +209,21 @@ void Vst3Bridge::run() {
// TODO: This needs changing when we get to `Vst3HostProxy` // TODO: This needs changing when we get to `Vst3HostProxy`
Steinberg::FUnknown* context = nullptr; Steinberg::FUnknown* context = nullptr;
if (request.host_application_context_args) { if (request.host_application_context_args) {
component_instances[request.instance_id] object_instances[request.instance_id]
.hsot_application_context = .hsot_application_context =
Steinberg::owned(new YaHostApplicationHostImpl( Steinberg::owned(new YaHostApplicationHostImpl(
*this, *this,
std::move(*request.host_application_context_args))); std::move(*request.host_application_context_args)));
context = component_instances[request.instance_id] context = object_instances[request.instance_id]
.hsot_application_context; .hsot_application_context;
} }
return component_instances[request.instance_id] return object_instances[request.instance_id]
.plugin_base->initialize(context); .plugin_base->initialize(context);
}, },
[&](const YaPluginBase::Terminate& request) [&](const YaPluginBase::Terminate& request)
-> YaPluginBase::Terminate::Response { -> YaPluginBase::Terminate::Response {
return component_instances[request.instance_id] return object_instances[request.instance_id]
.plugin_base->terminate(); .plugin_base->terminate();
}, },
[&](const YaPluginFactory::Construct&) [&](const YaPluginFactory::Construct&)
+24 -20
View File
@@ -25,17 +25,17 @@
#include "common.h" #include "common.h"
/** /**
* A holder for an `IComponent` instance created from the factory along with any * A holder for plugin object instance created from the factory. This stores all
* host context proxy objects belonging to it, and several predefined * relevant interface smart pointers to that object so we can handle control
* `FUnknownPtrs` so we don't have to do these dynamic casts all the times.. * messages sent by the plugin without having to do these expensive casts all
* * the time. This also stores any additional context data, such as the
* TODO: When implementing `IEditController`, change this to use `IPluginBase` * `IHostApplication` instance passed to the plugin during
* as the base interface. * `IPluginBase::initialize()`.
*/ */
struct ComponentInstance { struct PluginObject {
ComponentInstance(); PluginObject();
ComponentInstance(Steinberg::IPtr<Steinberg::Vst::IComponent> component); PluginObject(Steinberg::IPtr<Steinberg::FUnknown> object);
/** /**
* If the host passes an `IHostApplication` during * If the host passes an `IHostApplication` during
@@ -45,15 +45,16 @@ struct ComponentInstance {
Steinberg::IPtr<YaHostApplication> hsot_application_context; Steinberg::IPtr<YaHostApplication> hsot_application_context;
/** /**
* The `IComponent` instance we created. * The base object we cast from.
*/ */
Steinberg::IPtr<Steinberg::Vst::IComponent> component; Steinberg::IPtr<Steinberg::FUnknown> object;
// All smart pointers below are created from `component`. They will be null // All smart pointers below are created from `component`. They will be null
// pointers if `component` did not implement the interface. // pointers if `component` did not implement the interface.
Steinberg::FUnknownPtr<Steinberg::IPluginBase> plugin_base;
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor> audio_processor; Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor> audio_processor;
Steinberg::FUnknownPtr<Steinberg::Vst::IComponent> component;
Steinberg::FUnknownPtr<Steinberg::IPluginBase> plugin_base;
}; };
/** /**
@@ -138,12 +139,15 @@ class Vst3Bridge : public HostBridge {
*/ */
Steinberg::IPtr<YaHostApplication> plugin_factory_host_application_context; Steinberg::IPtr<YaHostApplication> plugin_factory_host_application_context;
// Below are managed instances we created for /**
// `IPluginFactory::createInstance()`. The keys in all of these maps are the * These are all the objects we have created through the Windows VST3
// unique identifiers we generated for them so we can identify specific * plugins' plugin factory. The keys in all of these maps are the unique
// instances. The mutexes are used for operations that insert or remove * identifiers we generated for them so we can identify specific instances.
// items, and not for regular access. * During the proxy object's destructor (on the plugin side), we'll get a
* request to remove the corresponding plugin object from this map. This
std::map<size_t, ComponentInstance> component_instances; * will cause all pointers to it to get dropped and the object to be cleaned
std::mutex component_instances_mutex; * up.
*/
std::map<size_t, PluginObject> object_instances;
std::mutex object_instances_mutex;
}; };