35template <
typename SmoothedValueType>
40 template <
typename T>
struct FloatTypeHelper;
42 template <
template <
typename>
class SmoothedValueClass,
typename FloatType>
43 struct FloatTypeHelper <SmoothedValueClass <FloatType>>
45 using Type = FloatType;
48 template <
template <
typename,
typename>
class SmoothedValueClass,
typename FloatType,
typename SmoothingType>
49 struct FloatTypeHelper <SmoothedValueClass <FloatType, SmoothingType>>
51 using Type = FloatType;
55 using FloatType =
typename FloatTypeHelper<SmoothedValueType>::Type;
79 target = currentValue = newValue;
89 void applyGain (FloatType* samples,
int numSamples)
noexcept
91 jassert (numSamples >= 0);
95 for (
int i = 0; i < numSamples; ++i)
96 samples[i] *= getNextSmoothedValue();
110 void applyGain (FloatType* samplesOut,
const FloatType* samplesIn,
int numSamples)
noexcept
112 jassert (numSamples >= 0);
116 for (
int i = 0; i < numSamples; ++i)
117 samplesOut[i] = samplesIn[i] * getNextSmoothedValue();
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
160 return static_cast <SmoothedValueType*
> (
this)->getNextValue();
165 FloatType currentValue = 0;
166 FloatType target = currentValue;
180namespace ValueSmoothingTypes
227template <
typename FloatType,
typename SmoothingType = ValueSmoothingTypes::Linear>
234 :
SmoothedValue ((FloatType) (std::is_same<SmoothingType, ValueSmoothingTypes::Linear>::value ? 0 : 1))
242 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && initialValue == 0));
245 this->currentValue = initialValue;
246 this->target = this->currentValue;
254 void reset (
double sampleRate,
double rampLengthInSeconds)
noexcept
256 jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
257 reset ((
int) std::floor (rampLengthInSeconds * sampleRate));
265 stepsToTarget = numSteps;
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>
364 LinearVoid<T> setStepSize() noexcept
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>
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>
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
418 CommonSmoothedValueTests()
419 : UnitTest (
"CommonSmoothedValueTests", UnitTestCategories::smoothedValues)
422 void runTest()
override
424 beginTest (
"Initial state");
426 SmoothedValueType sv;
428 auto value = sv.getCurrentValue();
429 expectEquals (sv.getTargetValue(), value);
432 expectEquals (sv.getCurrentValue(), value);
433 expect (! sv.isSmoothing());
436 beginTest (
"Resetting");
438 auto initialValue = 15.0f;
440 SmoothedValueType sv (initialValue);
442 expectEquals (sv.getCurrentValue(), initialValue);
444 auto targetValue = initialValue + 1.0f;
445 sv.setTargetValue (targetValue);
446 expectEquals (sv.getTargetValue(), targetValue);
447 expectEquals (sv.getCurrentValue(), initialValue);
448 expect (sv.isSmoothing());
450 auto currentValue = sv.getNextValue();
451 expect (currentValue > initialValue);
452 expectEquals (sv.getCurrentValue(), currentValue);
453 expectEquals (sv.getTargetValue(), targetValue);
454 expect (sv.isSmoothing());
458 expectEquals (sv.getCurrentValue(), targetValue);
459 expectEquals (sv.getTargetValue(), targetValue);
460 expect (! sv.isSmoothing());
463 expectEquals (sv.getCurrentValue(), targetValue);
465 sv.setTargetValue (1.5f);
468 float newStart = 0.2f;
469 sv.setCurrentAndTargetValue (newStart);
470 expectEquals (sv.getNextValue(), newStart);
471 expectEquals (sv.getTargetValue(), newStart);
472 expectEquals (sv.getCurrentValue(), newStart);
473 expect (! sv.isSmoothing());
476 beginTest (
"Sample rate");
478 SmoothedValueType svSamples { 3.0f };
479 auto svTime = svSamples;
481 auto numSamples = 12;
483 svSamples.reset (numSamples);
484 svTime.reset (numSamples * 2, 1.0);
486 for (
int i = 0; i < numSamples; ++i)
489 expectWithinAbsoluteError (svSamples.getNextValue(),
490 svTime.getNextValue(),
495 beginTest (
"Block processing");
497 SmoothedValueType sv (1.0f);
500 sv.setTargetValue (2.0f);
502 const auto numSamples = 15;
504 AudioBuffer<float> referenceData (1, numSamples);
506 for (
int i = 0; i < numSamples; ++i)
507 referenceData.setSample (0, i, sv.getNextValue());
509 expect (referenceData.getSample (0, 0) > 0);
510 expect (referenceData.getSample (0, 10) < sv.getTargetValue());
511 expectWithinAbsoluteError (referenceData.getSample (0, 11),
515 auto getUnitData = [] (
int numSamplesToGenerate)
517 AudioBuffer<float> result (1, numSamplesToGenerate);
519 for (
int i = 0; i < numSamplesToGenerate; ++i)
520 result.setSample (0, i, 1.0f);
525 auto compareData = [
this](
const AudioBuffer<float>& test,
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),
534 auto testData = getUnitData (numSamples);
535 sv.setCurrentAndTargetValue (1.0f);
536 sv.setTargetValue (2.0f);
537 sv.applyGain (testData.getWritePointer (0), numSamples);
538 compareData (testData, referenceData);
540 testData = getUnitData (numSamples);
541 AudioBuffer<float> destData (1, numSamples);
542 sv.setCurrentAndTargetValue (1.0f);
543 sv.setTargetValue (2.0f);
544 sv.applyGain (destData.getWritePointer (0),
545 testData.getReadPointer (0),
547 compareData (destData, referenceData);
548 compareData (testData, getUnitData (numSamples));
550 testData = getUnitData (numSamples);
551 sv.setCurrentAndTargetValue (1.0f);
552 sv.setTargetValue (2.0f);
553 sv.applyGain (testData, numSamples);
554 compareData (testData, referenceData);
559 SmoothedValueType sv;
562 sv.setCurrentAndTargetValue (1.0f);
563 sv.setTargetValue (2.0f);
565 Array<float> reference;
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");
584 SmoothedValueType sv;
587 sv.reset (numValues);
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);
599 auto val = sv.skip (numValues / 2);
602 expect (val > start && val < end);
604 expect (val < start && val > end);
606 auto nextVal = sv.getNextValue();
607 expect (end > start ? (nextVal > val) : (nextVal < val));
609 auto endVal = sv.skip (500);
610 expectEquals (endVal, end);
611 expectEquals (sv.getNextValue(), end);
612 expectEquals (sv.getCurrentValue(), end);
614 sv.setCurrentAndTargetValue (start);
615 sv.setTargetValue (end);
617 SmoothedValueType positiveSv { -start };
618 positiveSv.reset (numValues);
619 positiveSv.setTargetValue (-end);
621 for (
int i = 0; i < numValues + 2; ++i)
622 expectEquals (sv.getNextValue(), -positiveSv.getNextValue());
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
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