mirror of
https://github.com/robbert-vdh/yabridge.git
synced 2026-05-07 03:50:11 +02:00
b5dd806b2d
This is in some cases needed to get decent performance in REAPER, as REAPER seems to query this information (which cannot change without the plugin requesting a restart) four times per second.
1169 lines
43 KiB
C++
1169 lines
43 KiB
C++
// yabridge: a Wine VST bridge
|
|
// Copyright (C) 2020-2021 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 "plugin-proxy.h"
|
|
|
|
#include "plug-view-proxy.h"
|
|
|
|
Vst3PluginProxyImpl::ContextMenu::ContextMenu(
|
|
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu)
|
|
: menu(menu) {}
|
|
|
|
Vst3PluginProxyImpl::Vst3PluginProxyImpl(Vst3PluginBridge& bridge,
|
|
Vst3PluginProxy::ConstructArgs&& args)
|
|
: Vst3PluginProxy(std::move(args)), bridge(bridge) {
|
|
bridge.register_plugin_proxy(*this);
|
|
}
|
|
|
|
Vst3PluginProxyImpl::~Vst3PluginProxyImpl() {
|
|
bridge.send_message(
|
|
Vst3PluginProxy::Destruct{.instance_id = instance_id()});
|
|
bridge.unregister_plugin_proxy(*this);
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::queryInterface(const Steinberg::TUID _iid, void** obj) {
|
|
const tresult result = Vst3PluginProxy::queryInterface(_iid, obj);
|
|
bridge.logger.log_query_interface("In FUnknown::queryInterface()", result,
|
|
Steinberg::FUID::fromTUID(_iid));
|
|
|
|
return result;
|
|
}
|
|
|
|
size_t Vst3PluginProxyImpl::register_context_menu(
|
|
Steinberg::IPtr<Steinberg::Vst::IContextMenu> menu) {
|
|
std::lock_guard lock(context_menus_mutex);
|
|
|
|
const size_t context_menu_id = current_context_menu_id.fetch_add(1);
|
|
context_menus.emplace(context_menu_id, std::move(menu));
|
|
|
|
return context_menu_id;
|
|
}
|
|
|
|
/**
|
|
* Unregister a context menu using the ID generated by a previous call to
|
|
* `register_context_menu()`. This will release the context menu object
|
|
* returned by the host.
|
|
*/
|
|
bool Vst3PluginProxyImpl::unregister_context_menu(size_t context_menu_id) {
|
|
std::lock_guard lock(context_menus_mutex);
|
|
return context_menus.erase(context_menu_id);
|
|
}
|
|
|
|
void Vst3PluginProxyImpl::clear_caches() {
|
|
clear_bus_cache();
|
|
clear_parameter_cache();
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setAudioPresentationLatencySamples(
|
|
Steinberg::Vst::BusDirection dir,
|
|
int32 busIndex,
|
|
uint32 latencyInSamples) {
|
|
return bridge.send_message(
|
|
YaAudioPresentationLatency::SetAudioPresentationLatencySamples{
|
|
.instance_id = instance_id(),
|
|
.dir = dir,
|
|
.bus_index = busIndex,
|
|
.latency_in_samples = latencyInSamples});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setBusArrangements(
|
|
Steinberg::Vst::SpeakerArrangement* inputs,
|
|
int32 numIns,
|
|
Steinberg::Vst::SpeakerArrangement* outputs,
|
|
int32 numOuts) {
|
|
clear_bus_cache();
|
|
|
|
// NOTE: Ardour passes a null pointer when `numIns` or `numOuts` is 0, so we
|
|
// need to work around that
|
|
return bridge.send_audio_processor_message(
|
|
YaAudioProcessor::SetBusArrangements{
|
|
.instance_id = instance_id(),
|
|
.inputs =
|
|
(inputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
|
inputs, &inputs[numIns])
|
|
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
|
.num_ins = numIns,
|
|
.outputs =
|
|
(outputs ? std::vector<Steinberg::Vst::SpeakerArrangement>(
|
|
outputs, &outputs[numOuts])
|
|
: std::vector<Steinberg::Vst::SpeakerArrangement>()),
|
|
.num_outs = numOuts,
|
|
});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getBusArrangement(
|
|
Steinberg::Vst::BusDirection dir,
|
|
int32 index,
|
|
Steinberg::Vst::SpeakerArrangement& arr) {
|
|
const GetBusArrangementResponse response =
|
|
bridge.send_audio_processor_message(
|
|
YaAudioProcessor::GetBusArrangement{.instance_id = instance_id(),
|
|
.dir = dir,
|
|
.index = index,
|
|
.arr = arr});
|
|
|
|
arr = response.updated_arr;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::canProcessSampleSize(int32 symbolicSampleSize) {
|
|
return bridge.send_audio_processor_message(
|
|
YaAudioProcessor::CanProcessSampleSize{
|
|
.instance_id = instance_id(),
|
|
.symbolic_sample_size = symbolicSampleSize});
|
|
}
|
|
|
|
uint32 PLUGIN_API Vst3PluginProxyImpl::getLatencySamples() {
|
|
return bridge.send_audio_processor_message(
|
|
YaAudioProcessor::GetLatencySamples{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
|
|
return bridge.send_audio_processor_message(
|
|
YaAudioProcessor::SetupProcessing{.instance_id = instance_id(),
|
|
.setup = setup});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setProcessing(TBool state) {
|
|
// REAPER will repeatedly query the plugin for its bus information on every
|
|
// processing cycle. Because this really adds up in terms of latency we
|
|
// sadly have to deviate from yabridge's principles and implement a cache
|
|
if (state) {
|
|
processing_bus_cache.emplace();
|
|
} else {
|
|
processing_bus_cache.reset();
|
|
}
|
|
|
|
return bridge.send_audio_processor_message(YaAudioProcessor::SetProcessing{
|
|
.instance_id = instance_id(), .state = state});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
|
|
// We'll synchronize the scheduling priority of the audio thread on the Wine
|
|
// plugin host with that of the host's audio thread every once in a while
|
|
std::optional<int> new_realtime_priority = std::nullopt;
|
|
time_t now = std::time(nullptr);
|
|
if (now > last_audio_thread_priority_synchronization +
|
|
audio_thread_priority_synchronization_interval) {
|
|
new_realtime_priority = get_realtime_priority();
|
|
last_audio_thread_priority_synchronization = now;
|
|
}
|
|
|
|
// TODO: Check whether reusing a `YaProcessData` object make a difference in
|
|
// terms of performance
|
|
ProcessResponse response =
|
|
bridge.send_audio_processor_message(YaAudioProcessor::Process{
|
|
.instance_id = instance_id(),
|
|
.data = data,
|
|
.new_realtime_priority = new_realtime_priority});
|
|
|
|
response.output_data.write_back_outputs(data);
|
|
|
|
return response.result;
|
|
}
|
|
|
|
uint32 PLUGIN_API Vst3PluginProxyImpl::getTailSamples() {
|
|
return bridge.send_audio_processor_message(
|
|
YaAudioProcessor::GetTailSamples{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setAutomationState(int32 state) {
|
|
return bridge.send_message(YaAutomationState::SetAutomationState{
|
|
.instance_id = instance_id(), .state = state});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
|
|
if (classId) {
|
|
const GetControllerClassIdResponse response =
|
|
bridge.send_audio_processor_message(
|
|
YaComponent::GetControllerClassId{.instance_id =
|
|
instance_id()});
|
|
|
|
ArrayUID native_uid = response.editor_cid.get_native_uid();
|
|
std::copy(native_uid.begin(), native_uid.end(), classId);
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IComponent::getControllerClassId()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setIoMode(Steinberg::Vst::IoMode mode) {
|
|
return bridge.send_audio_processor_message(
|
|
YaComponent::SetIoMode{.instance_id = instance_id(), .mode = mode});
|
|
}
|
|
|
|
int32 PLUGIN_API
|
|
Vst3PluginProxyImpl::getBusCount(Steinberg::Vst::MediaType type,
|
|
Steinberg::Vst::BusDirection dir) {
|
|
const auto request = YaComponent::GetBusCount{
|
|
.instance_id = instance_id(), .type = type, .dir = dir};
|
|
|
|
// During processing we'll cache this info to work around an implementation
|
|
// issue in REAPER
|
|
std::tuple<Steinberg::Vst::MediaType, Steinberg::Vst::BusDirection> args{
|
|
type, dir};
|
|
if (processing_bus_cache) {
|
|
if (auto it = processing_bus_cache->bus_count.find(args);
|
|
it != processing_bus_cache->bus_count.end()) {
|
|
const bool log_response = bridge.logger.log_request(true, request);
|
|
if (log_response) {
|
|
bridge.logger.log_response(
|
|
true, YaComponent::GetBusCount::Response(it->second), true);
|
|
}
|
|
|
|
return it->second;
|
|
}
|
|
}
|
|
|
|
const int32 result = bridge.send_audio_processor_message(request);
|
|
|
|
if (processing_bus_cache) {
|
|
processing_bus_cache->bus_count[args] = result;
|
|
}
|
|
|
|
return result;
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
|
|
Steinberg::Vst::BusDirection dir,
|
|
int32 index,
|
|
Steinberg::Vst::BusInfo& bus /*out*/) {
|
|
const auto request = YaComponent::GetBusInfo{.instance_id = instance_id(),
|
|
.type = type,
|
|
.dir = dir,
|
|
.index = index,
|
|
.bus = bus};
|
|
|
|
// During processing we'll cache this info to work around an implementation
|
|
// issue in REAPER
|
|
std::tuple<Steinberg::Vst::MediaType, Steinberg::Vst::BusDirection, int32>
|
|
args{type, dir, index};
|
|
if (processing_bus_cache) {
|
|
if (auto it = processing_bus_cache->bus_info.find(args);
|
|
it != processing_bus_cache->bus_info.end()) {
|
|
const bool log_response = bridge.logger.log_request(true, request);
|
|
if (log_response) {
|
|
bridge.logger.log_response(true,
|
|
YaComponent::GetBusInfo::Response{
|
|
.result = Steinberg::kResultOk,
|
|
.updated_bus = it->second},
|
|
true);
|
|
}
|
|
|
|
bus = it->second;
|
|
|
|
return Steinberg::kResultOk;
|
|
}
|
|
}
|
|
|
|
const GetBusInfoResponse response =
|
|
bridge.send_audio_processor_message(request);
|
|
|
|
bus = response.updated_bus;
|
|
if (processing_bus_cache) {
|
|
processing_bus_cache->bus_info[args] = response.updated_bus;
|
|
}
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getRoutingInfo(
|
|
Steinberg::Vst::RoutingInfo& inInfo,
|
|
Steinberg::Vst::RoutingInfo& outInfo /*out*/) {
|
|
const GetRoutingInfoResponse response = bridge.send_audio_processor_message(
|
|
YaComponent::GetRoutingInfo{.instance_id = instance_id(),
|
|
.in_info = inInfo,
|
|
.out_info = outInfo});
|
|
|
|
inInfo = response.updated_in_info;
|
|
outInfo = response.updated_out_info;
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type,
|
|
Steinberg::Vst::BusDirection dir,
|
|
int32 index,
|
|
TBool state) {
|
|
return bridge.send_audio_processor_message(
|
|
YaComponent::ActivateBus{.instance_id = instance_id(),
|
|
.type = type,
|
|
.dir = dir,
|
|
.index = index,
|
|
.state = state});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setActive(TBool state) {
|
|
// HACK: Even though we have implemented this cache specifically for REAPER,
|
|
// REAPER doesn't use `IComponent::setProcessing` properly and calls
|
|
// it before doing setting up input and output busses. So now our
|
|
// workaround to get acceptable performance in REAPER needs a
|
|
// workaround of its ownn. Great!
|
|
clear_bus_cache();
|
|
|
|
return bridge.send_audio_processor_message(
|
|
YaComponent::SetActive{.instance_id = instance_id(), .state = state});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setState(Steinberg::IBStream* state) {
|
|
if (state) {
|
|
// Since both interfaces contain this function, this is used for both
|
|
// `IComponent::setState()` as well as `IEditController::setState()`
|
|
return bridge.send_message(Vst3PluginProxy::SetState{
|
|
.instance_id = instance_id(), .state = state});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'I{Component,EditController}::setState()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getState(Steinberg::IBStream* state) {
|
|
if (state) {
|
|
// Since both interfaces contain this function, this is used for both
|
|
// `IComponent::getState()` as well as `IEditController::getState()`
|
|
const GetStateResponse response =
|
|
bridge.send_message(Vst3PluginProxy::GetState{
|
|
.instance_id = instance_id(), .state = state});
|
|
|
|
assert(response.state.write_back(state) == Steinberg::kResultOk);
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'I{Component,EditController}::getState()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::connect(IConnectionPoint* other) {
|
|
// When the host is trying to connect two plugin proxy objects, we can just
|
|
// identify the other object by its instance IDs and then connect the
|
|
// objects in the Wine plugin host directly. Otherwise we'll have to set up
|
|
// a proxy for the host's connection proxy so the messages can be routed
|
|
// through that.
|
|
if (auto other_proxy = dynamic_cast<Vst3PluginProxy*>(other)) {
|
|
return bridge.send_message(YaConnectionPoint::Connect{
|
|
.instance_id = instance_id(), .other = other_proxy->instance_id()});
|
|
} else {
|
|
connection_point_proxy = other;
|
|
|
|
return bridge.send_message(YaConnectionPoint::Connect{
|
|
.instance_id = instance_id(),
|
|
.other =
|
|
Vst3ConnectionPointProxy::ConstructArgs(other, instance_id())});
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::disconnect(IConnectionPoint* other) {
|
|
// See `Vst3PluginProxyImpl::connect()`
|
|
if (auto other_proxy = dynamic_cast<Vst3PluginProxy*>(other)) {
|
|
return bridge.send_message(YaConnectionPoint::Disconnect{
|
|
.instance_id = instance_id(),
|
|
.other_instance_id = other_proxy->instance_id()});
|
|
} else {
|
|
const tresult result = bridge.send_message(
|
|
YaConnectionPoint::Disconnect{.instance_id = instance_id(),
|
|
.other_instance_id = std::nullopt});
|
|
connection_point_proxy.reset();
|
|
|
|
return result;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::notify(Steinberg::Vst::IMessage* message) {
|
|
// Since there is no way to enumerate over all values in an
|
|
// `IAttributeList`, we can only support relaying messages that were sent by
|
|
// our own objects. Additionally, the `IMessage*` we end up passing to the
|
|
// plugin needs to have the same lifetime as the original object, because
|
|
// some plugins are being a bit naughty. That's why we pass around a pointer
|
|
// to the original message object.
|
|
// All of this is only needed to support hosts that place a connection proxy
|
|
// between two objects instead of connecting them directly. If the objects
|
|
// are connected directly we also connected them directly on the Wine side,
|
|
// so we don't have to do any additional when those objects pass through
|
|
// messages.
|
|
if (auto message_ptr = dynamic_cast<YaMessagePtr*>(message)) {
|
|
return bridge.send_message(YaConnectionPoint::Notify{
|
|
.instance_id = instance_id(), .message_ptr = *message_ptr});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Unknown message type passed to "
|
|
"'IConnectionPoint::notify()', ignoring");
|
|
return Steinberg::kNotImplemented;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setComponentState(Steinberg::IBStream* state) {
|
|
if (state) {
|
|
return bridge.send_message(YaEditController::SetComponentState{
|
|
.instance_id = instance_id(), .state = state});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IEditController::setComponentState()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
int32 PLUGIN_API Vst3PluginProxyImpl::getParameterCount() {
|
|
const auto request =
|
|
YaEditController::GetParameterCount{.instance_id = instance_id()};
|
|
|
|
// We'll cache this information to work around an issue in REAPER, see
|
|
// `parameter_info_cache`
|
|
if (parameter_info_cache.parameter_count) {
|
|
const bool log_response = bridge.logger.log_request(true, request);
|
|
if (log_response) {
|
|
bridge.logger.log_response(
|
|
true,
|
|
YaEditController::GetParameterCount::Response(
|
|
*parameter_info_cache.parameter_count),
|
|
true);
|
|
}
|
|
|
|
return *parameter_info_cache.parameter_count;
|
|
}
|
|
|
|
const int32 result = bridge.send_message(request);
|
|
|
|
parameter_info_cache.parameter_count = result;
|
|
|
|
return result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getParameterInfo(
|
|
int32 paramIndex,
|
|
Steinberg::Vst::ParameterInfo& info /*out*/) {
|
|
const auto request = YaEditController::GetParameterInfo{
|
|
.instance_id = instance_id(), .param_index = paramIndex, .info = info};
|
|
|
|
// We'll cache this information to work around an issue in REAPER, see
|
|
// `parameter_info_cache`
|
|
if (auto it = parameter_info_cache.parameter_info.find(paramIndex);
|
|
it != parameter_info_cache.parameter_info.end()) {
|
|
const bool log_response = bridge.logger.log_request(true, request);
|
|
if (log_response) {
|
|
bridge.logger.log_response(
|
|
true,
|
|
YaEditController::GetParameterInfo::Response{
|
|
.result = Steinberg::kResultOk, .updated_info = it->second},
|
|
true);
|
|
}
|
|
|
|
info = it->second;
|
|
|
|
return Steinberg::kResultOk;
|
|
}
|
|
|
|
const GetParameterInfoResponse response = bridge.send_message(request);
|
|
|
|
info = response.updated_info;
|
|
parameter_info_cache.parameter_info[paramIndex] = response.updated_info;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getParamStringByValue(
|
|
Steinberg::Vst::ParamID id,
|
|
Steinberg::Vst::ParamValue valueNormalized /*in*/,
|
|
Steinberg::Vst::String128 string /*out*/) {
|
|
if (string) {
|
|
const GetParamStringByValueResponse response =
|
|
bridge.send_message(YaEditController::GetParamStringByValue{
|
|
.instance_id = instance_id(),
|
|
.id = id,
|
|
.value_normalized = valueNormalized});
|
|
|
|
std::copy(response.string.begin(), response.string.end(), string);
|
|
string[response.string.size()] = 0;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IEditController::getParamStringByValue()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getParamValueByString(
|
|
Steinberg::Vst::ParamID id,
|
|
Steinberg::Vst::TChar* string /*in*/,
|
|
Steinberg::Vst::ParamValue& valueNormalized /*out*/) {
|
|
if (string) {
|
|
const GetParamValueByStringResponse response =
|
|
bridge.send_message(YaEditController::GetParamValueByString{
|
|
.instance_id = instance_id(), .id = id, .string = string});
|
|
|
|
valueNormalized = response.value_normalized;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IEditController::getParamValueByString()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
Steinberg::Vst::ParamValue PLUGIN_API
|
|
Vst3PluginProxyImpl::normalizedParamToPlain(
|
|
Steinberg::Vst::ParamID id,
|
|
Steinberg::Vst::ParamValue valueNormalized) {
|
|
return bridge.send_message(YaEditController::NormalizedParamToPlain{
|
|
.instance_id = instance_id(),
|
|
.id = id,
|
|
.value_normalized = valueNormalized});
|
|
}
|
|
|
|
Steinberg::Vst::ParamValue PLUGIN_API
|
|
Vst3PluginProxyImpl::plainParamToNormalized(
|
|
Steinberg::Vst::ParamID id,
|
|
Steinberg::Vst::ParamValue plainValue) {
|
|
return bridge.send_message(YaEditController::PlainParamToNormalized{
|
|
.instance_id = instance_id(), .id = id, .plain_value = plainValue});
|
|
}
|
|
|
|
Steinberg::Vst::ParamValue PLUGIN_API
|
|
Vst3PluginProxyImpl::getParamNormalized(Steinberg::Vst::ParamID id) {
|
|
return bridge.send_message(YaEditController::GetParamNormalized{
|
|
.instance_id = instance_id(), .id = id});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setParamNormalized(Steinberg::Vst::ParamID id,
|
|
Steinberg::Vst::ParamValue value) {
|
|
return bridge.send_message(YaEditController::SetParamNormalized{
|
|
.instance_id = instance_id(), .id = id, .value = value});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setComponentHandler(
|
|
Steinberg::Vst::IComponentHandler* handler) {
|
|
// Null pointers are valid here going from the reference implementations in
|
|
// the SDK
|
|
if (handler) {
|
|
// We'll store the pointer for when the plugin later makes a callback to
|
|
// this component handler
|
|
component_handler = handler;
|
|
|
|
// Automatically converted smart pointers for when the plugin performs a
|
|
// callback later
|
|
component_handler_2 = component_handler;
|
|
component_handler_3 = component_handler;
|
|
component_handler_bus_activation = component_handler;
|
|
progress = component_handler;
|
|
unit_handler = component_handler;
|
|
unit_handler_2 = component_handler;
|
|
|
|
return bridge.send_message(YaEditController::SetComponentHandler{
|
|
.instance_id = instance_id(),
|
|
.component_handler_proxy_args =
|
|
Vst3ComponentHandlerProxy::ConstructArgs(component_handler,
|
|
instance_id())});
|
|
} else {
|
|
component_handler = nullptr;
|
|
|
|
component_handler_2 = nullptr;
|
|
component_handler_3 = nullptr;
|
|
component_handler_bus_activation = nullptr;
|
|
progress = nullptr;
|
|
unit_handler = nullptr;
|
|
unit_handler_2 = nullptr;
|
|
|
|
return bridge.send_message(YaEditController::SetComponentHandler{
|
|
.instance_id = instance_id(),
|
|
.component_handler_proxy_args = std::nullopt});
|
|
}
|
|
}
|
|
|
|
Steinberg::IPlugView* PLUGIN_API
|
|
Vst3PluginProxyImpl::createView(Steinberg::FIDString name) {
|
|
if (name) {
|
|
CreateViewResponse response =
|
|
bridge.send_message(YaEditController::CreateView{
|
|
.instance_id = instance_id(), .name = name});
|
|
|
|
if (response.plug_view_args) {
|
|
// The host should manage this. Returning raw pointers feels scary.
|
|
auto plug_view_proxy = new Vst3PlugViewProxyImpl(
|
|
bridge, std::move(*response.plug_view_args));
|
|
|
|
// We also need to store an (unmanaged, since we don't want to
|
|
// affect the reference counting) pointer to this to be able to
|
|
// handle calls to `IPlugFrame::resizeView()` in the future
|
|
last_created_plug_view = plug_view_proxy;
|
|
|
|
return plug_view_proxy;
|
|
} else {
|
|
return nullptr;
|
|
}
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IEditController::createView()'");
|
|
return nullptr;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setKnobMode(Steinberg::Vst::KnobMode mode) {
|
|
return bridge.send_message(YaEditController2::SetKnobMode{
|
|
.instance_id = instance_id(), .mode = mode});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::openHelp(TBool onlyCheck) {
|
|
return bridge.send_message(YaEditController2::OpenHelp{
|
|
.instance_id = instance_id(), .only_check = onlyCheck});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::openAboutBox(TBool onlyCheck) {
|
|
return bridge.send_message(YaEditController2::OpenAboutBox{
|
|
.instance_id = instance_id(), .only_check = onlyCheck});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::beginEditFromHost(Steinberg::Vst::ParamID paramID) {
|
|
return bridge.send_message(YaEditControllerHostEditing::BeginEditFromHost{
|
|
.instance_id = instance_id(), .param_id = paramID});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::endEditFromHost(Steinberg::Vst::ParamID paramID) {
|
|
return bridge.send_message(YaEditControllerHostEditing::EndEditFromHost{
|
|
.instance_id = instance_id(), .param_id = paramID});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::setChannelContextInfos(
|
|
Steinberg::Vst::IAttributeList* list) {
|
|
if (list) {
|
|
return bridge.send_message(YaInfoListener::SetChannelContextInfos{
|
|
.instance_id = instance_id(),
|
|
.list = YaAttributeList::read_channel_context(list)});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IInfoListener::setChannelContextInfos()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
int32 PLUGIN_API Vst3PluginProxyImpl::getKeyswitchCount(int32 busIndex,
|
|
int16 channel) {
|
|
return bridge.send_message(
|
|
YaKeyswitchController::GetKeyswitchCount{.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getKeyswitchInfo(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
int32 keySwitchIndex,
|
|
Steinberg::Vst::KeyswitchInfo& info /*out*/) {
|
|
const GetKeyswitchInfoResponse response =
|
|
bridge.send_message(YaKeyswitchController::GetKeyswitchInfo{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.key_switch_index = keySwitchIndex});
|
|
|
|
info = response.info;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::onLiveMIDIControllerInput(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
Steinberg::Vst::CtrlNumber midiCC) {
|
|
return bridge.send_message(
|
|
YaMidiLearn::OnLiveMIDIControllerInput{.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.midi_cc = midiCC});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getMidiControllerAssignment(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
Steinberg::Vst::CtrlNumber midiControllerNumber,
|
|
Steinberg::Vst::ParamID& id /*out*/) {
|
|
const GetMidiControllerAssignmentResponse response =
|
|
bridge.send_message(YaMidiMapping::GetMidiControllerAssignment{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.midi_controller_number = midiControllerNumber});
|
|
|
|
id = response.id;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
int32 PLUGIN_API Vst3PluginProxyImpl::getNoteExpressionCount(int32 busIndex,
|
|
int16 channel) {
|
|
return bridge.send_message(
|
|
YaNoteExpressionController::GetNoteExpressionCount{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getNoteExpressionInfo(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
int32 noteExpressionIndex,
|
|
Steinberg::Vst::NoteExpressionTypeInfo& info /*out*/) {
|
|
const GetNoteExpressionInfoResponse response =
|
|
bridge.send_message(YaNoteExpressionController::GetNoteExpressionInfo{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.note_expression_index = noteExpressionIndex});
|
|
|
|
info = response.info;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getNoteExpressionStringByValue(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
Steinberg::Vst::NoteExpressionTypeID id,
|
|
Steinberg::Vst::NoteExpressionValue valueNormalized /*in*/,
|
|
Steinberg::Vst::String128 string /*out*/) {
|
|
if (string) {
|
|
const GetNoteExpressionStringByValueResponse response =
|
|
bridge.send_message(
|
|
YaNoteExpressionController::GetNoteExpressionStringByValue{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.id = id,
|
|
.value_normalized = valueNormalized});
|
|
|
|
std::copy(response.string.begin(), response.string.end(), string);
|
|
string[response.string.size()] = 0;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'INoteExpressionController::getNoteExpressionStringByValue()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getNoteExpressionValueByString(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
Steinberg::Vst::NoteExpressionTypeID id,
|
|
const Steinberg::Vst::TChar* string /*in*/,
|
|
Steinberg::Vst::NoteExpressionValue& valueNormalized /*out*/) {
|
|
if (string) {
|
|
const GetNoteExpressionValueByStringResponse response =
|
|
bridge.send_message(
|
|
YaNoteExpressionController::GetNoteExpressionValueByString{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.id = id,
|
|
.string = string});
|
|
|
|
valueNormalized = response.value_normalized;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'INoteExpressionController::getNoteExpressionValueByString()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getPhysicalUIMapping(
|
|
int32 busIndex,
|
|
int16 channel,
|
|
Steinberg::Vst::PhysicalUIMapList& list) {
|
|
const GetNotePhysicalUIMappingResponse response = bridge.send_message(
|
|
YaNoteExpressionPhysicalUIMapping::GetNotePhysicalUIMapping{
|
|
.instance_id = instance_id(),
|
|
.bus_index = busIndex,
|
|
.channel = channel,
|
|
.list = list});
|
|
|
|
response.list.write_back(list);
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getParameterIDFromFunctionName(
|
|
Steinberg::Vst::UnitID unitID,
|
|
Steinberg::FIDString functionName,
|
|
Steinberg::Vst::ParamID& paramID) {
|
|
if (functionName) {
|
|
const GetParameterIDFromFunctionNameResponse response =
|
|
bridge.send_message(
|
|
YaParameterFunctionName::GetParameterIDFromFunctionName{
|
|
.instance_id = instance_id(),
|
|
.unit_id = unitID,
|
|
.function_name = functionName});
|
|
|
|
paramID = response.param_id;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IParameterFunctionName::getParameterIDFromFunctionName()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::initialize(FUnknown* context) {
|
|
if (context) {
|
|
// We will create a proxy object that that supports all the same
|
|
// interfaces as `context`, and then we'll store `context` in this
|
|
// object. We can then use it to handle callbacks made by the Windows
|
|
// VST3 plugin to this context.
|
|
host_context = context;
|
|
|
|
// Automatically converted smart pointers for when the plugin performs a
|
|
// callback later
|
|
host_application = host_context;
|
|
plug_interface_support = host_context;
|
|
|
|
return bridge.send_message(YaPluginBase::Initialize{
|
|
.instance_id = instance_id(),
|
|
.host_context_args = Vst3HostContextProxy::ConstructArgs(
|
|
host_context, instance_id())});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to 'IPluginBase::initialize()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::terminate() {
|
|
return bridge.send_message(
|
|
YaPluginBase::Terminate{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getPrefetchableSupport(
|
|
Steinberg::Vst::PrefetchableSupport& prefetchable /*out*/) {
|
|
const GetPrefetchableSupportResponse response =
|
|
bridge.send_audio_processor_message(
|
|
YaPrefetchableSupport::GetPrefetchableSupport{.instance_id =
|
|
instance_id()});
|
|
|
|
prefetchable = response.prefetchable;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
uint32 PLUGIN_API Vst3PluginProxyImpl::getProcessContextRequirements() {
|
|
return bridge.send_message(
|
|
YaProcessContextRequirements::GetProcessContextRequirements{
|
|
.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::programDataSupported(
|
|
Steinberg::Vst::ProgramListID listId) {
|
|
return bridge.send_message(YaProgramListData::ProgramDataSupported{
|
|
.instance_id = instance_id(), .list_id = listId});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getProgramData(Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex,
|
|
Steinberg::IBStream* data) {
|
|
if (data) {
|
|
const GetProgramDataResponse response = bridge.send_message(
|
|
YaProgramListData::GetProgramData{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex,
|
|
.data = data});
|
|
|
|
assert(response.data.write_back(data) == Steinberg::kResultOk);
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IProgramListData::getProgramData()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setProgramData(Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex,
|
|
Steinberg::IBStream* data) {
|
|
if (data) {
|
|
return bridge.send_message(
|
|
YaProgramListData::SetProgramData{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex,
|
|
.data = data});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IProgramListData::setProgramData()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::unitDataSupported(Steinberg::Vst::UnitID unitId) {
|
|
return bridge.send_message(YaUnitData::UnitDataSupported{
|
|
.instance_id = instance_id(), .unit_id = unitId});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getUnitData(Steinberg::Vst::UnitID unitId,
|
|
Steinberg::IBStream* data) {
|
|
if (data) {
|
|
const GetUnitDataResponse response =
|
|
bridge.send_message(YaUnitData::GetUnitData{
|
|
.instance_id = instance_id(), .unit_id = unitId, .data = data});
|
|
|
|
assert(response.data.write_back(data) == Steinberg::kResultOk);
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to 'IUnitData::getUnitData()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setUnitData(Steinberg::Vst::UnitID unitId,
|
|
Steinberg::IBStream* data) {
|
|
if (data) {
|
|
return bridge.send_message(YaUnitData::SetUnitData{
|
|
.instance_id = instance_id(), .unit_id = unitId, .data = data});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to 'IUnitData::setUnitData()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
int32 PLUGIN_API Vst3PluginProxyImpl::getUnitCount() {
|
|
return bridge.send_message(
|
|
YaUnitInfo::GetUnitCount{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getUnitInfo(int32 unitIndex,
|
|
Steinberg::Vst::UnitInfo& info /*out*/) {
|
|
const GetUnitInfoResponse response =
|
|
bridge.send_message(YaUnitInfo::GetUnitInfo{
|
|
.instance_id = instance_id(), .unit_index = unitIndex});
|
|
|
|
info = response.info;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
int32 PLUGIN_API Vst3PluginProxyImpl::getProgramListCount() {
|
|
return bridge.send_message(
|
|
YaUnitInfo::GetProgramListCount{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getProgramListInfo(
|
|
int32 listIndex,
|
|
Steinberg::Vst::ProgramListInfo& info /*out*/) {
|
|
const GetProgramListInfoResponse response =
|
|
bridge.send_message(YaUnitInfo::GetProgramListInfo{
|
|
.instance_id = instance_id(), .list_index = listIndex});
|
|
|
|
info = response.info;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getProgramName(Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex,
|
|
Steinberg::Vst::String128 name /*out*/) {
|
|
if (name) {
|
|
const GetProgramNameResponse response = bridge.send_message(
|
|
YaUnitInfo::GetProgramName{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex});
|
|
|
|
std::copy(response.name.begin(), response.name.end(), name);
|
|
name[response.name.size()] = 0;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to 'IUnitInfo::getProgramName()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getProgramInfo(
|
|
Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex,
|
|
Steinberg::Vst::CString attributeId /*in*/,
|
|
Steinberg::Vst::String128 attributeValue /*out*/) {
|
|
if (attributeId && attributeValue) {
|
|
const GetProgramInfoResponse response = bridge.send_message(
|
|
YaUnitInfo::GetProgramInfo{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex,
|
|
.attribute_id = attributeId});
|
|
|
|
std::copy(response.attribute_value.begin(),
|
|
response.attribute_value.end(), attributeValue);
|
|
attributeValue[response.attribute_value.size()] = 0;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to 'IUnitInfo::getProgramInfo()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::hasProgramPitchNames(Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex) {
|
|
return bridge.send_message(
|
|
YaUnitInfo::HasProgramPitchNames{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex});
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getProgramPitchName(
|
|
Steinberg::Vst::ProgramListID listId,
|
|
int32 programIndex,
|
|
int16 midiPitch,
|
|
Steinberg::Vst::String128 name /*out*/) {
|
|
if (name) {
|
|
const GetProgramPitchNameResponse response = bridge.send_message(
|
|
YaUnitInfo::GetProgramPitchName{.instance_id = instance_id(),
|
|
.list_id = listId,
|
|
.program_index = programIndex,
|
|
.midi_pitch = midiPitch});
|
|
|
|
std::copy(response.name.begin(), response.name.end(), name);
|
|
name[response.name.size()] = 0;
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IUnitInfo::getProgramPitchName()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
Steinberg::Vst::UnitID PLUGIN_API Vst3PluginProxyImpl::getSelectedUnit() {
|
|
return bridge.send_message(
|
|
YaUnitInfo::GetSelectedUnit{.instance_id = instance_id()});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::selectUnit(Steinberg::Vst::UnitID unitId) {
|
|
return bridge.send_message(YaUnitInfo::SelectUnit{
|
|
.instance_id = instance_id(), .unit_id = unitId});
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::getUnitByBus(Steinberg::Vst::MediaType type,
|
|
Steinberg::Vst::BusDirection dir,
|
|
int32 busIndex,
|
|
int32 channel,
|
|
Steinberg::Vst::UnitID& unitId /*out*/) {
|
|
const GetUnitByBusResponse response = bridge.send_message(
|
|
YaUnitInfo::GetUnitByBus{.instance_id = instance_id(),
|
|
.type = type,
|
|
.dir = dir,
|
|
.bus_index = busIndex,
|
|
.channel = channel});
|
|
|
|
unitId = response.unit_id;
|
|
|
|
return response.result;
|
|
}
|
|
|
|
tresult PLUGIN_API
|
|
Vst3PluginProxyImpl::setUnitProgramData(int32 listOrUnitId,
|
|
int32 programIndex,
|
|
Steinberg::IBStream* data) {
|
|
if (data) {
|
|
return bridge.send_message(
|
|
YaUnitInfo::SetUnitProgramData{.instance_id = instance_id(),
|
|
.list_or_unit_id = listOrUnitId,
|
|
.program_index = programIndex,
|
|
.data = data});
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IUnitInfo::setUnitProgramData()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
tresult PLUGIN_API Vst3PluginProxyImpl::getXmlRepresentationStream(
|
|
Steinberg::Vst::RepresentationInfo& info /*in*/,
|
|
Steinberg::IBStream* stream /*out*/) {
|
|
if (stream) {
|
|
const GetXmlRepresentationStreamResponse response = bridge.send_message(
|
|
YaXmlRepresentationController::GetXmlRepresentationStream{
|
|
.instance_id = instance_id(), .info = info, .stream = stream});
|
|
|
|
response.stream.write_back(stream);
|
|
|
|
return response.result;
|
|
} else {
|
|
bridge.logger.log(
|
|
"WARNING: Null pointer passed to "
|
|
"'IXmlRepresentationController::getXmlRepresentationStream()'");
|
|
return Steinberg::kInvalidArgument;
|
|
}
|
|
}
|
|
|
|
void Vst3PluginProxyImpl::clear_bus_cache() {
|
|
if (processing_bus_cache) {
|
|
processing_bus_cache.emplace();
|
|
}
|
|
}
|
|
|
|
void Vst3PluginProxyImpl::clear_parameter_cache() {
|
|
parameter_info_cache = ParameterInfoCache{};
|
|
}
|