diff --git a/meson.build b/meson.build index 1aeec32a..cca4136c 100644 --- a/meson.build +++ b/meson.build @@ -82,6 +82,7 @@ vst3_plugin_sources = [ 'src/common/plugins.cpp', 'src/common/utils.cpp', 'src/plugin/bridges/vst3.cpp', + 'src/plugin/bridges/vst3-impls.cpp', 'src/plugin/host-process.cpp', 'src/plugin/utils.cpp', 'src/plugin/vst3-plugin.cpp', @@ -109,6 +110,7 @@ if with_vst3 'src/common/logging/vst3.cpp', 'src/common/serialization/vst3/plugin-factory.cpp', 'src/wine-host/bridges/vst3.cpp', + 'src/wine-host/bridges/vst3-impls.cpp', ] endif diff --git a/src/common/serialization/vst3/README.md b/src/common/serialization/vst3/README.md index 9249ef9d..6693162e 100644 --- a/src/common/serialization/vst3/README.md +++ b/src/common/serialization/vst3/README.md @@ -43,9 +43,10 @@ instantiated and managed by the host. The model works as follows: can be sent between the native plugin and the Wine plugin host. 6. If `IFoo` has methods that have side effects (such as instantiating a new object), then the implementations of those functions in `YaFoo` will be pure - virtual and both the native plugin and the Wine plugin host should provide - their own implementation. Since the functions will ever only be called from - one of the two sides, the other side can just throw in their implementation. + virtual. The side that requested the object (so for the plugin factory that + would be on the side of the native plugin) should then provide a `YaFoo{Plugin,Host}Impl` + that implements those functions through yabridge's `Vst3MessageHandler` + callback interface. ## Plugin Factory diff --git a/src/common/serialization/vst3/plugin-factory.cpp b/src/common/serialization/vst3/plugin-factory.cpp index ba9dd46c..e86ee90c 100644 --- a/src/common/serialization/vst3/plugin-factory.cpp +++ b/src/common/serialization/vst3/plugin-factory.cpp @@ -119,24 +119,6 @@ tresult PLUGIN_API YaPluginFactory::getClassInfo(Steinberg::int32 index, } } -tresult PLUGIN_API -YaPluginFactory::createInstance(Steinberg::FIDString /*cid*/, - Steinberg::FIDString /*_iid*/, - void** /*obj*/) { - // TODO: Figure out how to implement this. Some considerations: - // - We have to sent a control message to the Wine plugin host to ask - // it to create an instance of `_iid`. - // - We then create a `Ya*` implementation of the same interface on - // the plugin side. - // - These two should be wired up so that when the host calls a - // function on it, it should be sent to the instance on the Wine - // plugin host side with the same cid. - // - We should have a list of interfaces we support. When we receive a - // request to create an instance of something we don't support, then - // we should log that and then fail. - return 0; -} - tresult PLUGIN_API YaPluginFactory::getClassInfo2(int32 /*index*/, Steinberg::PClassInfo2* /*info*/) { @@ -150,10 +132,3 @@ YaPluginFactory::getClassInfoUnicode(int32 /*index*/, // TODO: Implement return 0; } - -tresult PLUGIN_API -YaPluginFactory::setHostContext(Steinberg::FUnknown* /*context*/) { - // TODO: I guess this should do a callback and set the Wine host's host - // context, right? - return 0; -} diff --git a/src/common/serialization/vst3/plugin-factory.h b/src/common/serialization/vst3/plugin-factory.h index c93accde..55b2acde 100644 --- a/src/common/serialization/vst3/plugin-factory.h +++ b/src/common/serialization/vst3/plugin-factory.h @@ -47,6 +47,9 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { * TODO: Instead of a having a default constructor, we should probably be * passing a callback to this constructor that lets us communicate * with the Wine plugin host. + * TODO: Alternative to requiring a bunch of `fu::unique_function<>` + * callbacks would be to make the callback functions pure virtual, and + * then implement those functions directly using `Vst3MessageHandler`. */ YaPluginFactory(); @@ -59,7 +62,7 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { explicit YaPluginFactory( Steinberg::IPtr factory); - ~YaPluginFactory(); + virtual ~YaPluginFactory(); DECLARE_FUNKNOWN_METHODS @@ -68,9 +71,20 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { int32 PLUGIN_API countClasses() override; tresult PLUGIN_API getClassInfo(Steinberg::int32 index, Steinberg::PClassInfo* info) override; - tresult PLUGIN_API createInstance(Steinberg::FIDString cid, - Steinberg::FIDString _iid, - void** obj) override; + // TODO: Figure out how to implement this. Some considerations: + // - We have to sent a control message to the Wine plugin host to ask + // it to create an instance of `_iid`. + // - We then create a `Ya*` implementation of the same interface on + // the plugin side. + // - These two should be wired up so that when the host calls a + // function on it, it should be sent to the instance on the Wine + // plugin host side with the same cid. + // - We should have a list of interfaces we support. When we receive a + // request to create an instance of something we don't support, then + // we should log that and then fail. + virtual tresult PLUGIN_API createInstance(Steinberg::FIDString cid, + Steinberg::FIDString _iid, + void** obj) override = 0; // From `IPluginFactory2` tresult PLUGIN_API getClassInfo2(int32 index, @@ -79,7 +93,8 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 { // From `IPluginFactory3` tresult PLUGIN_API getClassInfoUnicode(int32 index, Steinberg::PClassInfoW* info) override; - tresult PLUGIN_API setHostContext(Steinberg::FUnknown* context) override; + virtual tresult PLUGIN_API + setHostContext(Steinberg::FUnknown* context) override = 0; /** * The IIDs that the interface we serialized supports. diff --git a/src/plugin/bridges/vst3-impls.cpp b/src/plugin/bridges/vst3-impls.cpp new file mode 100644 index 00000000..0a18bf9e --- /dev/null +++ b/src/plugin/bridges/vst3-impls.cpp @@ -0,0 +1,34 @@ +// 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 "vst3-impls.h" + +YaPluginFactoryPluginImpl::YaPluginFactoryPluginImpl(Vst3PluginBridge& bridge) + : bridge(bridge) {} + +tresult PLUGIN_API +YaPluginFactoryPluginImpl::createInstance(Steinberg::FIDString /*cid*/, + Steinberg::FIDString /*_iid*/, + void** /*obj*/) { + // TODO: Send a control message + return 0; +} + +tresult PLUGIN_API +YaPluginFactoryPluginImpl::setHostContext(Steinberg::FUnknown* /*context*/) { + // TODO: Send a control message + return 0; +} diff --git a/src/plugin/bridges/vst3-impls.h b/src/plugin/bridges/vst3-impls.h new file mode 100644 index 00000000..39a058f8 --- /dev/null +++ b/src/plugin/bridges/vst3-impls.h @@ -0,0 +1,36 @@ +// 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 "vst3.h" + +// These are implementation of the serialization clases in +// `src/common/serialization/vst3/` to provide callback support + +class YaPluginFactoryPluginImpl : public YaPluginFactory { + public: + YaPluginFactoryPluginImpl(Vst3PluginBridge& bridge); + + tresult PLUGIN_API createInstance(Steinberg::FIDString cid, + Steinberg::FIDString _iid, + void** obj) override; + + tresult PLUGIN_API setHostContext(Steinberg::FUnknown* context) override; + + private: + Vst3PluginBridge& bridge; +}; diff --git a/src/plugin/vst3-plugin.cpp b/src/plugin/vst3-plugin.cpp index 0e12f3fe..4052cd57 100644 --- a/src/plugin/vst3-plugin.cpp +++ b/src/plugin/vst3-plugin.cpp @@ -17,6 +17,9 @@ #include #include "bridges/vst3.h" +// TODO: Remove include, instantiating and returning the `YaPluginFactory` +// should be done in `Vst3PluginBridge` +#include "src/plugin/bridges/vst3-impls.h" #include @@ -87,8 +90,8 @@ SMTG_EXPORT_SYMBOL Steinberg::IPluginFactory* PLUGIN_API GetPluginFactory() { // TODO: Remove, this is just for type checking if (false) { boost::asio::local::stream_protocol::socket* socket; - YaPluginFactory* object; - write_object(*socket, *object); + YaPluginFactoryPluginImpl object(*bridge); + write_object(*socket, object); } if (!gPluginFactory) { diff --git a/src/wine-host/bridges/vst3-impls.cpp b/src/wine-host/bridges/vst3-impls.cpp new file mode 100644 index 00000000..b169063e --- /dev/null +++ b/src/wine-host/bridges/vst3-impls.cpp @@ -0,0 +1,33 @@ +// 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 "vst3-impls.h" + +YaPluginFactoryHostImpl::YaPluginFactoryHostImpl( + Steinberg::IPtr factory) + : YaPluginFactory(factory) {} + +tresult PLUGIN_API +YaPluginFactoryHostImpl::createInstance(Steinberg::FIDString /*cid*/, + Steinberg::FIDString /*_iid*/, + void** /*obj*/) { + throw std::runtime_error("Unexpected call to 'createInstance()'"); +} + +tresult PLUGIN_API +YaPluginFactoryHostImpl::setHostContext(Steinberg::FUnknown* /*context*/) { + throw std::runtime_error("Unexpected call to 'setHostContext()'"); +} diff --git a/src/wine-host/bridges/vst3-impls.h b/src/wine-host/bridges/vst3-impls.h new file mode 100644 index 00000000..59328696 --- /dev/null +++ b/src/wine-host/bridges/vst3-impls.h @@ -0,0 +1,31 @@ +// 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 "vst3.h" + +class YaPluginFactoryHostImpl : public YaPluginFactory { + public: + YaPluginFactoryHostImpl(Steinberg::IPtr factory); + + tresult PLUGIN_API createInstance(Steinberg::FIDString cid, + Steinberg::FIDString _iid, + void** obj) override; + + tresult PLUGIN_API + setHostContext(Steinberg::FUnknown* /*context*/) override; +}; diff --git a/src/wine-host/bridges/vst3.cpp b/src/wine-host/bridges/vst3.cpp index a905d94f..385e8009 100644 --- a/src/wine-host/bridges/vst3.cpp +++ b/src/wine-host/bridges/vst3.cpp @@ -17,6 +17,7 @@ #include "vst3.h" #include "../boost-fix.h" +#include "vst3-impls.h" #include @@ -45,8 +46,9 @@ void Vst3Bridge::run() { // TODO: Remove, this is just for type checking if (false) { boost::asio::local::stream_protocol::socket* socket; - YaPluginFactory* object; - write_object(*socket, *object); + Steinberg::IPtr factory; + YaPluginFactoryHostImpl object(factory); + write_object(*socket, object); } // TODO: Handle events