From 448230662beaaa5ef9a460e4ba6e6740a3f85bc7 Mon Sep 17 00:00:00 2001 From: jatinchowdhury18 Date: Fri, 17 Nov 2023 09:28:21 -0800 Subject: [PATCH] Tweaks for Buffer helpers and SmoothedBufferValue (#469) * Tweaks for Buffer helpers and SmoothedBufferValue * CI fixes --- .../Buffers/chowdsp_BufferView.h | 12 ++-- .../Buffers/chowdsp_SIMDBufferHelpers.h | 63 ++++++++++++------- .../Other/chowdsp_SmoothedBufferValue.cpp | 29 ++++++++- .../Other/chowdsp_SmoothedBufferValue.h | 18 ++++-- 4 files changed, 88 insertions(+), 34 deletions(-) diff --git a/modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h b/modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h index 12711039b..768b09b7e 100644 --- a/modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h +++ b/modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h @@ -14,9 +14,11 @@ class BufferView /** The sample type used by the buffer */ using Type = SampleType; - BufferView& operator= (const BufferView&) = delete; - BufferView (BufferView&&) = delete; - BufferView& operator= (BufferView&&) = delete; + BufferView() = default; + + BufferView& operator= (const BufferView&) = default; + BufferView (BufferView&&) noexcept = default; + BufferView& operator= (BufferView&&) noexcept = default; BufferView (SampleType* const* data, int dataNumChannels, int dataNumSamples, int sampleOffset = 0) : numChannels (dataNumChannels), numSamples (dataNumSamples) @@ -253,8 +255,8 @@ class BufferView channelPointers[ch] = data[ch + (size_t) startChannel] + sampleOffset; } - const int numChannels = 1; - const int numSamples; + int numChannels = 1; + int numSamples = 0; // Assuming we will never need an audio buffer with more than 64 channels. // Maybe we'll need to increase this is we're doing high-order ambisonics or something? diff --git a/modules/dsp/chowdsp_buffers/Buffers/chowdsp_SIMDBufferHelpers.h b/modules/dsp/chowdsp_buffers/Buffers/chowdsp_SIMDBufferHelpers.h index 3d47f49c2..742a09ad7 100644 --- a/modules/dsp/chowdsp_buffers/Buffers/chowdsp_SIMDBufferHelpers.h +++ b/modules/dsp/chowdsp_buffers/Buffers/chowdsp_SIMDBufferHelpers.h @@ -4,26 +4,23 @@ namespace chowdsp { #if ! CHOWDSP_NO_XSIMD /** - * Copies data from a chowdsp::Buffer of some scalar type, - * to a chowdsp::Buffer of the corresponding SIMD type. + * Copies data from a chowdsp::BufferView of some scalar type, + * to a chowdsp::BufferView of the corresponding SIMD type. * - * The SIMD buffer must have at least enough memory allocated - * to store all of the data in the scalar buffer. The SIMD buffer - * will be resized (without allocating) to match the size of - * the scalar buffer. If the number of channels in the scalar + * The SIMD BufferView is expected to be the correct size to + * hold the SIMD data. If the number of channels in the scalar * buffer does not divide evenly into the SIMD register size, * the SIMD buffer will be padded with some extra channels, * containing zeros. */ -template -[[maybe_unused]] static void copyToSIMDBuffer (const BufferView& scalarBuffer, Buffer>& simdBuffer) noexcept +template +[[maybe_unused]] static void copyToSIMDBuffer (const BufferView& scalarBuffer, const BufferView>& simdBuffer) noexcept { using Vec = xsimd::batch; static constexpr auto vecSize = (int) Vec::size; const auto numSamples = scalarBuffer.getNumSamples(); const auto numScalarChannels = scalarBuffer.getNumChannels(); - const auto numSIMDChannels = buffers_detail::ceiling_divide (numScalarChannels, vecSize); const auto interleaveSamples = [numSamples] (const T1** source, T2* dest, int numChannels) { @@ -42,8 +39,6 @@ template } }; - simdBuffer.setCurrentSize (numSIMDChannels, numSamples); - for (int ch = 0; ch < numScalarChannels; ch += vecSize) { const auto channelsToInterleave = juce::jmin (vecSize, numScalarChannels - ch); @@ -60,25 +55,49 @@ template } } +/** + * Copies data from a chowdsp::BufferView of some scalar type, + * to a chowdsp::Buffer of the corresponding SIMD type. + * + * The SIMD buffer must have at least enough memory allocated + * to store all of the data in the scalar buffer. The SIMD buffer + * will be resized (without allocating) to match the size of + * the scalar buffer. If the number of channels in the scalar + * buffer does not divide evenly into the SIMD register size, + * the SIMD buffer will be padded with some extra channels, + * containing zeros. + */ +template +[[maybe_unused]] static void copyToSIMDBuffer (const BufferView& scalarBuffer, Buffer>& simdBuffer) noexcept +{ + using Vec = xsimd::batch; + static constexpr auto vecSize = (int) Vec::size; + + const auto numSamples = scalarBuffer.getNumSamples(); + const auto numScalarChannels = scalarBuffer.getNumChannels(); + const auto numSIMDChannels = buffers_detail::ceiling_divide (numScalarChannels, vecSize); + + simdBuffer.setCurrentSize (numSIMDChannels, numSamples); + + copyToSIMDBuffer (scalarBuffer, BufferView { simdBuffer }); +} + /** * Copies data from a chowdsp::Buffer of some scalar type, * to a chowdsp::Buffer of the corresponding SIMD type. */ -template +template [[maybe_unused]] static void copyToSIMDBuffer (const Buffer& scalarBuffer, Buffer>& simdBuffer) noexcept { copyToSIMDBuffer (static_cast&> (scalarBuffer), simdBuffer); } /** - * Copies data from a chowdsp::Buffer of some SIMD type, - * to a chowdsp::Buffer of the corresponding scalar type. - * - * The scalar buffer will NOT be resized to match the size - * of the SIMD buffer. + * Copies data from a chowdsp::BufferView of some SIMD type, + * to a chowdsp::BufferView of the corresponding scalar type. */ -template -[[maybe_unused]] static void copyFromSIMDBuffer (const Buffer>& simdBuffer, const BufferView& scalarBuffer) noexcept +template +[[maybe_unused]] static void copyFromSIMDBuffer (const BufferView>& simdBuffer, const BufferView& scalarBuffer) noexcept { using Vec = xsimd::batch; static constexpr auto vecSize = (int) Vec::size; @@ -106,7 +125,7 @@ template for (int ch = 0; ch < numSIMDChannels; ++ch) { - const auto channelsToDeinterleave = juce::jmin (vecSize, scalarBuffer.getNumChannels() - ch * vecSize); + const auto channelsToDeinterleave = std::min (vecSize, scalarBuffer.getNumChannels() - ch * vecSize); T1* scalarChannelPointers[(size_t) vecSize] {}; for (int i = 0; i < channelsToDeinterleave; ++i) @@ -124,10 +143,10 @@ template * Copies data from a chowdsp::Buffer of some SIMD type, * to a chowdsp::Buffer of the corresponding scalar type. */ -template +template [[maybe_unused]] static void copyFromSIMDBuffer (const Buffer>& simdBuffer, Buffer& scalarBuffer) noexcept { - copyFromSIMDBuffer (simdBuffer, static_cast&> (scalarBuffer)); + copyFromSIMDBuffer (simdBuffer, static_cast&> (scalarBuffer)); } #endif // ! CHOWDSP_NO_XSIMD } // namespace chowdsp diff --git a/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp b/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp index 19d97423b..558450751 100644 --- a/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp +++ b/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.cpp @@ -2,6 +2,12 @@ namespace chowdsp { +#if ! CHOWDSP_NO_XSIMD +constexpr auto bufferAlignment = xsimd::default_arch::alignment(); +#else +constexpr size_t bufferAlignment = 16; +#endif + template void SmoothedBufferValue::setParameterHandle (std::atomic* handle) { @@ -23,10 +29,14 @@ void SmoothedBufferValue::setParameterHandle ([[ } template -void SmoothedBufferValue::prepare (double fs, int samplesPerBlock) +void SmoothedBufferValue::prepare (double fs, int samplesPerBlock, bool useInternalVector) { sampleRate = fs; - buffer.resize ((size_t) samplesPerBlock, {}); + if (useInternalVector) + { + buffer.resize ((size_t) samplesPerBlock, {}); + bufferData = buffer.data(); + } smoother.reset (sampleRate, rampLengthInSeconds); if (parameterHandle != nullptr) @@ -74,6 +84,13 @@ void SmoothedBufferValue::setRampLength (double isCurrentlySmoothing = false; } +template +void SmoothedBufferValue::process (int numSamples, ArenaAllocator& alloc) +{ + bufferData = alloc.allocate (numSamples, bufferAlignment); + process (numSamples); +} + template void SmoothedBufferValue::process (int numSamples) { @@ -95,13 +112,19 @@ void SmoothedBufferValue::process (int numSample } } +template +void SmoothedBufferValue::process (FloatType value, int numSamples, ArenaAllocator& alloc) +{ + bufferData = alloc.allocate (numSamples, bufferAlignment); + process (value, numSamples); +} + template void SmoothedBufferValue::process (FloatType value, int numSamples) { const auto mappedValue = mappingFunction (value); smoother.setTargetValue (mappedValue); - auto* bufferData = buffer.data(); if (! smoother.isSmoothing()) { isCurrentlySmoothing = false; diff --git a/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.h b/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.h index 5a9dbe2ca..b22d8e0c6 100644 --- a/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.h +++ b/modules/dsp/chowdsp_dsp_data_structures/Other/chowdsp_SmoothedBufferValue.h @@ -46,8 +46,14 @@ class SmoothedBufferValue */ void setParameterHandle (const FloatParameter* handle); - /** Prepare the smoother to process samples with a given sample rate and block size. */ - void prepare (double sampleRate, int samplesPerBlock); + /** + * Prepare the smoother to process samples with a given sample rate + * and block size. + * + * If you're planning to use the SmoothedBuffer with an arena allocator, + * set useInternalVector to false. + */ + void prepare (double sampleRate, int samplesPerBlock, bool useInternalVector = true); /** Resets the state of the smoother with a given value. */ void reset (FloatType resetValue); @@ -69,18 +75,20 @@ class SmoothedBufferValue /** * Process smoothing for the current parameter handle. - * Please don't call this function if the parameter handle has nt been set! + * Please don't call this function if the parameter handle hasn't been set! */ void process (int numSamples); + void process (int numSamples, ArenaAllocator& alloc); /** * Process smoothing for the input value. * If smoothing an audio parameter, it is recommended to use a parameter handle instead! */ void process (FloatType value, int numSamples); + void process (FloatType value, int numSamples, ArenaAllocator& alloc); /** Returns a pointer to the current smoothed buffer. */ - [[nodiscard]] const FloatType* getSmoothedBuffer() const { return buffer.data(); } + [[nodiscard]] const FloatType* getSmoothedBuffer() const { return bufferData; } /** * Optional mapping function to map from the set value to the smoothed value. @@ -97,6 +105,8 @@ class SmoothedBufferValue #else std::vector buffer; #endif + FloatType* bufferData = nullptr; + juce::SmoothedValue smoother; bool isCurrentlySmoothing = false;