diff --git a/meson.build b/meson.build index 9cb58b34..88c3280c 100644 --- a/meson.build +++ b/meson.build @@ -92,6 +92,7 @@ vst3_plugin_sources = [ '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/plug-view-proxy.cpp', 'src/common/serialization/vst3/plugin-proxy.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/common/serialization/vst3/process-data.cpp', @@ -141,6 +142,7 @@ if with_vst3 '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/plug-view-proxy.cpp', 'src/common/serialization/vst3/plugin-proxy.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/common/serialization/vst3/process-data.cpp', diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index ed41bb22..efe13210 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -7,16 +7,18 @@ serialization works. VST3 plugin interfaces are implemented as follows: -| yabridge class | Included in | Interfaces | -| ------------------- | ----------------- | ------------------------------------------------------ | -| `YaPluginFactory` | | `IPluginFactory`, `IPluginFactory2`, `IPluginFactory3` | -| `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` | +| `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/base.h b/src/common/serialization/vst3/base.h index 7c8d8319..8b0bfeb2 100644 --- a/src/common/serialization/vst3/base.h +++ b/src/common/serialization/vst3/base.h @@ -28,9 +28,9 @@ // Yet Another layer of includes, but these are some VST3-specific typedefs that // we'll need for all of our interfaces -using Steinberg::TBool, Steinberg::int8, Steinberg::int16, Steinberg::int32, - Steinberg::int64, Steinberg::uint8, Steinberg::uint16, Steinberg::uint32, - Steinberg::uint64, Steinberg::tresult; +using Steinberg::TBool, Steinberg::char16, Steinberg::int8, Steinberg::int16, + Steinberg::int32, Steinberg::int64, Steinberg::uint8, Steinberg::uint16, + Steinberg::uint32, Steinberg::uint64, Steinberg::tresult; /** * Both `TUID` (`int8_t[16]`) and `FIDString` (`char*`) are hard to work with diff --git a/src/common/serialization/vst3/component-handler-proxy.h b/src/common/serialization/vst3/component-handler-proxy.h index 522392c6..aa0a944d 100644 --- a/src/common/serialization/vst3/component-handler-proxy.h +++ b/src/common/serialization/vst3/component-handler-proxy.h @@ -81,7 +81,7 @@ class Vst3ComponentHandlerProxy : public YaComponentHandler { * dropped a corresponding `Vst3ComponentHandlerProxyImpl` should also be * dropped. */ - virtual ~Vst3ComponentHandlerProxy() = 0; + virtual ~Vst3ComponentHandlerProxy(); DECLARE_FUNKNOWN_METHODS diff --git a/src/common/serialization/vst3/host-context-proxy.h b/src/common/serialization/vst3/host-context-proxy.h index 9f590d4f..e2afe641 100644 --- a/src/common/serialization/vst3/host-context-proxy.h +++ b/src/common/serialization/vst3/host-context-proxy.h @@ -85,7 +85,7 @@ class Vst3HostContextProxy : public YaHostApplication { * dropped a corresponding `Vst3HostContextProxyImpl` should also be * dropped. */ - virtual ~Vst3HostContextProxy() = 0; + virtual ~Vst3HostContextProxy(); DECLARE_FUNKNOWN_METHODS diff --git a/src/common/serialization/vst3/plug-view-proxy.cpp b/src/common/serialization/vst3/plug-view-proxy.cpp new file mode 100644 index 00000000..de2fdf49 --- /dev/null +++ b/src/common/serialization/vst3/plug-view-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 "plug-view-proxy.h" + +Vst3PlugViewProxy::ConstructArgs::ConstructArgs() {} + +Vst3PlugViewProxy::ConstructArgs::ConstructArgs( + Steinberg::IPtr object, + size_t owner_instance_id) + : owner_instance_id(owner_instance_id), plug_view_args(object) {} + +Vst3PlugViewProxy::Vst3PlugViewProxy(const ConstructArgs&& args) + : YaPlugView(std::move(args.plug_view_args)), + arguments(std::move(args)){FUNKNOWN_CTOR} + + Vst3PlugViewProxy::~Vst3PlugViewProxy() { + FUNKNOWN_DTOR +} + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor" +IMPLEMENT_REFCOUNT(Vst3PlugViewProxy) +#pragma GCC diagnostic pop + +tresult PLUGIN_API Vst3PlugViewProxy::queryInterface(Steinberg::FIDString _iid, + void** obj) { + if (YaPlugView::supported()) { + QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid, + Steinberg::IPlugView) + QUERY_INTERFACE(_iid, obj, Steinberg::IPlugView::iid, + Steinberg::IPlugView) + } + + *obj = nullptr; + return Steinberg::kNoInterface; +} diff --git a/src/common/serialization/vst3/plug-view-proxy.h b/src/common/serialization/vst3/plug-view-proxy.h new file mode 100644 index 00000000..c8d50d4c --- /dev/null +++ b/src/common/serialization/vst3/plug-view-proxy.h @@ -0,0 +1,94 @@ +// 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 "plug-view/plug-view.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +/** + * An abstract class that implements `IPlugView`, and optionally also all + * extensions to `IPlugView` depending on what the plugin's implementation + * supports. This provides a proxy for the `IPlugView*` returned by a plugin on + * `IEditController::createView()`, and it works exactly the same as + * `Vst3PluginProxy`. + */ +class Vst3PlugViewProxy : public YaPlugView { + public: + /** + * These are the arguments for constructing a + * `Vst3PlugViewProxyImpl`. + */ + 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. + */ + ConstructArgs(Steinberg::IPtr object, + size_t owner_instance_id); + + /** + * The unique instance identifier of the proxy object that returned this + * `IPlugView*`. This way we can refer to the correct 'actual' + * `IPlugView*` when the host calls a function on this object. + */ + native_size_t owner_instance_id; + + YaPlugView::ConstructArgs plug_view_args; + + template + void serialize(S& s) { + s.value8b(owner_instance_id); + s.object(plug_view_args); + } + }; + + /** + * Instantiate this instance with arguments read from an actual component + * handler. + * + * @note Since this is passed as part of `IEditController::createView()`, + * there are is no direct `Construct` + * message. The destructor should still send a message to drop the + * original smart pointer. + */ + Vst3PlugViewProxy(const ConstructArgs&& args); + + /** + * @remark The plugin side implementation should send a control message to + * clean up the instance on the Wine side in its destructor. + */ + virtual ~Vst3PlugViewProxy() = 0; + + 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