diff --git a/meson.build b/meson.build index 532eb9a3..cb033ff4 100644 --- a/meson.build +++ b/meson.build @@ -85,6 +85,7 @@ vst3_plugin_sources = [ 'src/common/serialization/vst3/plugin/edit-controller.cpp', 'src/common/serialization/vst3/plugin/edit-controller-2.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', + 'src/common/serialization/vst3/plugin/unit-info.cpp', 'src/common/serialization/vst3/component-handler/component-handler.cpp', 'src/common/serialization/vst3/component-handler/unit-handler.cpp', 'src/common/serialization/vst3/host-context/host-application.cpp', @@ -142,6 +143,7 @@ if with_vst3 'src/common/serialization/vst3/plugin/edit-controller.cpp', 'src/common/serialization/vst3/plugin/edit-controller-2.cpp', 'src/common/serialization/vst3/plugin/plugin-base.cpp', + 'src/common/serialization/vst3/plugin/unit-info.cpp', 'src/common/serialization/vst3/component-handler/component-handler.cpp', 'src/common/serialization/vst3/component-handler/unit-handler.cpp', 'src/common/serialization/vst3/host-context/host-application.cpp', diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index 7fb81ac4..e1e1c1d8 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -20,6 +20,7 @@ VST3 plugin interfaces are implemented as follows: | `YaEditController` | `Vst3PluginProxy` | `IEditController` | | `YaEditController2` | `Vst3PluginProxy` | `IEditController2` | | `YaPluginBase` | `Vst3PluginProxy` | `IPluginBase` | +| `YaUnitInfo` | `Vst3PluginProxy` | `IUnitInfo` | VST3 host interfaces are implemented as follows: diff --git a/src/common/serialization/vst3/plugin-proxy.cpp b/src/common/serialization/vst3/plugin-proxy.cpp index 5f4b07a1..417b55ce 100644 --- a/src/common/serialization/vst3/plugin-proxy.cpp +++ b/src/common/serialization/vst3/plugin-proxy.cpp @@ -27,7 +27,8 @@ Vst3PluginProxy::ConstructArgs::ConstructArgs( connection_point_args(object), edit_controller_args(object), edit_controller_2_args(object), - plugin_base_args(object) {} + plugin_base_args(object), + unit_info_args(object) {} Vst3PluginProxy::Vst3PluginProxy(const ConstructArgs&& args) : YaAudioProcessor(std::move(args.audio_processor_args)), @@ -36,6 +37,7 @@ Vst3PluginProxy::Vst3PluginProxy(const ConstructArgs&& args) YaEditController(std::move(args.edit_controller_args)), YaEditController2(std::move(args.edit_controller_2_args)), YaPluginBase(std::move(args.plugin_base_args)), + YaUnitInfo(std::move(args.unit_info_args)), arguments(std::move(args)){FUNKNOWN_CTOR} Vst3PluginProxy::~Vst3PluginProxy() { @@ -87,6 +89,10 @@ tresult PLUGIN_API Vst3PluginProxy::queryInterface(Steinberg::FIDString _iid, QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IEditController2::iid, Steinberg::Vst::IEditController2) } + if (YaUnitInfo::supported()) { + QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IUnitInfo::iid, + Steinberg::Vst::IUnitInfo) + } *obj = nullptr; return Steinberg::kNoInterface; diff --git a/src/common/serialization/vst3/plugin-proxy.h b/src/common/serialization/vst3/plugin-proxy.h index 9e6d177e..892f2239 100644 --- a/src/common/serialization/vst3/plugin-proxy.h +++ b/src/common/serialization/vst3/plugin-proxy.h @@ -25,6 +25,7 @@ #include "plugin/edit-controller-2.h" #include "plugin/edit-controller.h" #include "plugin/plugin-base.h" +#include "plugin/unit-info.h" #pragma GCC diagnostic push #pragma GCC diagnostic ignored "-Wnon-virtual-dtor" @@ -57,7 +58,8 @@ class Vst3PluginProxy : public YaAudioProcessor, public YaConnectionPoint, public YaEditController, public YaEditController2, - public YaPluginBase { + public YaPluginBase, + public YaUnitInfo { public: /** * These are the arguments for constructing a `Vst3PluginProxyImpl`. @@ -82,6 +84,7 @@ class Vst3PluginProxy : public YaAudioProcessor, YaEditController::ConstructArgs edit_controller_args; YaEditController2::ConstructArgs edit_controller_2_args; YaPluginBase::ConstructArgs plugin_base_args; + YaUnitInfo::ConstructArgs unit_info_args; template void serialize(S& s) { @@ -92,6 +95,7 @@ class Vst3PluginProxy : public YaAudioProcessor, s.object(edit_controller_args); s.object(edit_controller_2_args); s.object(plugin_base_args); + s.object(unit_info_args); } }; diff --git a/src/common/serialization/vst3/plugin/unit-info.cpp b/src/common/serialization/vst3/plugin/unit-info.cpp new file mode 100644 index 00000000..8f8cf098 --- /dev/null +++ b/src/common/serialization/vst3/plugin/unit-info.cpp @@ -0,0 +1,26 @@ +// 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 "unit-info.h" + +YaUnitInfo::ConstructArgs::ConstructArgs() {} + +YaUnitInfo::ConstructArgs::ConstructArgs( + Steinberg::IPtr object) + : supported(Steinberg::FUnknownPtr(object)) {} + +YaUnitInfo::YaUnitInfo(const ConstructArgs&& args) + : arguments(std::move(args)) {} diff --git a/src/common/serialization/vst3/plugin/unit-info.h b/src/common/serialization/vst3/plugin/unit-info.h new file mode 100644 index 00000000..d421530d --- /dev/null +++ b/src/common/serialization/vst3/plugin/unit-info.h @@ -0,0 +1,108 @@ +// 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" +#include "../host-context-proxy.h" + +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wnon-virtual-dtor" + +/** + * Wraps around `IUnitInfo` for serialization purposes. This is instantiated as + * part of `Vst3PluginProxy`. + */ +class YaUnitInfo : public Steinberg::Vst::IUnitInfo { + public: + /** + * These are the arguments for creating a `YaUnitInfo`. + */ + struct ConstructArgs { + ConstructArgs(); + + /** + * Check whether an existing implementation implements `IUnitInfo` and + * read arguments from it. + */ + ConstructArgs(Steinberg::IPtr object); + + /** + * Whether the object supported this interface. + */ + bool supported; + + template + void serialize(S& s) { + s.value1b(supported); + } + }; + + /** + * Instantiate this instance with arguments read from another interface + * implementation. + */ + YaUnitInfo(const ConstructArgs&& args); + + inline bool supported() const { return arguments.supported; } + + virtual int32 PLUGIN_API getUnitCount() override = 0; + virtual tresult PLUGIN_API + getUnitInfo(int32 unitIndex, + Steinberg::Vst::UnitInfo& info /*out*/) override = 0; + virtual int32 PLUGIN_API getProgramListCount() override = 0; + virtual tresult PLUGIN_API getProgramListInfo( + int32 listIndex, + Steinberg::Vst::ProgramListInfo& info /*out*/) override = 0; + virtual tresult PLUGIN_API + getProgramName(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::String128 name /*out*/) override = 0; + virtual tresult PLUGIN_API getProgramInfo( + Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::CString attributeId /*in*/, + Steinberg::Vst::String128 attributeValue /*out*/) override = 0; + virtual tresult PLUGIN_API + hasProgramPitchNames(Steinberg::Vst::ProgramListID listId, + int32 programIndex) override = 0; + virtual tresult PLUGIN_API + getProgramPitchName(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + int16 midiPitch, + Steinberg::Vst::String128 name /*out*/) override = 0; + virtual Steinberg::Vst::UnitID PLUGIN_API getSelectedUnit() override = 0; + virtual tresult PLUGIN_API + selectUnit(Steinberg::Vst::UnitID unitId) override = 0; + virtual tresult PLUGIN_API + getUnitByBus(Steinberg::Vst::MediaType type, + Steinberg::Vst::BusDirection dir, + int32 busIndex, + int32 channel, + Steinberg::Vst::UnitID& unitId /*out*/) override = 0; + virtual tresult PLUGIN_API + setUnitProgramData(int32 listOrUnitId, + int32 programIndex, + Steinberg::IBStream* data) override = 0; + + protected: + ConstructArgs arguments; +}; + +#pragma GCC diagnostic pop diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index bf94bbd7..79e39057 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -439,3 +439,101 @@ tresult PLUGIN_API Vst3PluginProxyImpl::terminate() { return bridge.send_message( YaPluginBase::Terminate{.instance_id = instance_id()}); } + +int32 PLUGIN_API Vst3PluginProxyImpl::getUnitCount() { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getUnitCount()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::getUnitInfo(int32 unitIndex, + Steinberg::Vst::UnitInfo& info /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getUnitInfo()"); + return Steinberg::kNotImplemented; +} + +int32 PLUGIN_API Vst3PluginProxyImpl::getProgramListCount() { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getProgramListCount()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getProgramListInfo( + int32 listIndex, + Steinberg::Vst::ProgramListInfo& info /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getProgramListInfo()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::getProgramName(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::String128 name /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getProgramName()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getProgramInfo( + Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::CString attributeId /*in*/, + Steinberg::Vst::String128 attributeValue /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getProgramInfo()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::hasProgramPitchNames(Steinberg::Vst::ProgramListID listId, + int32 programIndex) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::hasProgramPitchNames()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API Vst3PluginProxyImpl::getProgramPitchName( + Steinberg::Vst::ProgramListID listId, + int32 programIndex, + int16 midiPitch, + Steinberg::Vst::String128 name /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getProgramPitchName()"); + return Steinberg::kNotImplemented; +} + +Steinberg::Vst::UnitID PLUGIN_API Vst3PluginProxyImpl::getSelectedUnit() { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getSelectedUnit()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::selectUnit(Steinberg::Vst::UnitID unitId) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::selectUnit()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::getUnitByBus(Steinberg::Vst::MediaType type, + Steinberg::Vst::BusDirection dir, + int32 busIndex, + int32 channel, + Steinberg::Vst::UnitID& unitId /*out*/) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::getUnitByBus()"); + return Steinberg::kNotImplemented; +} + +tresult PLUGIN_API +Vst3PluginProxyImpl::setUnitProgramData(int32 listOrUnitId, + int32 programIndex, + Steinberg::IBStream* data) { + // TODO: Implement + bridge.logger.log("TODO: IUnitInfo::setUnitProgramData()"); + return Steinberg::kNotImplemented; +} diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index c9ca866f..24a7ae84 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -124,6 +124,44 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { tresult PLUGIN_API initialize(FUnknown* context) override; tresult PLUGIN_API terminate() override; + // From `IUnitInfo` + int32 PLUGIN_API getUnitCount() override; + tresult PLUGIN_API + getUnitInfo(int32 unitIndex, + Steinberg::Vst::UnitInfo& info /*out*/) override; + int32 PLUGIN_API getProgramListCount() override; + tresult PLUGIN_API + getProgramListInfo(int32 listIndex, + Steinberg::Vst::ProgramListInfo& info /*out*/) override; + tresult PLUGIN_API + getProgramName(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::String128 name /*out*/) override; + tresult PLUGIN_API + getProgramInfo(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + Steinberg::Vst::CString attributeId /*in*/, + Steinberg::Vst::String128 attributeValue /*out*/) override; + tresult PLUGIN_API + hasProgramPitchNames(Steinberg::Vst::ProgramListID listId, + int32 programIndex) override; + tresult PLUGIN_API + getProgramPitchName(Steinberg::Vst::ProgramListID listId, + int32 programIndex, + int16 midiPitch, + Steinberg::Vst::String128 name /*out*/) override; + Steinberg::Vst::UnitID PLUGIN_API getSelectedUnit() override; + tresult PLUGIN_API selectUnit(Steinberg::Vst::UnitID unitId) override; + tresult PLUGIN_API + getUnitByBus(Steinberg::Vst::MediaType type, + Steinberg::Vst::BusDirection dir, + int32 busIndex, + int32 channel, + Steinberg::Vst::UnitID& unitId /*out*/) override; + tresult PLUGIN_API setUnitProgramData(int32 listOrUnitId, + int32 programIndex, + Steinberg::IBStream* data) override; + /** * The component handler the host passed to us during * `IEditController::setComponentHandler()`. When the plugin makes a