Mercurial > hg > pub > prymula > com
diff DPF-Prymula-audioplugins/dpf/distrho/extra/ValueSmoother.hpp @ 3:84e66ea83026
DPF-Prymula-audioplugins-0.231015-2
author | prymula <prymula76@outlook.com> |
---|---|
date | Mon, 16 Oct 2023 21:53:34 +0200 |
parents | |
children |
line wrap: on
line diff
--- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/DPF-Prymula-audioplugins/dpf/distrho/extra/ValueSmoother.hpp Mon Oct 16 21:53:34 2023 +0200 @@ -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