mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-09 20:29:10 +02:00
Replace ComponentInstance with a generic variant
This allows casting to supported interface from an FUnknown.
This commit is contained in:
@@ -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&)
|
||||||
|
|||||||
@@ -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;
|
||||||
};
|
};
|
||||||
|
|||||||
Reference in New Issue
Block a user