Skip to content

Commit

Permalink
Optional memory optomizations (#556)
Browse files Browse the repository at this point in the history
* Optionally using a minified version of chowdsp::SmoothedBufferValue

* FixedSizeFunction tweaks

* Delay updates
  • Loading branch information
jatinchowdhury18 authored Sep 24, 2024
1 parent 10ca93d commit ca1f0e4
Show file tree
Hide file tree
Showing 6 changed files with 76 additions and 51 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -125,7 +125,7 @@ namespace dsp
template <typename Callable,
typename Fn = Decay<Callable>,
IntIfValidConversion<Callable> = 0>
FixedSizeFunction (Callable&& callable)
FixedSizeFunction (Callable&& callable) // NOLINT
{
static_assert (sizeof (Fn) <= len,
"The requested function cannot fit in this FixedSizeFunction");
Expand All @@ -137,6 +137,7 @@ namespace dsp

auto* ptr = new (&storage) Fn (std::forward<Callable> (callable));
jassertquiet ((void*) ptr == (void*) &storage);
ignoreUnused (ptr);
}

/** Move constructor. */
Expand All @@ -148,7 +149,7 @@ namespace dsp

/** Converting constructor from smaller FixedSizeFunctions. */
template <size_t otherLen, typename std::enable_if<(otherLen < len), int>::type = 0>
FixedSizeFunction (FixedSizeFunction<otherLen, Ret (Args...)>&& other) noexcept
FixedSizeFunction (FixedSizeFunction<otherLen, Ret (Args...)>&& other) noexcept // NOLINT
: vtable (other.vtable)
{
move (std::move (other));
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -5,41 +5,51 @@ namespace chowdsp
template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setParameterHandle (std::atomic<float>* handle)
{
#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
modulatableParameterHandle = nullptr;
#endif

parameterHandle = handle;
reset (parameterHandle->load());
#endif
}

#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setParameterHandle ([[maybe_unused]] const FloatParameter* handle)
{
parameterHandle = nullptr;

#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
modulatableParameterHandle = handle;
reset (modulatableParameterHandle->getCurrentValue());
#endif
}
#endif

template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::prepare (double fs, int samplesPerBlock, bool useInternalVector)
{
sampleRate = fs;
if (useInternalVector)
{
#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
buffer.resize ((size_t) samplesPerBlock, {});
bufferData = buffer.data();
#else
jassertfalse;
#endif
}
smoother.reset (sampleRate, rampLengthInSeconds);

#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
if (parameterHandle != nullptr)
reset (parameterHandle->load());
#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
else if (modulatableParameterHandle != nullptr)
reset (modulatableParameterHandle->getCurrentValue());
#endif
else
#endif
reset();
}

Expand All @@ -53,6 +63,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::reset (FloatType reset
template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::reset()
{
#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
if (parameterHandle != nullptr)
{
reset ((FloatType) parameterHandle->load());
Expand All @@ -64,6 +75,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::reset()
}
#endif
else
#endif
{
reset (getCurrentValue());
}
Expand All @@ -81,6 +93,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::setRampLength (double
template <typename FloatType, typename ValueSmoothingTypes>
void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSamples)
{
#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
if (parameterHandle != nullptr)
{
process ((FloatType) parameterHandle->load(), numSamples);
Expand All @@ -92,6 +105,7 @@ void SmoothedBufferValue<FloatType, ValueSmoothingTypes>::process (int numSample
}
#endif
else
#endif
{
// you must set a parameter handle that is not nullptr using setParameterHandle
// before calling the method!
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -12,10 +12,6 @@ namespace juce

namespace chowdsp
{
#ifndef DOXYGEN
class FloatParameter;
#endif

/**
* Template class for smoothing a value over a series of buffers.
* This can be used with raw values or with parameter handles.
Expand All @@ -38,13 +34,15 @@ class SmoothedBufferValue
*/
void setParameterHandle (std::atomic<float>* handle);

#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
/**
* Sets a parameter handle for this buffer to use for smoothing.
* Note that the parameter handle must not be deleted before this object!
*
* @param handle A parameter handle to use for smoothing
*/
void setParameterHandle (const FloatParameter* handle);
#endif

/**
* Prepare the smoother to process samples with a given sample rate
Expand Down Expand Up @@ -98,23 +96,34 @@ class SmoothedBufferValue
* If using a custom mapping function, make sure this is set properly before calling
* `prepare()` or `reset()`.
*/
std::function<FloatType (FloatType)> mappingFunction = [] (auto x)
#if CHOWDSP_SMOOTHED_BUFFER_SMALL
using MappingFunction = juce::dsp::FixedSizeFunction<16, FloatType (FloatType)>;
#else
using MappingFunction = std::function<FloatType (FloatType)>;
#endif
MappingFunction mappingFunction = [] (auto x)
{ return x; };

private:
#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
#if ! CHOWDSP_NO_XSIMD
std::vector<FloatType, xsimd::default_allocator<FloatType>> buffer;
#else
std::vector<FloatType> buffer;
#endif
#endif
FloatType* bufferData = nullptr;

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

#if ! CHOWDSP_SMOOTHED_BUFFER_SMALL
std::atomic<float>* parameterHandle = nullptr;

#if JUCE_MODULE_AVAILABLE_chowdsp_parameters
const FloatParameter* modulatableParameterHandle = nullptr;
#endif
#endif

double sampleRate = 48000.0;
double rampLengthInSeconds = 0.05;
Expand Down
40 changes: 20 additions & 20 deletions modules/dsp/chowdsp_dsp_utils/Delay/chowdsp_DelayInterpolation.h
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ namespace DelayLineInterpolationTypes
{
}

template <typename SampleType, typename NumericType = SampleTypeHelpers::NumericType<SampleType>>
template <typename SampleType, typename NumericType = SampleTypeHelpers::NumericType<SampleType>, typename StorageType = SampleType>
inline SampleType call (const SampleType* buffer, int delayInt, NumericType /*delayFrac*/ = {}, const SampleType& /*state*/ = {})
{
return buffer[delayInt];
return static_cast<SampleType> (buffer[delayInt]);
}
};

Expand All @@ -40,14 +40,14 @@ namespace DelayLineInterpolationTypes
{
}

template <typename SampleType, typename NumericType>
inline SampleType call (const SampleType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
template <typename SampleType, typename NumericType, typename StorageType = SampleType>
inline SampleType call (const StorageType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
{
auto index1 = delayInt;
auto index2 = index1 + 1;

auto value1 = buffer[index1];
auto value2 = buffer[index2];
auto value1 = static_cast<SampleType> (buffer[index1]);
auto value2 = static_cast<SampleType> (buffer[index2]);

return value1 + (SampleType) delayFrac * (value2 - value1);
}
Expand All @@ -71,18 +71,18 @@ namespace DelayLineInterpolationTypes
}
}

template <typename SampleType, typename NumericType>
inline SampleType call (const SampleType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
template <typename SampleType, typename NumericType, typename StorageType = SampleType>
inline SampleType call (const StorageType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
{
auto index1 = delayInt;
auto index2 = index1 + 1;
auto index3 = index2 + 1;
auto index4 = index3 + 1;

auto value1 = buffer[index1];
auto value2 = buffer[index2];
auto value3 = buffer[index3];
auto value4 = buffer[index4];
auto value1 = static_cast<SampleType> (buffer[index1]);
auto value2 = static_cast<SampleType> (buffer[index2]);
auto value3 = static_cast<SampleType> (buffer[index3]);
auto value4 = static_cast<SampleType> (buffer[index4]);

auto d1 = delayFrac - (NumericType) 1.0;
auto d2 = delayFrac - (NumericType) 2.0;
Expand Down Expand Up @@ -114,8 +114,8 @@ namespace DelayLineInterpolationTypes
}
}

template <typename SampleType, typename NumericType>
inline SampleType call (const SampleType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
template <typename SampleType, typename NumericType, typename StorageType = SampleType>
inline SampleType call (const StorageType* buffer, int delayInt, NumericType delayFrac, const SampleType& /*state*/ = {})
{
auto index1 = delayInt;
auto index2 = index1 + 1;
Expand All @@ -124,12 +124,12 @@ namespace DelayLineInterpolationTypes
auto index5 = index4 + 1;
auto index6 = index5 + 1;

auto value1 = buffer[index1];
auto value2 = buffer[index2];
auto value3 = buffer[index3];
auto value4 = buffer[index4];
auto value5 = buffer[index5];
auto value6 = buffer[index6];
auto value1 = static_cast<SampleType> (buffer[index1]);
auto value2 = static_cast<SampleType> (buffer[index2]);
auto value3 = static_cast<SampleType> (buffer[index3]);
auto value4 = static_cast<SampleType> (buffer[index4]);
auto value5 = static_cast<SampleType> (buffer[index5]);
auto value6 = static_cast<SampleType> (buffer[index6]);

auto d1 = delayFrac - (NumericType) 1.0;
auto d2 = delayFrac - (NumericType) 2.0;
Expand Down
29 changes: 15 additions & 14 deletions modules/dsp/chowdsp_dsp_utils/Delay/chowdsp_DelayLine.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -26,23 +26,23 @@
namespace chowdsp
{
//==============================================================================
template <typename SampleType, typename InterpolationType>
DelayLine<SampleType, InterpolationType>::DelayLine()
template <typename SampleType, typename InterpolationType, typename StorageType>
DelayLine<SampleType, InterpolationType, StorageType>::DelayLine()
: DelayLine (1 << 18)
{
}

template <typename SampleType, typename InterpolationType>
DelayLine<SampleType, InterpolationType>::DelayLine (int maximumDelayInSamples)
template <typename SampleType, typename InterpolationType, typename StorageType>
DelayLine<SampleType, InterpolationType, StorageType>::DelayLine (int maximumDelayInSamples)
{
jassert (maximumDelayInSamples >= 0);

totalSize = juce::jmax (4, maximumDelayInSamples + 1);
}

//==============================================================================
template <typename SampleType, typename InterpolationType>
void DelayLine<SampleType, InterpolationType>::setDelay (DelayLine<SampleType, InterpolationType>::NumericType newDelayInSamples)
template <typename SampleType, typename InterpolationType, typename StorageType>
void DelayLine<SampleType, InterpolationType, StorageType>::setDelay (DelayLine<SampleType, InterpolationType, StorageType>::NumericType newDelayInSamples)
{
auto upperLimit = (NumericType) (totalSize - 1);
jassert (juce::isPositiveAndNotGreaterThan (newDelayInSamples, upperLimit));
Expand All @@ -54,15 +54,16 @@ void DelayLine<SampleType, InterpolationType>::setDelay (DelayLine<SampleType, I
interpolator.updateInternalVariables (delayInt, delayFrac);
}

template <typename SampleType, typename InterpolationType>
SampleTypeHelpers::ProcessorNumericType<DelayLine<SampleType, InterpolationType>> DelayLine<SampleType, InterpolationType>::getDelay() const
template <typename SampleType, typename InterpolationType, typename StorageType>
SampleTypeHelpers::ProcessorNumericType<DelayLine<SampleType, InterpolationType, StorageType>>
DelayLine<SampleType, InterpolationType, StorageType>::getDelay() const
{
return delay;
}

//==============================================================================
template <typename SampleType, typename InterpolationType>
void DelayLine<SampleType, InterpolationType>::prepare (const juce::dsp::ProcessSpec& spec)
template <typename SampleType, typename InterpolationType, typename StorageType>
void DelayLine<SampleType, InterpolationType, StorageType>::prepare (const juce::dsp::ProcessSpec& spec)
{
jassert (spec.numChannels > 0);

Expand All @@ -80,8 +81,8 @@ void DelayLine<SampleType, InterpolationType>::prepare (const juce::dsp::Process
bufferPtrs[(size_t) ch] = this->bufferData.getWritePointer (ch);
}

template <typename SampleType, typename InterpolationType>
void DelayLine<SampleType, InterpolationType>::free()
template <typename SampleType, typename InterpolationType, typename StorageType>
void DelayLine<SampleType, InterpolationType, StorageType>::free()
{
this->bufferData.setMaxSize (0, 0);

Expand All @@ -91,8 +92,8 @@ void DelayLine<SampleType, InterpolationType>::free()
bufferPtrs.clear();
}

template <typename SampleType, typename InterpolationType>
void DelayLine<SampleType, InterpolationType>::reset()
template <typename SampleType, typename InterpolationType, typename StorageType>
void DelayLine<SampleType, InterpolationType, StorageType>::reset()
{
for (auto vec : { &this->writePos, &this->readPos })
std::fill (vec->begin(), vec->end(), 0);
Expand Down
16 changes: 8 additions & 8 deletions modules/dsp/chowdsp_dsp_utils/Delay/chowdsp_DelayLine.h
Original file line number Diff line number Diff line change
Expand Up @@ -29,7 +29,7 @@ namespace chowdsp
{
#ifndef DOXYGEN
/** Base class for delay lines with any interpolation type */
template <typename SampleType>
template <typename SampleType, typename StorageType = SampleType>
class DelayLineBase
{
public:
Expand All @@ -50,7 +50,7 @@ class DelayLineBase
virtual SampleType popSample (int /* channel */, NumericType /* delayInSamples */, bool /* updateReadPointer */) noexcept = 0;
virtual void incrementReadPointer (int channel) noexcept = 0;

void copyState (const DelayLineBase<SampleType>& other)
void copyState (const DelayLineBase& other)
{
const auto numChannels = other.bufferData.getNumChannels();
const auto numSamples = other.bufferData.getNumSamples();
Expand All @@ -74,7 +74,7 @@ class DelayLineBase
[[nodiscard]] BufferView<const SampleType> getRawDelayBuffer() const { return bufferData; }

protected:
Buffer<SampleType> bufferData;
Buffer<StorageType> bufferData;
std::vector<SampleType> v;
std::vector<int> writePos, readPos;
};
Expand All @@ -93,8 +93,8 @@ class DelayLineBase
Note: If you intend to change the delay in real time, you may want to smooth
changes to the delay systematically using either a ramp or a low-pass filter.
*/
template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear>
class DelayLine : public DelayLineBase<SampleType>
template <typename SampleType, typename InterpolationType = DelayLineInterpolationTypes::Linear, typename StorageType = SampleType>
class DelayLine : public DelayLineBase<SampleType, StorageType>
{
using NumericType = SampleTypeHelpers::ProcessorNumericType<DelayLine>;

Expand Down Expand Up @@ -135,8 +135,8 @@ class DelayLine : public DelayLineBase<SampleType>
inline void pushSample (int channel, SampleType sample) noexcept final
{
const auto writePtr = this->writePos[(size_t) channel];
bufferPtrs[(size_t) channel][writePtr] = sample;
bufferPtrs[(size_t) channel][writePtr + totalSize] = sample;
bufferPtrs[(size_t) channel][writePtr] = static_cast<StorageType> (sample);
bufferPtrs[(size_t) channel][writePtr + totalSize] = static_cast<StorageType> (sample);
incrementWritePointer (channel);
}

Expand Down Expand Up @@ -266,7 +266,7 @@ class DelayLine : public DelayLineBase<SampleType>

//==============================================================================
InterpolationType interpolator;
std::vector<SampleType*> bufferPtrs;
std::vector<StorageType*> bufferPtrs;
NumericType delay = 0.0, delayFrac = 0.0;
int delayInt = 0, totalSize = 4;

Expand Down

0 comments on commit ca1f0e4

Please sign in to comment.