From 0522f84f4a2d8e6d34e36f0e18dff4e1de00026a Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sat, 19 Dec 2020 17:13:17 +0100 Subject: [PATCH] Create Vst3HostContextProxy from YaHostApplication This is quite a huge refactor, but note everything is consistent (and we're going to need one or two more of these `Vst3*Proxy` objects). Right now nothing extends `IHostApplication`, but this way it will be trivial to add support for more host context interfaces. --- meson.build | 8 +- src/common/logging/vst3.cpp | 14 ++- src/common/serialization/vst3.h | 1 + src/common/serialization/vst3/README.md | 3 +- .../serialization/vst3/host-context-proxy.cpp | 50 +++++++++++ ...ost-application.h => host-context-proxy.h} | 68 +++++++-------- .../{ => host-context}/host-application.cpp | 39 +++------ .../vst3/host-context/host-application.h | 86 +++++++++++++++++++ .../serialization/vst3/plugin-factory.cpp | 4 +- .../serialization/vst3/plugin-factory.h | 18 ++-- .../vst3/plugin/audio-processor.h | 1 - .../serialization/vst3/plugin/component.cpp | 8 +- .../serialization/vst3/plugin/plugin-base.h | 18 ++-- .../bridges/vst3-impls/plugin-factory.cpp | 31 +++---- .../bridges/vst3-impls/plugin-factory.h | 5 +- .../bridges/vst3-impls/plugin-proxy.cpp | 40 ++++----- src/plugin/bridges/vst3-impls/plugin-proxy.h | 18 ++-- ...application.cpp => host-context-proxy.cpp} | 22 ++--- ...ost-application.h => host-context-proxy.h} | 7 +- src/wine-host/bridges/vst3.cpp | 33 +++---- src/wine-host/bridges/vst3.h | 11 ++- 21 files changed, 301 insertions(+), 184 deletions(-) create mode 100644 src/common/serialization/vst3/host-context-proxy.cpp rename src/common/serialization/vst3/{host-application.h => host-context-proxy.h} (54%) rename src/common/serialization/vst3/{ => host-context}/host-application.cpp (57%) create mode 100644 src/common/serialization/vst3/host-context/host-application.h rename src/wine-host/bridges/vst3-impls/{host-application.cpp => host-context-proxy.cpp} (68%) rename src/wine-host/bridges/vst3-impls/{host-application.h => host-context-proxy.h} (85%) diff --git a/meson.build b/meson.build index 5d762f45..f88c0f0f 100644 --- a/meson.build +++ b/meson.build @@ -84,10 +84,11 @@ vst3_plugin_sources = [ 'src/common/serialization/vst3/plugin/edit-controller-2.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', 'src/common/serialization/vst3/component-handler/component-handler.cpp', + 'src/common/serialization/vst3/host-context/host-application.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component-handler-proxy.cpp', 'src/common/serialization/vst3/event-list.cpp', - 'src/common/serialization/vst3/host-application.cpp', + 'src/common/serialization/vst3/host-context-proxy.cpp', 'src/common/serialization/vst3/param-value-queue.cpp', 'src/common/serialization/vst3/parameter-changes.cpp', 'src/common/serialization/vst3/plugin-proxy.cpp', @@ -131,17 +132,18 @@ if with_vst3 'src/common/serialization/vst3/plugin/edit-controller-2.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', 'src/common/serialization/vst3/component-handler/component-handler.cpp', + 'src/common/serialization/vst3/host-context/host-application.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component-handler-proxy.cpp', 'src/common/serialization/vst3/event-list.cpp', - 'src/common/serialization/vst3/host-application.cpp', + 'src/common/serialization/vst3/host-context-proxy.cpp', 'src/common/serialization/vst3/param-value-queue.cpp', 'src/common/serialization/vst3/parameter-changes.cpp', 'src/common/serialization/vst3/plugin-proxy.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/common/serialization/vst3/process-data.cpp', 'src/wine-host/bridges/vst3-impls/component-handler-proxy.cpp', - 'src/wine-host/bridges/vst3-impls/host-application.cpp', + 'src/wine-host/bridges/vst3-impls/host-context-proxy.cpp', 'src/wine-host/bridges/vst3.cpp', ] endif diff --git a/src/common/logging/vst3.cpp b/src/common/logging/vst3.cpp index 8cd75273..9de2ee99 100644 --- a/src/common/logging/vst3.cpp +++ b/src/common/logging/vst3.cpp @@ -411,8 +411,8 @@ bool Vst3Logger::log_request(bool is_host_vst, return log_request_base(is_host_vst, [&](auto& message) { message << request.instance_id << ": IPluginBase::initialize(context = "; - if (request.host_application_context_args) { - message << ""; + if (request.host_context_args) { + message << ""; } else { message << ""; } @@ -434,9 +434,15 @@ bool Vst3Logger::log_request(bool is_host_vst, } bool Vst3Logger::log_request(bool is_host_vst, - const YaPluginFactory::SetHostContext&) { + const YaPluginFactory::SetHostContext& request) { return log_request_base(is_host_vst, [&](auto& message) { - message << "IPluginFactory3::setHostContext(IHostApplication*)"; + message << "IPluginFactory3::setHostContext("; + if (request.host_context_args) { + message << ""; + } else { + message << ""; + } + message << ")"; }); } diff --git a/src/common/serialization/vst3.h b/src/common/serialization/vst3.h index 295902b3..f8e33ae6 100644 --- a/src/common/serialization/vst3.h +++ b/src/common/serialization/vst3.h @@ -24,6 +24,7 @@ #include "../utils.h" #include "common.h" #include "vst3/component-handler-proxy.h" +#include "vst3/host-context-proxy.h" #include "vst3/plugin-factory.h" #include "vst3/plugin-proxy.h" diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index 7bbe6f94..ed41bb22 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -22,7 +22,8 @@ VST3 host interfaces are implemented as follows: | yabridge class | Included in | Interfaces | | --------------------------- | --------------------------- | ------------------- | -| `YaHostApplication` | | `IHostApplication` | +| `Vst3HostContextProxy` | | All of the below: | +| `YaHostApplication` | `Vst3HostContextProxy` | `IHostApplication` | | `Vst3ComponentHandlerProxy` | | All of the below: | | `YaComponentHandler` | `Vst3ComponentHandlerProxy` | `IComponentHandler` | diff --git a/src/common/serialization/vst3/host-context-proxy.cpp b/src/common/serialization/vst3/host-context-proxy.cpp new file mode 100644 index 00000000..1e32b6ab --- /dev/null +++ b/src/common/serialization/vst3/host-context-proxy.cpp @@ -0,0 +1,50 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#include "host-context-proxy.h" + +Vst3HostContextProxy::ConstructArgs::ConstructArgs() {} + +Vst3HostContextProxy::ConstructArgs::ConstructArgs( + Steinberg::IPtr object, + std::optional owner_instance_id) + : owner_instance_id(owner_instance_id), host_application_args(object) {} + +Vst3HostContextProxy::Vst3HostContextProxy(const ConstructArgs&& args) + : YaHostApplication(std::move(args.host_application_args)), + arguments(std::move(args)){FUNKNOWN_CTOR} + + Vst3HostContextProxy::~Vst3HostContextProxy() { + FUNKNOWN_DTOR +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +IMPLEMENT_REFCOUNT(Vst3HostContextProxy) +#pragma GCC diagnostic pop + +tresult PLUGIN_API +Vst3HostContextProxy::queryInterface(Steinberg::FIDString _iid, void** obj) { + if (YaHostApplication::supported()) { + QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid, + Steinberg::Vst::IHostApplication) + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IHostApplication::iid, + Steinberg::Vst::IHostApplication) + } + + *obj = nullptr; + return Steinberg::kNoInterface; +} diff --git a/src/common/serialization/vst3/host-application.h b/src/common/serialization/vst3/host-context-proxy.h similarity index 54% rename from src/common/serialization/vst3/host-application.h rename to src/common/serialization/vst3/host-context-proxy.h index d8aa46bd..9f590d4f 100644 --- a/src/common/serialization/vst3/host-application.h +++ b/src/common/serialization/vst3/host-context-proxy.h @@ -16,42 +16,36 @@ #pragma once -#include - -#include -#include -#include - #include "../common.h" -#include "base.h" +#include "host-context/host-application.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" /** - * Wraps around `IHostApplication` for serialization purposes. An instance of - * this proxy object will be initialized on the Wine plugin host side after the - * host passes an actual instance to the plugin, and all function calls made to - * this proxy will be passed through to the actual object. This is used to proxy - * both the host application context passed during `IPluginBase::intialize()` as - * well as for the 'global' context in `IPluginFactory3::setHostContext()`. - * - * TODO: Create a `Vst3HostContextProxy`, and make this to only interface it - * inherits. For uniformity's sake it's a good idea to have every kind of - * object we directly instantiate be in the same form. + * An abstract class that optionally implements all interfaces a `context` + * object passed to `IPluginBase::intialize()` or + * `IPluginFactory3::setHostContext()` might implement. This works exactly the + * same as `Vst3PluginProxy`, but instead of proxying for an object provided by + * the plugin we are proxying for the `FUnknown*` argument passed to plugin by + * the host. When we are proxying for a host context object passed to + * `IPluginBase::initialize()` we'll keep track of the object instance ID the + * actual context object belongs to. */ -class YaHostApplication : public Steinberg::Vst::IHostApplication { +class Vst3HostContextProxy : public YaHostApplication { public: /** - * These are the arguments for constructing a `YaHostApplicationImpl`. + * These are the arguments for constructing a + * `Vst3HostContextProxyImpl`. */ struct ConstructArgs { ConstructArgs(); /** - * Read arguments from an existing implementation. + * Read from an existing object. We will try to mimic this object, so + * we'll support any interfaces this object also supports. */ - ConstructArgs(Steinberg::IPtr context, + ConstructArgs(Steinberg::IPtr object, std::optional owner_instance_id); /** @@ -61,10 +55,7 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication { */ std::optional owner_instance_id; - /** - * For `IHostApplication::getName`. - */ - std::optional name; + YaHostApplication::ConstructArgs host_application_args; template void serialize(S& s) { @@ -72,10 +63,7 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication { [](S& s, native_size_t& instance_id) { s.value8b(instance_id); }); - s.ext(name, bitsery::ext::StdOptional{}, - [](S& s, std::u16string& name) { - s.text2b(name, std::extent_v); - }); + s.object(host_application_args); } }; @@ -89,25 +77,27 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication { * objects they are passed to. If those objects get dropped, then the host * contexts should also be dropped. */ - YaHostApplication(const ConstructArgs&& args); + Vst3HostContextProxy(const ConstructArgs&& args); /** * The lifetime of this object should be bound to the object we created it * for. When for instance the `Vst3PluginProxy` instance with id `n` gets - * dropped, the corresponding `YaHostApplicationImpl` then that should also - * be dropped. + * dropped a corresponding `Vst3HostContextProxyImpl` should also be + * dropped. */ - virtual ~YaHostApplication(); + virtual ~Vst3HostContextProxy() = 0; DECLARE_FUNKNOWN_METHODS - // From `IHostApplication` - tresult PLUGIN_API getName(Steinberg::Vst::String128 name) override; - virtual tresult PLUGIN_API createInstance(Steinberg::TUID cid, - Steinberg::TUID _iid, - void** obj) override = 0; + /** + * Get the instance ID of the owner of this object, if this is not the + * global host context passed to the module's plugin factory. + */ + inline std::optional owner_instance_id() const { + return arguments.owner_instance_id; + } - protected: + private: ConstructArgs arguments; }; diff --git a/src/common/serialization/vst3/host-application.cpp b/src/common/serialization/vst3/host-context/host-application.cpp similarity index 57% rename from src/common/serialization/vst3/host-application.cpp rename to src/common/serialization/vst3/host-context/host-application.cpp index 1b8b4b88..c4a7a3fd 100644 --- a/src/common/serialization/vst3/host-application.cpp +++ b/src/common/serialization/vst3/host-context/host-application.cpp @@ -19,37 +19,22 @@ YaHostApplication::ConstructArgs::ConstructArgs() {} YaHostApplication::ConstructArgs::ConstructArgs( - Steinberg::IPtr context, - std::optional owner_instance_id) - : owner_instance_id(owner_instance_id) { - Steinberg::Vst::String128 name_array; - if (context->getName(name_array) == Steinberg::kResultOk) { - name = tchar_pointer_to_u16string(name_array); + Steinberg::IPtr object) + : supported(false) { + if (auto host_application = + Steinberg::FUnknownPtr(object)) { + supported = true; + + // `IHostApplication::getName` + Steinberg::Vst::String128 name_array; + if (host_application->getName(name_array) == Steinberg::kResultOk) { + name = tchar_pointer_to_u16string(name_array); + } } } YaHostApplication::YaHostApplication(const ConstructArgs&& args) - : arguments(std::move(args)){FUNKNOWN_CTOR} - - YaHostApplication::~YaHostApplication() { - FUNKNOWN_DTOR -} - -#pragma GCC diagnostic push -#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" -IMPLEMENT_REFCOUNT(YaHostApplication) -#pragma GCC diagnostic pop - -tresult PLUGIN_API YaHostApplication::queryInterface(Steinberg::FIDString _iid, - void** obj) { - QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid, - Steinberg::Vst::IHostApplication); - QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IHostApplication::iid, - Steinberg::Vst::IHostApplication) - - *obj = nullptr; - return Steinberg::kNoInterface; -} + : arguments(std::move(args)) {} tresult PLUGIN_API YaHostApplication::getName(Steinberg::Vst::String128 name) { if (arguments.name) { diff --git a/src/common/serialization/vst3/host-context/host-application.h b/src/common/serialization/vst3/host-context/host-application.h new file mode 100644 index 00000000..7dc449a5 --- /dev/null +++ b/src/common/serialization/vst3/host-context/host-application.h @@ -0,0 +1,86 @@ +// yabridge: a Wine VST bridge +// Copyright (C) 2020 Robbert van der Helm +// +// This program is free software: you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation, either version 3 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License +// along with this program. If not, see . + +#pragma once + +#include + +#include +#include +#include + +#include "../../common.h" +#include "../base.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +/** + * Wraps around `IHostApplication` for serialization purposes. This is + * instantiated as part of `Vst3HostContextProxy`. + */ +class YaHostApplication : public Steinberg::Vst::IHostApplication { + public: + /** + * These are the arguments for creating a `YaHostApplication`. + */ + struct ConstructArgs { + ConstructArgs(); + + /** + * Check whether an existing implementation implements + * `IHostApplication` and read arguments from it. + */ + ConstructArgs(Steinberg::IPtr object); + + /** + * Whether the object supported this interface. + */ + bool supported; + + /** + * For `IHostApplication::getName`. + */ + std::optional name; + + template + void serialize(S& s) { + s.value1b(supported); + s.ext(name, bitsery::ext::StdOptional{}, + [](S& s, std::u16string& name) { + s.text2b(name, std::extent_v); + }); + } + }; + + /** + * Instantiate this instance with arguments read from another interface + * implementation. + */ + YaHostApplication(const ConstructArgs&& args); + + inline bool supported() const { return arguments.supported; } + + tresult PLUGIN_API getName(Steinberg::Vst::String128 name) override; + virtual tresult PLUGIN_API createInstance(Steinberg::TUID cid, + Steinberg::TUID _iid, + void** obj) override = 0; + + protected: + ConstructArgs arguments; +}; + +#pragma GCC diagnostic pop diff --git a/src/common/serialization/vst3/plugin-factory.cpp b/src/common/serialization/vst3/plugin-factory.cpp index 7a2a33a0..96d91a4e 100644 --- a/src/common/serialization/vst3/plugin-factory.cpp +++ b/src/common/serialization/vst3/plugin-factory.cpp @@ -41,7 +41,7 @@ YaPluginFactory::ConstructArgs::ConstructArgs( } } - auto factory2 = Steinberg::FUnknownPtr(factory); + Steinberg::FUnknownPtr factory2(factory); if (!factory2) { return; } @@ -56,7 +56,7 @@ YaPluginFactory::ConstructArgs::ConstructArgs( } } - auto factory3 = Steinberg::FUnknownPtr(factory); + Steinberg::FUnknownPtr factory3(factory); if (!factory3) { return; } diff --git a/src/common/serialization/vst3/plugin-factory.h b/src/common/serialization/vst3/plugin-factory.h index bf2a554e..ac78342e 100644 --- a/src/common/serialization/vst3/plugin-factory.h +++ b/src/common/serialization/vst3/plugin-factory.h @@ -22,7 +22,7 @@ #include "../../bitsery/ext/vst3.h" #include "base.h" -#include "host-application.h" +#include "host-context-proxy.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" @@ -155,20 +155,22 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { /** * Message to pass through a call to `IPluginFactory3::setHostContext()` to - * the Wine plugin host. A proxy `YaHostApplication` should be created on - * the Wine plugin host and then passed as an argument to - * `IPluginFactory3::setHostContext()`. If the host called - * `IPluginFactory3::setHostContext()` with something other than an - * `IHostApplication*`, we return an error immediately and log the call. + * the Wine plugin host. A `Vst3HostContextProxy` should be created on the + * Wine plugin host and then passed as an argument to + * `IPluginFactory3::setHostContext()`. */ struct SetHostContext { using Response = UniversalTResult; - YaHostApplication::ConstructArgs host_application_context_args; + /** + * Arguments for creating a proxy host context object. If we got passed + * an null pointer we'll reflect that. + */ + std::optional host_context_args; template void serialize(S& s) { - s.object(host_application_context_args); + s.ext(host_context_args, bitsery::ext::StdOptional{}); } }; diff --git a/src/common/serialization/vst3/plugin/audio-processor.h b/src/common/serialization/vst3/plugin/audio-processor.h index 7f15cbbf..3e3c28a7 100644 --- a/src/common/serialization/vst3/plugin/audio-processor.h +++ b/src/common/serialization/vst3/plugin/audio-processor.h @@ -21,7 +21,6 @@ #include "../../common.h" #include "../base.h" -#include "../host-application.h" #include "../process-data.h" #pragma GCC diagnostic push diff --git a/src/common/serialization/vst3/plugin/component.cpp b/src/common/serialization/vst3/plugin/component.cpp index 5d121d66..88debb6e 100644 --- a/src/common/serialization/vst3/plugin/component.cpp +++ b/src/common/serialization/vst3/plugin/component.cpp @@ -19,10 +19,10 @@ YaComponent::ConstructArgs::ConstructArgs() {} YaComponent::ConstructArgs::ConstructArgs( - Steinberg::IPtr object) { - auto component = Steinberg::FUnknownPtr(object); - - if (component) { + Steinberg::IPtr object) + : supported(false) { + if (auto component = + Steinberg::FUnknownPtr(object)) { supported = true; // `IComponent::getControllerClassId` diff --git a/src/common/serialization/vst3/plugin/plugin-base.h b/src/common/serialization/vst3/plugin/plugin-base.h index 4e44161b..ad89d37f 100644 --- a/src/common/serialization/vst3/plugin/plugin-base.h +++ b/src/common/serialization/vst3/plugin/plugin-base.h @@ -21,7 +21,7 @@ #include "../../common.h" #include "../base.h" -#include "../host-application.h" +#include "../host-context-proxy.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" @@ -66,23 +66,23 @@ class YaPluginBase : public Steinberg::IPluginBase { /** * Message to pass through a call to `IPluginBase::initialize()` to the Wine - * plugin host. if we pass an `IHostApplication` instance, then a proxy - * `YaHostApplication` should be created and passed as an argument to - * `IPluginBase::initialize()`. If this is absent a null pointer should be - * passed. The lifetime of this `YaHostApplication` object should be bound - * to the `IComponent` we are proxying. + * plugin host. We will read what interfaces the passed context object + * implements so we can then create a proxy object on the Wine side that the + * plugin can use to make callbacks with. The lifetime of this + * `Vst3HostContextProxy` object should be bound to the `IComponent` we are + * proxying. */ struct Initialize { using Response = UniversalTResult; native_size_t instance_id; - std::optional - host_application_context_args; + + std::optional host_context_args; template void serialize(S& s) { s.value8b(instance_id); - s.ext(host_application_context_args, bitsery::ext::StdOptional{}); + s.ext(host_context_args, bitsery::ext::StdOptional{}); } }; diff --git a/src/plugin/bridges/vst3-impls/plugin-factory.cpp b/src/plugin/bridges/vst3-impls/plugin-factory.cpp index b5ca25ce..64fa6c13 100644 --- a/src/plugin/bridges/vst3-impls/plugin-factory.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-factory.cpp @@ -100,24 +100,21 @@ YaPluginFactoryImpl::createInstance(Steinberg::FIDString cid, tresult PLUGIN_API YaPluginFactoryImpl::setHostContext(Steinberg::FUnknown* context) { - // This `context` will likely be an `IHostApplication`. If it is, we will - // store it for future calls, create a proxy object on the Wine side, and - // then pass it to the Windows VST3 plugin's plugin factory using the same - // function. If we get passed anything else we'll just return instead since - // there's nothing we can do with it. - host_application_context = context; + // We will create a proxy object that that supports all the same interfaces + // as `context`, and then we'll store `context` in this object. We can then + // use it to handle callbacks made by the Windows VST3 plugin to this + // context. + host_context = context; - if (host_application_context) { - YaHostApplication::ConstructArgs host_application_context_args( - host_application_context, std::nullopt); - - return bridge.send_message(YaPluginFactory::SetHostContext{ - .host_application_context_args = - std::move(host_application_context_args)}); + std::optional host_context_args{}; + if (host_context) { + host_context_args = + Vst3HostContextProxy::ConstructArgs(host_context, std::nullopt); } else { - bridge.logger.log_unknown_interface( - "In IPluginFactory3::setHostContext(), ignoring", - context ? std::optional(context->iid) : std::nullopt); - return Steinberg::kNotImplemented; + bridge.logger.log( + "Null pointer passed to 'IPluginFactory3::setHostContext()'"); } + + return bridge.send_message(YaPluginFactory::SetHostContext{ + .host_context_args = std::move(host_context_args)}); } diff --git a/src/plugin/bridges/vst3-impls/plugin-factory.h b/src/plugin/bridges/vst3-impls/plugin-factory.h index 7743f2d2..2e6ecc19 100644 --- a/src/plugin/bridges/vst3-impls/plugin-factory.h +++ b/src/plugin/bridges/vst3-impls/plugin-factory.h @@ -32,9 +32,8 @@ class YaPluginFactoryImpl : public YaPluginFactory { Vst3PluginBridge& bridge; /** - * An `IHostApplication` instance if we get one through + * An host context if we get passed one through * `IPluginFactory3::setHostContext()`. */ - Steinberg::FUnknownPtr - host_application_context; + Steinberg::IPtr host_context; }; diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index c2d42901..97b98e9d 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -315,18 +315,18 @@ Vst3PluginProxyImpl::setParamNormalized(Steinberg::Vst::ParamID id, tresult PLUGIN_API Vst3PluginProxyImpl::setComponentHandler( Steinberg::Vst::IComponentHandler* handler) { + // We'll store the pointer for when the plugin later makes a callback to + // this component handler + component_handler = handler; + std::optional component_handler_proxy_args = std::nullopt; if (handler) { - // We'll store the pointer for when the plugin later makes a callback to - // this component handler - component_handler = handler; - component_handler_proxy_args = Vst3ComponentHandlerProxy::ConstructArgs( component_handler, instance_id()); } else { bridge.logger.log( - "Null pointer passed to 'IEditController::setComponentHandler'"); + "Null pointer passed to 'IEditController::setComponentHandler()'"); } return bridge.send_message(YaEditController::SetComponentHandler{ @@ -362,27 +362,23 @@ tresult PLUGIN_API Vst3PluginProxyImpl::openAboutBox(TBool onlyCheck) { } tresult PLUGIN_API Vst3PluginProxyImpl::initialize(FUnknown* context) { - // This `context` will likely be an `IHostApplication`. If it is, we - // will store it here, and we'll proxy through all calls to it made from - // the Wine side. Otherwise we'll still call `IPluginBase::initialize()` - // but with a null pointer instead. - host_application_context = context; + // We will create a proxy object that that supports all the same interfaces + // as `context`, and then we'll store `context` in this object. We can then + // use it to handle callbacks made by the Windows VST3 plugin to this + // context. + host_context = context; - std::optional - host_application_context_args = std::nullopt; - if (host_application_context) { - host_application_context_args = YaHostApplication::ConstructArgs( - host_application_context, instance_id()); + std::optional host_context_args{}; + if (host_context) { + host_context_args = + Vst3HostContextProxy::ConstructArgs(host_context, instance_id()); } else { - bridge.logger.log_unknown_interface( - "In IPluginBase::initialize()", - context ? std::optional(context->iid) : std::nullopt); + bridge.logger.log("Null pointer passed to 'IPluginBase::initialize()'"); } - return bridge.send_message( - YaPluginBase::Initialize{.instance_id = instance_id(), - .host_application_context_args = - std::move(host_application_context_args)}); + return bridge.send_message(YaPluginBase::Initialize{ + .instance_id = instance_id(), + .host_context_args = std::move(host_context_args)}); } tresult PLUGIN_API Vst3PluginProxyImpl::terminate() { diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index 202e1cec..15e1ee37 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -122,15 +122,6 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { tresult PLUGIN_API initialize(FUnknown* context) override; tresult PLUGIN_API terminate() override; - /** - * An `IHostApplication` instance if we get one through - * `IPluginBase::initialize()`. This should be the same for all plugin - * instances so we should not have to store it here separately, but for the - * sake of correctness we will. - */ - Steinberg::FUnknownPtr - host_application_context; - /** * The component handler the host passed to us during * `IEditController::setComponentHandler()`. When the plugin makes a @@ -141,4 +132,13 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { private: Vst3PluginBridge& bridge; + + /** + * An host context if we get passed one through `IPluginBase::initialize()`. + * We'll read which interfaces it supports and we'll then create a proxy + * object that supports those same interfaces. This should be the same for + * all plugin instances so we should not have to store it here separately, + * but for the sake of correctness we will. + */ + Steinberg::IPtr host_context; }; diff --git a/src/wine-host/bridges/vst3-impls/host-application.cpp b/src/wine-host/bridges/vst3-impls/host-context-proxy.cpp similarity index 68% rename from src/wine-host/bridges/vst3-impls/host-application.cpp rename to src/wine-host/bridges/vst3-impls/host-context-proxy.cpp index 307cbbde..b20277b1 100644 --- a/src/wine-host/bridges/vst3-impls/host-application.cpp +++ b/src/wine-host/bridges/vst3-impls/host-context-proxy.cpp @@ -14,24 +14,25 @@ // You should have received a copy of the GNU General Public License // along with this program. If not, see . -#include "host-application.h" +#include "host-context-proxy.h" #include -YaHostApplicationImpl::YaHostApplicationImpl( +Vst3HostContextProxyImpl::Vst3HostContextProxyImpl( Vst3Bridge& bridge, - YaHostApplication::ConstructArgs&& args) - : YaHostApplication(std::move(args)), bridge(bridge) { + Vst3HostContextProxy::ConstructArgs&& args) + : Vst3HostContextProxy(std::move(args)), bridge(bridge) { // The lifecycle is thos object is managed together with that of the plugin - // object instance this belongs to + // object instance instance this belongs to } tresult PLUGIN_API -YaHostApplicationImpl::queryInterface(const Steinberg::TUID _iid, void** obj) { +Vst3HostContextProxyImpl::queryInterface(const Steinberg::TUID _iid, + void** obj) { // I don't think it's expected of a host to implement multiple interfaces on // this object, so if we do get a call here it's important that it's logged // TODO: Successful queries should also be logged - const tresult result = YaHostApplication::queryInterface(_iid, obj); + const tresult result = Vst3HostContextProxy::queryInterface(_iid, obj); if (result != Steinberg::kResultOk) { std::cerr << "TODO: Implement unknown interface logging on Wine side" << std::endl; @@ -40,9 +41,10 @@ YaHostApplicationImpl::queryInterface(const Steinberg::TUID _iid, void** obj) { return result; } -tresult PLUGIN_API YaHostApplicationImpl::createInstance(Steinberg::TUID cid, - Steinberg::TUID _iid, - void** obj) { +tresult PLUGIN_API +Vst3HostContextProxyImpl::createInstance(Steinberg::TUID cid, + Steinberg::TUID _iid, + void** obj) { // TODO: Implement std::cerr << "TODO: IHostApplication::createInstance()" << std::endl; return Steinberg::kNotImplemented; diff --git a/src/wine-host/bridges/vst3-impls/host-application.h b/src/wine-host/bridges/vst3-impls/host-context-proxy.h similarity index 85% rename from src/wine-host/bridges/vst3-impls/host-application.h rename to src/wine-host/bridges/vst3-impls/host-context-proxy.h index ae5df390..fe6d59a4 100644 --- a/src/wine-host/bridges/vst3-impls/host-application.h +++ b/src/wine-host/bridges/vst3-impls/host-context-proxy.h @@ -18,10 +18,10 @@ #include "../vst3.h" -class YaHostApplicationImpl : public YaHostApplication { +class Vst3HostContextProxyImpl : public Vst3HostContextProxy { public: - YaHostApplicationImpl(Vst3Bridge& bridge, - YaHostApplication::ConstructArgs&& args); + Vst3HostContextProxyImpl(Vst3Bridge& bridge, + Vst3HostContextProxy::ConstructArgs&& args); /** * We'll override the query interface to log queries for interfaces we do @@ -30,6 +30,7 @@ class YaHostApplicationImpl : public YaHostApplication { tresult PLUGIN_API queryInterface(const Steinberg::TUID _iid, void** obj) override; + // From `IHostApplication` tresult PLUGIN_API createInstance(Steinberg::TUID cid, Steinberg::TUID _iid, void** obj) override; diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index acf09ce3..1d3f0358 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -24,7 +24,7 @@ #include #include "vst3-impls/component-handler-proxy.h" -#include "vst3-impls/host-application.h" +#include "vst3-impls/host-context-proxy.h" InstanceInterfaces::InstanceInterfaces() {} @@ -371,21 +371,19 @@ void Vst3Bridge::run() { // `Vst3HostProxy` // TODO: Does this have to be run from the UI thread? Figure out // if it does - if (request.host_application_context_args) { - object_instances[request.instance_id] - .host_application_context = - Steinberg::owned(new YaHostApplicationImpl( - *this, - std::move(*request.host_application_context_args))); + if (request.host_context_args) { + object_instances[request.instance_id].host_context_proxy = + Steinberg::owned(new Vst3HostContextProxyImpl( + *this, std::move(*request.host_context_args))); } else { - object_instances[request.instance_id] - .host_application_context = nullptr; + object_instances[request.instance_id].host_context_proxy = + nullptr; } return object_instances[request.instance_id] .plugin_base->initialize( object_instances[request.instance_id] - .host_application_context); + .host_context_proxy); }, [&](const YaPluginBase::Terminate& request) -> YaPluginBase::Terminate::Response { @@ -399,16 +397,19 @@ void Vst3Bridge::run() { }, [&](YaPluginFactory::SetHostContext& request) -> YaPluginFactory::SetHostContext::Response { - plugin_factory_host_application_context = - Steinberg::owned(new YaHostApplicationImpl( - *this, - std::move(request.host_application_context_args))); + if (request.host_context_args) { + plugin_factory_host_context = + Steinberg::owned(new Vst3HostContextProxyImpl( + *this, std::move(*request.host_context_args))); + } else { + plugin_factory_host_context = nullptr; + } Steinberg::FUnknownPtr factory_3( module->getFactory().get()); + assert(factory_3); - return factory_3->setHostContext( - plugin_factory_host_application_context); + return factory_3->setHostContext(plugin_factory_host_context); }}); } diff --git a/src/wine-host/bridges/vst3.h b/src/wine-host/bridges/vst3.h index 8e2f2d88..1a955268 100644 --- a/src/wine-host/bridges/vst3.h +++ b/src/wine-host/bridges/vst3.h @@ -38,12 +38,12 @@ struct InstanceInterfaces { InstanceInterfaces(Steinberg::IPtr object); /** - * If the host passes an `IHostApplication` during + * If the host passes a host context object during * `IPluginBase::initialize()`, we'll store a proxy object here and then * pass it to `plugin_base->initialize()`. Will be initialized with a null * pointer until used. */ - Steinberg::IPtr host_application_context; + Steinberg::IPtr host_context_proxy; /** * After a call to `IEditController::setComponentHandler()`, we'll create a @@ -155,11 +155,10 @@ class Vst3Bridge : public HostBridge { std::atomic_size_t current_instance_id; /** - * The host application context proxy object if we got passed a host - * application context during a call to `IPluginFactory3::setHostContext()` - * by the host. + * The host context proxy object if we got passed a host context during a + * call to `IPluginFactory3::setHostContext()` by the host. */ - Steinberg::IPtr plugin_factory_host_application_context; + Steinberg::IPtr plugin_factory_host_context; /** * These are all the objects we have created through the Windows VST3