35template <
typename SmoothedValueType>
40 template <
typename T>
struct FloatTypeHelper;
45 using Type = FloatType;
51 using Type = FloatType;
55 using FloatType =
typename FloatTypeHelper<SmoothedValueType>::Type;
79 target = currentValue = newValue;
91 jassert (numSamples >= 0);
95 for (
int i = 0; i < numSamples; ++i)
96 samples[i] *= getNextSmoothedValue();
112 jassert (numSamples >= 0);
116 for (
int i = 0; i < numSamples; ++i)
128 jassert (numSamples >= 0);
132 if (buffer.getNumChannels() == 1)
134 auto*
samples = buffer.getWritePointer (0);
136 for (
int i = 0; i < numSamples; ++i)
137 samples[i] *= getNextSmoothedValue();
141 for (
auto i = 0; i < numSamples; ++i)
143 auto gain = getNextSmoothedValue();
145 for (
int channel = 0; channel < buffer.getNumChannels(); channel++)
146 buffer.setSample (channel, i, buffer.getSample (channel, i) * gain);
152 buffer.applyGain (0, numSamples, target);
158 FloatType getNextSmoothedValue()
noexcept
165 FloatType currentValue = 0;
166 FloatType target = currentValue;
180namespace ValueSmoothingTypes
227template <
typename FloatType,
typename SmoothingType = ValueSmoothingTypes::Linear>
242 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value &&
initialValue == 0));
246 this->target = this->currentValue;
275 if (newValue == this->target)
278 if (stepsToTarget <= 0)
285 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && newValue == 0));
287 this->target = newValue;
288 this->countdown = stepsToTarget;
307 this->currentValue = this->target;
309 return this->currentValue;
318 FloatType
skip (
int numSamples)
noexcept
320 if (numSamples >= this->countdown)
326 skipCurrentValue (numSamples);
328 this->countdown -= numSamples;
329 return this->currentValue;
343 JUCE_DEPRECATED_WITH_BODY (
void setValue (FloatType newValue,
bool force =
false)
noexcept,
356 template <typename T>
357 using LinearVoid = typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Linear>::value, void>::type;
359 template <
typename T>
360 using MultiplicativeVoid =
typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Multiplicative>::value,
void>::type;
363 template <
typename T = SmoothingType>
366 step = (this->target - this->currentValue) / (FloatType) this->countdown;
369 template <
typename T = SmoothingType>
372 step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / this->countdown);
376 template <
typename T = SmoothingType>
377 LinearVoid<T> setNextValue() noexcept
379 this->currentValue += step;
382 template <
typename T = SmoothingType>
383 MultiplicativeVoid<T> setNextValue() noexcept
385 this->currentValue *= step;
389 template <
typename T = SmoothingType>
390 LinearVoid<T> skipCurrentValue (
int numSamples)
noexcept
392 this->currentValue += step * (FloatType) numSamples;
395 template <
typename T = SmoothingType>
396 MultiplicativeVoid<T> skipCurrentValue (
int numSamples)
398 this->currentValue *= (FloatType) std::pow (step, numSamples);
402 FloatType step = FloatType();
403 int stepsToTarget = 0;
406template <
typename FloatType>
407using LinearSmoothedValue = SmoothedValue <FloatType, ValueSmoothingTypes::Linear>;
414template <
class SmoothedValueType>
415class CommonSmoothedValueTests :
public UnitTest
419 : UnitTest (
"CommonSmoothedValueTests", UnitTestCategories::smoothedValues)
422 void runTest()
override
424 beginTest (
"Initial state");
428 auto value =
sv.getCurrentValue();
429 expectEquals (
sv.getTargetValue(), value);
432 expectEquals (
sv.getCurrentValue(), value);
433 expect (!
sv.isSmoothing());
436 beginTest (
"Resetting");
448 expect (
sv.isSmoothing());
450 auto currentValue =
sv.getNextValue();
452 expectEquals (
sv.getCurrentValue(), currentValue);
454 expect (
sv.isSmoothing());
460 expect (!
sv.isSmoothing());
465 sv.setTargetValue (1.5f);
472 expectEquals (
sv.getCurrentValue(),
newStart);
473 expect (!
sv.isSmoothing());
476 beginTest (
"Sample rate");
481 auto numSamples = 12;
484 svTime.reset (numSamples * 2, 1.0);
486 for (
int i = 0; i < numSamples; ++i)
489 expectWithinAbsoluteError (
svSamples.getNextValue(),
495 beginTest (
"Block processing");
500 sv.setTargetValue (2.0f);
502 const auto numSamples = 15;
506 for (
int i = 0; i < numSamples; ++i)
520 result.setSample (0, i, 1.0f);
526 const AudioBuffer<float>& reference)
528 for (
int i = 0; i <
test.getNumSamples(); ++i)
529 expectWithinAbsoluteError (
test.getSample (0, i),
530 reference.getSample (0, i),
535 sv.setCurrentAndTargetValue (1.0f);
536 sv.setTargetValue (2.0f);
537 sv.applyGain (
testData.getWritePointer (0), numSamples);
541 AudioBuffer<float>
destData (1, numSamples);
542 sv.setCurrentAndTargetValue (1.0f);
543 sv.setTargetValue (2.0f);
551 sv.setCurrentAndTargetValue (1.0f);
552 sv.setTargetValue (2.0f);
562 sv.setCurrentAndTargetValue (1.0f);
563 sv.setTargetValue (2.0f);
567 for (
int i = 0; i < 15; ++i)
568 reference.add (
sv.getNextValue());
570 sv.setCurrentAndTargetValue (1.0f);
571 sv.setTargetValue (2.0f);
573 expectWithinAbsoluteError (
sv.skip (1), reference[0], 1.0e-6f);
574 expectWithinAbsoluteError (
sv.skip (1), reference[1], 1.0e-6f);
575 expectWithinAbsoluteError (
sv.skip (2), reference[3], 1.0e-6f);
577 expectWithinAbsoluteError (
sv.getCurrentValue(), reference[6], 1.0e-6f);
578 expectEquals (
sv.skip (300),
sv.getTargetValue());
579 expectEquals (
sv.getCurrentValue(),
sv.getTargetValue());
582 beginTest (
"Negative");
589 std::vector<std::pair<float, float>> ranges = { { -1.0f, -2.0f },
590 { -100.0f, -3.0f } };
592 for (
auto range : ranges)
594 auto start = range.first,
end = range.second;
596 sv.setCurrentAndTargetValue (start);
597 sv.setTargetValue (
end);
611 expectEquals (
sv.getNextValue(),
end);
612 expectEquals (
sv.getCurrentValue(),
end);
614 sv.setCurrentAndTargetValue (start);
615 sv.setTargetValue (
end);
622 expectEquals (
sv.getNextValue(), -
positiveSv.getNextValue());
ElementType * end() noexcept
static void JUCE_CALLTYPE multiply(float *dest, const float *src, int numValues) noexcept
bool isSmoothing() const noexcept
SmoothedValueBase()=default
void applyGain(FloatType *samples, int numSamples) noexcept
void applyGain(AudioBuffer< FloatType > &buffer, int numSamples) noexcept
void setCurrentAndTargetValue(FloatType newValue)
FloatType getTargetValue() const noexcept
FloatType getCurrentValue() const noexcept
void applyGain(FloatType *samplesOut, const FloatType *samplesIn, int numSamples) noexcept
FloatType skip(int numSamples) noexcept
FloatType getNextValue() noexcept
(void setValue(FloatType newValue, bool force=false) noexcept, { if(force) { this->setCurrentAndTargetValue(newValue);return;} setTargetValue(newValue);}) private typename std::enable_if< std::is_same< T, ValueSmoothingTypes::Multiplicative >::value, void >::type MultiplicativeVoid
SmoothedValue(FloatType initialValue) noexcept
void reset(double sampleRate, double rampLengthInSeconds) noexcept
void reset(int numSteps) noexcept
void setTargetValue(FloatType newValue) noexcept