+ Wavetable: one more wavetable (experimental, will be changed)
[calf.git] / src / calf / inertia.h
blobaca1fbfec4af148d763caa75e9329ea764a99af8
1 /* Calf DSP Library
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"
25 namespace dsp {
27 /// Algorithm for a constant time linear ramp
28 class linear_ramp
30 public:
31 int ramp_len;
32 float mul, delta;
33 public:
34 /// Construct for given ramp length
35 linear_ramp(int _ramp_len) {
36 ramp_len = _ramp_len;
37 mul = (float)(1.0f / ramp_len);
39 /// Change ramp length
40 inline void set_length(int _ramp_len) {
41 ramp_len = _ramp_len;
42 mul = (float)(1.0f / ramp_len);
44 inline int length()
46 return 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)
55 return value + delta;
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
67 public:
68 int ramp_len;
69 float root, delta;
70 public:
71 exponential_ramp(int _ramp_len) {
72 ramp_len = _ramp_len;
73 root = (float)(1.0f / ramp_len);
75 inline void set_length(int _ramp_len) {
76 ramp_len = _ramp_len;
77 root = (float)(1.0f / ramp_len);
79 inline int length()
81 return 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)
90 return value * delta;
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)
104 template<class Ramp>
105 class inertia
107 public:
108 float old_value;
109 float value;
110 unsigned int count;
111 Ramp ramp;
113 public:
114 inertia(const Ramp &_ramp, float init_value = 0.f)
115 : ramp(_ramp)
117 value = old_value = init_value;
118 count = 0;
120 /// Set value immediately (no inertia)
121 void set_now(float _value)
123 value = old_value = _value;
124 count = 0;
126 /// Set with inertia
127 void set_inertia(float source)
129 if (source != old_value) {
130 ramp.start_ramp(value, source);
131 count = ramp.length();
132 old_value = source;
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();
141 old_value = source;
143 if (!count)
144 return old_value;
145 value = ramp.ramp(value);
146 count--;
147 if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
148 value = old_value;
149 return value;
151 /// Get smoothed value assuming no new input
152 inline float get()
154 if (!count)
155 return old_value;
156 value = ramp.ramp(value);
157 count--;
158 if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
159 value = old_value;
160 return value;
162 /// Do one inertia step, without returning the new value and without changing destination value
163 inline void step()
165 if (count) {
166 value = ramp.ramp(value);
167 count--;
168 if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
169 value = old_value;
172 /// Do many inertia steps, without returning the new value and without changing destination value
173 inline void step_many(unsigned int steps)
175 if (steps < count) {
176 // Skip only a part of the current ramping period
177 value = ramp.ramp_many(value, steps);
178 count -= steps;
179 if (!count) // finished ramping, set to desired value to get rid of accumulated rounding errors
180 value = old_value;
182 else
184 // The whole ramping period has been skipped, just go to destination
185 value = old_value;
186 count = 0;
189 /// Get last smoothed value, without affecting anything
190 inline float get_last() const
192 return value;
194 /// Is it still ramping?
195 inline bool active() const
197 return count > 0;
201 class once_per_n
203 public:
204 unsigned int frequency;
205 unsigned int left;
206 public:
207 once_per_n(unsigned int _frequency)
208 : frequency(_frequency), left(_frequency)
210 inline void start()
212 left = frequency;
214 /// Set timer to "elapsed" state (elapsed() will return true during next call)
215 inline void signal()
217 left = 0;
219 inline unsigned int get(unsigned int desired)
221 if (desired > left) {
222 desired = left;
223 left = 0;
224 return desired;
226 left -= desired;
227 return desired;
229 inline bool elapsed()
231 if (!left) {
232 left = frequency;
233 return true;
235 return false;
239 class gain_smoothing: public inertia<linear_ramp>
241 public:
242 gain_smoothing()
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()
256 #endif