diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 55f9c115..a84fbd4f 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -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()"; + // We don't know what class this instance was originally instantiated + // as, but it also doesn't really matter + message << "::~FUnknown()"; }); } diff --git a/src/common/serialization/vst3/plugin-proxy.h b/src/common/serialization/vst3/plugin-proxy.h index feae9d1c..4bd14240 100644 --- a/src/common/serialization/vst3/plugin-proxy.h +++ b/src/common/serialization/vst3/plugin-proxy.h @@ -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, ...)`. + * ::iid, ...)`. */ struct Construct { using Response = std::variant; 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 void serialize(S& s) { s.container1b(cid); + s.value4b(requested_interface); } }; diff --git a/src/plugin/bridges/vst3-impls/plugin-factory.cpp b/src/plugin/bridges/vst3-impls/plugin-factory.cpp index 06a8319f..359fb740 100644 --- a/src/plugin/bridges/vst3-impls/plugin-factory.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-factory.cpp @@ -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`. 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 result = - bridge.send_message(Vst3PluginProxy::Construct{.cid = cid_array}); - return std::visit( - overload{ - [&](Vst3PluginProxy::ConstructArgs&& args) -> tresult { - *obj = static_cast( - 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 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`. + 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( + proxy_object); + break; + case Vst3PluginProxy::Construct::Interface::IEditController: + *obj = static_cast( + proxy_object); + break; + } + + return Steinberg::kResultOk; + }, + [&](const UniversalTResult& code) -> tresult { return code; }}, + std::move(result)); } tresult PLUGIN_API diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index 147d8b05..9a2062ee 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -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 object = - module->getFactory() - .createInstance(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 object; + switch (request.requested_interface) { + case Vst3PluginProxy::Construct::Interface::IComponent: + object = + module->getFactory() + .createInstance( + 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);