diff --git a/modules/juce_audio_processors/format_types/juce_VST3Common.h b/modules/juce_audio_processors/format_types/juce_VST3Common.h index 2779a1914b..8ef0fe3e43 100644 --- a/modules/juce_audio_processors/format_types/juce_VST3Common.h +++ b/modules/juce_audio_processors/format_types/juce_VST3Common.h @@ -921,6 +921,101 @@ template <> struct VST3FloatAndDoubleBusMapCompositeHelper static VST3BufferExchange::BusMap& get (VST3FloatAndDoubleBusMapComposite& impl) { return impl.doubleVersion; } }; +//============================================================================== +class FloatCache +{ + using FlagType = uint32_t; + +public: + FloatCache() = default; + + explicit FloatCache (size_t sizeIn) + : values (sizeIn), + flags (divCeil (sizeIn, numFlagBits)) + { + std::fill (values.begin(), values.end(), 0.0f); + std::fill (flags.begin(), flags.end(), 0); + } + + size_t size() const noexcept { return values.size(); } + + void set (size_t index, float value) + { + jassert (index < size()); + values[index].store (value, std::memory_order_relaxed); + flags[index / numFlagBits].fetch_or ((FlagType) 1 << (index % numFlagBits), + std::memory_order_acq_rel); + } + + float get (size_t index) const noexcept + { + jassert (index < size()); + return values[index].load (std::memory_order_relaxed); + } + + /* Calls the supplied callback for any entries which have been modified + since the last call to this function. + */ + template + void ifSet (Callback&& callback) + { + for (size_t flagIndex = 0; flagIndex < flags.size(); ++flagIndex) + { + const auto prevFlags = flags[flagIndex].exchange (0, std::memory_order_acq_rel); + + for (size_t bit = 0; bit < numFlagBits; ++bit) + { + if (prevFlags & ((FlagType) 1 << bit)) + { + const auto itemIndex = (flagIndex * numFlagBits) + bit; + callback (itemIndex, values[itemIndex].load (std::memory_order_relaxed)); + } + } + } + } + +private: + static constexpr size_t numFlagBits = 8 * sizeof (FlagType); + + static constexpr size_t divCeil (size_t a, size_t b) + { + return (a / b) + ((a % b) != 0); + } + + std::vector> values; + std::vector> flags; +}; + +/* Provides very quick polling of all parameter states. + + We must iterate all parameters on each processBlock call to check whether any + parameter value has changed. This class attempts to make this polling process + as quick as possible. +*/ +class CachedParamValues +{ +public: + CachedParamValues() = default; + + explicit CachedParamValues (std::vector paramIdsIn) + : paramIds (std::move (paramIdsIn)), floatCache (paramIds.size()) {} + + size_t size() const noexcept { return floatCache.size(); } + + Steinberg::Vst::ParamID getParamID (size_t index) const noexcept { return paramIds[index]; } + + void set (size_t index, float value) { floatCache.set (index, value); } + + float get (size_t index) const noexcept { return floatCache.get (index); } + + template + void ifSet (Callback&& callback) { floatCache.ifSet (std::forward (callback)); } + +private: + std::vector paramIds; + FloatCache floatCache; +}; + } // namespace juce #endif // ! DOXYGEN