Move all casted VST3 plugin interfaces to struct

To make Waves plugins happy we're going to have to replace this after
calling `IPluginBase::initialize()`.
This commit is contained in:
Robbert van der Helm
2021-07-05 15:21:49 +02:00
parent aaed5f0128
commit 3fbb01f225
2 changed files with 313 additions and 272 deletions
+218 -191
View File
@@ -48,10 +48,9 @@ Vst3PlugViewInterfaces::Vst3PlugViewInterfaces(
parameter_finder(plug_view), parameter_finder(plug_view),
plug_view_content_scale_support(plug_view) {} plug_view_content_scale_support(plug_view) {}
Vst3PluginInstance::Vst3PluginInstance( Vst3PluginInterfaces::Vst3PluginInterfaces(
Steinberg::IPtr<Steinberg::FUnknown> object) noexcept Steinberg::IPtr<Steinberg::FUnknown> object) noexcept
: object(object), : audio_presentation_latency(object),
audio_presentation_latency(object),
audio_processor(object), audio_processor(object),
automation_state(object), automation_state(object),
component(object), component(object),
@@ -72,11 +71,16 @@ Vst3PluginInstance::Vst3PluginInstance(
process_context_requirements(object), process_context_requirements(object),
program_list_data(object), program_list_data(object),
unit_info(object), unit_info(object),
xml_representation_controller(object), xml_representation_controller(object) {}
Vst3PluginInstance::Vst3PluginInstance(
Steinberg::IPtr<Steinberg::FUnknown> object) noexcept
: object(object),
interfaces(object),
// If the object doesn't support `IPlugBase` then the object cannot be // If the object doesn't support `IPlugBase` then the object cannot be
// uninitialized (this isn't possible right now, but, who knows what the // uninitialized (this isn't possible right now, but, who knows what the
// future might bring) // future might bring)
is_initialized(!plugin_base) {} is_initialized(!interfaces.plugin_base) {}
Vst3Bridge::Vst3Bridge(MainContext& main_context, Vst3Bridge::Vst3Bridge(MainContext& main_context,
std::string plugin_dll_path, std::string plugin_dll_path,
@@ -221,6 +225,9 @@ void Vst3Bridge::run() {
}, },
[&](Vst3PluginProxy::SetState& request) [&](Vst3PluginProxy::SetState& request)
-> Vst3PluginProxy::SetState::Response { -> Vst3PluginProxy::SetState::Response {
const Vst3PluginInterfaces& interfaces =
object_instances.at(request.instance_id).interfaces;
// We need to run `getState()` from the main thread, so we might // We need to run `getState()` from the main thread, so we might
// as well do the same thing with `setState()`. See below. // as well do the same thing with `setState()`. See below.
// NOTE: We also try to handle mutual recursion here, in case // NOTE: We also try to handle mutual recursion here, in case
@@ -229,17 +236,19 @@ void Vst3Bridge::run() {
// This same function is defined in both `IComponent` and // This same function is defined in both `IComponent` and
// `IEditController`, so the host is calling one or the // `IEditController`, so the host is calling one or the
// other // other
if (object_instances.at(request.instance_id).component) { if (interfaces.component) {
return object_instances.at(request.instance_id) return interfaces.component->setState(&request.state);
.component->setState(&request.state);
} else { } else {
return object_instances.at(request.instance_id) return interfaces.edit_controller->setState(
.edit_controller->setState(&request.state); &request.state);
} }
}); });
}, },
[&](Vst3PluginProxy::GetState& request) [&](Vst3PluginProxy::GetState& request)
-> Vst3PluginProxy::GetState::Response { -> Vst3PluginProxy::GetState::Response {
const Vst3PluginInterfaces& interfaces =
object_instances.at(request.instance_id).interfaces;
// NOTE: The VST3 version of Algonaut Atlas doesn't restore // NOTE: The VST3 version of Algonaut Atlas doesn't restore
// state unless this function is run from the GUI thread // state unless this function is run from the GUI thread
// NOTE: This also requires mutual recursion because REAPER will // NOTE: This also requires mutual recursion because REAPER will
@@ -249,13 +258,12 @@ void Vst3Bridge::run() {
// This same function is defined in both `IComponent` // This same function is defined in both `IComponent`
// and `IEditController`, so the host is calling one or // and `IEditController`, so the host is calling one or
// the other // the other
if (object_instances.at(request.instance_id) if (interfaces.component) {
.component) { return interfaces.component->getState(
return object_instances.at(request.instance_id) &request.state);
.component->getState(&request.state);
} else { } else {
return object_instances.at(request.instance_id) return interfaces.edit_controller->getState(
.edit_controller->getState(&request.state); &request.state);
} }
}); });
@@ -267,7 +275,7 @@ void Vst3Bridge::run() {
SetAudioPresentationLatencySamples::Response { SetAudioPresentationLatencySamples::Response {
return object_instances return object_instances
.at(request.instance_id) .at(request.instance_id)
.audio_presentation_latency .interfaces.audio_presentation_latency
->setAudioPresentationLatencySamples( ->setAudioPresentationLatencySamples(
request.dir, request.bus_index, request.dir, request.bus_index,
request.latency_in_samples); request.latency_in_samples);
@@ -275,10 +283,14 @@ void Vst3Bridge::run() {
[&](YaAutomationState::SetAutomationState& request) [&](YaAutomationState::SetAutomationState& request)
-> YaAutomationState::SetAutomationState::Response { -> YaAutomationState::SetAutomationState::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.automation_state->setAutomationState(request.state); .interfaces.automation_state->setAutomationState(
request.state);
}, },
[&](YaConnectionPoint::Connect& request) [&](YaConnectionPoint::Connect& request)
-> YaConnectionPoint::Connect::Response { -> YaConnectionPoint::Connect::Response {
Vst3PluginInstance& this_instance =
object_instances.at(request.instance_id);
// If the host directly connected the underlying objects then we // If the host directly connected the underlying objects then we
// can directly connect them as well. Some hosts, like Ardour // can directly connect them as well. Some hosts, like Ardour
// and Mixbus, will place a proxy between the two plugins This // and Mixbus, will place a proxy between the two plugins This
@@ -292,49 +304,55 @@ void Vst3Bridge::run() {
return std::visit( return std::visit(
overload{ overload{
[&](const native_size_t& other_instance_id) -> tresult { [&](const native_size_t& other_instance_id) -> tresult {
return object_instances.at(request.instance_id) const Vst3PluginInstance& other_instance =
.connection_point->connect( object_instances.at(other_instance_id);
object_instances.at(other_instance_id)
.connection_point); return this_instance.interfaces.connection_point
->connect(
other_instance.interfaces.connection_point);
}, },
[&](Vst3ConnectionPointProxy::ConstructArgs& args) [&](Vst3ConnectionPointProxy::ConstructArgs& args)
-> tresult { -> tresult {
object_instances.at(request.instance_id) this_instance.connection_point_proxy =
.connection_point_proxy = Steinberg::owned( Steinberg::owned(
new Vst3ConnectionPointProxyImpl( new Vst3ConnectionPointProxyImpl(
*this, std::move(args))); *this, std::move(args)));
return object_instances.at(request.instance_id) return this_instance.interfaces.connection_point
.connection_point->connect( ->connect(this_instance.connection_point_proxy);
object_instances.at(request.instance_id)
.connection_point_proxy);
}}, }},
request.other); request.other);
}, },
[&](const YaConnectionPoint::Disconnect& request) [&](const YaConnectionPoint::Disconnect& request)
-> YaConnectionPoint::Disconnect::Response { -> YaConnectionPoint::Disconnect::Response {
Vst3PluginInstance& this_instance =
object_instances.at(request.instance_id);
// If the objects were connected directly we can also disconnect // If the objects were connected directly we can also disconnect
// them directly. Otherwise we'll disconnect them from our proxy // them directly. Otherwise we'll disconnect them from our proxy
// object and then destroy that proxy object. // object and then destroy that proxy object.
if (request.other_instance_id) { if (request.other_instance_id) {
return object_instances.at(request.instance_id) const Vst3PluginInstance& other_instance =
.connection_point->disconnect( object_instances.at(*request.other_instance_id);
object_instances.at(*request.other_instance_id)
.connection_point); return this_instance.interfaces.connection_point
->disconnect(
other_instance.interfaces.connection_point);
} else { } else {
const tresult result = const tresult result =
object_instances.at(request.instance_id) this_instance.interfaces.connection_point->disconnect(
.connection_point->disconnect(
object_instances.at(*request.other_instance_id) object_instances.at(*request.other_instance_id)
.connection_point_proxy); .connection_point_proxy);
object_instances.at(*request.other_instance_id) this_instance.connection_point_proxy.reset();
.connection_point_proxy.reset();
return result; return result;
} }
}, },
[&](const YaConnectionPoint::Notify& request) [&](const YaConnectionPoint::Notify& request)
-> YaConnectionPoint::Notify::Response { -> YaConnectionPoint::Notify::Response {
const Vst3PluginInstance& this_instance =
object_instances.at(request.instance_id);
// NOTE: We're using a few tricks here to pass through a pointer // NOTE: We're using a few tricks here to pass through a pointer
// to the _original_ `IMessage` object passed to a // to the _original_ `IMessage` object passed to a
// connection proxy. This is needed because some plugins // connection proxy. This is needed because some plugins
@@ -351,8 +369,7 @@ void Vst3Bridge::run() {
// solution for this (and bypassing Ardour's connection // solution for this (and bypassing Ardour's connection
// proxies sort of goes against the idea behind yabridge) // proxies sort of goes against the idea behind yabridge)
return do_mutual_recursion_on_gui_thread([&]() -> tresult { return do_mutual_recursion_on_gui_thread([&]() -> tresult {
return object_instances.at(request.instance_id) return this_instance.interfaces.connection_point->notify(
.connection_point->notify(
request.message_ptr.get_original()); request.message_ptr.get_original());
}); });
}, },
@@ -367,18 +384,20 @@ void Vst3Bridge::run() {
[&](YaEditController::SetComponentState& request) [&](YaEditController::SetComponentState& request)
-> YaEditController::SetComponentState::Response { -> YaEditController::SetComponentState::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->setComponentState(&request.state); .interfaces.edit_controller->setComponentState(
&request.state);
}, },
[&](const YaEditController::GetParameterCount& request) [&](const YaEditController::GetParameterCount& request)
-> YaEditController::GetParameterCount::Response { -> YaEditController::GetParameterCount::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->getParameterCount(); .interfaces.edit_controller->getParameterCount();
}, },
[&](YaEditController::GetParameterInfo& request) [&](YaEditController::GetParameterInfo& request)
-> YaEditController::GetParameterInfo::Response { -> YaEditController::GetParameterInfo::Response {
Steinberg::Vst::ParameterInfo info{}; Steinberg::Vst::ParameterInfo info{};
const tresult result = object_instances.at(request.instance_id) const tresult result =
.edit_controller->getParameterInfo( object_instances.at(request.instance_id)
.interfaces.edit_controller->getParameterInfo(
request.param_index, info); request.param_index, info);
return YaEditController::GetParameterInfoResponse{ return YaEditController::GetParameterInfoResponse{
@@ -389,7 +408,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::String128 string{0}; Steinberg::Vst::String128 string{0};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.edit_controller->getParamStringByValue( .interfaces.edit_controller->getParamStringByValue(
request.id, request.value_normalized, string); request.id, request.value_normalized, string);
return YaEditController::GetParamStringByValueResponse{ return YaEditController::GetParamStringByValueResponse{
@@ -401,7 +420,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::ParamValue value_normalized; Steinberg::Vst::ParamValue value_normalized;
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.edit_controller->getParamValueByString( .interfaces.edit_controller->getParamValueByString(
request.id, request.id,
const_cast<Steinberg::Vst::TChar*>( const_cast<Steinberg::Vst::TChar*>(
u16string_to_tchar_pointer(request.string)), u16string_to_tchar_pointer(request.string)),
@@ -413,19 +432,19 @@ void Vst3Bridge::run() {
[&](const YaEditController::NormalizedParamToPlain& request) [&](const YaEditController::NormalizedParamToPlain& request)
-> YaEditController::NormalizedParamToPlain::Response { -> YaEditController::NormalizedParamToPlain::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->normalizedParamToPlain( .interfaces.edit_controller->normalizedParamToPlain(
request.id, request.value_normalized); request.id, request.value_normalized);
}, },
[&](const YaEditController::PlainParamToNormalized& request) [&](const YaEditController::PlainParamToNormalized& request)
-> YaEditController::PlainParamToNormalized::Response { -> YaEditController::PlainParamToNormalized::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->plainParamToNormalized( .interfaces.edit_controller->plainParamToNormalized(
request.id, request.plain_value); request.id, request.plain_value);
}, },
[&](const YaEditController::GetParamNormalized& request) [&](const YaEditController::GetParamNormalized& request)
-> YaEditController::GetParamNormalized::Response { -> YaEditController::GetParamNormalized::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->getParamNormalized(request.id); .interfaces.edit_controller->getParamNormalized(request.id);
}, },
[&](const YaEditController::SetParamNormalized& request) [&](const YaEditController::SetParamNormalized& request)
-> YaEditController::SetParamNormalized::Response { -> YaEditController::SetParamNormalized::Response {
@@ -436,48 +455,48 @@ void Vst3Bridge::run() {
// announced. // announced.
return do_mutual_recursion_on_off_thread([&]() -> tresult { return do_mutual_recursion_on_off_thread([&]() -> tresult {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller->setParamNormalized(request.id, .interfaces.edit_controller->setParamNormalized(
request.value); request.id, request.value);
}); });
}, },
[&](YaEditController::SetComponentHandler& request) [&](YaEditController::SetComponentHandler& request)
-> YaEditController::SetComponentHandler::Response { -> YaEditController::SetComponentHandler::Response {
Vst3PluginInstance& instance =
object_instances.at(request.instance_id);
// If the host passed a valid component handler, then we'll // If the host passed a valid component handler, then we'll
// create a proxy object for the component handler and pass that // create a proxy object for the component handler and pass that
// to the initialize function. The lifetime of this object is // to the initialize function. The lifetime of this object is
// tied to that of the actual plugin object we're proxying for. // tied to that of the actual plugin object we're proxying for.
// Otherwise we'll also pass a null pointer. This often happens // Otherwise we'll also pass a null pointer. This often happens
// just before the host terminates the plugin. // just before the host terminates the plugin.
object_instances.at(request.instance_id) instance.component_handler_proxy =
.component_handler_proxy =
request.component_handler_proxy_args request.component_handler_proxy_args
? Steinberg::owned(new Vst3ComponentHandlerProxyImpl( ? Steinberg::owned(new Vst3ComponentHandlerProxyImpl(
*this, *this,
std::move(*request.component_handler_proxy_args))) std::move(*request.component_handler_proxy_args)))
: nullptr; : nullptr;
return object_instances.at(request.instance_id) return instance.interfaces.edit_controller->setComponentHandler(
.edit_controller->setComponentHandler( instance.component_handler_proxy);
object_instances.at(request.instance_id)
.component_handler_proxy);
}, },
[&](const YaEditController::CreateView& request) [&](const YaEditController::CreateView& request)
-> YaEditController::CreateView::Response { -> YaEditController::CreateView::Response {
Vst3PluginInstance& instance =
object_instances.at(request.instance_id);
// Instantiate the object from the GUI thread // Instantiate the object from the GUI thread
main_context main_context
.run_in_context([&]() -> void { .run_in_context([&]() -> void {
Steinberg::IPtr<Steinberg::IPlugView> plug_view( Steinberg::IPtr<Steinberg::IPlugView> plug_view(
Steinberg::owned( Steinberg::owned(
object_instances.at(request.instance_id) instance.interfaces.edit_controller->createView(
.edit_controller->createView(
request.name.c_str()))); request.name.c_str())));
if (plug_view) { if (plug_view) {
object_instances.at(request.instance_id) instance.plug_view_instance.emplace(plug_view);
.plug_view_instance.emplace(plug_view);
} else { } else {
object_instances.at(request.instance_id) instance.plug_view_instance.reset();
.plug_view_instance.reset()
} }
}) })
.wait(); .wait();
@@ -486,40 +505,39 @@ void Vst3Bridge::run() {
// `IPlugView` object // `IPlugView` object
return YaEditController::CreateViewResponse{ return YaEditController::CreateViewResponse{
.plug_view_args = .plug_view_args =
(object_instances.at(request.instance_id) (instance.plug_view_instance
.plug_view_instance
? std::make_optional< ? std::make_optional<
Vst3PlugViewProxy::ConstructArgs>( Vst3PlugViewProxy::ConstructArgs>(
object_instances.at(request.instance_id) instance.plug_view_instance->plug_view,
.plug_view_instance->plug_view,
request.instance_id) request.instance_id)
: std::nullopt)}; : std::nullopt)};
}, },
[&](const YaEditController2::SetKnobMode& request) [&](const YaEditController2::SetKnobMode& request)
-> YaEditController2::SetKnobMode::Response { -> YaEditController2::SetKnobMode::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller_2->setKnobMode(request.mode); .interfaces.edit_controller_2->setKnobMode(request.mode);
}, },
[&](const YaEditController2::OpenHelp& request) [&](const YaEditController2::OpenHelp& request)
-> YaEditController2::OpenHelp::Response { -> YaEditController2::OpenHelp::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller_2->openHelp(request.only_check); .interfaces.edit_controller_2->openHelp(request.only_check);
}, },
[&](const YaEditController2::OpenAboutBox& request) [&](const YaEditController2::OpenAboutBox& request)
-> YaEditController2::OpenAboutBox::Response { -> YaEditController2::OpenAboutBox::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller_2->openAboutBox(request.only_check); .interfaces.edit_controller_2->openAboutBox(
request.only_check);
}, },
[&](const YaEditControllerHostEditing::BeginEditFromHost& request) [&](const YaEditControllerHostEditing::BeginEditFromHost& request)
-> YaEditControllerHostEditing::BeginEditFromHost::Response { -> YaEditControllerHostEditing::BeginEditFromHost::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller_host_editing->beginEditFromHost( .interfaces.edit_controller_host_editing->beginEditFromHost(
request.param_id); request.param_id);
}, },
[&](const YaEditControllerHostEditing::EndEditFromHost& request) [&](const YaEditControllerHostEditing::EndEditFromHost& request)
-> YaEditControllerHostEditing::EndEditFromHost::Response { -> YaEditControllerHostEditing::EndEditFromHost::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.edit_controller_host_editing->endEditFromHost( .interfaces.edit_controller_host_editing->endEditFromHost(
request.param_id); request.param_id);
}, },
[&](YaInfoListener::SetChannelContextInfos& request) [&](YaInfoListener::SetChannelContextInfos& request)
@@ -530,7 +548,7 @@ void Vst3Bridge::run() {
return main_context return main_context
.run_in_context([&]() -> tresult { .run_in_context([&]() -> tresult {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.info_listener->setChannelContextInfos( .interfaces.info_listener->setChannelContextInfos(
&request.list); &request.list);
}) })
.get(); .get();
@@ -538,15 +556,15 @@ void Vst3Bridge::run() {
[&](const YaKeyswitchController::GetKeyswitchCount& request) [&](const YaKeyswitchController::GetKeyswitchCount& request)
-> YaKeyswitchController::GetKeyswitchCount::Response { -> YaKeyswitchController::GetKeyswitchCount::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.keyswitch_controller->getKeyswitchCount(request.bus_index, .interfaces.keyswitch_controller->getKeyswitchCount(
request.channel); request.bus_index, request.channel);
}, },
[&](const YaKeyswitchController::GetKeyswitchInfo& request) [&](const YaKeyswitchController::GetKeyswitchInfo& request)
-> YaKeyswitchController::GetKeyswitchInfo::Response { -> YaKeyswitchController::GetKeyswitchInfo::Response {
Steinberg::Vst::KeyswitchInfo info{}; Steinberg::Vst::KeyswitchInfo info{};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.keyswitch_controller->getKeyswitchInfo( .interfaces.keyswitch_controller->getKeyswitchInfo(
request.bus_index, request.channel, request.bus_index, request.channel,
request.key_switch_index, info); request.key_switch_index, info);
@@ -556,7 +574,7 @@ void Vst3Bridge::run() {
[&](const YaMidiLearn::OnLiveMIDIControllerInput& request) [&](const YaMidiLearn::OnLiveMIDIControllerInput& request)
-> YaMidiLearn::OnLiveMIDIControllerInput::Response { -> YaMidiLearn::OnLiveMIDIControllerInput::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.midi_learn->onLiveMIDIControllerInput( .interfaces.midi_learn->onLiveMIDIControllerInput(
request.bus_index, request.channel, request.midi_cc); request.bus_index, request.channel, request.midi_cc);
}, },
[&](const YaMidiMapping::GetMidiControllerAssignment& request) [&](const YaMidiMapping::GetMidiControllerAssignment& request)
@@ -564,7 +582,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::ParamID id; Steinberg::Vst::ParamID id;
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.midi_mapping->getMidiControllerAssignment( .interfaces.midi_mapping->getMidiControllerAssignment(
request.bus_index, request.channel, request.bus_index, request.channel,
request.midi_controller_number, id); request.midi_controller_number, id);
@@ -572,12 +590,14 @@ void Vst3Bridge::run() {
.result = result, .id = id}; .result = result, .id = id};
}, },
[&](const YaNoteExpressionController::GetNoteExpressionCount& [&](const YaNoteExpressionController::GetNoteExpressionCount&
request) request) -> YaNoteExpressionController::
-> YaNoteExpressionController::GetNoteExpressionCount:: GetNoteExpressionCount::Response {
Response { return object_instances
return object_instances.at(request.instance_id) .at(request.instance_id)
.note_expression_controller->getNoteExpressionCount( .interfaces.note_expression_controller
request.bus_index, request.channel); ->getNoteExpressionCount(
request.bus_index,
request.channel);
}, },
[&](const YaNoteExpressionController::GetNoteExpressionInfo& [&](const YaNoteExpressionController::GetNoteExpressionInfo&
request) request)
@@ -585,7 +605,8 @@ void Vst3Bridge::run() {
Steinberg::Vst::NoteExpressionTypeInfo info{}; Steinberg::Vst::NoteExpressionTypeInfo info{};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.note_expression_controller->getNoteExpressionInfo( .interfaces.note_expression_controller
->getNoteExpressionInfo(
request.bus_index, request.channel, request.bus_index, request.channel,
request.note_expression_index, info); request.note_expression_index, info);
@@ -600,7 +621,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::String128 string{0}; Steinberg::Vst::String128 string{0};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.note_expression_controller .interfaces.note_expression_controller
->getNoteExpressionStringByValue( ->getNoteExpressionStringByValue(
request.bus_index, request.channel, request.bus_index, request.channel,
request.id, request.value_normalized, request.id, request.value_normalized,
@@ -618,7 +639,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::NoteExpressionValue value_normalized; Steinberg::Vst::NoteExpressionValue value_normalized;
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.note_expression_controller .interfaces.note_expression_controller
->getNoteExpressionValueByString( ->getNoteExpressionValueByString(
request.bus_index, request.channel, request.bus_index, request.channel,
request.id, request.id,
@@ -638,7 +659,7 @@ void Vst3Bridge::run() {
request.list.get(); request.list.get();
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.note_expression_physical_ui_mapping .interfaces.note_expression_physical_ui_mapping
->getPhysicalUIMapping(request.bus_index, ->getPhysicalUIMapping(request.bus_index,
request.channel, request.channel,
reconstructed_list); reconstructed_list);
@@ -660,22 +681,20 @@ void Vst3Bridge::run() {
.result = result, .result_tag = result_tag}; .result = result, .result_tag = result_tag};
}, },
[&](const YaParameterFunctionName::GetParameterIDFromFunctionName& [&](const YaParameterFunctionName::GetParameterIDFromFunctionName&
request) -> YaParameterFunctionName:: request)
GetParameterIDFromFunctionName::Response { -> YaParameterFunctionName::GetParameterIDFromFunctionName::
Response {
Steinberg::Vst::ParamID param_id; Steinberg::Vst::ParamID param_id;
const tresult result = const tresult result =
object_instances object_instances.at(request.instance_id)
.at(request.instance_id) .interfaces.parameter_function_name
.parameter_function_name
->getParameterIDFromFunctionName( ->getParameterIDFromFunctionName(
request.unit_id, request.unit_id,
request.function_name.c_str(), request.function_name.c_str(), param_id);
param_id);
return YaParameterFunctionName:: return YaParameterFunctionName::
GetParameterIDFromFunctionNameResponse{ GetParameterIDFromFunctionNameResponse{
.result = result, .result = result, .param_id = param_id};
.param_id = param_id};
}, },
[&](const YaPlugView::IsPlatformTypeSupported& request) [&](const YaPlugView::IsPlatformTypeSupported& request)
-> YaPlugView::IsPlatformTypeSupported::Response { -> YaPlugView::IsPlatformTypeSupported::Response {
@@ -889,11 +908,14 @@ void Vst3Bridge::run() {
}, },
[&](YaPluginBase::Initialize& request) [&](YaPluginBase::Initialize& request)
-> YaPluginBase::Initialize::Response { -> YaPluginBase::Initialize::Response {
Vst3PluginInstance& instance =
object_instances.at(request.instance_id);
// We'll create a proxy object for the host context passed by // We'll create a proxy object for the host context passed by
// the host and pass that to the initialize function. The // the host and pass that to the initialize function. The
// lifetime of this object is tied to that of the actual plugin // lifetime of this object is tied to that of the actual plugin
// object we're proxying for. // object we're proxying for.
object_instances.at(request.instance_id).host_context_proxy = instance.host_context_proxy =
Steinberg::owned(new Vst3HostContextProxyImpl( Steinberg::owned(new Vst3HostContextProxyImpl(
*this, std::move(request.host_context_args))); *this, std::move(request.host_context_args)));
@@ -907,18 +929,15 @@ void Vst3Bridge::run() {
set_realtime_priority(true); set_realtime_priority(true);
// This static cast is required to upcast to `FUnknown*` // This static cast is required to upcast to `FUnknown*`
const tresult result = const tresult result =
object_instances.at(request.instance_id) instance.interfaces.plugin_base->initialize(
.plugin_base->initialize(
static_cast<YaHostApplication*>( static_cast<YaHostApplication*>(
object_instances.at(request.instance_id) instance.host_context_proxy));
.host_context_proxy));
set_realtime_priority(false); set_realtime_priority(false);
// The Win32 message loop will not be run up to this // The Win32 message loop will not be run up to this
// point to prevent plugins with partially initialized // point to prevent plugins with partially initialized
// states from misbehaving // states from misbehaving
object_instances.at(request.instance_id) instance.is_initialized = true;
.is_initialized = true;
return result; return result;
}) })
@@ -929,28 +948,29 @@ void Vst3Bridge::run() {
return main_context return main_context
.run_in_context([&]() -> tresult { .run_in_context([&]() -> tresult {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.plugin_base->terminate(); .interfaces.plugin_base->terminate();
}) })
.get(); .get();
}, },
[&](const YaProgramListData::ProgramDataSupported& request) [&](const YaProgramListData::ProgramDataSupported& request)
-> YaProgramListData::ProgramDataSupported::Response { -> YaProgramListData::ProgramDataSupported::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.program_list_data->programDataSupported(request.list_id); .interfaces.program_list_data->programDataSupported(
request.list_id);
}, },
[&](const YaProcessContextRequirements:: [&](const YaProcessContextRequirements::
GetProcessContextRequirements& request) GetProcessContextRequirements& request)
-> YaProcessContextRequirements::GetProcessContextRequirements:: -> YaProcessContextRequirements::GetProcessContextRequirements::
Response { Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.process_context_requirements .interfaces.process_context_requirements
->getProcessContextRequirements(); ->getProcessContextRequirements();
}, },
[&](YaProgramListData::GetProgramData& request) [&](YaProgramListData::GetProgramData& request)
-> YaProgramListData::GetProgramData::Response { -> YaProgramListData::GetProgramData::Response {
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.program_list_data->getProgramData( .interfaces.program_list_data->getProgramData(
request.list_id, request.program_index, request.list_id, request.program_index,
&request.data); &request.data);
@@ -960,19 +980,19 @@ void Vst3Bridge::run() {
[&](YaProgramListData::SetProgramData& request) [&](YaProgramListData::SetProgramData& request)
-> YaProgramListData::SetProgramData::Response { -> YaProgramListData::SetProgramData::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.program_list_data->setProgramData( .interfaces.program_list_data->setProgramData(
request.list_id, request.program_index, &request.data); request.list_id, request.program_index, &request.data);
}, },
[&](const YaUnitData::UnitDataSupported& request) [&](const YaUnitData::UnitDataSupported& request)
-> YaUnitData::UnitDataSupported::Response { -> YaUnitData::UnitDataSupported::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_data->unitDataSupported(request.unit_id); .interfaces.unit_data->unitDataSupported(request.unit_id);
}, },
[&](YaUnitData::GetUnitData& request) [&](YaUnitData::GetUnitData& request)
-> YaUnitData::GetUnitData::Response { -> YaUnitData::GetUnitData::Response {
const tresult result = const tresult result = object_instances.at(request.instance_id)
object_instances.at(request.instance_id) .interfaces.unit_data->getUnitData(
.unit_data->getUnitData(request.unit_id, &request.data); request.unit_id, &request.data);
return YaUnitData::GetUnitDataResponse{ return YaUnitData::GetUnitDataResponse{
.result = result, .data = std::move(request.data)}; .result = result, .data = std::move(request.data)};
@@ -980,7 +1000,8 @@ void Vst3Bridge::run() {
[&](YaUnitData::SetUnitData& request) [&](YaUnitData::SetUnitData& request)
-> YaUnitData::SetUnitData::Response { -> YaUnitData::SetUnitData::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_data->setUnitData(request.unit_id, &request.data); .interfaces.unit_data->setUnitData(request.unit_id,
&request.data);
}, },
[&](YaPluginFactory3::SetHostContext& request) [&](YaPluginFactory3::SetHostContext& request)
-> YaPluginFactory3::SetHostContext::Response { -> YaPluginFactory3::SetHostContext::Response {
@@ -1000,14 +1021,14 @@ void Vst3Bridge::run() {
[&](const YaUnitInfo::GetUnitCount& request) [&](const YaUnitInfo::GetUnitCount& request)
-> YaUnitInfo::GetUnitCount::Response { -> YaUnitInfo::GetUnitCount::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->getUnitCount(); .interfaces.unit_info->getUnitCount();
}, },
[&](const YaUnitInfo::GetUnitInfo& request) [&](const YaUnitInfo::GetUnitInfo& request)
-> YaUnitInfo::GetUnitInfo::Response { -> YaUnitInfo::GetUnitInfo::Response {
Steinberg::Vst::UnitInfo info{}; Steinberg::Vst::UnitInfo info{};
const tresult result = const tresult result = object_instances.at(request.instance_id)
object_instances.at(request.instance_id) .interfaces.unit_info->getUnitInfo(
.unit_info->getUnitInfo(request.unit_index, info); request.unit_index, info);
return YaUnitInfo::GetUnitInfoResponse{.result = result, return YaUnitInfo::GetUnitInfoResponse{.result = result,
.info = std::move(info)}; .info = std::move(info)};
@@ -1015,13 +1036,14 @@ void Vst3Bridge::run() {
[&](const YaUnitInfo::GetProgramListCount& request) [&](const YaUnitInfo::GetProgramListCount& request)
-> YaUnitInfo::GetProgramListCount::Response { -> YaUnitInfo::GetProgramListCount::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->getProgramListCount(); .interfaces.unit_info->getProgramListCount();
}, },
[&](const YaUnitInfo::GetProgramListInfo& request) [&](const YaUnitInfo::GetProgramListInfo& request)
-> YaUnitInfo::GetProgramListInfo::Response { -> YaUnitInfo::GetProgramListInfo::Response {
Steinberg::Vst::ProgramListInfo info{}; Steinberg::Vst::ProgramListInfo info{};
const tresult result = object_instances.at(request.instance_id) const tresult result =
.unit_info->getProgramListInfo( object_instances.at(request.instance_id)
.interfaces.unit_info->getProgramListInfo(
request.list_index, info); request.list_index, info);
return YaUnitInfo::GetProgramListInfoResponse{ return YaUnitInfo::GetProgramListInfoResponse{
@@ -1037,7 +1059,7 @@ void Vst3Bridge::run() {
const tresult result = const tresult result =
do_mutual_recursion_on_off_thread([&]() -> tresult { do_mutual_recursion_on_off_thread([&]() -> tresult {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->getProgramName( .interfaces.unit_info->getProgramName(
request.list_id, request.program_index, name); request.list_id, request.program_index, name);
}); });
@@ -1049,7 +1071,7 @@ void Vst3Bridge::run() {
Steinberg::Vst::String128 attribute_value{0}; Steinberg::Vst::String128 attribute_value{0};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.unit_info->getProgramInfo( .interfaces.unit_info->getProgramInfo(
request.list_id, request.program_index, request.list_id, request.program_index,
request.attribute_id.c_str(), attribute_value); request.attribute_id.c_str(), attribute_value);
@@ -1061,15 +1083,15 @@ void Vst3Bridge::run() {
[&](const YaUnitInfo::HasProgramPitchNames& request) [&](const YaUnitInfo::HasProgramPitchNames& request)
-> YaUnitInfo::HasProgramPitchNames::Response { -> YaUnitInfo::HasProgramPitchNames::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->hasProgramPitchNames(request.list_id, .interfaces.unit_info->hasProgramPitchNames(
request.program_index); request.list_id, request.program_index);
}, },
[&](const YaUnitInfo::GetProgramPitchName& request) [&](const YaUnitInfo::GetProgramPitchName& request)
-> YaUnitInfo::GetProgramPitchName::Response { -> YaUnitInfo::GetProgramPitchName::Response {
Steinberg::Vst::String128 name{0}; Steinberg::Vst::String128 name{0};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.unit_info->getProgramPitchName( .interfaces.unit_info->getProgramPitchName(
request.list_id, request.program_index, request.list_id, request.program_index,
request.midi_pitch, name); request.midi_pitch, name);
@@ -1079,20 +1101,20 @@ void Vst3Bridge::run() {
[&](const YaUnitInfo::GetSelectedUnit& request) [&](const YaUnitInfo::GetSelectedUnit& request)
-> YaUnitInfo::GetSelectedUnit::Response { -> YaUnitInfo::GetSelectedUnit::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->getSelectedUnit(); .interfaces.unit_info->getSelectedUnit();
}, },
[&](const YaUnitInfo::SelectUnit& request) [&](const YaUnitInfo::SelectUnit& request)
-> YaUnitInfo::SelectUnit::Response { -> YaUnitInfo::SelectUnit::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->selectUnit(request.unit_id); .interfaces.unit_info->selectUnit(request.unit_id);
}, },
[&](const YaUnitInfo::GetUnitByBus& request) [&](const YaUnitInfo::GetUnitByBus& request)
-> YaUnitInfo::GetUnitByBus::Response { -> YaUnitInfo::GetUnitByBus::Response {
Steinberg::Vst::UnitID unit_id; Steinberg::Vst::UnitID unit_id;
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.unit_info->getUnitByBus(request.type, request.dir, .interfaces.unit_info->getUnitByBus(
request.bus_index, request.type, request.dir, request.bus_index,
request.channel, unit_id); request.channel, unit_id);
return YaUnitInfo::GetUnitByBusResponse{.result = result, return YaUnitInfo::GetUnitByBusResponse{.result = result,
@@ -1101,25 +1123,24 @@ void Vst3Bridge::run() {
[&](YaUnitInfo::SetUnitProgramData& request) [&](YaUnitInfo::SetUnitProgramData& request)
-> YaUnitInfo::SetUnitProgramData::Response { -> YaUnitInfo::SetUnitProgramData::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.unit_info->setUnitProgramData(request.list_or_unit_id, .interfaces.unit_info->setUnitProgramData(
request.program_index, request.list_or_unit_id, request.program_index,
&request.data); &request.data);
}, },
[&](YaXmlRepresentationController::GetXmlRepresentationStream& [&](YaXmlRepresentationController::GetXmlRepresentationStream&
request) -> YaXmlRepresentationController:: request)
GetXmlRepresentationStream::Response { -> YaXmlRepresentationController::GetXmlRepresentationStream::
Response {
const tresult result = const tresult result =
object_instances object_instances.at(request.instance_id)
.at(request.instance_id) .interfaces.xml_representation_controller
.xml_representation_controller ->getXmlRepresentationStream(request.info,
->getXmlRepresentationStream( &request.stream);
request.info, &request.stream);
return YaXmlRepresentationController:: return YaXmlRepresentationController::
GetXmlRepresentationStreamResponse{ GetXmlRepresentationStreamResponse{
.result = result, .result = result,
.stream = .stream = std::move(request.stream)};
std::move(request.stream)};
}, },
}); });
} }
@@ -1164,10 +1185,12 @@ size_t Vst3Bridge::generate_instance_id() noexcept {
AudioShmBuffer::Config Vst3Bridge::setup_shared_audio_buffers( AudioShmBuffer::Config Vst3Bridge::setup_shared_audio_buffers(
size_t instance_id, size_t instance_id,
const Steinberg::Vst::ProcessSetup& setup) { const Steinberg::Vst::ProcessSetup& setup) {
auto& instance = object_instances.at(instance_id);
const Steinberg::IPtr<Steinberg::Vst::IComponent> component = const Steinberg::IPtr<Steinberg::Vst::IComponent> component =
object_instances.at(instance_id).component; instance.interfaces.component;
const Steinberg::IPtr<Steinberg::Vst::IAudioProcessor> audio_processor = const Steinberg::IPtr<Steinberg::Vst::IAudioProcessor> audio_processor =
object_instances.at(instance_id).audio_processor; instance.interfaces.audio_processor;
assert(component && audio_processor); assert(component && audio_processor);
// We'll query the plugin for its audio bus layouts, and then create // We'll query the plugin for its audio bus layouts, and then create
@@ -1225,13 +1248,10 @@ AudioShmBuffer::Config Vst3Bridge::setup_shared_audio_buffers(
.size = buffer_size, .size = buffer_size,
.input_offsets = std::move(input_bus_offsets), .input_offsets = std::move(input_bus_offsets),
.output_offsets = std::move(output_bus_offsets)}; .output_offsets = std::move(output_bus_offsets)};
if (!instance.process_buffers) {
std::optional<AudioShmBuffer>& process_buffers = instance.process_buffers.emplace(buffer_config);
object_instances.at(instance_id).process_buffers;
if (!process_buffers) {
process_buffers.emplace(buffer_config);
} else { } else {
process_buffers->resize(buffer_config); instance.process_buffers->resize(buffer_config);
} }
// After setting up the shared memory buffer, we need to create a vector of // After setting up the shared memory buffer, we need to create a vector of
@@ -1258,24 +1278,27 @@ AudioShmBuffer::Config Vst3Bridge::setup_shared_audio_buffers(
}; };
set_bus_pointers( set_bus_pointers(
object_instances.at(instance_id).process_buffers_input_pointers, instance.process_buffers_input_pointers,
process_buffers->config.input_offsets, instance.process_buffers->config.input_offsets,
[&](uint32_t bus, uint32_t channel) -> void* { [&](uint32_t bus, uint32_t channel) -> void* {
if (double_precision) { if (double_precision) {
return process_buffers->input_channel_ptr<double>(bus, channel); return instance.process_buffers->input_channel_ptr<double>(
bus, channel);
} else { } else {
return process_buffers->input_channel_ptr<float>(bus, channel); return instance.process_buffers->input_channel_ptr<float>(
bus, channel);
} }
}); });
set_bus_pointers( set_bus_pointers(
object_instances.at(instance_id).process_buffers_output_pointers, instance.process_buffers_output_pointers,
process_buffers->config.output_offsets, instance.process_buffers->config.output_offsets,
[&](uint32_t bus, uint32_t channel) -> void* { [&](uint32_t bus, uint32_t channel) -> void* {
if (double_precision) { if (double_precision) {
return process_buffers->output_channel_ptr<double>(bus, return instance.process_buffers->output_channel_ptr<double>(
channel); bus, channel);
} else { } else {
return process_buffers->output_channel_ptr<float>(bus, channel); return instance.process_buffers->output_channel_ptr<float>(
bus, channel);
} }
}); });
@@ -1292,8 +1315,8 @@ size_t Vst3Bridge::register_object_instance(
// If the object supports `IComponent` or `IAudioProcessor`, // If the object supports `IComponent` or `IAudioProcessor`,
// then we'll set up a dedicated thread for function calls for // then we'll set up a dedicated thread for function calls for
// those interfaces. // those interfaces.
if (object_instances.at(instance_id).audio_processor || if (object_instances.at(instance_id).interfaces.audio_processor ||
object_instances.at(instance_id).component) { object_instances.at(instance_id).interfaces.component) {
std::promise<void> socket_listening_latch; std::promise<void> socket_listening_latch;
object_instances.at(instance_id) object_instances.at(instance_id)
@@ -1320,7 +1343,7 @@ size_t Vst3Bridge::register_object_instance(
0b00000000; 0b00000000;
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.audio_processor->setBusArrangements( .interfaces.audio_processor->setBusArrangements(
request.num_ins > 0 ? request.inputs.data() request.num_ins > 0 ? request.inputs.data()
: &empty_arrangement, : &empty_arrangement,
request.num_ins, request.num_ins,
@@ -1333,7 +1356,7 @@ size_t Vst3Bridge::register_object_instance(
Steinberg::Vst::SpeakerArrangement arr{}; Steinberg::Vst::SpeakerArrangement arr{};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.audio_processor->getBusArrangement( .interfaces.audio_processor->getBusArrangement(
request.dir, request.index, arr); request.dir, request.index, arr);
return YaAudioProcessor::GetBusArrangementResponse{ return YaAudioProcessor::GetBusArrangementResponse{
@@ -1342,19 +1365,19 @@ size_t Vst3Bridge::register_object_instance(
[&](const YaAudioProcessor::CanProcessSampleSize& request) [&](const YaAudioProcessor::CanProcessSampleSize& request)
-> YaAudioProcessor::CanProcessSampleSize::Response { -> YaAudioProcessor::CanProcessSampleSize::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.audio_processor->canProcessSampleSize( .interfaces.audio_processor->canProcessSampleSize(
request.symbolic_sample_size); request.symbolic_sample_size);
}, },
[&](const YaAudioProcessor::GetLatencySamples& request) [&](const YaAudioProcessor::GetLatencySamples& request)
-> YaAudioProcessor::GetLatencySamples::Response { -> YaAudioProcessor::GetLatencySamples::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.audio_processor->getLatencySamples(); .interfaces.audio_processor->getLatencySamples();
}, },
[&](YaAudioProcessor::SetupProcessing& request) [&](YaAudioProcessor::SetupProcessing& request)
-> YaAudioProcessor::SetupProcessing::Response { -> YaAudioProcessor::SetupProcessing::Response {
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.audio_processor->setupProcessing( .interfaces.audio_processor->setupProcessing(
request.setup); request.setup);
// We'll set up the shared audio buffers on the Wine // We'll set up the shared audio buffers on the Wine
@@ -1374,7 +1397,8 @@ size_t Vst3Bridge::register_object_instance(
[&](const YaAudioProcessor::SetProcessing& request) [&](const YaAudioProcessor::SetProcessing& request)
-> YaAudioProcessor::SetProcessing::Response { -> YaAudioProcessor::SetProcessing::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.audio_processor->setProcessing(request.state); .interfaces.audio_processor->setProcessing(
request.state);
}, },
[&](MessageReference<YaAudioProcessor::Process>& [&](MessageReference<YaAudioProcessor::Process>&
request_ref) request_ref)
@@ -1388,12 +1412,6 @@ size_t Vst3Bridge::register_object_instance(
// `bitsery::ext::MessageReference`) // `bitsery::ext::MessageReference`)
YaAudioProcessor::Process& request = request_ref.get(); YaAudioProcessor::Process& request = request_ref.get();
// Most plugins will already enable FTZ, but there are a
// handful of plugins that don't that suffer from
// extreme DSP load increases when they start producing
// denormals
ScopedFlushToZero ftz_guard;
// As suggested by Jack Winter, we'll synchronize this // As suggested by Jack Winter, we'll synchronize this
// thread's audio processing priority with that of the // thread's audio processing priority with that of the
// host's audio thread every once in a while // host's audio thread every once in a while
@@ -1402,17 +1420,23 @@ size_t Vst3Bridge::register_object_instance(
true, *request.new_realtime_priority); true, *request.new_realtime_priority);
} }
Vst3PluginInstance& instance =
object_instances.at(request.instance_id);
// Most plugins will already enable FTZ, but there are a
// handful of plugins that don't that suffer from
// extreme DSP load increases when they start producing
// denormals
ScopedFlushToZero ftz_guard;
// The actual audio is stored in the shared memory // The actual audio is stored in the shared memory
// buffers, so the reconstruction function will need to // buffers, so the reconstruction function will need to
// know where it should point the `AudioBusBuffers` to // know where it should point the `AudioBusBuffers` to
const tresult result = const tresult result =
object_instances.at(request.instance_id) instance.interfaces.audio_processor->process(
.audio_processor->process(
request.data.reconstruct( request.data.reconstruct(
object_instances.at(request.instance_id) instance.process_buffers_input_pointers,
.process_buffers_input_pointers, instance.process_buffers_output_pointers));
object_instances.at(request.instance_id)
.process_buffers_output_pointers));
return YaAudioProcessor::ProcessResponse{ return YaAudioProcessor::ProcessResponse{
.result = result, .result = result,
@@ -1421,14 +1445,15 @@ size_t Vst3Bridge::register_object_instance(
[&](const YaAudioProcessor::GetTailSamples& request) [&](const YaAudioProcessor::GetTailSamples& request)
-> YaAudioProcessor::GetTailSamples::Response { -> YaAudioProcessor::GetTailSamples::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.audio_processor->getTailSamples(); .interfaces.audio_processor->getTailSamples();
}, },
[&](const YaComponent::GetControllerClassId& request) [&](const YaComponent::GetControllerClassId& request)
-> YaComponent::GetControllerClassId::Response { -> YaComponent::GetControllerClassId::Response {
Steinberg::TUID cid{0}; Steinberg::TUID cid{0};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.component->getControllerClassId(cid); .interfaces.component->getControllerClassId(
cid);
return YaComponent::GetControllerClassIdResponse{ return YaComponent::GetControllerClassIdResponse{
.result = result, .editor_cid = cid}; .result = result, .editor_cid = cid};
@@ -1436,21 +1461,22 @@ size_t Vst3Bridge::register_object_instance(
[&](const YaComponent::SetIoMode& request) [&](const YaComponent::SetIoMode& request)
-> YaComponent::SetIoMode::Response { -> YaComponent::SetIoMode::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.component->setIoMode(request.mode); .interfaces.component->setIoMode(request.mode);
}, },
[&](const YaComponent::GetBusCount& request) [&](const YaComponent::GetBusCount& request)
-> YaComponent::GetBusCount::Response { -> YaComponent::GetBusCount::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.component->getBusCount(request.type, request.dir); .interfaces.component->getBusCount(request.type,
request.dir);
}, },
[&](YaComponent::GetBusInfo& request) [&](YaComponent::GetBusInfo& request)
-> YaComponent::GetBusInfo::Response { -> YaComponent::GetBusInfo::Response {
Steinberg::Vst::BusInfo bus{}; Steinberg::Vst::BusInfo bus{};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.component->getBusInfo(request.type, .interfaces.component->getBusInfo(
request.dir, request.type, request.dir, request.index,
request.index, bus); bus);
return YaComponent::GetBusInfoResponse{ return YaComponent::GetBusInfoResponse{
.result = result, .bus = std::move(bus)}; .result = result, .bus = std::move(bus)};
@@ -1460,8 +1486,8 @@ size_t Vst3Bridge::register_object_instance(
Steinberg::Vst::RoutingInfo out_info{}; Steinberg::Vst::RoutingInfo out_info{};
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.component->getRoutingInfo(request.in_info, .interfaces.component->getRoutingInfo(
out_info); request.in_info, out_info);
return YaComponent::GetRoutingInfoResponse{ return YaComponent::GetRoutingInfoResponse{
.result = result, .out_info = std::move(out_info)}; .result = result, .out_info = std::move(out_info)};
@@ -1469,8 +1495,8 @@ size_t Vst3Bridge::register_object_instance(
[&](const YaComponent::ActivateBus& request) [&](const YaComponent::ActivateBus& request)
-> YaComponent::ActivateBus::Response { -> YaComponent::ActivateBus::Response {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.component->activateBus(request.type, request.dir, .interfaces.component->activateBus(
request.index, request.type, request.dir, request.index,
request.state); request.state);
}, },
[&](const YaComponent::SetActive& request) [&](const YaComponent::SetActive& request)
@@ -1486,7 +1512,8 @@ size_t Vst3Bridge::register_object_instance(
return do_mutual_recursion_on_off_thread( return do_mutual_recursion_on_off_thread(
[&]() -> tresult { [&]() -> tresult {
return object_instances.at(request.instance_id) return object_instances.at(request.instance_id)
.component->setActive(request.state); .interfaces.component->setActive(
request.state);
}); });
}, },
[&](const YaPrefetchableSupport::GetPrefetchableSupport& [&](const YaPrefetchableSupport::GetPrefetchableSupport&
@@ -1497,7 +1524,7 @@ size_t Vst3Bridge::register_object_instance(
prefetchable; prefetchable;
const tresult result = const tresult result =
object_instances.at(request.instance_id) object_instances.at(request.instance_id)
.prefetchable_support .interfaces.prefetchable_support
->getPrefetchableSupport(prefetchable); ->getPrefetchableSupport(prefetchable);
return YaPrefetchableSupport:: return YaPrefetchableSupport::
@@ -1520,8 +1547,8 @@ size_t Vst3Bridge::register_object_instance(
void Vst3Bridge::unregister_object_instance(size_t instance_id) { void Vst3Bridge::unregister_object_instance(size_t instance_id) {
// Tear the dedicated audio processing socket down again if we // Tear the dedicated audio processing socket down again if we
// created one while handling `Vst3PluginProxy::Construct` // created one while handling `Vst3PluginProxy::Construct`
if (object_instances.at(instance_id).audio_processor || if (object_instances.at(instance_id).interfaces.audio_processor ||
object_instances.at(instance_id).component) { object_instances.at(instance_id).interfaces.component) {
sockets.remove_audio_processor(instance_id); sockets.remove_audio_processor(instance_id);
} }
+69 -55
View File
@@ -53,12 +53,54 @@ struct Vst3PlugViewInterfaces {
}; };
/** /**
* A holder for plugin object instance created from the factory. This stores all * Smart pointers for all interfaces a VST3 plugin object might support.
* relevant interface smart pointers to that object so we can handle control *
* messages sent by the plugin without having to do these expensive casts all * @relates Vst3PluginInstance
* the time. This also stores any additional context data, such as the */
* `IHostApplication` instance passed to the plugin during struct Vst3PluginInterfaces {
* `IPluginBase::initialize()`. Vst3PluginInterfaces(Steinberg::IPtr<Steinberg::FUnknown> object) noexcept;
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioPresentationLatency>
audio_presentation_latency;
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor> audio_processor;
Steinberg::FUnknownPtr<Steinberg::Vst::IAutomationState> automation_state;
Steinberg::FUnknownPtr<Steinberg::Vst::IComponent> component;
Steinberg::FUnknownPtr<Steinberg::Vst::IConnectionPoint> connection_point;
Steinberg::FUnknownPtr<Steinberg::Vst::IEditController> edit_controller;
Steinberg::FUnknownPtr<Steinberg::Vst::IEditController2> edit_controller_2;
Steinberg::FUnknownPtr<Steinberg::Vst::IEditControllerHostEditing>
edit_controller_host_editing;
Steinberg::FUnknownPtr<Steinberg::Vst::ChannelContext::IInfoListener>
info_listener;
Steinberg::FUnknownPtr<Steinberg::Vst::IKeyswitchController>
keyswitch_controller;
Steinberg::FUnknownPtr<Steinberg::Vst::IMidiLearn> midi_learn;
Steinberg::FUnknownPtr<Steinberg::Vst::IMidiMapping> midi_mapping;
Steinberg::FUnknownPtr<Steinberg::Vst::INoteExpressionController>
note_expression_controller;
Steinberg::FUnknownPtr<Steinberg::Vst::INoteExpressionPhysicalUIMapping>
note_expression_physical_ui_mapping;
Steinberg::FUnknownPtr<Steinberg::IPluginBase> plugin_base;
Steinberg::FUnknownPtr<Steinberg::Vst::IUnitData> unit_data;
Steinberg::FUnknownPtr<Steinberg::Vst::IParameterFunctionName>
parameter_function_name;
Steinberg::FUnknownPtr<Steinberg::Vst::IPrefetchableSupport>
prefetchable_support;
Steinberg::FUnknownPtr<Steinberg::Vst::IProcessContextRequirements>
process_context_requirements;
Steinberg::FUnknownPtr<Steinberg::Vst::IProgramListData> program_list_data;
Steinberg::FUnknownPtr<Steinberg::Vst::IUnitInfo> unit_info;
Steinberg::FUnknownPtr<Steinberg::Vst::IXmlRepresentationController>
xml_representation_controller;
};
/**
* A holder for plugin object instance created from the factory. This contains a
* smart pointer to the object's `FUnknown` interface and everything else we
* need to proxy for this object, like audio threads and proxy objects for
* callbacks. We also store an `interfaces` object that contains smart pointers
* to all relevant VST3 interface so we can handle control messages sent by the
* plugin without having to do these expensive casts all the time.
*/ */
struct Vst3PluginInstance { struct Vst3PluginInstance {
Vst3PluginInstance(Steinberg::IPtr<Steinberg::FUnknown> object) noexcept; Vst3PluginInstance(Steinberg::IPtr<Steinberg::FUnknown> object) noexcept;
@@ -123,21 +165,6 @@ struct Vst3PluginInstance {
registered_context_menus; registered_context_menus;
std::mutex registered_context_menus_mutex; std::mutex registered_context_menus_mutex;
/**
* The base object we cast from.
*/
Steinberg::IPtr<Steinberg::FUnknown> object;
/**
* The `IPlugView` object the plugin returned from a call to
* `IEditController::createView()`.
*
* XXX: Technically VST3 supports multiple named views, so we could have
* multiple different view for a single plugin. This is not used within
* the SDK, so a single pointer should be fine for now.
*/
std::optional<Vst3PlugViewInterfaces> plug_view_instance;
/** /**
* A shared memory object we'll write the input audio buffers to on the * A shared memory object we'll write the input audio buffers to on the
* native plugin side. We'll then let the plugin write its outputs here on * native plugin side. We'll then let the plugin write its outputs here on
@@ -172,41 +199,28 @@ struct Vst3PluginInstance {
*/ */
std::optional<Editor> editor; std::optional<Editor> editor;
// All smart pointers below are created from `component`. They will be null /**
// pointers if `component` did not implement the interface. * The base object we cast from. This is upcasted form the object created by
* the factory.
*/
Steinberg::IPtr<Steinberg::FUnknown> object;
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioPresentationLatency> /**
audio_presentation_latency; * The `IPlugView` object the plugin returned from a call to
Steinberg::FUnknownPtr<Steinberg::Vst::IAudioProcessor> audio_processor; * `IEditController::createView()`. This object can also implement multiple
Steinberg::FUnknownPtr<Steinberg::Vst::IAutomationState> automation_state; * interfaces.
Steinberg::FUnknownPtr<Steinberg::Vst::IComponent> component; *
Steinberg::FUnknownPtr<Steinberg::Vst::IConnectionPoint> connection_point; * XXX: Technically VST3 supports multiple named views, so we could have
Steinberg::FUnknownPtr<Steinberg::Vst::IEditController> edit_controller; * multiple different view for a single plugin. This is not used within
Steinberg::FUnknownPtr<Steinberg::Vst::IEditController2> edit_controller_2; * the SDK, so a single pointer should be fine for now.
Steinberg::FUnknownPtr<Steinberg::Vst::IEditControllerHostEditing> */
edit_controller_host_editing; std::optional<Vst3PlugViewInterfaces> plug_view_instance;
Steinberg::FUnknownPtr<Steinberg::Vst::ChannelContext::IInfoListener>
info_listener; /**
Steinberg::FUnknownPtr<Steinberg::Vst::IKeyswitchController> * This contains smart pointers to all VST3 plugin interfaces that can be
keyswitch_controller; * casted from `object`.
Steinberg::FUnknownPtr<Steinberg::Vst::IMidiLearn> midi_learn; */
Steinberg::FUnknownPtr<Steinberg::Vst::IMidiMapping> midi_mapping; Vst3PluginInterfaces interfaces;
Steinberg::FUnknownPtr<Steinberg::Vst::INoteExpressionController>
note_expression_controller;
Steinberg::FUnknownPtr<Steinberg::Vst::INoteExpressionPhysicalUIMapping>
note_expression_physical_ui_mapping;
Steinberg::FUnknownPtr<Steinberg::IPluginBase> plugin_base;
Steinberg::FUnknownPtr<Steinberg::Vst::IUnitData> unit_data;
Steinberg::FUnknownPtr<Steinberg::Vst::IParameterFunctionName>
parameter_function_name;
Steinberg::FUnknownPtr<Steinberg::Vst::IPrefetchableSupport>
prefetchable_support;
Steinberg::FUnknownPtr<Steinberg::Vst::IProcessContextRequirements>
process_context_requirements;
Steinberg::FUnknownPtr<Steinberg::Vst::IProgramListData> program_list_data;
Steinberg::FUnknownPtr<Steinberg::Vst::IUnitInfo> unit_info;
Steinberg::FUnknownPtr<Steinberg::Vst::IXmlRepresentationController>
xml_representation_controller;
/** /**
* Whether `IPluginBase:initialize()` has already been called for this * Whether `IPluginBase:initialize()` has already been called for this