Last active
February 3, 2021 08:42
-
-
Save fefanto/3057474c020c2cdfab5c462c50b1cc48 to your computer and use it in GitHub Desktop.
Utility class based on juce::LinearSmoothedValue for exponential smoothing of parameters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
============================================================================== | |
Utility class for exponentially smoothed values like volume etc. that should | |
not change abruptly to avoid audio glitches. | |
This Class is based on juce::LinearSmoothedValue, | |
part of the JUCE Library (https://github.com/julianstorer/JUCE). | |
Smoothing algorithm is based on a 1 pole IIR lowpass: | |
y(n) = A0 * x[n] + B1 * y[n-1] | |
Coefficient calculation is based on Csound's one pole lowpass: | |
http://www.csounds.com/manual/html/tone.html , | |
with one additional optimization: the A0 * x[n] part is computed at control rate (setNextValue) | |
saving one multiplication from the audio rate method (getNextValue) | |
NOTE: | |
Currently no smoothing optimization is peformed, i.e. filter calculation is always performed. | |
Maybe no optimization is needed since getNextValue is pretty light (one add + one multiply + | |
one assign) and comparable with its linear counterpart. | |
USAGE: | |
To use this class | |
(1) place this header file alongside | |
<JUCE_folder>/modules/juce_audio_basics/effects/juce_LinearSmoothedValue.h | |
(2) add the include reference: | |
#include "effects/juce_LowPassSmoothedValue.h" | |
in <JUCE_folder>/modules/juce_audio_basics/juce_audio_basics.h | |
============================================================================== | |
*/ | |
#ifndef JUCE_LOWPASSSMOOTHEDVALUE_H_INCLUDED | |
#define JUCE_LOWPASSSMOOTHEDVALUE_H_INCLUDED | |
//============================================================================== | |
template <typename FloatType> | |
class LowpassSmoothedValue | |
{ | |
public: | |
/** Constructor. | |
If no reset(sampleRate,time) is called, initial behaviour is similar to LinearSmoothedValue construction, | |
i.e. with A0=1 and B1=0, currentValue goes to targetValue right when you call setTarget. | |
*/ | |
LowpassSmoothedValue() noexcept | |
: currentValue (0), target (0), A0 (1), B1 (0), xv(0) | |
{ | |
} | |
/** Constructor. | |
Same behaviour as constructor above. | |
*/ | |
LowpassSmoothedValue (FloatType initialValue) noexcept | |
: currentValue (0), target (initialValue), A0 (1), B1 (0), xv(0) | |
{ | |
} | |
//============================================================================== | |
/** Reset to a new sample rate and time constant length. */ | |
void reset (double sampleRate, double filterTimeInSeconds) noexcept | |
{ | |
// sanity check: 0.00005 ms = 20kHz cutoff ≈ 99% of target in double of this time ≈ 4 samples at 44100 | |
// if you use this setting you won't get a divbyzero below, but you may get the clicks you were trying to avoid. | |
jassert (sampleRate > 0 && filterTimeInSeconds >= 0.00005); | |
double lowpassCutoffFreq = 1/filterTimeInSeconds; | |
double cosf = 2.0 - cos (2* double_Pi * (lowpassCutoffFreq / 2.0) / sampleRate); | |
double cb1 = cosf - sqrt(cosf * cosf - 1.0); | |
B1 = (FloatType)cb1; | |
A0 = (FloatType)(1.0 - cb1); | |
setValue (target); | |
} | |
/** Set a new target value. */ | |
void setValue (FloatType newValue) noexcept | |
{ | |
target = newValue; | |
xv = A0 * newValue; // set the "A0" part of the IIR filter output at "Control rate". | |
} | |
/** Compute the next value. */ | |
FloatType getNextValue() noexcept | |
{ | |
return currentValue = xv + B1 * currentValue; // Audio rate | |
} | |
/** Do not Compute the next value. */ | |
FloatType getCurrentValue() noexcept | |
{ | |
return currentValue; | |
} | |
/** Returns true if the current value is currently being interpolated. */ | |
bool isSmoothing() const noexcept | |
{ | |
return true; // no smoothing optimization - TBD set a normalized threshold [value-target] under which we stop smoothing | |
} | |
/** Returns the target value towards which the smoothed value is currently moving. */ | |
FloatType getTargetValue() const noexcept | |
{ | |
return target; | |
} | |
private: | |
FloatType A0; | |
FloatType B1; | |
FloatType xv; | |
FloatType currentValue, target; | |
}; | |
#endif // JUCE_LOWPASSSMOOTHEDVALUE_H_INCLUDED |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment