Add dedicated IAudioProcessor/IComponent sockets

This way every relevant object instance will get its own thread for
handling these calls. The alternative would be creating a full fat
Vst3MessageHandler pair for all object instances, but that would be a
huge waste.
This commit is contained in:
Robbert van der Helm
2020-12-21 17:25:08 +01:00
parent 415c1b5683
commit 51877796fa
10 changed files with 764 additions and 500 deletions
+41 -35
View File
@@ -27,7 +27,7 @@ Vst3PluginProxyImpl::Vst3PluginProxyImpl(Vst3PluginBridge& bridge,
Vst3PluginProxyImpl::~Vst3PluginProxyImpl() {
bridge.send_message(
Vst3PluginProxy::Destruct{.instance_id = instance_id()});
bridge.unregister_plugin_proxy(instance_id());
bridge.unregister_plugin_proxy(*this);
}
tresult PLUGIN_API
@@ -49,29 +49,32 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setBusArrangements(
int32 numOuts) {
// NOTE: Ardour passes a null pointer when `numIns` or `numOuts` is 0, so we
// need to work around that
return bridge.send_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,
});
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_message(
YaAudioProcessor::GetBusArrangement{.instance_id = instance_id(),
.dir = dir,
.index = index,
.arr = 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;
@@ -80,24 +83,26 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getBusArrangement(
tresult PLUGIN_API
Vst3PluginProxyImpl::canProcessSampleSize(int32 symbolicSampleSize) {
return bridge.send_message(YaAudioProcessor::CanProcessSampleSize{
.instance_id = instance_id(),
.symbolic_sample_size = 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_message(
return bridge.send_audio_processor_message(
YaAudioProcessor::GetLatencySamples{.instance_id = instance_id()});
}
tresult PLUGIN_API
Vst3PluginProxyImpl::setupProcessing(Steinberg::Vst::ProcessSetup& setup) {
return bridge.send_message(YaAudioProcessor::SetupProcessing{
.instance_id = instance_id(), .setup = setup});
return bridge.send_audio_processor_message(
YaAudioProcessor::SetupProcessing{.instance_id = instance_id(),
.setup = setup});
}
tresult PLUGIN_API Vst3PluginProxyImpl::setProcessing(TBool state) {
return bridge.send_message(YaAudioProcessor::SetProcessing{
return bridge.send_audio_processor_message(YaAudioProcessor::SetProcessing{
.instance_id = instance_id(), .state = state});
}
@@ -105,7 +110,7 @@ tresult PLUGIN_API
Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
// TODO: Check whether reusing a `YaProcessData` object make a difference in
// terms of performance
ProcessResponse response = bridge.send_message(
ProcessResponse response = bridge.send_audio_processor_message(
YaAudioProcessor::Process{.instance_id = instance_id(), .data = data});
response.output_data.write_back_outputs(data);
@@ -114,14 +119,15 @@ Vst3PluginProxyImpl::process(Steinberg::Vst::ProcessData& data) {
}
uint32 PLUGIN_API Vst3PluginProxyImpl::getTailSamples() {
return bridge.send_message(
return bridge.send_audio_processor_message(
YaAudioProcessor::GetTailSamples{.instance_id = instance_id()});
}
tresult PLUGIN_API
Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
const GetControllerClassIdResponse response = bridge.send_message(
YaComponent::GetControllerClassId{.instance_id = instance_id()});
const GetControllerClassIdResponse response =
bridge.send_audio_processor_message(
YaComponent::GetControllerClassId{.instance_id = instance_id()});
std::copy(response.editor_cid.begin(), response.editor_cid.end(), classId);
@@ -129,14 +135,14 @@ Vst3PluginProxyImpl::getControllerClassId(Steinberg::TUID classId) {
}
tresult PLUGIN_API Vst3PluginProxyImpl::setIoMode(Steinberg::Vst::IoMode mode) {
return bridge.send_message(
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) {
return bridge.send_message(YaComponent::GetBusCount{
return bridge.send_audio_processor_message(YaComponent::GetBusCount{
.instance_id = instance_id(), .type = type, .dir = dir});
}
@@ -145,7 +151,7 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::BusInfo& bus /*out*/) {
const GetBusInfoResponse response = bridge.send_message(
const GetBusInfoResponse response = bridge.send_audio_processor_message(
YaComponent::GetBusInfo{.instance_id = instance_id(),
.type = type,
.dir = dir,
@@ -159,7 +165,7 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
tresult PLUGIN_API Vst3PluginProxyImpl::getRoutingInfo(
Steinberg::Vst::RoutingInfo& inInfo,
Steinberg::Vst::RoutingInfo& outInfo /*out*/) {
const GetRoutingInfoResponse response = bridge.send_message(
const GetRoutingInfoResponse response = bridge.send_audio_processor_message(
YaComponent::GetRoutingInfo{.instance_id = instance_id(),
.in_info = inInfo,
.out_info = outInfo});
@@ -174,7 +180,7 @@ Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type,
Steinberg::Vst::BusDirection dir,
int32 index,
TBool state) {
return bridge.send_message(
return bridge.send_audio_processor_message(
YaComponent::ActivateBus{.instance_id = instance_id(),
.type = type,
.dir = dir,
@@ -183,7 +189,7 @@ Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type,
}
tresult PLUGIN_API Vst3PluginProxyImpl::setActive(TBool state) {
return bridge.send_message(
return bridge.send_audio_processor_message(
YaComponent::SetActive{.instance_id = instance_id(), .state = state});
}
+20 -5
View File
@@ -161,13 +161,28 @@ Steinberg::IPluginFactory* Vst3PluginBridge::get_plugin_factory() {
return plugin_factory;
}
void Vst3PluginBridge::register_plugin_proxy(Vst3PluginProxyImpl& component) {
void Vst3PluginBridge::register_plugin_proxy(
Vst3PluginProxyImpl& proxy_object) {
std::lock_guard lock(plugin_proxies_mutex);
plugin_proxies.emplace(component.instance_id(),
std::ref<Vst3PluginProxyImpl>(component));
plugin_proxies.emplace(proxy_object.instance_id(),
std::ref<Vst3PluginProxyImpl>(proxy_object));
// For optimization reaons we use dedicated sockets for functions that will
// be run in the audio processing loop
if (proxy_object.YaAudioProcessor::supported() ||
proxy_object.YaComponent::supported()) {
sockets.add_audio_processor_and_connect(proxy_object.instance_id());
}
}
void Vst3PluginBridge::unregister_plugin_proxy(size_t instance_id) {
void Vst3PluginBridge::unregister_plugin_proxy(
Vst3PluginProxyImpl& proxy_object) {
std::lock_guard lock(plugin_proxies_mutex);
plugin_proxies.erase(instance_id);
plugin_proxies.erase(proxy_object.instance_id());
if (proxy_object.YaAudioProcessor::supported() ||
proxy_object.YaComponent::supported()) {
sockets.remove_audio_processor(proxy_object.instance_id());
}
}
+20 -10
View File
@@ -76,13 +76,12 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
/**
* Add a `Vst3PluginProxyImpl` to the list of registered proxy objects so we
* can handle host callbacks. This function is called in
* `Vst3PluginProxyImpl`'s constructor.
* `Vst3PluginProxyImpl`'s constructor. If the plugin supports the
* `IAudioProcessor` or `IComponent` interfaces, then we'll also connect to
* a dedicated audio processing socket.
*
* @param instance_id The instance ID generated by the plugin host when
* instantiating the `IComponent`. Used as a stable name to refer to
* these.
* @param plugin_proxy The actual proxy object we can access its host
* context.
* @param proxy_object The proxy object so we can access its host context
* and unique instance identifier.
*
* @see plugin_proxies
*/
@@ -93,13 +92,12 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
* registered proxy objects. Called during the object's destructor after
* asking the Wine plugin host to destroy the component on its side.
*
* @param instance_id The instance ID generated by the plugin host when
* instantiating the `IComponent`. Used as a stable name to refer to
* these.
* @param proxy_object The proxy object so we can access its unique instance
* identifier.
*
* @see plugin_proxies
*/
void unregister_plugin_proxy(size_t instance_id);
void unregister_plugin_proxy(Vst3PluginProxyImpl& proxy_object);
/**
* Send a control message to the Wine plugin host return the response. This
@@ -112,6 +110,18 @@ class Vst3PluginBridge : PluginBridge<Vst3Sockets<std::jthread>> {
object, std::pair<Vst3Logger&, bool>(logger, true));
}
/**
* Send an `IAudioProcessor` or `IComponent` control message to a specific
* plugin instance. This is separated from the above `send_message()` for
* performance reasons, as this way every instance has its own dedicated
* socket and thread.
*/
template <typename T>
typename T::Response send_audio_processor_message(const T& object) {
return sockets.send_audio_processor_message(
object, std::pair<Vst3Logger&, bool>(logger, true));
}
/**
* The logging facility used for this instance of yabridge. Wraps around
* `PluginBridge::generic_logger`.