39 template <
typename SmoothedValueType>
44 template <
typename T>
struct FloatTypeHelper;
46 template <
template <
typename>
class SmoothedValueClass,
typename FloatType>
47 struct FloatTypeHelper <SmoothedValueClass <FloatType>>
49 using Type = FloatType;
52 template <
template <
typename,
typename>
class SmoothedValueClass,
typename FloatType,
typename SmoothingType>
53 struct FloatTypeHelper <SmoothedValueClass <FloatType, SmoothingType>>
55 using Type = FloatType;
59 using FloatType =
typename FloatTypeHelper<SmoothedValueType>::Type;
83 target = currentValue = newValue;
93 void applyGain (FloatType* samples,
int numSamples) noexcept
95 jassert (numSamples >= 0);
99 for (
int i = 0; i < numSamples; ++i)
100 samples[i] *= getNextSmoothedValue();
114 void applyGain (FloatType* samplesOut,
const FloatType* samplesIn,
int numSamples) noexcept
116 jassert (numSamples >= 0);
120 for (
int i = 0; i < numSamples; ++i)
121 samplesOut[i] = samplesIn[i] * getNextSmoothedValue();
132 jassert (numSamples >= 0);
136 if (buffer.getNumChannels() == 1)
138 auto* samples = buffer.getWritePointer (0);
140 for (
int i = 0; i < numSamples; ++i)
141 samples[i] *= getNextSmoothedValue();
145 for (
auto i = 0; i < numSamples; ++i)
147 auto gain = getNextSmoothedValue();
149 for (
int channel = 0; channel < buffer.getNumChannels(); channel++)
150 buffer.setSample (channel, i, buffer.getSample (channel, i) * gain);
156 buffer.applyGain (0, numSamples, target);
162 FloatType getNextSmoothedValue() noexcept
164 return static_cast <SmoothedValueType*
> (
this)->getNextValue();
169 FloatType currentValue = 0;
170 FloatType target = currentValue;
184 namespace ValueSmoothingTypes
223 template <
typename FloatType,
typename SmoothingType = ValueSmoothingTypes::Linear>
230 :
SmoothedValue ((FloatType) (std::is_same<SmoothingType, ValueSmoothingTypes::Linear>::value ? 0 : 1))
238 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && initialValue == 0));
241 this->currentValue = initialValue;
242 this->target = this->currentValue;
250 void reset (
double sampleRate,
double rampLengthInSeconds) noexcept
252 jassert (sampleRate > 0 && rampLengthInSeconds >= 0);
253 reset ((
int) std::floor (rampLengthInSeconds * sampleRate));
261 stepsToTarget = numSteps;
271 if (newValue == this->target)
274 if (stepsToTarget <= 0)
281 jassert (! (std::is_same<SmoothingType, ValueSmoothingTypes::Multiplicative>::value && newValue == 0));
283 this->target = newValue;
284 this->countdown = stepsToTarget;
303 this->currentValue = this->target;
305 return this->currentValue;
314 FloatType
skip (
int numSamples) noexcept
316 if (numSamples >= this->countdown)
322 skipCurrentValue (numSamples);
324 this->countdown -= numSamples;
325 return this->currentValue;
339 JUCE_DEPRECATED_WITH_BODY (
void setValue (FloatType newValue,
bool force =
false) noexcept,
352 template <typename T>
353 using LinearVoid =
typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Linear>::value,
void>::type;
355 template <
typename T>
356 using MultiplicativeVoid =
typename std::enable_if <std::is_same <T, ValueSmoothingTypes::Multiplicative>::value,
void>::type;
359 template <
typename T = SmoothingType>
360 LinearVoid<T> setStepSize() noexcept
362 step = (this->target - this->currentValue) / (FloatType) this->countdown;
365 template <
typename T = SmoothingType>
366 MultiplicativeVoid<T> setStepSize()
368 step = std::exp ((std::log (std::abs (this->target)) - std::log (std::abs (this->currentValue))) / this->countdown);
372 template <
typename T = SmoothingType>
373 LinearVoid<T> setNextValue() noexcept
375 this->currentValue += step;
378 template <
typename T = SmoothingType>
379 MultiplicativeVoid<T> setNextValue() noexcept
381 this->currentValue *= step;
385 template <
typename T = SmoothingType>
386 LinearVoid<T> skipCurrentValue (
int numSamples) noexcept
388 this->currentValue += step * (FloatType) numSamples;
391 template <
typename T = SmoothingType>
392 MultiplicativeVoid<T> skipCurrentValue (
int numSamples)
394 this->currentValue *= (FloatType) std::pow (step, numSamples);
398 FloatType step = FloatType();
399 int stepsToTarget = 0;
402 template <
typename FloatType>
403 using LinearSmoothedValue = SmoothedValue <FloatType, ValueSmoothingTypes::Linear>;
410 template <
class SmoothedValueType>
411 class CommonSmoothedValueTests :
public UnitTest
414 CommonSmoothedValueTests()
415 : UnitTest (
"CommonSmoothedValueTests",
"SmoothedValues")
418 void runTest()
override
420 beginTest (
"Initial state");
422 SmoothedValueType sv;
424 auto value = sv.getCurrentValue();
425 expectEquals (sv.getTargetValue(), value);
428 expectEquals (sv.getCurrentValue(), value);
429 expect (! sv.isSmoothing());
432 beginTest (
"Resetting");
434 auto initialValue = 15.0f;
436 SmoothedValueType sv (initialValue);
438 expectEquals (sv.getCurrentValue(), initialValue);
440 auto targetValue = initialValue + 1.0f;
441 sv.setTargetValue (targetValue);
442 expectEquals (sv.getTargetValue(), targetValue);
443 expectEquals (sv.getCurrentValue(), initialValue);
444 expect (sv.isSmoothing());
446 auto currentValue = sv.getNextValue();
447 expect (currentValue > initialValue);
448 expectEquals (sv.getCurrentValue(), currentValue);
449 expectEquals (sv.getTargetValue(), targetValue);
450 expect (sv.isSmoothing());
454 expectEquals (sv.getCurrentValue(), targetValue);
455 expectEquals (sv.getTargetValue(), targetValue);
456 expect (! sv.isSmoothing());
459 expectEquals (sv.getCurrentValue(), targetValue);
461 sv.setTargetValue (1.5f);
464 float newStart = 0.2f;
465 sv.setCurrentAndTargetValue (newStart);
466 expectEquals (sv.getNextValue(), newStart);
467 expectEquals (sv.getTargetValue(), newStart);
468 expectEquals (sv.getCurrentValue(), newStart);
469 expect (! sv.isSmoothing());
472 beginTest (
"Sample rate");
474 SmoothedValueType svSamples { 3.0f };
475 auto svTime = svSamples;
477 auto numSamples = 12;
479 svSamples.reset (numSamples);
480 svTime.reset (numSamples * 2, 1.0);
482 for (
int i = 0; i < numSamples; ++i)
485 expectWithinAbsoluteError (svSamples.getNextValue(),
486 svTime.getNextValue(),
491 beginTest (
"Block processing");
493 SmoothedValueType sv (1.0f);
496 sv.setTargetValue (2.0f);
498 const auto numSamples = 15;
500 AudioBuffer<float> referenceData (1, numSamples);
502 for (
int i = 0; i < numSamples; ++i)
503 referenceData.setSample (0, i, sv.getNextValue());
505 expect (referenceData.getSample (0, 0) > 0);
506 expect (referenceData.getSample (0, 10) < sv.getTargetValue());
507 expectWithinAbsoluteError (referenceData.getSample (0, 11),
511 auto getUnitData = [] (
int numSamplesToGenerate)
513 AudioBuffer<float> result (1, numSamplesToGenerate);
515 for (
int i = 0; i < numSamplesToGenerate; ++i)
516 result.setSample (0, i, 1.0f);
521 auto compareData = [
this](
const AudioBuffer<float>& test,
522 const AudioBuffer<float>& reference)
524 for (
int i = 0; i < test.getNumSamples(); ++i)
525 expectWithinAbsoluteError (test.getSample (0, i),
526 reference.getSample (0, i),
530 auto testData = getUnitData (numSamples);
531 sv.setCurrentAndTargetValue (1.0f);
532 sv.setTargetValue (2.0f);
533 sv.applyGain (testData.getWritePointer (0), numSamples);
534 compareData (testData, referenceData);
536 testData = getUnitData (numSamples);
537 AudioBuffer<float> destData (1, numSamples);
538 sv.setCurrentAndTargetValue (1.0f);
539 sv.setTargetValue (2.0f);
540 sv.applyGain (destData.getWritePointer (0),
541 testData.getReadPointer (0),
543 compareData (destData, referenceData);
544 compareData (testData, getUnitData (numSamples));
546 testData = getUnitData (numSamples);
547 sv.setCurrentAndTargetValue (1.0f);
548 sv.setTargetValue (2.0f);
549 sv.applyGain (testData, numSamples);
550 compareData (testData, referenceData);
555 SmoothedValueType sv;
558 sv.setCurrentAndTargetValue (1.0f);
559 sv.setTargetValue (2.0f);
561 Array<float> reference;
563 for (
int i = 0; i < 15; ++i)
564 reference.add (sv.getNextValue());
566 sv.setCurrentAndTargetValue (1.0f);
567 sv.setTargetValue (2.0f);
569 expectWithinAbsoluteError (sv.skip (1), reference[0], 1.0e-6f);
570 expectWithinAbsoluteError (sv.skip (1), reference[1], 1.0e-6f);
571 expectWithinAbsoluteError (sv.skip (2), reference[3], 1.0e-6f);
573 expectWithinAbsoluteError (sv.getCurrentValue(), reference[6], 1.0e-6f);
574 expectEquals (sv.skip (300), sv.getTargetValue());
575 expectEquals (sv.getCurrentValue(), sv.getTargetValue());
578 beginTest (
"Negative");
580 SmoothedValueType sv;
583 sv.reset (numValues);
585 std::vector<std::pair<float, float>> ranges = { { -1.0f, -2.0f },
586 { -100.0f, -3.0f } };
588 for (
auto range : ranges)
590 auto start = range.first, end = range.second;
592 sv.setCurrentAndTargetValue (start);
593 sv.setTargetValue (end);
595 auto val = sv.skip (numValues / 2);
598 expect (val > start && val < end);
600 expect (val < start && val > end);
602 auto nextVal = sv.getNextValue();
603 expect (end > start ? (nextVal > val) : (nextVal < val));
605 auto endVal = sv.skip (500);
606 expectEquals (endVal, end);
607 expectEquals (sv.getNextValue(), end);
608 expectEquals (sv.getCurrentValue(), end);
610 sv.setCurrentAndTargetValue (start);
611 sv.setTargetValue (end);
613 SmoothedValueType positiveSv { -start };
614 positiveSv.reset (numValues);
615 positiveSv.setTargetValue (-end);
617 for (
int i = 0; i < numValues + 2; ++i)
618 expectEquals (sv.getNextValue(), -positiveSv.getNextValue());