From 919987298ceac1196f3a380500e78b0712c333db Mon Sep 17 00:00:00 2001 From: Robbert van der Helm Date: Sun, 13 Dec 2020 13:45:30 +0100 Subject: [PATCH] Add the base for YaHostApplication --- README.md | 4 +- meson.build | 2 + .../serialization/vst3/host-application.cpp | 69 +++++++++++ .../serialization/vst3/host-application.h | 111 ++++++++++++++++++ .../serialization/vst3/plugin-factory.h | 6 +- 5 files changed, 187 insertions(+), 5 deletions(-) create mode 100644 src/common/serialization/vst3/host-application.cpp create mode 100644 src/common/serialization/vst3/host-application.h diff --git a/README.md b/README.md index 6e2e4005..75fbfbed 100644 --- a/README.md +++ b/README.md @@ -16,8 +16,8 @@ This branch is still very far removed from being in a usable state. Below is an imcomplete list of things that still have to be done before this can be used: - Left to implement: - - `IHostApplication` for both `IPluginBase::initialize()` as well as for - `IPluginFactory3::setHostContext()`. + - `IHostApplication` implementations for both `IPluginBase::initialize()` as + well as for `IPluginFactory3::setHostContext()`. - The rest of `IComponent`'s functions after implementing `intialize()` - `IPluginFactory3::setHostContext()` - All other mandatory interfaces diff --git a/meson.build b/meson.build index 5d12b3d5..b6b09d2a 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,7 @@ vst3_plugin_sources = [ 'src/common/logging/vst3.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component.cpp', + 'src/common/serialization/vst3/host-application.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/common/configuration.cpp', 'src/common/plugins.cpp', @@ -113,6 +114,7 @@ if with_vst3 'src/common/logging/vst3.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/component.cpp', + 'src/common/serialization/vst3/host-application.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/wine-host/bridges/vst3.cpp', ] diff --git a/src/common/serialization/vst3/host-application.cpp b/src/common/serialization/vst3/host-application.cpp new file mode 100644 index 00000000..d270e277 --- /dev/null +++ b/src/common/serialization/vst3/host-application.cpp @@ -0,0 +1,69 @@ +// 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-application.h" + +YaHostApplication::ConstructArgs::ConstructArgs() {} + +YaHostApplication::ConstructArgs::ConstructArgs( + Steinberg::IPtr context, + size_t component_instance_id) + : component_instance_id(component_instance_id) { + Steinberg::Vst::String128 name_array; + if (context->getName(name_array) == Steinberg::kResultOk) { +#ifdef __WINE__ + // Who even invented UTF-16 + static_assert(sizeof(wchar_t) == sizeof(char16_t)); +#endif + name = std::u16string(reinterpret_cast(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; +} + +tresult PLUGIN_API YaHostApplication::getName(Steinberg::Vst::String128 name) { + if (arguments.name) { + // Terminate with a null byte. There are no nice functions for copying + // UTF-16 strings (because who would use those?). + std::copy(arguments.name->begin(), arguments.name->end(), name); + name[arguments.name->size()] = 0; + + return Steinberg::kResultOk; + } else { + return Steinberg::kNotImplemented; + } +} diff --git a/src/common/serialization/vst3/host-application.h b/src/common/serialization/vst3/host-application.h new file mode 100644 index 00000000..0589feee --- /dev/null +++ b/src/common/serialization/vst3/host-application.h @@ -0,0 +1,111 @@ +// 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. See `README.md` + * for more information on how this works. This is used both to proxy the host + * application context passed during `IPluginBase::intialize()` as well as for + * `IPluginFactory3::setHostContext()`. This interface is thus implemented on + * both the native plugin side as well as the Wine plugin host side. + */ +class YaHostApplication : public Steinberg::Vst::IHostApplication { + public: + /** + * These are the arguments for creating a + * `YaYaHostApplication{Plugin,Host}Impl`. + */ + struct ConstructArgs { + ConstructArgs(); + + /** + * Read arguments from an existing implementation. + */ + ConstructArgs(Steinberg::IPtr context, + size_t component_isntance_id); + + /** + * The unique instance identifier of the component this host context has + * been passed to and thus belongs to. + * + * TODO: When we implement `IPluginFactory3::setHostContext()` this + * should be made optional. + */ + native_size_t component_instance_id; + + /** + * For `IHostApplication::getName`. + */ + std::optional name; + + template + void serialize(S& s) { + s.value8b(component_instance_id); + s.ext(name, bitsery::ext::StdOptional{}, + [](S& s, std::string& name) { + s.text2b(name, std::extent_v); + }); + } + }; + + /** + * Instantiate this instance with arguments read from an actual host + * context. + * + * @note Since this is passed as part of ``IPluginBase::intialize()` and + * `IPluginFactory3::setHostContext()``, there are no direct `Construct` + * or `Destruct` messages. This object's lifetime is bound to that of the + * objects they are passed to. If those objects get dropped, then the host + * contexts should also be dropped. + * + * TODO: Check if this ends up working out this way + */ + YaHostApplication(const ConstructArgs&& args); + + /** + * The lifetime of this object should be bound to the object we created it + * for. When for instance the `IComponent` instance with id `x` gets dropped + * and we also track a `YaHostApplicationHostImpl` for the component with + * instance id `x`, then that should also be dropped. + */ + ~YaHostApplication(); + + 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; + + protected: + ConstructArgs arguments; +}; + +#pragma GCC diagnostic pop diff --git a/src/common/serialization/vst3/plugin-factory.h b/src/common/serialization/vst3/plugin-factory.h index 118eb305..979038ce 100644 --- a/src/common/serialization/vst3/plugin-factory.h +++ b/src/common/serialization/vst3/plugin-factory.h @@ -127,9 +127,9 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { YaPluginFactory(const ConstructArgs&& args); /** - * We do not need to implement the destructor, since when the sockets are - * closed, RAII will clean up the Windows VST3 module we loaded along with - * its factory for us. + * We do not need to implement the destructor in + * `YaPluginFactoryPluginImpl`, since when the sockets are closed, RAII will + * clean up the Windows VST3 module we loaded along with its factory for us. */ virtual ~YaPluginFactory();