|
|
@@ -0,0 +1,204 @@ |
|
|
|
/* |
|
|
|
* DISTRHO Plugin Framework (DPF) |
|
|
|
* Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru> |
|
|
|
* Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com> |
|
|
|
* |
|
|
|
* Permission to use, copy, modify, and/or distribute this software for any purpose with |
|
|
|
* or without fee is hereby granted, provided that the above copyright notice and this |
|
|
|
* permission notice appear in all copies. |
|
|
|
* |
|
|
|
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD |
|
|
|
* TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN |
|
|
|
* NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL |
|
|
|
* DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER |
|
|
|
* IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN |
|
|
|
* CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. |
|
|
|
*/ |
|
|
|
|
|
|
|
#ifndef DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED |
|
|
|
#define DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED |
|
|
|
|
|
|
|
#include "../DistrhoUtils.hpp" |
|
|
|
|
|
|
|
START_NAMESPACE_DISTRHO |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
/** |
|
|
|
* @brief An exponential smoother for control values |
|
|
|
* |
|
|
|
* This continually smooths a value towards a defined target, |
|
|
|
* using a low-pass filter of the 1st order, which creates an exponential curve. |
|
|
|
* |
|
|
|
* The length of the curve is defined by a T60 constant, |
|
|
|
* which is the time it takes for a 1-to-0 smoothing to fall to -60dB. |
|
|
|
* |
|
|
|
* Note that this smoother has asymptotical behavior, |
|
|
|
* and it must not be assumed that the final target is ever reached. |
|
|
|
*/ |
|
|
|
class ExponentialValueSmoother { |
|
|
|
float coef; |
|
|
|
float target; |
|
|
|
float mem; |
|
|
|
float tau; |
|
|
|
float sampleRate; |
|
|
|
|
|
|
|
public: |
|
|
|
ExponentialValueSmoother() |
|
|
|
: coef(0.f), |
|
|
|
target(0.f), |
|
|
|
mem(0.f), |
|
|
|
tau(0.f), |
|
|
|
sampleRate(0.f) {} |
|
|
|
|
|
|
|
void setSampleRate(const float newSampleRate) noexcept |
|
|
|
{ |
|
|
|
if (d_isNotEqual(sampleRate, newSampleRate)) |
|
|
|
{ |
|
|
|
sampleRate = newSampleRate; |
|
|
|
updateCoef(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void setTimeConstant(const float newT60) noexcept |
|
|
|
{ |
|
|
|
const float newTau = newT60 * (float)(1.0 / 6.91); |
|
|
|
|
|
|
|
if (d_isNotEqual(tau, newTau)) |
|
|
|
{ |
|
|
|
tau = newTau; |
|
|
|
updateCoef(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
float getCurrentValue() const noexcept |
|
|
|
{ |
|
|
|
return mem; |
|
|
|
} |
|
|
|
|
|
|
|
float getTargetValue() const noexcept |
|
|
|
{ |
|
|
|
return target; |
|
|
|
} |
|
|
|
|
|
|
|
void setTargetValue(const float newTarget) noexcept |
|
|
|
{ |
|
|
|
target = newTarget; |
|
|
|
} |
|
|
|
|
|
|
|
void clearToTargetValue() noexcept |
|
|
|
{ |
|
|
|
mem = target; |
|
|
|
} |
|
|
|
|
|
|
|
inline float peek() const noexcept |
|
|
|
{ |
|
|
|
return mem * coef + target * (1.f - coef); |
|
|
|
} |
|
|
|
|
|
|
|
inline float next() noexcept |
|
|
|
{ |
|
|
|
return (mem = mem * coef + target * (1.f - coef)); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
void updateCoef() noexcept |
|
|
|
{ |
|
|
|
coef = std::exp(-1.f / (tau * sampleRate)); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
/** |
|
|
|
* @brief A linear smoother for control values |
|
|
|
* |
|
|
|
* This continually smooths a value towards a defined target, using linear segments. |
|
|
|
* |
|
|
|
* The duration of the smoothing segment is defined by the given time constant. |
|
|
|
* Every time the target changes, a new segment restarts for the whole duration of the time constant. |
|
|
|
* |
|
|
|
* Note that this smoother, unlike an exponential smoother, eventually should converge to its target value. |
|
|
|
*/ |
|
|
|
class LinearValueSmoother { |
|
|
|
float step; |
|
|
|
float target; |
|
|
|
float mem; |
|
|
|
float tau; |
|
|
|
float sampleRate; |
|
|
|
|
|
|
|
public: |
|
|
|
LinearValueSmoother() |
|
|
|
: step(0.f), |
|
|
|
target(0.f), |
|
|
|
mem(0.f), |
|
|
|
tau(0.f), |
|
|
|
sampleRate(0.f) {} |
|
|
|
|
|
|
|
void setSampleRate(const float newSampleRate) noexcept |
|
|
|
{ |
|
|
|
if (d_isNotEqual(sampleRate, newSampleRate)) |
|
|
|
{ |
|
|
|
sampleRate = newSampleRate; |
|
|
|
updateStep(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void setTimeConstant(const float newTau) noexcept |
|
|
|
{ |
|
|
|
if (d_isNotEqual(tau, newTau)) |
|
|
|
{ |
|
|
|
tau = newTau; |
|
|
|
updateStep(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
float getCurrentValue() const noexcept |
|
|
|
{ |
|
|
|
return mem; |
|
|
|
} |
|
|
|
|
|
|
|
float getTargetValue() const noexcept |
|
|
|
{ |
|
|
|
return target; |
|
|
|
} |
|
|
|
|
|
|
|
void setTargetValue(const float newTarget) noexcept |
|
|
|
{ |
|
|
|
if (d_isNotEqual(target, newTarget)) |
|
|
|
{ |
|
|
|
target = newTarget; |
|
|
|
updateStep(); |
|
|
|
} |
|
|
|
} |
|
|
|
|
|
|
|
void clearToTargetValue() noexcept |
|
|
|
{ |
|
|
|
mem = target; |
|
|
|
} |
|
|
|
|
|
|
|
inline float peek() const noexcept |
|
|
|
{ |
|
|
|
const float dy = target - mem; |
|
|
|
return mem + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy); |
|
|
|
} |
|
|
|
|
|
|
|
inline float next() noexcept |
|
|
|
{ |
|
|
|
const float y0 = mem; |
|
|
|
const float dy = target - y0; |
|
|
|
return (mem = y0 + std::copysign(std::fmin(std::abs(dy), std::abs(step)), dy)); |
|
|
|
} |
|
|
|
|
|
|
|
private: |
|
|
|
void updateStep() noexcept |
|
|
|
{ |
|
|
|
step = (target - mem) / (tau * sampleRate); |
|
|
|
} |
|
|
|
}; |
|
|
|
|
|
|
|
// -------------------------------------------------------------------------------------------------------------------- |
|
|
|
|
|
|
|
END_NAMESPACE_DISTRHO |
|
|
|
|
|
|
|
#endif // DISTRHO_VALUE_SMOOTHER_HPP_INCLUDED |