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
);
40 /// Change ramp length
41 inline void set_length(int _ramp_len
) {
43 mul
= (float)(1.0f
/ ramp_len
);
49 inline void start_ramp(float start
, float end
)
51 delta
= mul
* (end
- start
);
53 /// Return value after single step
54 inline float ramp(float value
)
58 /// Return value after many steps
59 inline float ramp_many(float value
, int count
)
61 return value
+ delta
* count
;
65 /// Algorithm for a constant time linear ramp
66 class exponential_ramp
72 exponential_ramp(int _ramp_len
) {
74 root
= (float)(1.0f
/ ramp_len
);
77 inline void set_length(int _ramp_len
) {
79 root
= (float)(1.0f
/ ramp_len
);
85 inline void start_ramp(float start
, float end
)
87 delta
= pow(end
/ start
, root
);
89 /// Return value after single step
90 inline float ramp(float value
)
94 /// Return value after many steps
95 inline float ramp_many(float value
, float count
)
97 return value
* pow(delta
, count
);
101 /// Generic inertia using ramping algorithm specified as template argument. The basic idea
102 /// is producing smooth(ish) output for discrete input, using specified algorithm to go from
103 /// last output value to input value. It is not the same as classic running average lowpass
104 /// filter, because ramping time is finite and pre-determined (it calls ramp algorithm's length()
105 /// function to obtain the expected ramp length)
116 inertia(const Ramp
&_ramp
, float init_value
= 0.f
)
119 value
= old_value
= init_value
;
122 /// Set value immediately (no inertia)
123 void set_now(float _value
)
125 value
= old_value
= _value
;
129 void set_inertia(float source
)
131 if (source
!= old_value
) {
132 ramp
.start_ramp(value
, source
);
133 count
= ramp
.length();
137 /// Get smoothed value of given source value
138 inline float get(float source
)
140 if (source
!= old_value
) {
141 ramp
.start_ramp(value
, source
);
142 count
= ramp
.length();
147 value
= ramp
.ramp(value
);
149 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
153 /// Get smoothed value assuming no new input
158 value
= ramp
.ramp(value
);
160 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
164 /// Do one inertia step, without returning the new value and without changing destination value
168 value
= ramp
.ramp(value
);
170 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
174 /// Do many inertia steps, without returning the new value and without changing destination value
175 inline void step_many(unsigned int steps
)
178 // Skip only a part of the current ramping period
179 value
= ramp
.ramp_many(value
, steps
);
181 if (!count
) // finished ramping, set to desired value to get rid of accumulated rounding errors
186 // The whole ramping period has been skipped, just go to destination
191 /// Get last smoothed value, without affecting anything
192 inline float get_last() const
196 /// Is it still ramping?
197 inline bool active() const
206 unsigned int frequency
;
209 once_per_n(unsigned int _frequency
)
210 : frequency(_frequency
), left(_frequency
)
216 /// Set timer to "elapsed" state (elapsed() will return true during next call)
221 inline unsigned int get(unsigned int desired
)
223 if (desired
> left
) {
231 inline bool elapsed()
241 class gain_smoothing
: public inertia
<linear_ramp
>
245 : inertia
<linear_ramp
>(linear_ramp(64))
248 void set_sample_rate(int sr
)
250 ramp
= linear_ramp(sr
/ 100);
252 // to change param, use set_inertia(value)
253 // to read param, use get()
256 template < typename T
>
266 switcher(unsigned int samples
) : cont_val_cur(), cont_val_prev()
279 void set_previous(T ctr
)
286 return cont_val_prev
;
293 /// Decrease value to zero
297 else if(acc
>= 0.5 && acc
<= 1.0) {
298 /// Switch and increase value to one
299 cont_val_prev
= cont_val_cur
;
301 return (acc
- 0.5)*2;
304 /// Switching finished