Dusk Audio Framework
Loading...
Searching...
No Matches
ValueSmoother.hpp
1/*
2 * DISTRHO Plugin Framework (DPF)
3 * Copyright (C) 2021 Jean Pierre Cimalando <jp-dev@inbox.ru>
4 * Copyright (C) 2021-2023 Filipe Coelho <falktx@falktx.com>
5 *
6 * Permission to use, copy, modify, and/or distribute this software for any purpose with
7 * or without fee is hereby granted, provided that the above copyright notice and this
8 * permission notice appear in all copies.
9 *
10 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH REGARD
11 * TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. IN
12 * NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL
13 * DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER
14 * IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
15 * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16 */
17
18#ifndef DAF_VALUE_SMOOTHER_HPP_INCLUDED
19#define DAF_VALUE_SMOOTHER_HPP_INCLUDED
20
21#include "../DafUtils.hpp"
22
24
25// --------------------------------------------------------------------------------------------------------------------
26
27/**
28 * @brief An exponential smoother for control values
29 *
30 * This continually smooths a value towards a defined target,
31 * using a low-pass filter of the 1st order, which creates an exponential curve.
32 *
33 * The length of the curve is defined by a T60 constant,
34 * which is the time it takes for a 1-to-0 smoothing to fall to -60dB.
35 *
36 * Note that this smoother has asymptotical behavior,
37 * and it must not be assumed that the final target is ever reached.
38 */
39class ExponentialValueSmoother {
40 float coef;
41 float target;
42 float mem;
43 float tau;
44 float sampleRate;
45
46public:
47 ExponentialValueSmoother()
48 : coef(0.f),
49 target(0.f),
50 mem(0.f),
51 tau(0.f),
52 sampleRate(0.f) {}
53
54 void setSampleRate(const float newSampleRate) noexcept
55 {
56 if (d_isNotEqual(sampleRate, newSampleRate))
57 {
58 sampleRate = newSampleRate;
59 updateCoef();
60 }
61 }
62
63 void setTimeConstant(const float newT60) noexcept
64 {
65 const float newTau = newT60 * (float)(1.0 / 6.91);
66
67 if (d_isNotEqual(tau, newTau))
68 {
69 tau = newTau;
70 updateCoef();
71 }
72 }
73
74 float getCurrentValue() const noexcept
75 {
76 return mem;
77 }
78
79 float getTargetValue() const noexcept
80 {
81 return target;
82 }
83
84 void setTargetValue(const float newTarget) noexcept
85 {
86 target = newTarget;
87 }
88
89 void clearToTargetValue() noexcept
90 {
91 mem = target;
92 }
93
94 inline float peek() const noexcept
95 {
96 return mem * coef + target * (1.f - coef);
97 }
98
99 inline float next() noexcept
100 {
101 return (mem = mem * coef + target * (1.f - coef));
102 }
103
104private:
105 void updateCoef() noexcept
106 {
107 coef = std::exp(-1.f / (tau * sampleRate));
108 }
109};
110
111// --------------------------------------------------------------------------------------------------------------------
112
113/**
114 * @brief A linear smoother for control values
115 *
116 * This continually smooths a value towards a defined target, using linear segments.
117 *
118 * The duration of the smoothing segment is defined by the given time constant.
119 * Every time the target changes, a new segment restarts for the whole duration of the time constant.
120 *
121 * Note that this smoother, unlike an exponential smoother, eventually should converge to its target value.
122 */
123class LinearValueSmoother {
124 float step;
125 float target;
126 float mem;
127 float tau;
128 float sampleRate;
129
130public:
131 LinearValueSmoother()
132 : step(0.f),
133 target(0.f),
134 mem(0.f),
135 tau(0.f),
136 sampleRate(0.f) {}
137
138 void setSampleRate(const float newSampleRate) noexcept
139 {
140 if (d_isNotEqual(sampleRate, newSampleRate))
141 {
142 sampleRate = newSampleRate;
143 updateStep();
144 }
145 }
146
147 void setTimeConstant(const float newTau) noexcept
148 {
149 if (d_isNotEqual(tau, newTau))
150 {
151 tau = newTau;
152 updateStep();
153 }
154 }
155
156 float getCurrentValue() const noexcept
157 {
158 return mem;
159 }
160
161 float getTargetValue() const noexcept
162 {
163 return target;
164 }
165
166 void setTargetValue(const float newTarget) noexcept
167 {
168 if (d_isNotEqual(target, newTarget))
169 {
170 target = newTarget;
171 updateStep();
172 }
173 }
174
175 void clearToTargetValue() noexcept
176 {
177 mem = target;
178 }
179
180 inline float peek() const noexcept
181 {
182 const float dy = target - mem;
183 return mem + std::copysign(std::fmin(std::abs(dy), step), dy);
184 }
185
186 inline float next() noexcept
187 {
188 const float y0 = mem;
189 const float dy = target - y0;
190 return (mem = y0 + std::copysign(std::fmin(std::abs(dy), step), dy));
191 }
192
193private:
194 void updateStep() noexcept
195 {
196 step = std::abs(target - mem) / (tau * sampleRate);
197 }
198};
199
200// --------------------------------------------------------------------------------------------------------------------
201
203
204#endif // DAF_VALUE_SMOOTHER_HPP_INCLUDED
#define END_NAMESPACE_DAF
Definition DafInfo.hpp:996
#define START_NAMESPACE_DAF
Definition DafInfo.hpp:990