mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-10 04:30:12 +02:00
Redesign how interface instantiation works
Transferring some argument pack is much easier than trying to deserialize into an existing object when you also have to transfer more information than just that object.
This commit is contained in:
@@ -77,6 +77,7 @@ vst3_plugin_sources = [
|
|||||||
'src/common/communication/common.cpp',
|
'src/common/communication/common.cpp',
|
||||||
'src/common/logging/common.cpp',
|
'src/common/logging/common.cpp',
|
||||||
'src/common/logging/vst3.cpp',
|
'src/common/logging/vst3.cpp',
|
||||||
|
'src/common/serialization/vst3/component.cpp',
|
||||||
'src/common/serialization/vst3/plugin-factory.cpp',
|
'src/common/serialization/vst3/plugin-factory.cpp',
|
||||||
'src/common/configuration.cpp',
|
'src/common/configuration.cpp',
|
||||||
'src/common/plugins.cpp',
|
'src/common/plugins.cpp',
|
||||||
@@ -108,6 +109,7 @@ host_sources = [
|
|||||||
if with_vst3
|
if with_vst3
|
||||||
host_sources += [
|
host_sources += [
|
||||||
'src/common/logging/vst3.cpp',
|
'src/common/logging/vst3.cpp',
|
||||||
|
'src/common/serialization/vst3/component.cpp',
|
||||||
'src/common/serialization/vst3/plugin-factory.cpp',
|
'src/common/serialization/vst3/plugin-factory.cpp',
|
||||||
'src/wine-host/bridges/vst3.cpp',
|
'src/wine-host/bridges/vst3.cpp',
|
||||||
'src/wine-host/bridges/vst3-impls.cpp',
|
'src/wine-host/bridges/vst3-impls.cpp',
|
||||||
|
|||||||
@@ -56,20 +56,26 @@ void Vst3Logger::log_request(bool is_host_vst, const WantsPluginFactory&) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vst3Logger::log_response(bool is_host_vst, const Configuration&) {
|
void Vst3Logger::log_response(
|
||||||
|
bool is_host_vst,
|
||||||
|
const std::optional<YaComponent::Arguments>& args) {
|
||||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||||
std::ostringstream message;
|
std::ostringstream message;
|
||||||
message << get_log_prefix(is_host_vst) << " <Configuration>";
|
if (args) {
|
||||||
|
message << get_log_prefix(is_host_vst) << " <IComponent* #"
|
||||||
|
<< args->instance_id << ">";
|
||||||
|
} else {
|
||||||
|
message << get_log_prefix(is_host_vst) << " <nullptr>";
|
||||||
|
}
|
||||||
|
|
||||||
log(message.str());
|
log(message.str());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
void Vst3Logger::log_response(bool is_host_vst, const YaComponent&) {
|
void Vst3Logger::log_response(bool is_host_vst, const Configuration&) {
|
||||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||||
std::ostringstream message;
|
std::ostringstream message;
|
||||||
// TODO: Add the instance ID after we implement that
|
message << get_log_prefix(is_host_vst) << " <Configuration>";
|
||||||
message << get_log_prefix(is_host_vst) << " <IComponent*>";
|
|
||||||
|
|
||||||
log(message.str());
|
log(message.str());
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -49,8 +49,9 @@ class Vst3Logger {
|
|||||||
void log_request(bool is_host_vst, const WantsConfiguration&);
|
void log_request(bool is_host_vst, const WantsConfiguration&);
|
||||||
void log_request(bool is_host_vst, const WantsPluginFactory&);
|
void log_request(bool is_host_vst, const WantsPluginFactory&);
|
||||||
|
|
||||||
|
void log_response(bool is_host_vst,
|
||||||
|
const std::optional<YaComponent::Arguments>&);
|
||||||
void log_response(bool is_host_vst, const Configuration&);
|
void log_response(bool is_host_vst, const Configuration&);
|
||||||
void log_response(bool is_host_vst, const YaComponent&);
|
|
||||||
void log_response(bool is_host_vst, const YaPluginFactory&);
|
void log_response(bool is_host_vst, const YaPluginFactory&);
|
||||||
|
|
||||||
Logger& logger;
|
Logger& logger;
|
||||||
|
|||||||
@@ -3,6 +3,12 @@
|
|||||||
TODO: Once this is more fleshed out, move this document to `docs/`, and perhaps
|
TODO: Once this is more fleshed out, move this document to `docs/`, and perhaps
|
||||||
replace this readme with a link to that document.
|
replace this readme with a link to that document.
|
||||||
|
|
||||||
|
TODO: There are now two approaches in use: the factory takes an interface
|
||||||
|
pointer for serialization and deserializes into an object directly, and the
|
||||||
|
component uses an args struct because the alternative involving pointers is just
|
||||||
|
too unsafe (as we also have to communicate additional payload data). This should
|
||||||
|
probably be unified into only using the latter appraoch.
|
||||||
|
|
||||||
The VST3 SDK uses an architecture where every object inherits from an interface,
|
The VST3 SDK uses an architecture where every object inherits from an interface,
|
||||||
and every interface inherits from `FUnknown` which offers a dynamic casting
|
and every interface inherits from `FUnknown` which offers a dynamic casting
|
||||||
interface through `queryInterface()`. Every interface gets a unique identifier.
|
interface through `queryInterface()`. Every interface gets a unique identifier.
|
||||||
|
|||||||
@@ -16,14 +16,19 @@
|
|||||||
|
|
||||||
#include "component.h"
|
#include "component.h"
|
||||||
|
|
||||||
YaComponent::YaComponent(){FUNKNOWN_CTOR}
|
YaComponent::Arguments::Arguments(
|
||||||
|
Steinberg::IPtr<Steinberg::Vst::IComponent> component,
|
||||||
YaComponent::YaComponent(
|
size_t instance_id)
|
||||||
Steinberg::IPtr<Steinberg::Vst::IComponent> component) {
|
: instance_id(instance_id) {
|
||||||
FUNKNOWN_CTOR
|
|
||||||
|
|
||||||
// `IComponent::getControllerClassId`
|
// `IComponent::getControllerClassId`
|
||||||
component->getControllerClassId(edit_controller_cid);
|
Steinberg::TUID cid;
|
||||||
|
if (component->getControllerClassId(cid) == Steinberg::kResultOk) {
|
||||||
|
edit_controller_cid = std::to_array(cid);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
YaComponent::YaComponent(const Arguments&& args) : arguments(std::move(args)) {
|
||||||
|
FUNKNOWN_CTOR
|
||||||
|
|
||||||
// Everything else is handled directly through callbacks to minimize the
|
// Everything else is handled directly through callbacks to minimize the
|
||||||
// potential for errors
|
// potential for errors
|
||||||
@@ -49,3 +54,13 @@ tresult PLUGIN_API YaComponent::queryInterface(Steinberg::FIDString _iid,
|
|||||||
*obj = nullptr;
|
*obj = nullptr;
|
||||||
return Steinberg::kNoInterface;
|
return Steinberg::kNoInterface;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
tresult PLUGIN_API YaComponent::getControllerClassId(Steinberg::TUID classId) {
|
||||||
|
if (arguments.edit_controller_cid) {
|
||||||
|
std::copy(arguments.edit_controller_cid->begin(),
|
||||||
|
arguments.edit_controller_cid->end(), classId);
|
||||||
|
return Steinberg::kResultOk;
|
||||||
|
} else {
|
||||||
|
return Steinberg::kNotImplemented;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|||||||
@@ -16,9 +16,15 @@
|
|||||||
|
|
||||||
#pragma once
|
#pragma once
|
||||||
|
|
||||||
|
#include <optional>
|
||||||
|
#include "src/common/serialization/common.h"
|
||||||
|
|
||||||
|
#include <bitsery/ext/pointer.h>
|
||||||
|
#include <bitsery/ext/std_optional.h>
|
||||||
|
#include <bitsery/traits/array.h>
|
||||||
#include <pluginterfaces/vst/ivstcomponent.h>
|
#include <pluginterfaces/vst/ivstcomponent.h>
|
||||||
|
|
||||||
using Steinberg::TBool, Steinberg::int32, Steinberg::tresult;
|
using Steinberg::TBool, Steinberg::int8, Steinberg::int32, Steinberg::tresult;
|
||||||
|
|
||||||
#pragma GCC diagnostic push
|
#pragma GCC diagnostic push
|
||||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||||
@@ -36,14 +42,44 @@ using Steinberg::TBool, Steinberg::int32, Steinberg::tresult;
|
|||||||
class YaComponent : public Steinberg::Vst::IComponent {
|
class YaComponent : public Steinberg::Vst::IComponent {
|
||||||
public:
|
public:
|
||||||
/**
|
/**
|
||||||
* Request the Wine plugin host to instantiate a new IComponent to pass
|
* These are the arguments for creating a `YaComponentPluginImpl`.
|
||||||
* through a call to `IPluginFactory::createInstance(cid, IComponent::iid,
|
*/
|
||||||
|
struct Arguments {
|
||||||
|
/**
|
||||||
|
* Read arguments from an existing implementation.
|
||||||
|
*/
|
||||||
|
Arguments(Steinberg::IPtr<Steinberg::Vst::IComponent> component,
|
||||||
|
size_t isntance_id);
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The unique identifier for this specific instance.
|
||||||
|
*/
|
||||||
|
native_size_t instance_id;
|
||||||
|
|
||||||
|
/**
|
||||||
|
* The class ID of this component's corresponding editor controller. You
|
||||||
|
* can't use C-style array in `std::optional`s.
|
||||||
|
*/
|
||||||
|
std::optional<std::array<int8, std::extent_v<Steinberg::TUID>>>
|
||||||
|
edit_controller_cid;
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
void serialize(S& s) {
|
||||||
|
s.value8b(instance_id);
|
||||||
|
s.ext(edit_controller_cid, bitsery::ext::StdOptional{},
|
||||||
|
[](S& s, auto& cid) { s.container1b(cid); });
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
/**
|
||||||
|
* Message to request the Wine plugin host to instantiate a new IComponent
|
||||||
|
* to pass through a call to `IPluginFactory::createInstance(cid,
|
||||||
|
* IComponent::iid,
|
||||||
* ...)`.
|
* ...)`.
|
||||||
*/
|
*/
|
||||||
struct Create {
|
struct Create {
|
||||||
// TODO: This should be `std::optional<YaComponent>`, and we need a way
|
// TODO: Create a `native_tvalue` wrapper, and then also add them here
|
||||||
// to deserialize that into an existing YaComponent.
|
using Response = std::optional<Arguments>;
|
||||||
using Response = YaComponent&;
|
|
||||||
|
|
||||||
Steinberg::TUID cid;
|
Steinberg::TUID cid;
|
||||||
|
|
||||||
@@ -53,12 +89,11 @@ class YaComponent : public Steinberg::Vst::IComponent {
|
|||||||
}
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
YaComponent();
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* Create a copy of an existing component.
|
* Instantiate this instance with arguments read from another interface
|
||||||
|
* implementation.
|
||||||
*/
|
*/
|
||||||
explicit YaComponent(Steinberg::IPtr<Steinberg::Vst::IComponent> component);
|
YaComponent(const Arguments&& args);
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* @remark The plugin side implementation should send a control message to
|
* @remark The plugin side implementation should send a control message to
|
||||||
@@ -97,19 +132,16 @@ class YaComponent : public Steinberg::Vst::IComponent {
|
|||||||
virtual tresult PLUGIN_API
|
virtual tresult PLUGIN_API
|
||||||
getState(Steinberg::IBStream* state) override = 0;
|
getState(Steinberg::IBStream* state) override = 0;
|
||||||
|
|
||||||
template <typename S>
|
|
||||||
void serialize(S& s) {
|
|
||||||
s.container1b(edit_controller_cid);
|
|
||||||
}
|
|
||||||
|
|
||||||
private:
|
private:
|
||||||
/**
|
Arguments arguments;
|
||||||
* The class ID of this component's corresponding editor controller.
|
|
||||||
*/
|
|
||||||
Steinberg::TUID edit_controller_cid;
|
|
||||||
|
|
||||||
// TODO: As explained in a few other places, `YaComponent` objects should be
|
// TODO: As explained in a few other places, `YaComponent` objects should be
|
||||||
// assigned a unique ID for identification
|
// assigned a unique ID for identification
|
||||||
};
|
};
|
||||||
|
|
||||||
|
template <typename S>
|
||||||
|
void serialize(S& s, std::optional<YaComponent::Arguments>& args) {
|
||||||
|
s.ext(args, bitsery::ext::StdOptional{});
|
||||||
|
}
|
||||||
|
|
||||||
#pragma GCC diagnostic pop
|
#pragma GCC diagnostic pop
|
||||||
|
|||||||
@@ -66,17 +66,13 @@ void Vst3Bridge::run() {
|
|||||||
// ID to that.
|
// ID to that.
|
||||||
// - Add that ID to `YaComponent` and set it in the object
|
// - Add that ID to `YaComponent` and set it in the object
|
||||||
// we create here.
|
// we create here.
|
||||||
// - In case `factory` is a null pointer, allow returning
|
if (component) {
|
||||||
// `nullopt`. Not sure how that is going to work with
|
// TODO: Generate a unique instance ID
|
||||||
// the deserialization.
|
return std::make_optional<YaComponent::Arguments>(
|
||||||
if (!component) {
|
component, 420691337);
|
||||||
// TODO: Handle
|
} else {
|
||||||
|
return std::nullopt;
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Implement `YaComponentHostImpl` and create an instance
|
|
||||||
// based on `component`
|
|
||||||
YaComponent* removeme = nullptr;
|
|
||||||
return *removeme;
|
|
||||||
},
|
},
|
||||||
[&](const WantsPluginFactory&) -> WantsPluginFactory::Response {
|
[&](const WantsPluginFactory&) -> WantsPluginFactory::Response {
|
||||||
return *plugin_factory;
|
return *plugin_factory;
|
||||||
|
|||||||
Reference in New Issue
Block a user