mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-08 04:20:13 +02:00
Create Vst3HostContextProxy from YaHostApplication
This is quite a huge refactor, but note everything is consistent (and we're going to need one or two more of these `Vst3*Proxy` objects). Right now nothing extends `IHostApplication`, but this way it will be trivial to add support for more host context interfaces.
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
#include "../utils.h"
|
||||
#include "common.h"
|
||||
#include "vst3/component-handler-proxy.h"
|
||||
#include "vst3/host-context-proxy.h"
|
||||
#include "vst3/plugin-factory.h"
|
||||
#include "vst3/plugin-proxy.h"
|
||||
|
||||
|
||||
@@ -22,7 +22,8 @@ VST3 host interfaces are implemented as follows:
|
||||
|
||||
| yabridge class | Included in | Interfaces |
|
||||
| --------------------------- | --------------------------- | ------------------- |
|
||||
| `YaHostApplication` | | `IHostApplication` |
|
||||
| `Vst3HostContextProxy` | | All of the below: |
|
||||
| `YaHostApplication` | `Vst3HostContextProxy` | `IHostApplication` |
|
||||
| `Vst3ComponentHandlerProxy` | | All of the below: |
|
||||
| `YaComponentHandler` | `Vst3ComponentHandlerProxy` | `IComponentHandler` |
|
||||
|
||||
|
||||
@@ -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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#include "host-context-proxy.h"
|
||||
|
||||
Vst3HostContextProxy::ConstructArgs::ConstructArgs() {}
|
||||
|
||||
Vst3HostContextProxy::ConstructArgs::ConstructArgs(
|
||||
Steinberg::IPtr<Steinberg::FUnknown> object,
|
||||
std::optional<size_t> owner_instance_id)
|
||||
: owner_instance_id(owner_instance_id), host_application_args(object) {}
|
||||
|
||||
Vst3HostContextProxy::Vst3HostContextProxy(const ConstructArgs&& args)
|
||||
: YaHostApplication(std::move(args.host_application_args)),
|
||||
arguments(std::move(args)){FUNKNOWN_CTOR}
|
||||
|
||||
Vst3HostContextProxy::~Vst3HostContextProxy() {
|
||||
FUNKNOWN_DTOR
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
|
||||
IMPLEMENT_REFCOUNT(Vst3HostContextProxy)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
tresult PLUGIN_API
|
||||
Vst3HostContextProxy::queryInterface(Steinberg::FIDString _iid, void** obj) {
|
||||
if (YaHostApplication::supported()) {
|
||||
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;
|
||||
}
|
||||
+29
-39
@@ -16,42 +16,36 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <bitsery/ext/std_optional.h>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <pluginterfaces/vst/ivsthostapplication.h>
|
||||
|
||||
#include "../common.h"
|
||||
#include "base.h"
|
||||
#include "host-context/host-application.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
|
||||
/**
|
||||
* Wraps around `IHostApplication` for serialization purposes. An instance of
|
||||
* this proxy object will be initialized on the Wine plugin host side after the
|
||||
* host passes an actual instance to the plugin, and all function calls made to
|
||||
* this proxy will be passed through to the actual object. This is used to proxy
|
||||
* both the host application context passed during `IPluginBase::intialize()` as
|
||||
* well as for the 'global' context in `IPluginFactory3::setHostContext()`.
|
||||
*
|
||||
* TODO: Create a `Vst3HostContextProxy`, and make this to only interface it
|
||||
* inherits. For uniformity's sake it's a good idea to have every kind of
|
||||
* object we directly instantiate be in the same form.
|
||||
* An abstract class that optionally implements all interfaces a `context`
|
||||
* object passed to `IPluginBase::intialize()` or
|
||||
* `IPluginFactory3::setHostContext()` might implement. This works exactly the
|
||||
* same as `Vst3PluginProxy`, but instead of proxying for an object provided by
|
||||
* the plugin we are proxying for the `FUnknown*` argument passed to plugin by
|
||||
* the host. When we are proxying for a host context object passed to
|
||||
* `IPluginBase::initialize()` we'll keep track of the object instance ID the
|
||||
* actual context object belongs to.
|
||||
*/
|
||||
class YaHostApplication : public Steinberg::Vst::IHostApplication {
|
||||
class Vst3HostContextProxy : public YaHostApplication {
|
||||
public:
|
||||
/**
|
||||
* These are the arguments for constructing a `YaHostApplicationImpl`.
|
||||
* These are the arguments for constructing a
|
||||
* `Vst3HostContextProxyImpl`.
|
||||
*/
|
||||
struct ConstructArgs {
|
||||
ConstructArgs();
|
||||
|
||||
/**
|
||||
* Read arguments from an existing implementation.
|
||||
* 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<Steinberg::Vst::IHostApplication> context,
|
||||
ConstructArgs(Steinberg::IPtr<FUnknown> object,
|
||||
std::optional<size_t> owner_instance_id);
|
||||
|
||||
/**
|
||||
@@ -61,10 +55,7 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication {
|
||||
*/
|
||||
std::optional<native_size_t> owner_instance_id;
|
||||
|
||||
/**
|
||||
* For `IHostApplication::getName`.
|
||||
*/
|
||||
std::optional<std::u16string> name;
|
||||
YaHostApplication::ConstructArgs host_application_args;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
@@ -72,10 +63,7 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication {
|
||||
[](S& s, native_size_t& instance_id) {
|
||||
s.value8b(instance_id);
|
||||
});
|
||||
s.ext(name, bitsery::ext::StdOptional{},
|
||||
[](S& s, std::u16string& name) {
|
||||
s.text2b(name, std::extent_v<Steinberg::Vst::String128>);
|
||||
});
|
||||
s.object(host_application_args);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -89,25 +77,27 @@ class YaHostApplication : public Steinberg::Vst::IHostApplication {
|
||||
* objects they are passed to. If those objects get dropped, then the host
|
||||
* contexts should also be dropped.
|
||||
*/
|
||||
YaHostApplication(const ConstructArgs&& args);
|
||||
Vst3HostContextProxy(const ConstructArgs&& args);
|
||||
|
||||
/**
|
||||
* The lifetime of this object should be bound to the object we created it
|
||||
* for. When for instance the `Vst3PluginProxy` instance with id `n` gets
|
||||
* dropped, the corresponding `YaHostApplicationImpl` then that should also
|
||||
* be dropped.
|
||||
* dropped a corresponding `Vst3HostContextProxyImpl` should also be
|
||||
* dropped.
|
||||
*/
|
||||
virtual ~YaHostApplication();
|
||||
virtual ~Vst3HostContextProxy() = 0;
|
||||
|
||||
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;
|
||||
/**
|
||||
* Get the instance ID of the owner of this object, if this is not the
|
||||
* global host context passed to the module's plugin factory.
|
||||
*/
|
||||
inline std::optional<size_t> owner_instance_id() const {
|
||||
return arguments.owner_instance_id;
|
||||
}
|
||||
|
||||
protected:
|
||||
private:
|
||||
ConstructArgs arguments;
|
||||
};
|
||||
|
||||
+12
-27
@@ -19,37 +19,22 @@
|
||||
YaHostApplication::ConstructArgs::ConstructArgs() {}
|
||||
|
||||
YaHostApplication::ConstructArgs::ConstructArgs(
|
||||
Steinberg::IPtr<Steinberg::Vst::IHostApplication> context,
|
||||
std::optional<size_t> owner_instance_id)
|
||||
: owner_instance_id(owner_instance_id) {
|
||||
Steinberg::Vst::String128 name_array;
|
||||
if (context->getName(name_array) == Steinberg::kResultOk) {
|
||||
name = tchar_pointer_to_u16string(name_array);
|
||||
Steinberg::IPtr<Steinberg::FUnknown> object)
|
||||
: supported(false) {
|
||||
if (auto host_application =
|
||||
Steinberg::FUnknownPtr<Steinberg::Vst::IHostApplication>(object)) {
|
||||
supported = true;
|
||||
|
||||
// `IHostApplication::getName`
|
||||
Steinberg::Vst::String128 name_array;
|
||||
if (host_application->getName(name_array) == Steinberg::kResultOk) {
|
||||
name = tchar_pointer_to_u16string(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;
|
||||
}
|
||||
: arguments(std::move(args)) {}
|
||||
|
||||
tresult PLUGIN_API YaHostApplication::getName(Steinberg::Vst::String128 name) {
|
||||
if (arguments.name) {
|
||||
@@ -0,0 +1,86 @@
|
||||
// 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 <https://www.gnu.org/licenses/>.
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <type_traits>
|
||||
|
||||
#include <bitsery/ext/std_optional.h>
|
||||
#include <bitsery/traits/string.h>
|
||||
#include <pluginterfaces/vst/ivsthostapplication.h>
|
||||
|
||||
#include "../../common.h"
|
||||
#include "../base.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
|
||||
/**
|
||||
* Wraps around `IHostApplication` for serialization purposes. This is
|
||||
* instantiated as part of `Vst3HostContextProxy`.
|
||||
*/
|
||||
class YaHostApplication : public Steinberg::Vst::IHostApplication {
|
||||
public:
|
||||
/**
|
||||
* These are the arguments for creating a `YaHostApplication`.
|
||||
*/
|
||||
struct ConstructArgs {
|
||||
ConstructArgs();
|
||||
|
||||
/**
|
||||
* Check whether an existing implementation implements
|
||||
* `IHostApplication` and read arguments from it.
|
||||
*/
|
||||
ConstructArgs(Steinberg::IPtr<Steinberg::FUnknown> object);
|
||||
|
||||
/**
|
||||
* Whether the object supported this interface.
|
||||
*/
|
||||
bool supported;
|
||||
|
||||
/**
|
||||
* For `IHostApplication::getName`.
|
||||
*/
|
||||
std::optional<std::u16string> name;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
s.value1b(supported);
|
||||
s.ext(name, bitsery::ext::StdOptional{},
|
||||
[](S& s, std::u16string& name) {
|
||||
s.text2b(name, std::extent_v<Steinberg::Vst::String128>);
|
||||
});
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Instantiate this instance with arguments read from another interface
|
||||
* implementation.
|
||||
*/
|
||||
YaHostApplication(const ConstructArgs&& args);
|
||||
|
||||
inline bool supported() const { return arguments.supported; }
|
||||
|
||||
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
|
||||
@@ -41,7 +41,7 @@ YaPluginFactory::ConstructArgs::ConstructArgs(
|
||||
}
|
||||
}
|
||||
|
||||
auto factory2 = Steinberg::FUnknownPtr<Steinberg::IPluginFactory2>(factory);
|
||||
Steinberg::FUnknownPtr<Steinberg::IPluginFactory2> factory2(factory);
|
||||
if (!factory2) {
|
||||
return;
|
||||
}
|
||||
@@ -56,7 +56,7 @@ YaPluginFactory::ConstructArgs::ConstructArgs(
|
||||
}
|
||||
}
|
||||
|
||||
auto factory3 = Steinberg::FUnknownPtr<Steinberg::IPluginFactory3>(factory);
|
||||
Steinberg::FUnknownPtr<Steinberg::IPluginFactory3> factory3(factory);
|
||||
if (!factory3) {
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -22,7 +22,7 @@
|
||||
|
||||
#include "../../bitsery/ext/vst3.h"
|
||||
#include "base.h"
|
||||
#include "host-application.h"
|
||||
#include "host-context-proxy.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
@@ -155,20 +155,22 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 {
|
||||
|
||||
/**
|
||||
* Message to pass through a call to `IPluginFactory3::setHostContext()` to
|
||||
* the Wine plugin host. A proxy `YaHostApplication` should be created on
|
||||
* the Wine plugin host and then passed as an argument to
|
||||
* `IPluginFactory3::setHostContext()`. If the host called
|
||||
* `IPluginFactory3::setHostContext()` with something other than an
|
||||
* `IHostApplication*`, we return an error immediately and log the call.
|
||||
* the Wine plugin host. A `Vst3HostContextProxy` should be created on the
|
||||
* Wine plugin host and then passed as an argument to
|
||||
* `IPluginFactory3::setHostContext()`.
|
||||
*/
|
||||
struct SetHostContext {
|
||||
using Response = UniversalTResult;
|
||||
|
||||
YaHostApplication::ConstructArgs host_application_context_args;
|
||||
/**
|
||||
* Arguments for creating a proxy host context object. If we got passed
|
||||
* an null pointer we'll reflect that.
|
||||
*/
|
||||
std::optional<Vst3HostContextProxy::ConstructArgs> host_context_args;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
s.object(host_application_context_args);
|
||||
s.ext(host_context_args, bitsery::ext::StdOptional{});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
|
||||
#include "../../common.h"
|
||||
#include "../base.h"
|
||||
#include "../host-application.h"
|
||||
#include "../process-data.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
|
||||
@@ -19,10 +19,10 @@
|
||||
YaComponent::ConstructArgs::ConstructArgs() {}
|
||||
|
||||
YaComponent::ConstructArgs::ConstructArgs(
|
||||
Steinberg::IPtr<Steinberg::FUnknown> object) {
|
||||
auto component = Steinberg::FUnknownPtr<Steinberg::Vst::IComponent>(object);
|
||||
|
||||
if (component) {
|
||||
Steinberg::IPtr<Steinberg::FUnknown> object)
|
||||
: supported(false) {
|
||||
if (auto component =
|
||||
Steinberg::FUnknownPtr<Steinberg::Vst::IComponent>(object)) {
|
||||
supported = true;
|
||||
|
||||
// `IComponent::getControllerClassId`
|
||||
|
||||
@@ -21,7 +21,7 @@
|
||||
|
||||
#include "../../common.h"
|
||||
#include "../base.h"
|
||||
#include "../host-application.h"
|
||||
#include "../host-context-proxy.h"
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
@@ -66,23 +66,23 @@ class YaPluginBase : public Steinberg::IPluginBase {
|
||||
|
||||
/**
|
||||
* Message to pass through a call to `IPluginBase::initialize()` to the Wine
|
||||
* plugin host. if we pass an `IHostApplication` instance, then a proxy
|
||||
* `YaHostApplication` should be created and passed as an argument to
|
||||
* `IPluginBase::initialize()`. If this is absent a null pointer should be
|
||||
* passed. The lifetime of this `YaHostApplication` object should be bound
|
||||
* to the `IComponent` we are proxying.
|
||||
* plugin host. We will read what interfaces the passed context object
|
||||
* implements so we can then create a proxy object on the Wine side that the
|
||||
* plugin can use to make callbacks with. The lifetime of this
|
||||
* `Vst3HostContextProxy` object should be bound to the `IComponent` we are
|
||||
* proxying.
|
||||
*/
|
||||
struct Initialize {
|
||||
using Response = UniversalTResult;
|
||||
|
||||
native_size_t instance_id;
|
||||
std::optional<YaHostApplication::ConstructArgs>
|
||||
host_application_context_args;
|
||||
|
||||
std::optional<Vst3HostContextProxy::ConstructArgs> host_context_args;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
s.value8b(instance_id);
|
||||
s.ext(host_application_context_args, bitsery::ext::StdOptional{});
|
||||
s.ext(host_context_args, bitsery::ext::StdOptional{});
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
Reference in New Issue
Block a user