Split YaAudioProcessor from YaComponent

Now all that's left is splitting YaComponent into the IComponent bits
and separate YaPluginMonlith that implements everything.
This commit is contained in:
Robbert van der Helm
2020-12-17 00:28:23 +01:00
parent 602bbc5d35
commit d6c28f48d9
12 changed files with 634 additions and 532 deletions
+2
View File
@@ -77,6 +77,7 @@ vst3_plugin_sources = [
'src/common/communication/common.cpp',
'src/common/logging/common.cpp',
'src/common/logging/vst3.cpp',
'src/common/serialization/vst3/audio-processor.cpp',
'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/event-list.cpp',
@@ -117,6 +118,7 @@ host_sources = [
if with_vst3
host_sources += [
'src/common/logging/vst3.cpp',
'src/common/serialization/vst3/audio-processor.cpp',
'src/common/serialization/vst3/base.cpp',
'src/common/serialization/vst3/component.cpp',
'src/common/serialization/vst3/event-list.cpp',
+98 -97
View File
@@ -36,6 +36,82 @@ void Vst3Logger::log_unknown_interface(
}
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetBusArrangements& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setBusArrangements(inputs = [SpeakerArrangement; "
<< request.inputs.size() << "], numIns = " << request.num_ins
<< ", outputs = [SpeakerArrangement; " << request.outputs.size()
<< "], numOuts = " << request.num_outs << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetBusArrangement& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getBusArrangement(dir = " << request.dir
<< ", index = " << request.index << ", &arr)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::CanProcessSampleSize& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::canProcessSampleSize(symbolicSampleSize = "
<< request.symbolic_sample_size << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetLatencySamples& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getLatencySamples()";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetupProcessing& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setupProcessing(setup = <SetupProcessing with mode = "
<< request.setup.processMode << ", symbolic_sample_size = "
<< request.setup.symbolicSampleSize
<< ", max_buffer_size = " << request.setup.maxSamplesPerBlock
<< " and sample_rate = " << request.setup.sampleRate << ">)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetProcessing& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setProcessing(state = "
<< (request.state ? "true" : "false") << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::Process& request) {
// TODO: Only log this on log level 2
log_request_base(is_host_vst, [&](auto& message) {
// TODO: Log about the process data
message << "<IAudioProcessor* #" << request.instance_id
<< ">::process(TODO)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetTailSamples& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getTailSamples()";
});
}
void Vst3Logger::log_request(bool is_host_vst, const YaComponent::Construct&) {
log_request_base(is_host_vst, [&](auto& message) {
// TODO: Log the CID on verbosity level 2, and then also report all CIDs
@@ -130,82 +206,6 @@ void Vst3Logger::log_request(bool is_host_vst,
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetBusArrangements& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setBusArrangements(inputs = [SpeakerArrangement; "
<< request.inputs.size() << "], numIns = " << request.num_ins
<< ", outputs = [SpeakerArrangement; " << request.outputs.size()
<< "], numOuts = " << request.num_outs << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetBusArrangement& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getBusArrangement(dir = " << request.dir
<< ", index = " << request.index << ", &arr)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::CanProcessSampleSize& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::canProcessSampleSize(symbolicSampleSize = "
<< request.symbolic_sample_size << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetLatencySamples& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getLatencySamples()";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetupProcessing& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setupProcessing(setup = <SetupProcessing with mode = "
<< request.setup.processMode << ", symbolic_sample_size = "
<< request.setup.symbolicSampleSize
<< ", max_buffer_size = " << request.setup.maxSamplesPerBlock
<< " and sample_rate = " << request.setup.sampleRate << ">)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::SetProcessing& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::setProcessing(state = "
<< (request.state ? "true" : "false") << ")";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::Process& request) {
// TODO: Only log this on log level 2
log_request_base(is_host_vst, [&](auto& message) {
// TODO: Log about the process data
message << "<IAudioProcessor* #" << request.instance_id
<< ">::process(TODO)";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaComponent::GetTailSamples& request) {
log_request_base(is_host_vst, [&](auto& message) {
message << "<IAudioProcessor* #" << request.instance_id
<< ">::getTailSamples()";
});
}
void Vst3Logger::log_request(bool is_host_vst,
const YaPluginBase::Initialize& request) {
log_request_base(is_host_vst, [&](auto& message) {
@@ -246,6 +246,28 @@ void Vst3Logger::log_request(bool is_host_vst, const WantsConfiguration&) {
});
}
void Vst3Logger::log_response(
bool is_host_vst,
const YaAudioProcessor::GetBusArrangementResponse& response) {
log_response_base(is_host_vst, [&](auto& message) {
message << response.result.string();
if (response.result == Steinberg::kResultOk) {
message << ", <SpeakerArrangement>";
}
});
}
void Vst3Logger::log_response(
bool is_host_vst,
const YaAudioProcessor::ProcessResponse& response) {
// TODO: Only log this on verbosity level 2
log_response_base(is_host_vst, [&](auto& message) {
message << response.result.string();
// TODO: Log response
});
}
void Vst3Logger::log_response(bool is_host_vst, const Ack&) {
log_response_base(is_host_vst, [&](auto& message) { message << "ACK"; });
}
@@ -302,27 +324,6 @@ void Vst3Logger::log_response(bool is_host_vst,
});
}
void Vst3Logger::log_response(
bool is_host_vst,
const YaComponent::GetBusArrangementResponse& response) {
log_response_base(is_host_vst, [&](auto& message) {
message << response.result.string();
if (response.result == Steinberg::kResultOk) {
message << ", <SpeakerArrangement>";
}
});
}
void Vst3Logger::log_response(bool is_host_vst,
const YaComponent::ProcessResponse& response) {
// TODO: Only log this on verbosity level 2
log_response_base(is_host_vst, [&](auto& message) {
message << response.result.string();
// TODO: Log response
});
}
void Vst3Logger::log_response(bool is_host_vst,
const YaPluginFactory::ConstructArgs& args) {
log_response_base(is_host_vst, [&](auto& message) {
+17 -12
View File
@@ -56,6 +56,19 @@ 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 YaAudioProcessor::SetBusArrangements&);
void log_request(bool is_host_vst,
const YaAudioProcessor::GetBusArrangement&);
void log_request(bool is_host_vst,
const YaAudioProcessor::CanProcessSampleSize&);
void log_request(bool is_host_vst,
const YaAudioProcessor::GetLatencySamples&);
void log_request(bool is_host_vst,
const YaAudioProcessor::SetupProcessing&);
void log_request(bool is_host_vst, const YaAudioProcessor::SetProcessing&);
void log_request(bool is_host_vst, const YaAudioProcessor::Process&);
void log_request(bool is_host_vst, const YaAudioProcessor::GetTailSamples&);
void log_request(bool is_host_vst, const YaComponent::Construct&);
void log_request(bool is_host_vst, const YaComponent::Destruct&);
void log_request(bool is_host_vst, const YaComponent::SetIoMode&);
@@ -66,15 +79,6 @@ class Vst3Logger {
void log_request(bool is_host_vst, const YaComponent::SetActive&);
void log_request(bool is_host_vst, const YaComponent::SetState&);
void log_request(bool is_host_vst, const YaComponent::GetState&);
void log_request(bool is_host_vst, const YaComponent::SetBusArrangements&);
void log_request(bool is_host_vst, const YaComponent::GetBusArrangement&);
void log_request(bool is_host_vst,
const YaComponent::CanProcessSampleSize&);
void log_request(bool is_host_vst, const YaComponent::GetLatencySamples&);
void log_request(bool is_host_vst, const YaComponent::SetupProcessing&);
void log_request(bool is_host_vst, const YaComponent::SetProcessing&);
void log_request(bool is_host_vst, const YaComponent::Process&);
void log_request(bool is_host_vst, const YaComponent::GetTailSamples&);
void log_request(bool is_host_vst, const YaPluginBase::Initialize&);
void log_request(bool is_host_vst, const YaPluginBase::Terminate&);
void log_request(bool is_host_vst, const YaPluginFactory::Construct&);
@@ -82,6 +86,10 @@ class Vst3Logger {
void log_request(bool is_host_vst, const WantsConfiguration&);
void log_response(bool is_host_vst, const Ack&);
void log_response(bool is_host_vst,
const YaAudioProcessor::GetBusArrangementResponse&);
void log_response(bool is_host_vst,
const YaAudioProcessor::ProcessResponse&);
void log_response(
bool is_host_vst,
const std::variant<YaComponent::ConstructArgs, UniversalTResult>&);
@@ -89,9 +97,6 @@ class Vst3Logger {
void log_response(bool is_host_vst,
const YaComponent::GetRoutingInfoResponse&);
void log_response(bool is_host_vst, const YaComponent::GetStateResponse&);
void log_response(bool is_host_vst,
const YaComponent::GetBusArrangementResponse&);
void log_response(bool is_host_vst, const YaComponent::ProcessResponse&);
void log_response(bool is_host_vst, const YaPluginFactory::ConstructArgs&);
void log_response(bool is_host_vst, const Configuration&);
+3 -2
View File
@@ -9,9 +9,10 @@ VST3 interfaces are implemented as follows:
| Yabridge class | Included in | Interfaces |
| ------------------- | ------------- | ------------------------------------------------------ |
| `YaComponent` | | `IComponent`, `IAudioProcessor` |
| `YaHostApplication` | | `iHostAPplication` |
| `YaComponent` | | `IComponent` |
| `YaAudioProcessor` | `YaComponent` | `IAudioProcessor` |
| `YaPluginBase` | `YaComponent` | `IPluginBase` |
| `YaHostApplication` | | `iHostAPplication` |
| `YaPluginFactory` | | `IPluginFactory`, `IPluginFactory2`, `IPluginFactory3` |
The following interfaces are implemented purely fur serialization purposes:
@@ -0,0 +1,27 @@
// 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 "audio-processor.h"
YaAudioProcessor::ConstructArgs::ConstructArgs() {}
YaAudioProcessor::ConstructArgs::ConstructArgs(
Steinberg::IPtr<Steinberg::FUnknown> component)
: supported(
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor>(component)) {}
YaAudioProcessor::YaAudioProcessor(const ConstructArgs&& args)
: arguments(std::move(args)) {}
@@ -0,0 +1,314 @@
// 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 <bitsery/ext/std_optional.h>
#include <pluginterfaces/vst/ivstaudioprocessor.h>
#include "../common.h"
#include "base.h"
#include "host-application.h"
#include "process-data.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
/**
* Wraps around `IAudioProcessor` for serialization purposes. This is
* instantiated as part of `YaComponent`.
*/
class YaAudioProcessor : public Steinberg::Vst::IAudioProcessor {
public:
/**
* These are the arguments for creating a `YaAudioProcessor`.
*/
struct ConstructArgs {
ConstructArgs();
/**
* Check whether an existing implementation implements `IPluginBase` and
* read arguments from it.
*/
ConstructArgs(Steinberg::IPtr<Steinberg::FUnknown> object);
/**
* Whether the object supported this interface.
*/
bool supported;
template <typename S>
void serialize(S& s) {
s.value1b(supported);
}
};
/**
* Instantiate this instance with arguments read from another interface
* implementation.
*/
YaAudioProcessor(const ConstructArgs&& args);
inline bool supported() { return arguments.supported; }
/**
* Message to pass through a call to
* `IAudioProcessor::setBusArrangements(inputs, num_ins, outputs, num_outs)`
* to the Wine plugin host.
*/
struct SetBusArrangements {
using Response = UniversalTResult;
native_size_t instance_id;
// These are orginally C-style heap arrays, not normal pointers
std::vector<Steinberg::Vst::SpeakerArrangement> inputs;
int32 num_ins;
std::vector<Steinberg::Vst::SpeakerArrangement> outputs;
int32 num_outs;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.container8b(inputs, max_num_speakers);
s.value4b(num_ins);
s.container8b(outputs, max_num_speakers);
s.value4b(num_outs);
}
};
virtual tresult PLUGIN_API
setBusArrangements(Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) override = 0;
/**
* The response code and written state for a call to
* `IAudioProcessor::getBusArrangement(dir, index, arr)`.
*/
struct GetBusArrangementResponse {
UniversalTResult result;
Steinberg::Vst::SpeakerArrangement updated_arr;
template <typename S>
void serialize(S& s) {
s.object(result);
s.value8b(updated_arr);
}
};
/**
* Message to pass through a call to
* `IAudioProcessor::getBusArrangement(dir, index, arr)` to the Wine
* plugin host.
*/
struct GetBusArrangement {
using Response = GetBusArrangementResponse;
native_size_t instance_id;
Steinberg::Vst::BusDirection dir;
int32 index;
Steinberg::Vst::SpeakerArrangement arr;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value4b(dir);
s.value4b(index);
s.value8b(arr);
}
};
virtual tresult PLUGIN_API
getBusArrangement(Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) override = 0;
/**
* Message to pass through a call to
* `IAudioProcessor::canProcessSampleSize(symbolic_sample_size)` to the Wine
* plugin host.
*/
struct CanProcessSampleSize {
using Response = UniversalTResult;
native_size_t instance_id;
int32 symbolic_sample_size;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value4b(symbolic_sample_size);
}
};
virtual tresult PLUGIN_API
canProcessSampleSize(int32 symbolicSampleSize) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::getLatencySamples()`
* to the Wine plugin host.
*/
struct GetLatencySamples {
using Response = PrimitiveWrapper<uint32>;
native_size_t instance_id;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
}
};
virtual uint32 PLUGIN_API getLatencySamples() override = 0;
/**
* Message to pass through a call to
* `IAudioProcessor::setupProcessing(setup)` to the Wine plugin host.
*/
struct SetupProcessing {
using Response = UniversalTResult;
native_size_t instance_id;
Steinberg::Vst::ProcessSetup setup;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.object(setup);
}
};
virtual tresult PLUGIN_API
setupProcessing(Steinberg::Vst::ProcessSetup& setup) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::setProcessing(state)`
* to the Wine plugin host.
*/
struct SetProcessing {
using Response = UniversalTResult;
native_size_t instance_id;
TBool state;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value1b(state);
}
};
virtual tresult PLUGIN_API setProcessing(TBool state) override = 0;
/**
* The response code and all the output data resulting from a call to
* `IAudioProcessor::process(data)`.
*/
struct ProcessResponse {
UniversalTResult result;
YaProcessDataResponse output_data;
template <typename S>
void serialize(S& s) {
s.object(result);
s.object(output_data);
}
};
/**
* Message to pass through a call to `IAudioProcessor::process(data)` to the
* Wine plugin host. This `YaProcessData` object wraps around all input
* audio buffers, parameter changes and events along with all context data
* provided by the host so we can send it to the Wine plugin host. We can
* then use `YaProcessData::get()` on the Wine plugin host side to
* reconstruct the original `ProcessData` object, and we then finally use
* `YaProcessData::move_outputs_to_response()` to create a response object
* that we can write back to the `ProcessData` object provided by the host.
*/
struct Process {
using Response = ProcessResponse;
native_size_t instance_id;
YaProcessData data;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.object(data);
}
};
virtual tresult PLUGIN_API
process(Steinberg::Vst::ProcessData& data) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::getTailSamples()`
* to the Wine plugin host.
*/
struct GetTailSamples {
using Response = PrimitiveWrapper<uint32>;
native_size_t instance_id;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
}
};
virtual uint32 PLUGIN_API getTailSamples() override = 0;
protected:
ConstructArgs arguments;
};
#pragma GCC diagnostic pop
namespace Steinberg {
namespace Vst {
template <typename S>
void serialize(S& s, Steinberg::Vst::BusInfo& info) {
s.value4b(info.mediaType);
s.value4b(info.direction);
s.value4b(info.channelCount);
s.container2b(info.name);
s.value4b(info.busType);
s.value4b(info.flags);
}
template <typename S>
void serialize(S& s, Steinberg::Vst::RoutingInfo& info) {
s.value4b(info.mediaType);
s.value4b(info.busIndex);
s.value4b(info.channel);
}
template <typename S>
void serialize(S& s, Steinberg::Vst::ProcessSetup& setup) {
s.value4b(setup.processMode);
s.value4b(setup.symbolicSampleSize);
s.value4b(setup.maxSamplesPerBlock);
s.value8b(setup.sampleRate);
}
} // namespace Vst
} // namespace Steinberg
+5 -4
View File
@@ -22,8 +22,8 @@ YaComponent::ConstructArgs::ConstructArgs(
Steinberg::IPtr<Steinberg::Vst::IComponent> component,
size_t instance_id)
: instance_id(instance_id),
audio_processor_supported(
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor>(component)) {
audio_processor_args(component),
plugin_base_args(component) {
// `IComponent::getControllerClassId`
Steinberg::TUID cid;
if (component->getControllerClassId(cid) == Steinberg::kResultOk) {
@@ -32,7 +32,8 @@ YaComponent::ConstructArgs::ConstructArgs(
}
YaComponent::YaComponent(const ConstructArgs&& args)
: YaPluginBase(std::move(args.plugin_base_args)),
: YaAudioProcessor(std::move(args.audio_processor_args)),
YaPluginBase(std::move(args.plugin_base_args)),
arguments(std::move(args)){FUNKNOWN_CTOR}
YaComponent::~YaComponent() {
@@ -61,7 +62,7 @@ tresult PLUGIN_API YaComponent::queryInterface(Steinberg::FIDString _iid,
}
QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IComponent::iid,
Steinberg::Vst::IComponent)
if (arguments.audio_processor_supported) {
if (YaAudioProcessor::supported()) {
QUERY_INTERFACE(_iid, obj, Steinberg::Vst::IAudioProcessor::iid,
Steinberg::Vst::IAudioProcessor)
}
+6 -256
View File
@@ -25,15 +25,14 @@
#include <bitsery/ext/std_set.h>
#include <bitsery/ext/std_variant.h>
#include <bitsery/traits/array.h>
#include <pluginterfaces/vst/ivstaudioprocessor.h>
#include <pluginterfaces/vst/ivstcomponent.h>
#include "../../bitsery/ext/vst3.h"
#include "../common.h"
#include "audio-processor.h"
#include "base.h"
#include "host-application.h"
#include "plugin-base.h"
#include "process-data.h"
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wnon-virtual-dtor"
@@ -55,8 +54,8 @@
* the SDK's `AudioEffect` component.
*/
class YaComponent : public Steinberg::Vst::IComponent,
public YaPluginBase,
public Steinberg::Vst::IAudioProcessor {
public YaAudioProcessor,
public YaPluginBase {
public:
/**
* These are the arguments for creating a `YaComponentPluginImpl`.
@@ -77,11 +76,9 @@ class YaComponent : public Steinberg::Vst::IComponent,
*/
native_size_t instance_id;
YaAudioProcessor::ConstructArgs audio_processor_args;
YaPluginBase::ConstructArgs plugin_base_args;
// TODO: Remove, transitional
bool audio_processor_supported;
/**
* The class ID of this component's corresponding editor controller. You
* can't use C-style array in `std::optional`s.
@@ -91,8 +88,8 @@ class YaComponent : public Steinberg::Vst::IComponent,
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.object(audio_processor_args);
s.object(plugin_base_args);
s.value1b(audio_processor_supported);
s.ext(edit_controller_cid, bitsery::ext::StdOptional{},
[](S& s, auto& cid) { s.container1b(cid); });
}
@@ -101,8 +98,7 @@ class YaComponent : public Steinberg::Vst::IComponent,
/**
* Message to request the Wine plugin host to instantiate a new IComponent
* to pass through a call to `IComponent::createInstance(cid,
* IComponent::iid,
* ...)`.
* IComponent::iid, ...)`.
*/
struct Construct {
using Response = std::variant<ConstructArgs, UniversalTResult>;
@@ -145,7 +141,6 @@ class YaComponent : public Steinberg::Vst::IComponent,
DECLARE_FUNKNOWN_METHODS
// From `IComponent`
tresult PLUGIN_API getControllerClassId(Steinberg::TUID classId) override;
/**
@@ -381,222 +376,6 @@ class YaComponent : public Steinberg::Vst::IComponent,
virtual tresult PLUGIN_API
getState(Steinberg::IBStream* state) override = 0;
// From `IAudioProcessor`
/**
* Message to pass through a call to
* `IAudioProcessor::setBusArrangements(inputs, num_ins, outputs, num_outs)`
* to the Wine plugin host.
*/
struct SetBusArrangements {
using Response = UniversalTResult;
native_size_t instance_id;
// These are orginally C-style heap arrays, not normal pointers
std::vector<Steinberg::Vst::SpeakerArrangement> inputs;
int32 num_ins;
std::vector<Steinberg::Vst::SpeakerArrangement> outputs;
int32 num_outs;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.container8b(inputs, max_num_speakers);
s.value4b(num_ins);
s.container8b(outputs, max_num_speakers);
s.value4b(num_outs);
}
};
virtual tresult PLUGIN_API
setBusArrangements(Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) override = 0;
/**
* The response code and written state for a call to
* `IAudioProcessor::getBusArrangement(dir, index, arr)`.
*/
struct GetBusArrangementResponse {
UniversalTResult result;
Steinberg::Vst::SpeakerArrangement updated_arr;
template <typename S>
void serialize(S& s) {
s.object(result);
s.value8b(updated_arr);
}
};
/**
* Message to pass through a call to
* `IAudioProcessor::getBusArrangement(dir, index, arr)` to the Wine
* plugin host.
*/
struct GetBusArrangement {
using Response = GetBusArrangementResponse;
native_size_t instance_id;
Steinberg::Vst::BusDirection dir;
int32 index;
Steinberg::Vst::SpeakerArrangement arr;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value4b(dir);
s.value4b(index);
s.value8b(arr);
}
};
virtual tresult PLUGIN_API
getBusArrangement(Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) override = 0;
/**
* Message to pass through a call to
* `IAudioProcessor::canProcessSampleSize(symbolic_sample_size)` to the Wine
* plugin host.
*/
struct CanProcessSampleSize {
using Response = UniversalTResult;
native_size_t instance_id;
int32 symbolic_sample_size;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value4b(symbolic_sample_size);
}
};
virtual tresult PLUGIN_API
canProcessSampleSize(int32 symbolicSampleSize) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::getLatencySamples()`
* to the Wine plugin host.
*/
struct GetLatencySamples {
using Response = PrimitiveWrapper<uint32>;
native_size_t instance_id;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
}
};
virtual uint32 PLUGIN_API getLatencySamples() override = 0;
/**
* Message to pass through a call to
* `IAudioProcessor::setupProcessing(setup)` to the Wine plugin host.
*/
struct SetupProcessing {
using Response = UniversalTResult;
native_size_t instance_id;
Steinberg::Vst::ProcessSetup setup;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.object(setup);
}
};
virtual tresult PLUGIN_API
setupProcessing(Steinberg::Vst::ProcessSetup& setup) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::setProcessing(state)`
* to the Wine plugin host.
*/
struct SetProcessing {
using Response = UniversalTResult;
native_size_t instance_id;
TBool state;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.value1b(state);
}
};
virtual tresult PLUGIN_API setProcessing(TBool state) override = 0;
/**
* The response code and all the output data resulting from a call to
* `IAudioProcessor::process(data)`.
*/
struct ProcessResponse {
UniversalTResult result;
YaProcessDataResponse output_data;
template <typename S>
void serialize(S& s) {
s.object(result);
s.object(output_data);
}
};
/**
* Message to pass through a call to `IAudioProcessor::process(data)` to the
* Wine plugin host. This `YaProcessData` object wraps around all input
* audio buffers, parameter changes and events along with all context data
* provided by the host so we can send it to the Wine plugin host. We can
* then use `YaProcessData::get()` on the Wine plugin host side to
* reconstruct the original `ProcessData` object, and we then finally use
* `YaProcessData::move_outputs_to_response()` to create a response object
* that we can write back to the `ProcessData` object provided by the host.
*/
struct Process {
using Response = ProcessResponse;
native_size_t instance_id;
YaProcessData data;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
s.object(data);
}
};
virtual tresult PLUGIN_API
process(Steinberg::Vst::ProcessData& data) override = 0;
/**
* Message to pass through a call to `IAudioProcessor::getTailSamples()`
* to the Wine plugin host.
*/
struct GetTailSamples {
using Response = PrimitiveWrapper<uint32>;
native_size_t instance_id;
template <typename S>
void serialize(S& s) {
s.value8b(instance_id);
}
};
virtual uint32 PLUGIN_API getTailSamples() override = 0;
protected:
ConstructArgs arguments;
};
@@ -609,32 +388,3 @@ void serialize(
std::variant<YaComponent::ConstructArgs, UniversalTResult>& result) {
s.ext(result, bitsery::ext::StdVariant{});
}
namespace Steinberg {
namespace Vst {
template <typename S>
void serialize(S& s, Steinberg::Vst::BusInfo& info) {
s.value4b(info.mediaType);
s.value4b(info.direction);
s.value4b(info.channelCount);
s.container2b(info.name);
s.value4b(info.busType);
s.value4b(info.flags);
}
template <typename S>
void serialize(S& s, Steinberg::Vst::RoutingInfo& info) {
s.value4b(info.mediaType);
s.value4b(info.busIndex);
s.value4b(info.channel);
}
template <typename S>
void serialize(S& s, Steinberg::Vst::ProcessSetup& setup) {
s.value4b(setup.processMode);
s.value4b(setup.symbolicSampleSize);
s.value4b(setup.maxSamplesPerBlock);
s.value8b(setup.sampleRate);
}
} // namespace Vst
} // namespace Steinberg
+2 -3
View File
@@ -40,9 +40,8 @@ class YaPluginBase : public Steinberg::IPluginBase {
ConstructArgs();
/**
* Read arguments from an existing implementation. Depending on the
* supported interface function more or less of this struct will be left
* empty, and `known_iids` will be set accordingly.
* Check whether an existing implementation implements `IPluginBase` and
* read arguments from it.
*/
ConstructArgs(Steinberg::IPtr<Steinberg::FUnknown> object);
+71 -70
View File
@@ -40,6 +40,77 @@ YaComponentPluginImpl::queryInterface(const Steinberg::TUID _iid, void** obj) {
return result;
}
tresult PLUGIN_API YaComponentPluginImpl::setBusArrangements(
Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) {
assert(inputs && outputs);
return bridge.send_message(YaAudioProcessor::SetBusArrangements{
.instance_id = arguments.instance_id,
.inputs = std::vector<Steinberg::Vst::SpeakerArrangement>(
inputs, &inputs[numIns]),
.num_ins = numIns,
.outputs = std::vector<Steinberg::Vst::SpeakerArrangement>(
outputs, &outputs[numOuts]),
.num_outs = numOuts,
});
}
tresult PLUGIN_API YaComponentPluginImpl::getBusArrangement(
Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) {
const GetBusArrangementResponse response =
bridge.send_message(YaAudioProcessor::GetBusArrangement{
.instance_id = arguments.instance_id,
.dir = dir,
.index = index,
.arr = arr});
arr = response.updated_arr;
return response.result;
}
tresult PLUGIN_API
YaComponentPluginImpl::canProcessSampleSize(int32 symbolicSampleSize) {
return bridge.send_message(YaAudioProcessor::CanProcessSampleSize{
.instance_id = arguments.instance_id,
.symbolic_sample_size = symbolicSampleSize});
}
uint32 PLUGIN_API YaComponentPluginImpl::getLatencySamples() {
return bridge.send_message(YaAudioProcessor::GetLatencySamples{
.instance_id = arguments.instance_id});
}
tresult PLUGIN_API
YaComponentPluginImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
return bridge.send_message(YaAudioProcessor::SetupProcessing{
.instance_id = arguments.instance_id, .setup = setup});
}
tresult PLUGIN_API YaComponentPluginImpl::setProcessing(TBool state) {
return bridge.send_message(YaAudioProcessor::SetProcessing{
.instance_id = arguments.instance_id, .state = state});
}
tresult PLUGIN_API
YaComponentPluginImpl::process(Steinberg::Vst::ProcessData& data) {
ProcessResponse response = bridge.send_message(YaAudioProcessor::Process{
.instance_id = arguments.instance_id, .data = data});
response.output_data.write_back_outputs(data);
return response.result;
}
uint32 PLUGIN_API YaComponentPluginImpl::getTailSamples() {
return bridge.send_message(
YaAudioProcessor::GetTailSamples{.instance_id = arguments.instance_id});
}
tresult PLUGIN_API
YaComponentPluginImpl::setIoMode(Steinberg::Vst::IoMode mode) {
return bridge.send_message(YaComponent::SetIoMode{
@@ -142,73 +213,3 @@ tresult PLUGIN_API YaComponentPluginImpl::terminate() {
return bridge.send_message(
YaPluginBase::Terminate{.instance_id = arguments.instance_id});
}
tresult PLUGIN_API YaComponentPluginImpl::setBusArrangements(
Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) {
assert(inputs && outputs);
return bridge.send_message(YaComponent::SetBusArrangements{
.instance_id = arguments.instance_id,
.inputs = std::vector<Steinberg::Vst::SpeakerArrangement>(
inputs, &inputs[numIns]),
.num_ins = numIns,
.outputs = std::vector<Steinberg::Vst::SpeakerArrangement>(
outputs, &outputs[numOuts]),
.num_outs = numOuts,
});
}
tresult PLUGIN_API YaComponentPluginImpl::getBusArrangement(
Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) {
const GetBusArrangementResponse response = bridge.send_message(
YaComponent::GetBusArrangement{.instance_id = arguments.instance_id,
.dir = dir,
.index = index,
.arr = arr});
arr = response.updated_arr;
return response.result;
}
tresult PLUGIN_API
YaComponentPluginImpl::canProcessSampleSize(int32 symbolicSampleSize) {
return bridge.send_message(YaComponent::CanProcessSampleSize{
.instance_id = arguments.instance_id,
.symbolic_sample_size = symbolicSampleSize});
}
uint32 PLUGIN_API YaComponentPluginImpl::getLatencySamples() {
return bridge.send_message(
YaComponent::GetLatencySamples{.instance_id = arguments.instance_id});
}
tresult PLUGIN_API
YaComponentPluginImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
return bridge.send_message(YaComponent::SetupProcessing{
.instance_id = arguments.instance_id, .setup = setup});
}
tresult PLUGIN_API YaComponentPluginImpl::setProcessing(TBool state) {
return bridge.send_message(YaComponent::SetProcessing{
.instance_id = arguments.instance_id, .state = state});
}
tresult PLUGIN_API
YaComponentPluginImpl::process(Steinberg::Vst::ProcessData& data) {
ProcessResponse response = bridge.send_message(YaComponent::Process{
.instance_id = arguments.instance_id, .data = data});
response.output_data.write_back_outputs(data);
return response.result;
}
uint32 PLUGIN_API YaComponentPluginImpl::getTailSamples() {
return bridge.send_message(
YaComponent::GetTailSamples{.instance_id = arguments.instance_id});
}
+18 -17
View File
@@ -39,6 +39,24 @@ class YaComponentPluginImpl : public YaComponent {
tresult PLUGIN_API queryInterface(const Steinberg::TUID _iid,
void** obj) override;
// From `IAudioProcessor`
tresult PLUGIN_API
setBusArrangements(Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) override;
tresult PLUGIN_API
getBusArrangement(Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) override;
tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override;
uint32 PLUGIN_API getLatencySamples() override;
tresult PLUGIN_API
setupProcessing(Steinberg::Vst::ProcessSetup& setup) override;
tresult PLUGIN_API setProcessing(TBool state) override;
tresult PLUGIN_API process(Steinberg::Vst::ProcessData& data) override;
uint32 PLUGIN_API getTailSamples() override;
// From `IComponent`
tresult PLUGIN_API setIoMode(Steinberg::Vst::IoMode mode) override;
int32 PLUGIN_API getBusCount(Steinberg::Vst::MediaType type,
@@ -63,23 +81,6 @@ class YaComponentPluginImpl : public YaComponent {
tresult PLUGIN_API initialize(FUnknown* context) override;
tresult PLUGIN_API terminate() override;
tresult PLUGIN_API
setBusArrangements(Steinberg::Vst::SpeakerArrangement* inputs,
int32 numIns,
Steinberg::Vst::SpeakerArrangement* outputs,
int32 numOuts) override;
tresult PLUGIN_API
getBusArrangement(Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::SpeakerArrangement& arr) override;
tresult PLUGIN_API canProcessSampleSize(int32 symbolicSampleSize) override;
uint32 PLUGIN_API getLatencySamples() override;
tresult PLUGIN_API
setupProcessing(Steinberg::Vst::ProcessSetup& setup) override;
tresult PLUGIN_API setProcessing(TBool state) override;
tresult PLUGIN_API process(Steinberg::Vst::ProcessData& data) override;
uint32 PLUGIN_API getTailSamples() override;
private:
Vst3PluginBridge& bridge;
+71 -71
View File
@@ -60,6 +60,59 @@ void Vst3Bridge::run() {
sockets.host_vst_control.receive_messages(
std::nullopt,
overload{
[&](YaAudioProcessor::SetBusArrangements& request)
-> YaAudioProcessor::SetBusArrangements::Response {
return component_instances[request.instance_id]
.audio_processor->setBusArrangements(
request.inputs.data(), request.num_ins,
request.outputs.data(), request.num_outs);
},
[&](YaAudioProcessor::GetBusArrangement& request)
-> YaAudioProcessor::GetBusArrangement::Response {
const tresult result =
component_instances[request.instance_id]
.audio_processor->getBusArrangement(
request.dir, request.index, request.arr);
return YaAudioProcessor::GetBusArrangementResponse{
.result = result, .updated_arr = request.arr};
},
[&](const YaAudioProcessor::CanProcessSampleSize& request)
-> YaAudioProcessor::CanProcessSampleSize::Response {
return component_instances[request.instance_id]
.audio_processor->canProcessSampleSize(
request.symbolic_sample_size);
},
[&](const YaAudioProcessor::GetLatencySamples& request)
-> YaAudioProcessor::GetLatencySamples::Response {
return component_instances[request.instance_id]
.audio_processor->getLatencySamples();
},
[&](YaAudioProcessor::SetupProcessing& request)
-> YaAudioProcessor::SetupProcessing::Response {
return component_instances[request.instance_id]
.audio_processor->setupProcessing(request.setup);
},
[&](const YaAudioProcessor::SetProcessing& request)
-> YaAudioProcessor::SetProcessing::Response {
return component_instances[request.instance_id]
.audio_processor->setProcessing(request.state);
},
[&](YaAudioProcessor::Process& request)
-> YaAudioProcessor::Process::Response {
const tresult result =
component_instances[request.instance_id]
.audio_processor->process(request.data.get());
return YaAudioProcessor::ProcessResponse{
.result = result,
.output_data = request.data.move_outputs_to_response()};
},
[&](const YaAudioProcessor::GetTailSamples& request)
-> YaAudioProcessor::GetTailSamples::Response {
return component_instances[request.instance_id]
.audio_processor->getTailSamples();
},
[&](const YaComponent::Construct& args)
-> YaComponent::Construct::Response {
Steinberg::TUID cid;
@@ -88,30 +141,6 @@ void Vst3Bridge::run() {
return Ack{};
},
[&](YaPluginBase::Initialize& request)
-> YaPluginBase::Initialize::Response {
// If we got passed a host context, we'll create a proxy object
// and pass that to the initialize function. This object should
// be cleaned up again during `YaComponent::Destruct`.
Steinberg::FUnknown* context = nullptr;
if (request.host_application_context_args) {
component_instances[request.instance_id]
.hsot_application_context =
Steinberg::owned(new YaHostApplicationHostImpl(
*this,
std::move(*request.host_application_context_args)));
context = component_instances[request.instance_id]
.hsot_application_context;
}
return component_instances[request.instance_id]
.plugin_base->initialize(context);
},
[&](const YaPluginBase::Terminate& request)
-> YaPluginBase::Terminate::Response {
return component_instances[request.instance_id]
.plugin_base->terminate();
},
[&](const YaComponent::SetIoMode& request)
-> YaComponent::SetIoMode::Response {
return component_instances[request.instance_id]
@@ -169,58 +198,29 @@ void Vst3Bridge::run() {
return YaComponent::GetStateResponse{
.result = result, .updated_state = std::move(stream)};
},
[&](YaComponent::SetBusArrangements& request)
-> YaComponent::SetBusArrangements::Response {
return component_instances[request.instance_id]
.audio_processor->setBusArrangements(
request.inputs.data(), request.num_ins,
request.outputs.data(), request.num_outs);
},
[&](YaComponent::GetBusArrangement& request)
-> YaComponent::GetBusArrangement::Response {
const tresult result =
[&](YaPluginBase::Initialize& request)
-> YaPluginBase::Initialize::Response {
// If we got passed a host context, we'll create a proxy object
// and pass that to the initialize function. This object should
// be cleaned up again during `YaComponent::Destruct`.
Steinberg::FUnknown* context = nullptr;
if (request.host_application_context_args) {
component_instances[request.instance_id]
.audio_processor->getBusArrangement(
request.dir, request.index, request.arr);
.hsot_application_context =
Steinberg::owned(new YaHostApplicationHostImpl(
*this,
std::move(*request.host_application_context_args)));
context = component_instances[request.instance_id]
.hsot_application_context;
}
return YaComponent::GetBusArrangementResponse{
.result = result, .updated_arr = request.arr};
},
[&](const YaComponent::CanProcessSampleSize& request)
-> YaComponent::CanProcessSampleSize::Response {
return component_instances[request.instance_id]
.audio_processor->canProcessSampleSize(
request.symbolic_sample_size);
.plugin_base->initialize(context);
},
[&](const YaComponent::GetLatencySamples& request)
-> YaComponent::GetLatencySamples::Response {
[&](const YaPluginBase::Terminate& request)
-> YaPluginBase::Terminate::Response {
return component_instances[request.instance_id]
.audio_processor->getLatencySamples();
},
[&](YaComponent::SetupProcessing& request)
-> YaComponent::SetupProcessing::Response {
return component_instances[request.instance_id]
.audio_processor->setupProcessing(request.setup);
},
[&](const YaComponent::SetProcessing& request)
-> YaComponent::SetProcessing::Response {
return component_instances[request.instance_id]
.audio_processor->setProcessing(request.state);
},
[&](YaComponent::Process& request)
-> YaComponent::Process::Response {
const tresult result =
component_instances[request.instance_id]
.audio_processor->process(request.data.get());
return YaComponent::ProcessResponse{
.result = result,
.output_data = request.data.move_outputs_to_response()};
},
[&](const YaComponent::GetTailSamples& request)
-> YaComponent::GetTailSamples::Response {
return component_instances[request.instance_id]
.audio_processor->getTailSamples();
.plugin_base->terminate();
},
[&](const YaPluginFactory::Construct&)
-> YaPluginFactory::Construct::Response {