diff --git a/meson.build b/meson.build index 2a1b1b09..649acc47 100644 --- a/meson.build +++ b/meson.build @@ -79,6 +79,7 @@ vst3_plugin_sources = [ 'src/common/logging/vst3.cpp', 'src/common/serialization/vst3/plugin/audio-processor.cpp', 'src/common/serialization/vst3/plugin/component.cpp', + 'src/common/serialization/vst3/plugin/edit-controller.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/event-list.cpp', @@ -121,6 +122,7 @@ if with_vst3 'src/common/logging/vst3.cpp', 'src/common/serialization/vst3/plugin/audio-processor.cpp', 'src/common/serialization/vst3/plugin/component.cpp', + 'src/common/serialization/vst3/plugin/edit-controller.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', 'src/common/serialization/vst3/base.cpp', 'src/common/serialization/vst3/event-list.cpp', diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index add0c5b3..800bc2af 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -12,6 +12,7 @@ VST3 interfaces are implemented as follows: | `Vst3PluginProxy` | | All of the below: | | `YaAudioProcessor` | `Vst3PluginProxy` | `IAudioProcessor` | | `YaComponent` | `Vst3PluginProxy` | `IComponent` | +| `YaEditController` | `Vst3PluginProxy` | `IEditController`, `IEditController2` | | `YaPluginBase` | `Vst3PluginProxy` | `IPluginBase` | | `YaHostApplication` | | `iHostAPplication` | | `YaPluginFactory` | | `IPluginFactory`, `IPluginFactory2`, `IPluginFactory3` | diff --git a/src/common/serialization/vst3/plugin-monolith.h b/src/common/serialization/vst3/plugin-monolith.h deleted file mode 100644 index 49da2d38..00000000 --- a/src/common/serialization/vst3/plugin-monolith.h +++ /dev/null @@ -1 +0,0 @@ -Vst3PluginProxyVst3PluginProxyVst3PluginProxyVst3PluginProxy diff --git a/src/common/serialization/vst3/plugin-proxy.cpp b/src/common/serialization/vst3/plugin-proxy.cpp index a286abc5..db6b5746 100644 --- a/src/common/serialization/vst3/plugin-proxy.cpp +++ b/src/common/serialization/vst3/plugin-proxy.cpp @@ -24,11 +24,13 @@ Vst3PluginProxy::ConstructArgs::ConstructArgs( : instance_id(instance_id), audio_processor_args(object), component_args(object), + edit_controller_2_args(object), plugin_base_args(object) {} Vst3PluginProxy::Vst3PluginProxy(const ConstructArgs&& args) : YaAudioProcessor(std::move(args.audio_processor_args)), YaComponent(std::move(args.component_args)), + YaEditController2(std::move(args.edit_controller_2_args)), YaPluginBase(std::move(args.plugin_base_args)), arguments(std::move(args)){FUNKNOWN_CTOR} @@ -61,13 +63,21 @@ tresult PLUGIN_API Vst3PluginProxy::queryInterface(Steinberg::FIDString _iid, return ::Steinberg ::kResultOk; } } + if (YaAudioProcessor::supported()) { + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IAudioProcessor::iid, + Steinberg::Vst::IAudioProcessor) + } if (YaComponent::supported()) { QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IComponent::iid, Steinberg::Vst::IComponent) } - if (YaAudioProcessor::supported()) { - QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IAudioProcessor::iid, - Steinberg::Vst::IAudioProcessor) + if (YaEditController2::supported_version_1()) { + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IEditController::iid, + Steinberg::Vst::IEditController) + } + if (YaEditController2::supported_version_2()) { + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IEditController2::iid, + Steinberg::Vst::IEditController2) } *obj = nullptr; diff --git a/src/common/serialization/vst3/plugin-proxy.h b/src/common/serialization/vst3/plugin-proxy.h index 2b0730f8..feae9d1c 100644 --- a/src/common/serialization/vst3/plugin-proxy.h +++ b/src/common/serialization/vst3/plugin-proxy.h @@ -24,6 +24,7 @@ #include "host-application.h" #include "plugin/audio-processor.h" #include "plugin/component.h" +#include "plugin/edit-controller.h" #include "plugin/plugin-base.h" #pragma GCC diagnostic push @@ -54,6 +55,7 @@ */ class Vst3PluginProxy : public YaAudioProcessor, public YaComponent, + public YaEditController2, public YaPluginBase { public: /** @@ -75,12 +77,14 @@ class Vst3PluginProxy : public YaAudioProcessor, YaAudioProcessor::ConstructArgs audio_processor_args; YaComponent::ConstructArgs component_args; + YaEditController2::ConstructArgs edit_controller_2_args; YaPluginBase::ConstructArgs plugin_base_args; template void serialize(S& s) { s.value8b(instance_id); s.object(audio_processor_args); + s.object(edit_controller_2_args); s.object(component_args); s.object(plugin_base_args); } diff --git a/src/common/serialization/vst3/plugin/audio-processor.h b/src/common/serialization/vst3/plugin/audio-processor.h index 88deb6d7..7f15cbbf 100644 --- a/src/common/serialization/vst3/plugin/audio-processor.h +++ b/src/common/serialization/vst3/plugin/audio-processor.h @@ -62,7 +62,7 @@ class YaAudioProcessor : public Steinberg::Vst::IAudioProcessor { */ YaAudioProcessor(const ConstructArgs&& args); - inline bool supported() { return arguments.supported; } + inline bool supported() const { return arguments.supported; } /** * Message to pass through a call to diff --git a/src/common/serialization/vst3/plugin/component.h b/src/common/serialization/vst3/plugin/component.h index 8700e81f..6fb190bd 100644 --- a/src/common/serialization/vst3/plugin/component.h +++ b/src/common/serialization/vst3/plugin/component.h @@ -72,7 +72,7 @@ class YaComponent : public Steinberg::Vst::IComponent { */ YaComponent(const ConstructArgs&& args); - inline bool supported() { return arguments.supported; } + inline bool supported() const { return arguments.supported; } tresult PLUGIN_API getControllerClassId(Steinberg::TUID classId) override; diff --git a/src/common/serialization/vst3/plugin/edit-controller.cpp b/src/common/serialization/vst3/plugin/edit-controller.cpp new file mode 100644 index 00000000..720cabac --- /dev/null +++ b/src/common/serialization/vst3/plugin/edit-controller.cpp @@ -0,0 +1,29 @@ +// 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 "edit-controller.h" + +YaEditController2::ConstructArgs::ConstructArgs() {} + +YaEditController2::ConstructArgs::ConstructArgs( + Steinberg::IPtr object) + : supported_version_1( + Steinberg::FUnknownPtr(object)), + supported_version_2( + Steinberg::FUnknownPtr(object)) {} + +YaEditController2::YaEditController2(const ConstructArgs&& args) + : arguments(std::move(args)) {} diff --git a/src/common/serialization/vst3/plugin/edit-controller.h b/src/common/serialization/vst3/plugin/edit-controller.h new file mode 100644 index 00000000..2a9e42d9 --- /dev/null +++ b/src/common/serialization/vst3/plugin/edit-controller.h @@ -0,0 +1,126 @@ +// 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 "../../common.h" +#include "../base.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +/** + * Wraps around `IEditController{,2}` for serialization purposes. This is + * instantiated as part of `Vst3PluginProxy`. + * + * Steinberg forgot to inherit `IEditController2` from `IEditController` event + * if it says it does in the docs, so we'll pretend they just that. + */ +class YaEditController2 : public Steinberg::Vst::IEditController, + public Steinberg::Vst::IEditController2 { + public: + /** + * These are the arguments for creating a `YaEditController2`. + */ + struct ConstructArgs { + ConstructArgs(); + + /** + * Check whether an existing implementation implements `IEditController` + * and `IEditController2` and read arguments from it. + */ + ConstructArgs(Steinberg::IPtr object); + + /** + * Whether the object supported `IEditController`. + */ + bool supported_version_1; + + /** + * Whether the object supported `IEditController2`. + */ + bool supported_version_2; + + template + void serialize(S& s) { + s.value1b(supported_version_1); + s.value1b(supported_version_2); + } + }; + + /** + * Instantiate this instance with arguments read from another interface + * implementation. + */ + YaEditController2(const ConstructArgs&& args); + + inline bool supported_version_1() const { + return arguments.supported_version_1; + } + inline bool supported_version_2() const { + return arguments.supported_version_2; + } + + // From `IEditController` + + virtual tresult PLUGIN_API + setComponentState(Steinberg::IBStream* state) override = 0; + virtual tresult PLUGIN_API + setState(Steinberg::IBStream* state) override = 0; + virtual tresult PLUGIN_API + getState(Steinberg::IBStream* state) override = 0; + virtual int32 PLUGIN_API getParameterCount() override = 0; + virtual tresult PLUGIN_API + getParameterInfo(int32 paramIndex, + Steinberg::Vst::ParameterInfo& info /*out*/) override = 0; + virtual tresult PLUGIN_API getParamStringByValue( + Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized /*in*/, + Steinberg::Vst::String128 string /*out*/) override = 0; + virtual tresult PLUGIN_API getParamValueByString( + Steinberg::Vst::ParamID id, + Steinberg::Vst::TChar* string /*in*/, + Steinberg::Vst::ParamValue& valueNormalized /*out*/) override = 0; + virtual Steinberg::Vst::ParamValue PLUGIN_API normalizedParamToPlain( + Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized) override = 0; + virtual Steinberg::Vst::ParamValue PLUGIN_API + plainParamToNormalized(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue plainValue) override = 0; + virtual Steinberg::Vst::ParamValue PLUGIN_API + getParamNormalized(Steinberg::Vst::ParamID id) override = 0; + virtual tresult PLUGIN_API + setParamNormalized(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue value) override = 0; + virtual tresult PLUGIN_API setComponentHandler( + Steinberg::Vst::IComponentHandler* handler) override = 0; + virtual Steinberg::IPlugView* PLUGIN_API + createView(Steinberg::FIDString name) override = 0; + + // From `IEditController2` + + virtual tresult PLUGIN_API + setKnobMode(Steinberg::Vst::KnobMode mode) override = 0; + virtual tresult PLUGIN_API openHelp(TBool onlyCheck) override = 0; + virtual tresult PLUGIN_API openAboutBox(TBool onlyCheck) override = 0; + + protected: + ConstructArgs arguments; +}; + +#pragma GCC diagnostic pop diff --git a/src/common/serialization/vst3/plugin/plugin-base.h b/src/common/serialization/vst3/plugin/plugin-base.h index 3ad5f118..4e44161b 100644 --- a/src/common/serialization/vst3/plugin/plugin-base.h +++ b/src/common/serialization/vst3/plugin/plugin-base.h @@ -62,7 +62,7 @@ class YaPluginBase : public Steinberg::IPluginBase { */ YaPluginBase(const ConstructArgs&& args); - inline bool supported() { return arguments.supported; } + inline bool supported() const { return arguments.supported; } /** * Message to pass through a call to `IPluginBase::initialize()` to the Wine diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index 5744e35a..7a36cee6 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -184,6 +184,114 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getState(Steinberg::IBStream* state) { return response.result; } +// FIXME: Fix `{set,get}State()` for `IEditController` as mentioned in the +// header + +tresult PLUGIN_API +Vst3PluginProxyImpl::setComponentState(Steinberg::IBStream* state) { + // TODO: Implement + bridge.logger.log("TODO IEditController::setComponentState()"); + return Steinberg::kNotImplemented; +} + +int32 PLUGIN_API Vst3PluginProxyImpl::getParameterCount() { + // TODO: Implement + bridge.logger.log("TODO IEditController::getParameterCount()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getParameterInfo( + int32 paramIndex, + Steinberg::Vst::ParameterInfo& info /*out*/) { + // TODO: Implement + bridge.logger.log("TODO IEditController::getParameterInfo()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getParamStringByValue( + Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized /*in*/, + Steinberg::Vst::String128 string /*out*/) { + // TODO: Implement + bridge.logger.log("TODO IEditController::getParamStringByValue()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getParamValueByString( + Steinberg::Vst::ParamID id, + Steinberg::Vst::TChar* string /*in*/, + Steinberg::Vst::ParamValue& valueNormalized /*out*/) { + // TODO: Implement + bridge.logger.log("TODO IEditController::getParamValueByString()"); + return Steinberg::kNotImplemented; +} + +Steinberg::Vst::ParamValue PLUGIN_API +Vst3PluginProxyImpl::normalizedParamToPlain( + Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized) { + // TODO: Implement + bridge.logger.log("TODO IEditController::normalizedParamToPlain()"); + return Steinberg::kNotImplemented; +} + +Steinberg::Vst::ParamValue PLUGIN_API +Vst3PluginProxyImpl::plainParamToNormalized( + Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue plainValue) { + // TODO: Implement + bridge.logger.log("TODO IEditController::plainParamToNormalized()"); + return Steinberg::kNotImplemented; +} + +Steinberg::Vst::ParamValue PLUGIN_API +Vst3PluginProxyImpl::getParamNormalized(Steinberg::Vst::ParamID id) { + // TODO: Implement + bridge.logger.log("TODO IEditController::getParamNormalized()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::setParamNormalized(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue value) { + // TODO: Implement + bridge.logger.log("TODO IEditController::setParamNormalized()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::setComponentHandler( + Steinberg::Vst::IComponentHandler* handler) { + // TODO: Implement + bridge.logger.log("TODO IEditController::setComponentHandler()"); + return Steinberg::kNotImplemented; +} + +Steinberg::IPlugView* PLUGIN_API +Vst3PluginProxyImpl::createView(Steinberg::FIDString name) { + // TODO: Implement + bridge.logger.log("TODO IEditController::createView()"); + return nullptr; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::setKnobMode(Steinberg::Vst::KnobMode mode) { + // TODO: Implement + bridge.logger.log("TODO IEditController2::setKnobMode()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::openHelp(TBool onlyCheck) { + // TODO: Implement + bridge.logger.log("TODO IEditController2::openHelp()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::openAboutBox(TBool onlyCheck) { + // TODO: Implement + bridge.logger.log("TODO IEditController2::openAboutBox()"); + return Steinberg::kNotImplemented; +} + 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 diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index a6123023..a8df71c6 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -79,6 +79,47 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { tresult PLUGIN_API setState(Steinberg::IBStream* state) override; tresult PLUGIN_API getState(Steinberg::IBStream* state) override; + // From `IEditController` + tresult PLUGIN_API setComponentState(Steinberg::IBStream* state) override; + // FIXME: These are duplicate, we need to change the implementation to call + // this on either `object_instances[instance_id].component` or + // `object_instances[instance_id].edit_controller` depending on which + // one exists. + // tresult PLUGIN_API setState(Steinberg::IBStream* state) override; + // tresult PLUGIN_API getState(Steinberg::IBStream* state) override; + int32 PLUGIN_API getParameterCount() override; + tresult PLUGIN_API + getParameterInfo(int32 paramIndex, + Steinberg::Vst::ParameterInfo& info /*out*/) override; + tresult PLUGIN_API + getParamStringByValue(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized /*in*/, + Steinberg::Vst::String128 string /*out*/) override; + tresult PLUGIN_API getParamValueByString( + Steinberg::Vst::ParamID id, + Steinberg::Vst::TChar* string /*in*/, + Steinberg::Vst::ParamValue& valueNormalized /*out*/) override; + Steinberg::Vst::ParamValue PLUGIN_API + normalizedParamToPlain(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue valueNormalized) override; + Steinberg::Vst::ParamValue PLUGIN_API + plainParamToNormalized(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue plainValue) override; + Steinberg::Vst::ParamValue PLUGIN_API + getParamNormalized(Steinberg::Vst::ParamID id) override; + tresult PLUGIN_API + setParamNormalized(Steinberg::Vst::ParamID id, + Steinberg::Vst::ParamValue value) override; + tresult PLUGIN_API + setComponentHandler(Steinberg::Vst::IComponentHandler* handler) override; + Steinberg::IPlugView* PLUGIN_API + createView(Steinberg::FIDString name) override; + + // From `IEditController2` + tresult PLUGIN_API setKnobMode(Steinberg::Vst::KnobMode mode) override; + tresult PLUGIN_API openHelp(TBool onlyCheck) override; + tresult PLUGIN_API openAboutBox(TBool onlyCheck) override; + // From `IPluginBase` tresult PLUGIN_API initialize(FUnknown* context) override; tresult PLUGIN_API terminate() override;