2 * Basic "inertia" (parameter smoothing) classes.
3 * Copyright (C) 2001-2007 Krzysztof Foltman
5 * This program is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
15 * You should have received a copy of the GNU Lesser General
16 * Public License along with this program; if not, write to the
17 * Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
18 * Boston, MA 02111-1307, USA.
20 #ifndef __CALF_INERTIA_H
21 #define __CALF_INERTIA_H
23 #include "primitives.h"
27 /// Algorithm for a constant time linear ramp
34 /// Construct for given ramp length
35 linear_ramp(int _ramp_len
) {
37 mul
= (float)(1.0f
/ ramp_len
);
39 /// Change ramp length
40 inline void set_length(int _ramp_len
) {
42 mul
= (float)(1.0f
/ ramp_len
);
48 inline void start_ramp(float start
, float end
)
50 delta
= mul
* (end
- start
);
52 /// Return value after single step
53 inline float ramp(float value
)
57 /// Return value after many steps
58 inline float ramp_many(float value
, int count
)
60 return value
+ delta
* count
;
64 /// Algorithm for a constant time linear ramp
65 class exponential_ramp
71 exponential_ramp(int _ramp_len
) {
73 root
= (float)(1.0f
/ ramp_len
);
75 inline void set_length(int _ramp_len
) {
77 root
= (float)(1.0f
/ ramp_len
);
83 inline void start_ramp(float start
, float end
)
85 delta
= pow(end
/ start
, root
);
87 /// Return value after single step
88 inline float ramp(float value
)
92 /// Return value after many steps
93 inline float ramp_many(float value
, float count
)
95 return value
* pow(delta
, count
);
99 /// Generic inertia using ramping algorithm specified as template argument. The basic idea
100 /// is producing smooth(ish) output for discrete input, using specified algorithm to go from
101 /// last output value to input value. It is not the same as classic running average lowpass
102 /// filter, because ramping time is finite and pre-determined (it calls ramp algorithm's length()
103 /// function to obtain the expected ramp length)
114 inertia(const Ramp
&_ramp
, float init_value
= 0.f
)
117 value
= old_value
= init_value
;
120 /// Set value immediately (no inertia)
121 void set_now(float _value
)
123 value
= old_value
= _value
;
127 void set_inertia(float source
)
129 if (source
!= old_value
) {
130 ramp
.start_ramp(value
, source
);
131 count
= ramp
.length();
135 /// Get smoothed value of given source value
136 inline float get(float source
)
138 if (source
!= old_value
) {
139 ramp
.start_ramp(value
, source
);
140 count
= ramp
.length();
145 value
= ramp
.ramp(value
);
147 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
151 /// Get smoothed value assuming no new input
156 value
= ramp
.ramp(value
);
158 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
162 /// Do one inertia step, without returning the new value and without changing destination value
166 value
= ramp
.ramp(value
);
168 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
172 /// Do many inertia steps, without returning the new value and without changing destination value
173 inline void step_many(unsigned int steps
)
176 // Skip only a part of the current ramping period
177 value
= ramp
.ramp_many(value
, steps
);
179 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
184 // The whole ramping period has been skipped, just go to destination
189 /// Get last smoothed value, without affecting anything
190 inline float get_last() const
194 /// Is it still ramping?
195 inline bool active() const
204 unsigned int frequency
;
207 once_per_n(unsigned int _frequency
)
208 : frequency(_frequency
), left(_frequency
)
214 /// Set timer to "elapsed" state (elapsed() will return true during next call)
219 inline unsigned int get(unsigned int desired
)
221 if (desired
> left
) {
229 inline bool elapsed()
239 class gain_smoothing
: public inertia
<linear_ramp
>
243 : inertia
<linear_ramp
>(linear_ramp(64))
246 void set_sample_rate(int sr
)
248 ramp
= linear_ramp(sr
/ 441);
250 // to change param, use set_inertia(value)
251 // to read param, use get()