Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Tweaks for Buffer helpers and SmoothedBufferValue #469

Merged
merged 2 commits into from
Nov 17, 2023
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
12 changes: 7 additions & 5 deletions modules/dsp/chowdsp_buffers/Buffers/chowdsp_BufferView.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,9 +14,11 @@ class BufferView
/** The sample type used by the buffer */
using Type = SampleType;

BufferView& operator= (const BufferView<SampleType>&) = delete;
BufferView (BufferView<SampleType>&&) = delete;
BufferView& operator= (BufferView<SampleType>&&) = delete;
BufferView() = default;

BufferView& operator= (const BufferView<SampleType>&) = default;
BufferView (BufferView<SampleType>&&) noexcept = default;
BufferView& operator= (BufferView<SampleType>&&) noexcept = default;

BufferView (SampleType* const* data, int dataNumChannels, int dataNumSamples, int sampleOffset = 0) : numChannels (dataNumChannels),
numSamples (dataNumSamples)
Expand Down Expand Up @@ -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?
Expand Down
63 changes: 41 additions & 22 deletions modules/dsp/chowdsp_buffers/Buffers/chowdsp_SIMDBufferHelpers.h
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename T1, typename T2>
[[maybe_unused]] static void copyToSIMDBuffer (const BufferView<const T1>& scalarBuffer, Buffer<xsimd::batch<T2>>& simdBuffer) noexcept
template <typename T1, typename T2 = T1>
[[maybe_unused]] static void copyToSIMDBuffer (const BufferView<const T1>& scalarBuffer, const BufferView<xsimd::batch<T2>>& simdBuffer) noexcept
{
using Vec = xsimd::batch<T2>;
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)
{
Expand All @@ -42,8 +39,6 @@ template <typename T1, typename T2>
}
};

simdBuffer.setCurrentSize (numSIMDChannels, numSamples);

for (int ch = 0; ch < numScalarChannels; ch += vecSize)
{
const auto channelsToInterleave = juce::jmin (vecSize, numScalarChannels - ch);
Expand All @@ -60,25 +55,49 @@ template <typename T1, typename T2>
}
}

/**
* 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 <typename T1, typename T2 = T1>
[[maybe_unused]] static void copyToSIMDBuffer (const BufferView<const T1>& scalarBuffer, Buffer<xsimd::batch<T2>>& simdBuffer) noexcept
{
using Vec = xsimd::batch<T2>;
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 <typename T1, typename T2>
template <typename T1, typename T2 = T1>
[[maybe_unused]] static void copyToSIMDBuffer (const Buffer<T1>& scalarBuffer, Buffer<xsimd::batch<T2>>& simdBuffer) noexcept
{
copyToSIMDBuffer (static_cast<const BufferView<const T1>&> (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 <typename T1, typename T2>
[[maybe_unused]] static void copyFromSIMDBuffer (const Buffer<xsimd::batch<T2>>& simdBuffer, const BufferView<T1>& scalarBuffer) noexcept
template <typename T1, typename T2 = T1>
[[maybe_unused]] static void copyFromSIMDBuffer (const BufferView<const xsimd::batch<T2>>& simdBuffer, const BufferView<T1>& scalarBuffer) noexcept
{
using Vec = xsimd::batch<T2>;
static constexpr auto vecSize = (int) Vec::size;
Expand Down Expand Up @@ -106,7 +125,7 @@ template <typename T1, typename T2>

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)
Expand All @@ -124,10 +143,10 @@ template <typename T1, typename T2>
* Copies data from a chowdsp::Buffer of some SIMD type,
* to a chowdsp::Buffer of the corresponding scalar type.
*/
template <typename T1, typename T2>
template <typename T1, typename T2 = T1>
[[maybe_unused]] static void copyFromSIMDBuffer (const Buffer<xsimd::batch<T2>>& simdBuffer, Buffer<T1>& scalarBuffer) noexcept
{
copyFromSIMDBuffer (simdBuffer, static_cast<const BufferView<T1>&> (scalarBuffer));
copyFromSIMDBuffer<T1, T2> (simdBuffer, static_cast<const BufferView<T1>&> (scalarBuffer));
}
#endif // ! CHOWDSP_NO_XSIMD
} // namespace chowdsp
Original file line number Diff line number Diff line change
Expand Up @@ -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 <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setParameterHandle (std::atomic<float>* handle)
{
Expand All @@ -23,10 +29,14 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setParameterHandle ([[
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::prepare (double fs, int samplesPerBlock)
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::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)
Expand Down Expand Up @@ -74,6 +84,13 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setRampLength (double
isCurrentlySmoothing = false;
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples, ArenaAllocator& alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
process (numSamples);
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples)
{
Expand All @@ -95,13 +112,19 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSample
}
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples, ArenaAllocator& alloc)
{
bufferData = alloc.allocate<FloatType> (numSamples, bufferAlignment);
process (value, numSamples);
}

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (FloatType value, int numSamples)
{
const auto mappedValue = mappingFunction (value);
smoother.setTargetValue (mappedValue);

auto* bufferData = buffer.data();
if (! smoother.isSmoothing())
{
isCurrentlySmoothing = false;
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -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);
Expand All @@ -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.
Expand All @@ -97,6 +105,8 @@ class SmoothedBufferValue
#else
std::vector<FloatType> buffer;
#endif
FloatType* bufferData = nullptr;

juce::SmoothedValue<FloatType, ValueSmoothingType> smoother;
bool isCurrentlySmoothing = false;

Expand Down
Loading