commit 5b7670584d16e76a27cf0d6575b8bf9921de2714
parent 34952157be7db5e01c58266431aab253b59f9259
Author: falkTX <falktx@falktx.com>
Date: Fri, 14 Apr 2023 17:20:54 +0200
Add value smoother classes, originally from Jean Pierre Cimalando
Signed-off-by: falkTX <falktx@falktx.com>
Diffstat:
1 file changed, 204 insertions(+), 0 deletions(-)
diff --git a/distrho/extra/ValueSmoother.hpp b/distrho/extra/ValueSmoother.hpp
@@ -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