diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp index 8d3cb2aa..627ce6f0 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.cpp +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.cpp @@ -156,9 +156,11 @@ 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 + // REAPER used to 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. We keep this in because it can still help performance a little in + // some DAWs. { std::lock_guard lock(processing_bus_cache_mutex); if (state) { @@ -238,8 +240,6 @@ Vst3PluginProxyImpl::getBusCount(Steinberg::Vst::MediaType type, 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 args{ type, dir}; { @@ -280,8 +280,6 @@ Vst3PluginProxyImpl::getBusInfo(Steinberg::Vst::MediaType type, const auto request = YaComponent::GetBusInfo{ .instance_id = instance_id(), .type = type, .dir = dir, .index = index}; - // During processing we'll cache this info to work around an implementation - // issue in REAPER std::tuple args{type, dir, index}; { @@ -347,10 +345,10 @@ Vst3PluginProxyImpl::activateBus(Steinberg::Vst::MediaType type, } 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 + // HACK: Even though we initially 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(); @@ -552,8 +550,6 @@ 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` { std::lock_guard lock(parameter_info_cache_mutex); if (parameter_info_cache.parameter_count) { @@ -586,8 +582,6 @@ tresult PLUGIN_API Vst3PluginProxyImpl::getParameterInfo( const auto request = YaEditController::GetParameterInfo{ .instance_id = instance_id(), .param_index = paramIndex}; - // We'll cache this information to work around an issue in REAPER, see - // `parameter_info_cache` { std::lock_guard lock(parameter_info_cache_mutex); if (auto it = parameter_info_cache.parameter_info.find(paramIndex); diff --git a/src/plugin/bridges/vst3-impls/plugin-proxy.h b/src/plugin/bridges/vst3-impls/plugin-proxy.h index a5364aa8..ccd60e7c 100644 --- a/src/plugin/bridges/vst3-impls/plugin-proxy.h +++ b/src/plugin/bridges/vst3-impls/plugin-proxy.h @@ -21,22 +21,10 @@ /** * Here we pass though all function calls made by the host to the Windows VST3 - * plugin. We sadly had to deviate from yabridge's 'one-to-one passthrough' - * philosphy in two places: - * - * 1. We cache parameter information, and these caches are flushed whenever the - * plugin requests a restart. This is needed because REAPER repeatedly - * queries this information four times per second for all of a plugin's - * parameters while the editor is open. The issue has been reported and it's - * been fixed in REAPER's current pre-release builds (as of February 2021). - * Bitwig also seems to query this information twice on startup, so the cache - * is likely also useful there. - * 2. We also cache input and output bus counts and information. REAPER would - * query this information for every I/O bus before processing audio, which - * ended up increasing audio processing latency considerably for no reason - * (since this information cannot change during processing). REAPER has fixed - * this issue as of a pre-release build in February 2021. JUCE based hosts - * like Carla also seem to query the bus counts every processing cycle. + * plugin. We had to deviate from yabridge's 'one-to-one passthrough' philosphy + * by implementing a few caches for easily memoizable functions that got called + * so many times by DAWs that it started to hurt performance. These are + * documented near the bottom of this class. */ class Vst3PluginProxyImpl : public Vst3PluginProxy { public: @@ -502,12 +490,14 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { */ std::atomic_size_t current_context_menu_id; + // Caches + /** * 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. + * `IAudioProcessor::getBusInfo()`. We'll memoize the function calls for + * these two functions while processing audio (since at that time these + * values should be immutable until the plugin tells the host that this + * information has changed). * * @see processing_bus_cache */ @@ -524,27 +514,25 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { }; /** - * 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. + * This cache originally intended because REAPER would query this + * information at the start of every audio processing cycle. This would hurt + * performance considerably if a plugin has many input or output busses. + * This issue has since been fixed, but some DAWs still query this + * information repeatedly so it seems like a good idea to keep the caches + * in. * - * Since this information cannot change during processing, this will not - * contain a value while the plugin is not processing audio. + * Since this information is immutable during audio processing, this cache + * will only be available at those times. * - * HACK: See the doc comment on this class + * @see clear_bus_cache */ std::optional processing_bus_cache; std::mutex processing_bus_cache_mutex; /** * A cache for `IEditController::getParameterCount()` and - * `IEditController::getParameterInfo()` to work around an implementation - * issue in REAPER. In some situations REAPER will query this information - * four times a second, and all of this back and forth communication really - * adds up when a plugin starts having thousands of parameters. + * `IEditController::getParameterInfo()`. We'll memoize these function calls + * until the plugin tells the host that parameter information has changed. * * @see parameter_cache */ @@ -554,13 +542,16 @@ class Vst3PluginProxyImpl : public Vst3PluginProxy { }; /** - * A cache for the parameter count and infos. This is necessary because in - * some situations REAPER queries this information four times per second - * even though it cannot change. This happens when using the plugin bridges, - * but it can also happen in some other cases so I'm not quite sure what the - * trigger is. + * A cache for the parameter count and infos. This used to be necessary + * because in some situations REAPER would query this information many times + * times per second even though it cannot change unless the plugin tells the + * host that it has. This issue has since been fixed, but we'll keep it in + * because some other hosts also query this information more than once. * - * HACK: See the doc comment on this class + * The cache will be cleared when the plugin tells the host that some of its + * parameter values have changed. + * + * @see clear_parameter_cache */ ParameterInfoCache parameter_info_cache; std::mutex parameter_info_cache_mutex;