Cache bus information during processing

This works around an issue with REAPER. During every processing cycle
REAPER would query how many input and output busses we have, and it
would then enumerate over all of those busses. This meant that if a VST3
plugin has 32 output busses, then REAPER will do 34 extra function calls
before processing audio.
This commit is contained in:
Robbert van der Helm
2021-01-30 00:02:06 +01:00
parent 3f7f67fc2d
commit f5b4a28bd0
2 changed files with 99 additions and 8 deletions
+65 -8
View File
@@ -135,6 +135,15 @@ Vst3PluginProxyImpl::setupProcessing(Steinberg::Vst::ProcessSetup& 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});
}
@@ -202,8 +211,31 @@ tresult PLUGIN_API Vst3PluginProxyImpl::setIoMode(Steinberg::Vst::IoMode mode) {
int32 PLUGIN_API
Vst3PluginProxyImpl::getBusCount(Steinberg::Vst::MediaType type,
Steinberg::Vst::BusDirection dir) {
return bridge.send_audio_processor_message(YaComponent::GetBusCount{
.instance_id = instance_id(), .type = type, .dir = 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()) {
bridge.logger.log_request(true, request);
// TODO: Add to the log message that this information was cached
bridge.logger.log_response(true, PrimitiveWrapper(it->second));
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
@@ -211,14 +243,39 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type,
Steinberg::Vst::BusDirection dir,
int32 index,
Steinberg::Vst::BusInfo& bus /*out*/) {
const GetBusInfoResponse response = bridge.send_audio_processor_message(
YaComponent::GetBusInfo{.instance_id = instance_id(),
.type = type,
.dir = dir,
.index = index,
.bus = bus});
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()) {
bridge.logger.log_request(true, request);
// TODO: Add to the log message that this information was cached
bridge.logger.log_response(
true, GetBusInfoResponse{.result = Steinberg::kResultOk,
.updated_bus = it->second});
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;
}
@@ -389,4 +389,38 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy {
* @related Vst3PluginProxyImpl::register_context_menu
*/
std::atomic_size_t current_context_menu_id;
/**
* A cache for `IAudioProcessor::getBusCount()` and
* `IAudioProcessor::getBusInfo()` to work around an implementation issue in
* REAPER. If during processing a plugin returns a value for one of these
* function calls, we'll memoize the function call using the maps defined
* below.
*
* @see processing_bus_cache
*/
struct BusInfoCache {
std::map<
std::tuple<Steinberg::Vst::MediaType, Steinberg::Vst::BusDirection>,
int32>
bus_count;
std::map<std::tuple<Steinberg::Vst::MediaType,
Steinberg::Vst::BusDirection,
int32>,
Steinberg::Vst::BusInfo>
bus_info;
};
/**
* HACK: To work around some behaviour in REAPER where it will repeatedly
* query the same bus information for bus during every processing
* cycle, we'll cache this information during processing. Otherwise
* this will cause `input_busses + output_busses + 2` extra
* unnecessary back and forths for every processing cycle. This can
* really add up for plugins with 16, or even 32 outputs.
*
* Since this information cannot change during processing, this will not
* contain a value while the plugin is not processing audio.
*/
std::optional<BusInfoCache> processing_bus_cache;
};