Allow creating IEditController instances

Now `IPluginFactory::createInstance()` can create multiple (and in our
case, all relevant) different types of objects.
This commit is contained in:
Robbert van der Helm
2020-12-17 17:01:26 +01:00
parent 2155240cca
commit 286023bc22
4 changed files with 88 additions and 38 deletions
+15 -10
View File
@@ -34,24 +34,29 @@ void Vst3Logger::log_unknown_interface(
}
void Vst3Logger::log_request(bool is_host_vst,
const Vst3PluginProxy::Construct& args) {
const Vst3PluginProxy::Construct& request) {
log_request_base(is_host_vst, [&](auto& message) {
// TODO: When adding the enum class for instantiating different types,
// make sure to reflect those in the constructor and destructor
// logging
message << "IPluginFactory::createComponent(cid = "
<< format_uid(Steinberg::FUID::fromTUID(args.cid.data()))
<< ", _iid = "
"IComponent::iid, "
"&obj)";
<< format_uid(Steinberg::FUID::fromTUID(request.cid.data()))
<< ", _iid = ";
switch (request.requested_interface) {
case Vst3PluginProxy::Construct::Interface::IComponent:
message << "IComponent::iid";
break;
case Vst3PluginProxy::Construct::Interface::IEditController:
message << "IEditController::iid";
break;
}
message << ", &obj)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const Vst3PluginProxy::Destruct& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IComponent* #" << request.instance_id
<< ">::~IComponent()";
// We don't know what class this instance was originally instantiated
// as, but it also doesn't really matter
message << "<FUnknown* #" << request.instance_id << ">::~FUnknown()";
});
}
+13 -4
View File
@@ -93,20 +93,29 @@ class Vst3PluginProxy : public YaAudioProcessor,
/**
* Message to request the Wine plugin host to instantiate a new IComponent
* to pass through a call to `IComponent::createInstance(cid,
* IComponent::iid, ...)`.
* <requested_interface>::iid, ...)`.
*/
struct Construct {
using Response = std::variant<ConstructArgs, UniversalTResult>;
ArrayUID cid;
// TODO: Add an enum class to reify the type of object we want to
// instantiate so we can initialize things other than
// `IComponent`, like `IEditController.`
/**
* The interface the host was trying to instantiate an object for.
* Technically the host can create any kind of object, but these are the
* objects that are actually used.
*/
enum class Interface {
IComponent,
IEditController,
};
Interface requested_interface;
template <typename S>
void serialize(S& s) {
s.container1b(cid);
s.value4b(requested_interface);
}
};
@@ -28,26 +28,16 @@ tresult PLUGIN_API
YaPluginFactoryImpl::createInstance(Steinberg::FIDString cid,
Steinberg::FIDString _iid,
void** obj) {
// TODO: Do the same thing for other types
// These arw pointers are scary. The idea here is that we return a newly
// initialized object (that initializes itself with a reference count of 1),
// and then the receiving side will use `Steinberg::owned()` to adopt it to
// an `IPtr<T>`.
ArrayUID cid_array;
std::copy(cid, cid + sizeof(Steinberg::TUID), cid_array.begin());
Vst3PluginProxy::Construct::Interface requested_interface;
if (Steinberg::FIDStringsEqual(_iid, Steinberg::Vst::IComponent::iid)) {
std::variant<Vst3PluginProxy::ConstructArgs, UniversalTResult> result =
bridge.send_message(Vst3PluginProxy::Construct{.cid = cid_array});
return std::visit(
overload{
[&](Vst3PluginProxy::ConstructArgs&& args) -> tresult {
*obj = static_cast<Steinberg::Vst::IComponent*>(
new Vst3PluginProxyImpl(bridge, std::move(args)));
return Steinberg::kResultOk;
},
[&](const UniversalTResult& code) -> tresult { return code; }},
std::move(result));
requested_interface = Vst3PluginProxy::Construct::Interface::IComponent;
} else if (Steinberg::FIDStringsEqual(
_iid, Steinberg::Vst::IEditController::iid)) {
requested_interface =
Vst3PluginProxy::Construct::Interface::IEditController;
} else {
// When the host requests an interface we do not (yet) implement, we'll
// print a recognizable log message. I don't think they include a safe
@@ -65,6 +55,38 @@ YaPluginFactoryImpl::createInstance(Steinberg::FIDString cid,
return Steinberg::kNotImplemented;
}
std::variant<Vst3PluginProxy::ConstructArgs, UniversalTResult> result =
bridge.send_message(Vst3PluginProxy::Construct{
.cid = cid_array, .requested_interface = requested_interface});
return std::visit(
overload{
[&](Vst3PluginProxy::ConstructArgs&& args) -> tresult {
// These pointers are scary. The idea here is that we return a
// newly initialized object (that initializes itself with a
// reference count of 1), and then the receiving side will use
// `Steinberg::owned()` to adopt it to an `IPtr<T>`.
Vst3PluginProxyImpl* proxy_object =
new Vst3PluginProxyImpl(bridge, std::move(args));
// We return a properly downcasted version of the proxy object
// we just created
switch (requested_interface) {
case Vst3PluginProxy::Construct::Interface::IComponent:
*obj = static_cast<Steinberg::Vst::IComponent*>(
proxy_object);
break;
case Vst3PluginProxy::Construct::Interface::IEditController:
*obj = static_cast<Steinberg::Vst::IEditController*>(
proxy_object);
break;
}
return Steinberg::kResultOk;
},
[&](const UniversalTResult& code) -> tresult { return code; }},
std::move(result));
}
tresult PLUGIN_API
+21 -7
View File
@@ -60,15 +60,29 @@ void Vst3Bridge::run() {
sockets.host_vst_control.receive_messages(
std::nullopt,
overload{
[&](const Vst3PluginProxy::Construct& args)
[&](const Vst3PluginProxy::Construct& request)
-> Vst3PluginProxy::Construct::Response {
Steinberg::TUID cid;
std::copy(args.cid.begin(), args.cid.end(), cid);
// TODO: Change this to allow creating different tyeps of
// objects
Steinberg::IPtr<Steinberg::FUnknown> object =
module->getFactory()
.createInstance<Steinberg::Vst::IComponent>(cid);
std::copy(request.cid.begin(), request.cid.end(), cid);
// Even though we're requesting a specific interface (to mimic
// what the host is doing), we're immediately upcasting it to an
// `FUnknown` so we can create a perfect proxy object.
Steinberg::IPtr<Steinberg::FUnknown> object;
switch (request.requested_interface) {
case Vst3PluginProxy::Construct::Interface::IComponent:
object =
module->getFactory()
.createInstance<Steinberg::Vst::IComponent>(
cid);
break;
case Vst3PluginProxy::Construct::Interface::IEditController:
object = module->getFactory()
.createInstance<
Steinberg::Vst::IEditController>(cid);
break;
}
if (object) {
std::lock_guard lock(object_instances_mutex);