Mozzi  version v1.1.0
sound synthesis library for Arduino
Smooth.h
1 /*
2  * Smooth.h
3  *
4  * Copyright 2012 Tim Barrass.
5  *
6  * This file is part of Mozzi.
7  *
8  * Mozzi is licensed under a Creative Commons Attribution-NonCommercial-ShareAlike 4.0 International License.
9  *
10  */
11 
12 #ifndef SMOOTH_H_
13 #define SMOOTH_H_
14 
15 #include "Arduino.h"
16 #include "mozzi_fixmath.h"
17 
18 /** A simple infinite impulse response low pass filter for smoothing control or audio signals.
19 This algorithm comes from http://en.wikipedia.org/wiki/Low-pass_filter:
20 y[i] := y[i-1] + α * (x[i] - y[i-1]),
21 translated as
22 out = last_out + a * (in - last_out).
23 It's not calibrated to any real-world update rate, so if you use it at
24 CONTROL_RATE and you change CONTROL_RATE, you'll need to adjust the smoothness
25 value to suit.
26 @tparam T the type of numbers being smoothed. Watch out for numbers overflowing the
27 internal calculations. Some experimentation is recommended.
28 @note Timing: ~5us for 16 bit types, ~1us for 8 bit types.
29 @todo Check if 8 bit templates can work efficiently with a higher res smoothness -
30  as is they don't have enough resolution to work well at audio rate. See if Line might be
31  more useful in most cases.
32 */
33 
34 template <class T>
35 class Smooth
36 {
37 private:
38  long last_out;
39  Q0n16 a;
40 
41 public:
42  /** Constructor.
43  @param smoothness sets how much smoothing the filter will apply to
44  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
45  very smooth.
46  */
47  Smooth(float smoothness)
48  {
49  setSmoothness(smoothness);
50  }
51 
52  /** Constructor.
53  This constructor which doesn't take a smoothness parameter is useful when you incorporate Smooth into another class definition.
54  You need to call setSmoothness(float) for your object before using Smooth.
55  @note there's probably a better way to do this...
56  */
58  {}
59 
60 
61  /** Filters the input and returns the filtered value. You can also use the operator() function, eg. something like mySmoother(input-value).
62  @param in the signal to be smoothed.
63  @return the filtered signal.
64  */
65  inline
66  T next(T in)
67  {
68  long out = ((((((long)in - (last_out>>8)) * a))>>8) + last_out);
69  last_out = out;
70  return (T)(out>>8);
71  }
72 
73 
74  /** Filters the input and returns the filtered value. Same as next(input-value).
75  @param in the signal to be smoothed.
76  @return the filtered signal.
77  */
78  inline
79  T operator()(T n) {
80  return next(n);
81  }
82 
83 
84  /** Sets how much smoothing the filter will apply to its input.
85  @param smoothness sets how much smoothing the filter will apply to
86  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
87  very smooth.
88  */
89  inline
90  void setSmoothness(float smoothness)
91  {
92  a=float_to_Q0n16(1.f-smoothness);
93  }
94 
95 };
96 
97 
98 /** @cond */ // doxygen can ignore the specialisations
99 
100 /** uint8_t specialisation of Smooth template*/
101 template <>
102 class Smooth <uint8_t>
103 {
104 private:
105  unsigned int last_out;
106  Q0n8 a;
107 
108 public:
109  /** Constructor.
110  @param smoothness sets how much smoothing the filter will apply to
111  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
112  very smooth.
113  */
114  Smooth(float smoothness)
115  {
116  setSmoothness(smoothness);
117  }
118 
119  /** Filters the input and returns the filtered value. You can also use the operator() function, eg. something like mySmoother(input-value).
120  @param in the signal to be smoothed.
121  @return the filtered signal.
122  */
123  inline
124  uint8_t next(uint8_t in)
125  {
126  unsigned int out = (((((int)in - (last_out>>8)) * a)) + last_out);
127  last_out = out;
128  return (uint8_t)(out>>8);
129  }
130 
131 
132  /** Filters the input and returns the filtered value. Same as next(input-value).
133  @param in the signal to be smoothed.
134  @return the filtered signal.
135  */
136  inline
137  uint8_t operator()(uint8_t n) {
138  return next(n);
139  }
140 
141 
142  /** Sets how much smoothing the filter will apply to its input.
143  @param smoothness sets how much smoothing the filter will apply to
144  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
145  very smooth.
146  */
147  inline
148  void setSmoothness(float smoothness)
149  {
150  a=float_to_Q0n8(1.f-smoothness);
151  }
152 
153 };
154 
155 
156 /** int8_t specialisation of Smooth template*/
157 template <>
158 class Smooth <int8_t>
159 {
160 private:
161  int last_out;
162  Q0n8 a;
163 
164 public:
165  /** Constructor.
166  @param smoothness sets how much smoothing the filter will apply to
167  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
168  very smooth.
169  */
170  Smooth(float smoothness)
171  {
172  setSmoothness(smoothness);
173  }
174 
175 
176  /** Filters the input and returns the filtered value. You can also use the operator() function, eg. something like mySmoother(input-value).
177  @param in the signal to be smoothed.
178  @return the filtered signal.
179  */
180  inline
181  int8_t next(int8_t in)
182  {
183  int out = (((((int)in - (last_out>>8)) * a)) + last_out);
184  last_out = out;
185  return (int8_t)(out>>8);
186  }
187 
188 
189  /** Filters the input and returns the filtered value. Same as next(input-value).
190  @param in the signal to be smoothed.
191  @return the filtered signal.
192  */
193  inline
194  int8_t operator()(int8_t n) {
195  return next(n);
196  }
197 
198 
199  /** Sets how much smoothing the filter will apply to its input.
200  @param smoothness sets how much smoothing the filter will apply to
201  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
202  very smooth.
203  */
204  inline
205  void setSmoothness(float smoothness)
206  {
207  a=float_to_Q0n8(1.f-smoothness);
208  }
209 
210 };
211 
212 /** float specialisation of Smooth template*/
213 template <>
214 class Smooth <float>
215 {
216 private:
217  float last_out;
218  float a;
219 
220 public:
221  /** Constructor.
222  @param smoothness sets how much smoothing the filter will apply to
223  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
224  very smooth.
225  */
226  Smooth(float smoothness)
227  {
228  setSmoothness(smoothness);
229  }
230 
231  /** Filters the input and returns the filtered value. You can also use the operator() function, eg. something like mySmoother(input-value).
232  @param in the signal to be smoothed.
233  @return the filtered signal.
234  */
235  inline
236  float next(float in)
237  {
238  float out = last_out + a * (in - last_out);
239  //float out = (in - last_out * a) + last_out;
240  last_out = out;
241  return out;
242  }
243 
244 
245  /** Filters the input and returns the filtered value. Same as next(input-value).
246  @param in the signal to be smoothed.
247  @return the filtered signal.
248  */
249  inline
250  float operator()(float n) {
251  return next(n);
252  }
253 
254 
255  /** Sets how much smoothing the filter will apply to its input.
256  @param smoothness sets how much smoothing the filter will apply to
257  its input. Use a float in the range 0~1, where 0 is not very smooth and 0.99 is
258  very smooth.
259  */
260  inline
261  void setSmoothness(float smoothness)
262  {
263  a=1.f-smoothness;
264  }
265 
266 };
267 
268 
269 /** @endcond */
270 
271 /**
272 @example 05.Control_Filters/Smooth/Smooth.ino
273 This example demonstrates the Smooth class.
274 */
275 
276 #endif /* SMOOTH_H_ */
void setSmoothness(float smoothness)
Sets how much smoothing the filter will apply to its input.
Definition: Smooth.h:90
Smooth(float smoothness)
Constructor.
Definition: Smooth.h:47
uint16_t Q0n16
unsigned fractional number using 16 fractional bits, represents 0.0 to 0.999
Definition: mozzi_fixmath.h:29
A simple infinite impulse response low pass filter for smoothing control or audio signals...
Definition: Smooth.h:35
T operator()(T n)
Filters the input and returns the filtered value.
Definition: Smooth.h:79
Q0n16 float_to_Q0n16(float a)
Convert float to Q0n16 fix.
T next(T in)
Filters the input and returns the filtered value.
Definition: Smooth.h:66
Smooth()
Constructor.
Definition: Smooth.h:57