From 0fce9c9eed40eb7229d39b10f496e38cf63c9dc8 Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Fri, 25 Dec 2020 13:28:03 +0100 Subject: [PATCH] Add an IConnectionPoint proxy proxy This is a bit dumb, but this way we can support indirectly connected objects. --- meson.build | 2 + src/common/serialization/vst3/README.md | 25 +++-- .../vst3/connection-point-proxy.cpp | 51 +++++++++ .../vst3/connection-point-proxy.h | 104 ++++++++++++++++++ 4 files changed, 170 insertions(+), 12 deletions(-) create mode 100644 src/common/serialization/vst3/connection-point-proxy.cpp create mode 100644 src/common/serialization/vst3/connection-point-proxy.h diff --git a/meson.build b/meson.build index 4a061d94..86ea1751 100644 --- a/meson.build +++ b/meson.build @@ -90,6 +90,7 @@ vst3_plugin_sources = [ 'src/common/serialization/vst3/attribute-list.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component-handler-proxy.cpp', + 'src/common/serialization/vst3/connection-point-proxy.cpp', 'src/common/serialization/vst3/event-list.cpp', 'src/common/serialization/vst3/host-context-proxy.cpp', 'src/common/serialization/vst3/message.cpp', @@ -145,6 +146,7 @@ if with_vst3 'src/common/serialization/vst3/attribute-list.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component-handler-proxy.cpp', + 'src/common/serialization/vst3/connection-point-proxy.cpp', 'src/common/serialization/vst3/event-list.cpp', 'src/common/serialization/vst3/host-context-proxy.cpp', 'src/common/serialization/vst3/message.cpp', diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index 7e9ddc79..b9b8aeae 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -7,18 +7,19 @@ serialization works. VST3 plugin interfaces are implemented as follows: -| yabridge class | Included in | Interfaces | -| ------------------- | ------------------- | ------------------------------------------------------ | -| `YaPluginFactory` | | `IPluginFactory`, `IPluginFactory2`, `IPluginFactory3` | -| `Vst3PlugViewProxy` | | All of the below: | -| `YaPlugView` | `Vst3PlugViewProxy` | `IPlugView` | -| `Vst3PluginProxy` | | All of the below: | -| `YaAudioProcessor` | `Vst3PluginProxy` | `IAudioProcessor` | -| `YaComponent` | `Vst3PluginProxy` | `IComponent` | -| `YaConnectionPoint` | `Vst3PluginProxy` | `IConnectionPoint` | -| `YaEditController` | `Vst3PluginProxy` | `IEditController` | -| `YaEditController2` | `Vst3PluginProxy` | `IEditController2` | -| `YaPluginBase` | `Vst3PluginProxy` | `IPluginBase` | +| yabridge class | Included in | Interfaces | +| -------------------------- | ------------------- | ------------------------------------------------------ | +| `YaPluginFactory` | | `IPluginFactory`, `IPluginFactory2`, `IPluginFactory3` | +| `Vst3ConnectionPointProxy` | | `IConnectionPoint` through `YaConnectionPoint` | +| `Vst3PlugViewProxy` | | All of the below: | +| `YaPlugView` | `Vst3PlugViewProxy` | `IPlugView` | +| `Vst3PluginProxy` | | All of the below: | +| `YaAudioProcessor` | `Vst3PluginProxy` | `IAudioProcessor` | +| `YaComponent` | `Vst3PluginProxy` | `IComponent` | +| `YaConnectionPoint` | `Vst3PluginProxy` | `IConnectionPoint` | +| `YaEditController` | `Vst3PluginProxy` | `IEditController` | +| `YaEditController2` | `Vst3PluginProxy` | `IEditController2` | +| `YaPluginBase` | `Vst3PluginProxy` | `IPluginBase` | VST3 host interfaces are implemented as follows: diff --git a/src/common/serialization/vst3/connection-point-proxy.cpp b/src/common/serialization/vst3/connection-point-proxy.cpp new file mode 100644 index 00000000..8bf0cf61 --- /dev/null +++ b/src/common/serialization/vst3/connection-point-proxy.cpp @@ -0,0 +1,51 @@ +// 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 "connection-point-proxy.h" + +Vst3ConnectionPointProxy::ConstructArgs::ConstructArgs() {} + +Vst3ConnectionPointProxy::ConstructArgs::ConstructArgs( + Steinberg::IPtr object, + size_t owner_instance_id) + : owner_instance_id(owner_instance_id), connection_point_args(object) {} + +Vst3ConnectionPointProxy::Vst3ConnectionPointProxy(const ConstructArgs&& args) + : YaConnectionPoint(std::move(args.connection_point_args)), + arguments(std::move(args)){FUNKNOWN_CTOR} + + Vst3ConnectionPointProxy::~Vst3ConnectionPointProxy() { + FUNKNOWN_DTOR +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +IMPLEMENT_REFCOUNT(Vst3ConnectionPointProxy) +#pragma GCC diagnostic pop + +tresult PLUGIN_API +Vst3ConnectionPointProxy::queryInterface(Steinberg::FIDString _iid, + void** obj) { + if (YaConnectionPoint::supported()) { + QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid, + Steinberg::Vst::IConnectionPoint) + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IConnectionPoint::iid, + Steinberg::Vst::IConnectionPoint) + } + + *obj = nullptr; + return Steinberg::kNoInterface; +} diff --git a/src/common/serialization/vst3/connection-point-proxy.h b/src/common/serialization/vst3/connection-point-proxy.h new file mode 100644 index 00000000..48b255aa --- /dev/null +++ b/src/common/serialization/vst3/connection-point-proxy.h @@ -0,0 +1,104 @@ +// 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 "../common.h" +#include "plugin/connection-point.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +/** + * This is only needed to...proxy a connection point proxy. Most hosts will + * connect a plugin's processor and controller directly using + * `IConnectionPoint::connect()`. But some hosts, like Ardour, will place a + * proxy object between them that forwards calls to + * `IConnectionPoint::notify()`. When objects are connected directly by the host + * we can also connect them directly in the Wine plugin host, but when the host + * uses proxies we'll also have to go through that proxy. The purpose of this + * class is to provide a proxy for such a connection proxy. So when the plugin + * calls `notify()` on an object of this class, then we will forward that call + * to the `IConnectionPoint` proxy provided by the host, which will then in turn + * call `IConnectionPoint::notify()` on the other object and we'll then forward + * that message again to them Wine plugin host. + */ +class Vst3ConnectionPointProxy : public YaConnectionPoint { + public: + /** + * These are the arguments for constructing a + * `Vst3ConnectionPointProxyImpl`. + */ + struct ConstructArgs { + ConstructArgs(); + + /** + * Read from an existing object. We will try to mimic this object, so + * we'll support any interfaces this object also supports. + * + * This is not necessary in this case since the object has to support + * `IConnectionPoint`, but let's stay consistent with the overall style + * here. + */ + ConstructArgs(Steinberg::IPtr object, + size_t owner_instance_id); + + /** + * The unique instance identifier of the proxy object instance this + * connection proxy has been passed to and thus belongs to. This way we + * can refer to the correct 'actual' `IConnectionPoint` instance when + * the plugin calls `notify()` on this proxy object. + */ + native_size_t owner_instance_id; + + YaConnectionPoint::ConstructArgs connection_point_args; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + s.object(connection_point_args); + } + }; + + /** + * Instantiate this instance with arguments read from an actual + * `IConnectionPoint` object/proxy. + * + * @note This object will be created as part of handling + * `IConnectionPoint::connect()` if the connection is indirect. + */ + Vst3ConnectionPointProxy(const ConstructArgs&& args); + + /** + * This object will be destroyed again during + * `IConnectionPoint::disconnect()`. + */ + virtual ~Vst3ConnectionPointProxy(); + + DECLARE_FUNKNOWN_METHODS + + /** + * Get the instance ID of the owner of this object. + */ + inline size_t owner_instance_id() const { + return arguments.owner_instance_id; + } + + private: + ConstructArgs arguments; +}; + +#pragma GCC diagnostic pop