mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
Add the base for an IComponent implementation
This commit is contained in:
@@ -24,6 +24,18 @@
|
||||
|
||||
Vst3Logger::Vst3Logger(Logger& generic_logger) : logger(generic_logger) {}
|
||||
|
||||
void Vst3Logger::log_request(bool is_host_vst, const CreateInstaneIComponent&) {
|
||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||
std::ostringstream message;
|
||||
// TODO: Log the cid in some readable way, if possible
|
||||
message << get_log_prefix(is_host_vst)
|
||||
<< " >> IPluginFactory::createComponent(cid, IComponent::iid, "
|
||||
"&obj)";
|
||||
|
||||
log(message.str());
|
||||
}
|
||||
}
|
||||
|
||||
void Vst3Logger::log_request(bool is_host_vst, const WantsConfiguration&) {
|
||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||
std::ostringstream message;
|
||||
@@ -53,6 +65,16 @@ void Vst3Logger::log_response(bool is_host_vst, const Configuration&) {
|
||||
}
|
||||
}
|
||||
|
||||
void Vst3Logger::log_response(bool is_host_vst, const YaComponent&) {
|
||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||
std::ostringstream message;
|
||||
// TODO: Add the instance ID after we implement that
|
||||
message << get_log_prefix(is_host_vst) << " <IComponent*>";
|
||||
|
||||
log(message.str());
|
||||
}
|
||||
}
|
||||
|
||||
void Vst3Logger::log_response(bool is_host_vst,
|
||||
const YaPluginFactory& factory) {
|
||||
if (BOOST_UNLIKELY(logger.verbosity >= Logger::Verbosity::most_events)) {
|
||||
|
||||
@@ -45,10 +45,12 @@ class Vst3Logger {
|
||||
// flag here indicates whether the request was initiated on the host side
|
||||
// (what we'll call a control message).
|
||||
|
||||
void log_request(bool is_host_vst, const CreateInstaneIComponent&);
|
||||
void log_request(bool is_host_vst, const WantsConfiguration&);
|
||||
void log_request(bool is_host_vst, const WantsPluginFactory&);
|
||||
|
||||
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&);
|
||||
|
||||
Logger& logger;
|
||||
|
||||
@@ -23,6 +23,7 @@
|
||||
#include "../configuration.h"
|
||||
#include "../utils.h"
|
||||
#include "common.h"
|
||||
#include "vst3/component.h"
|
||||
#include "vst3/plugin-factory.h"
|
||||
|
||||
// Event handling for our VST3 plugins works slightly different from how we
|
||||
@@ -37,6 +38,21 @@
|
||||
// TODO: If this approach works, maybe we can also refactor the VST2 handling to
|
||||
// do this since it's a bit safer and easier to read
|
||||
|
||||
/**
|
||||
* Request the Wine plugin host to instantiate a new IComponent to pass through
|
||||
* a call to `IPluginFactory::createInstance(cid, IComponent::iid, ...)`.
|
||||
*/
|
||||
struct CreateInstaneIComponent {
|
||||
using Response = YaComponent&;
|
||||
|
||||
Steinberg::TUID cid;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
s.container1b(cid);
|
||||
}
|
||||
};
|
||||
|
||||
/**
|
||||
* Marker struct to indicate the other side (the plugin) should send a copy of
|
||||
* the configuration.
|
||||
@@ -64,7 +80,8 @@ struct WantsPluginFactory {
|
||||
* encodes the information we request or the operation we want to perform. A
|
||||
* request of type `ControlRequest(T)` should send back a `T::Response`.
|
||||
*/
|
||||
using ControlRequest = std::variant<WantsPluginFactory>;
|
||||
using ControlRequest =
|
||||
std::variant<CreateInstaneIComponent, WantsPluginFactory>;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s, ControlRequest& payload) {
|
||||
|
||||
@@ -50,7 +50,7 @@ instantiated and managed by the host. The model works as follows:
|
||||
|
||||
## Plugin Factory
|
||||
|
||||
TODO: Explain how we implement `createInstance()`
|
||||
TODO: Explain how we implement `createInstance()`, based on the todo comment there.
|
||||
|
||||
## Safety notes
|
||||
|
||||
|
||||
@@ -0,0 +1,51 @@
|
||||
// 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 "component.h"
|
||||
|
||||
YaComponent::YaComponent(){FUNKNOWN_CTOR}
|
||||
|
||||
YaComponent::YaComponent(
|
||||
Steinberg::IPtr<Steinberg::Vst::IComponent> component) {
|
||||
FUNKNOWN_CTOR
|
||||
|
||||
// `IComponent::getControllerClassId`
|
||||
component->getControllerClassId(edit_controller_cid);
|
||||
|
||||
// Everything else is handled directly through callbacks to minimize the
|
||||
// potential for errors
|
||||
}
|
||||
|
||||
YaComponent::~YaComponent() {
|
||||
FUNKNOWN_DTOR
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wdelete-non-virtual-dtor"
|
||||
IMPLEMENT_REFCOUNT(YaComponent)
|
||||
#pragma GCC diagnostic pop
|
||||
|
||||
tresult PLUGIN_API YaComponent::queryInterface(Steinberg::FIDString _iid,
|
||||
void** obj) {
|
||||
QUERY_INTERFACE(_iid, obj, Steinberg::FUnknown::iid, Steinberg::IPluginBase)
|
||||
QUERY_INTERFACE(_iid, obj, Steinberg::IPluginBase::iid,
|
||||
Steinberg::IPluginBase)
|
||||
QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IComponent::iid,
|
||||
Steinberg::Vst::IComponent)
|
||||
|
||||
*obj = nullptr;
|
||||
return Steinberg::kNoInterface;
|
||||
}
|
||||
@@ -0,0 +1,93 @@
|
||||
// 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 <pluginterfaces/vst/ivstcomponent.h>
|
||||
|
||||
using Steinberg::TBool, Steinberg::int32, Steinberg::tresult;
|
||||
|
||||
#pragma GCC diagnostic push
|
||||
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
|
||||
|
||||
/**
|
||||
* Wraps around `IComponent` for serialization purposes. See `README.md` for
|
||||
* more information on how this works. On the Wine plugin host side this is only
|
||||
* used for serialization, and on the plugin side have an implementation that
|
||||
* can send control messages.
|
||||
*
|
||||
* We might be able to do some caching here with the buss infos, but since that
|
||||
* sounds like a huge potential source of errors we'll just do pure callbacks
|
||||
* for everything other than the edit controller's class ID.
|
||||
*/
|
||||
class YaComponent : public Steinberg::Vst::IComponent {
|
||||
public:
|
||||
YaComponent();
|
||||
|
||||
/**
|
||||
* Create a copy of an existing component.
|
||||
*/
|
||||
explicit YaComponent(Steinberg::IPtr<Steinberg::Vst::IComponent> component);
|
||||
|
||||
virtual ~YaComponent();
|
||||
|
||||
DECLARE_FUNKNOWN_METHODS
|
||||
|
||||
// From `IPluginBase`
|
||||
virtual tresult PLUGIN_API initialize(FUnknown* context) override = 0;
|
||||
virtual tresult PLUGIN_API terminate() override = 0;
|
||||
|
||||
// From `IComponent`
|
||||
tresult PLUGIN_API getControllerClassId(Steinberg::TUID classId) override;
|
||||
virtual tresult PLUGIN_API
|
||||
setIoMode(Steinberg::Vst::IoMode mode) override = 0;
|
||||
virtual int32 PLUGIN_API
|
||||
getBusCount(Steinberg::Vst::MediaType type,
|
||||
Steinberg::Vst::BusDirection dir) override = 0;
|
||||
virtual tresult PLUGIN_API
|
||||
getBusInfo(Steinberg::Vst::MediaType type,
|
||||
Steinberg::Vst::BusDirection dir,
|
||||
int32 index,
|
||||
Steinberg::Vst::BusInfo& bus /*out*/) override = 0;
|
||||
virtual tresult PLUGIN_API
|
||||
getRoutingInfo(Steinberg::Vst::RoutingInfo& inInfo,
|
||||
Steinberg::Vst::RoutingInfo& outInfo /*out*/) override = 0;
|
||||
virtual tresult PLUGIN_API activateBus(Steinberg::Vst::MediaType type,
|
||||
Steinberg::Vst::BusDirection dir,
|
||||
int32 index,
|
||||
TBool state) override = 0;
|
||||
virtual tresult PLUGIN_API setActive(TBool state) override = 0;
|
||||
virtual tresult PLUGIN_API
|
||||
setState(Steinberg::IBStream* state) override = 0;
|
||||
virtual tresult PLUGIN_API
|
||||
getState(Steinberg::IBStream* state) override = 0;
|
||||
|
||||
template <typename S>
|
||||
void serialize(S& s) {
|
||||
s.container1b(edit_controller_cid);
|
||||
}
|
||||
|
||||
private:
|
||||
/**
|
||||
* 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
|
||||
// assigned a unique ID for identification
|
||||
};
|
||||
|
||||
#pragma GCC diagnostic pop
|
||||
@@ -44,8 +44,7 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 {
|
||||
YaPluginFactory();
|
||||
|
||||
/**
|
||||
* Create a copy of an existing plugin factory. Depending on the
|
||||
supported
|
||||
* Create a copy of an existing plugin factory. Depending on the supported
|
||||
* interface function more or less of this struct will be left empty, and
|
||||
* `iid` will be set accordingly.
|
||||
*/
|
||||
@@ -61,17 +60,10 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 {
|
||||
int32 PLUGIN_API countClasses() override;
|
||||
tresult PLUGIN_API getClassInfo(Steinberg::int32 index,
|
||||
Steinberg::PClassInfo* info) 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.
|
||||
/**
|
||||
* See the implementation in `YaPluginFactoryPluginImpl` for how this is
|
||||
* handled.
|
||||
*/
|
||||
virtual tresult PLUGIN_API createInstance(Steinberg::FIDString cid,
|
||||
Steinberg::FIDString _iid,
|
||||
void** obj) override = 0;
|
||||
@@ -83,6 +75,10 @@ class YaPluginFactory : public Steinberg::IPluginFactory3 {
|
||||
// From `IPluginFactory3`
|
||||
tresult PLUGIN_API
|
||||
getClassInfoUnicode(int32 index, Steinberg::PClassInfoW* info) override;
|
||||
/**
|
||||
* We'll pass a `IHostApplication` to the Windows VST3 plugin's factory when
|
||||
* this is called so it can send messages.
|
||||
*/
|
||||
virtual tresult PLUGIN_API
|
||||
setHostContext(Steinberg::FUnknown* context) override = 0;
|
||||
|
||||
|
||||
@@ -51,6 +51,33 @@ void Vst3Bridge::run() {
|
||||
sockets.host_vst_control.receive_messages(
|
||||
std::nullopt,
|
||||
overload{
|
||||
[&](const CreateInstaneIComponent& args)
|
||||
-> CreateInstaneIComponent::Response {
|
||||
Steinberg::IPtr<Steinberg::Vst::IComponent> component =
|
||||
module->getFactory()
|
||||
.createInstance<Steinberg::Vst::IComponent>(args.cid);
|
||||
|
||||
// TODO: Next steps are:
|
||||
// - Generate a new unique ID using an atomic size_t and
|
||||
// fetch-and-add.
|
||||
// - Add an `std::map<size_t,
|
||||
// Steinberg::IPtr<Steinberg::Vst::IComponent>`
|
||||
// to this class and add `component` with the generated
|
||||
// ID to that.
|
||||
// - Add that ID to `YaComponent` and set it in the object
|
||||
// we create here.
|
||||
// - In case `factory` is a null pointer, allow returning
|
||||
// `nullopt`. Not sure how that is going to work with
|
||||
// the deserialization.
|
||||
if (!component) {
|
||||
// TODO: Handle
|
||||
}
|
||||
|
||||
// TODO: Implement `YaComponentHostImpl` and create an instance
|
||||
// based on `component`
|
||||
YaComponent* removeme = nullptr;
|
||||
return *removeme;
|
||||
},
|
||||
[&](const WantsPluginFactory&) -> WantsPluginFactory::Response {
|
||||
return *plugin_factory;
|
||||
}});
|
||||
|
||||
Reference in New Issue
Block a user