Mozzi  version v1.1.0
sound synthesis library for Arduino
ResonantFilter.h
1 /*
2  * ResonantFilter.h
3  *
4  * Copyright 2012 Tim Barrass
5  *
6  * This file is part of Mozzi.
7  *
8  * Mozzi is licensed under a Creative Commons
9  * Attribution-NonCommercial-ShareAlike 4.0 International License.
10  *
11  */
12 
13 #ifndef RESONANTFILTER_H_
14 #define RESONANTFILTER_H_
15 
16 #include "IntegerType.h"
17 #include "AudioOutput.h"
18 #include "meta.h"
19 
20 
21 
22 /*
23 simple resonant filter posted to musicdsp.org by Paul Kellett
24 http://www.musicdsp.org/archive.php?classid=3#259, applying the
25 modification from Peter Schoffhauzer to make it able to output
26 all filter types (LowPass, HighPass, Notch and BandPass).
27 
28 The generic filter is ResonantFilter<unsigned_t type, FILTER_TYPE>.
29  - type specifies the type expected for the cutoff and resonance. Only uint8_t and uint16_t have been tested. These are denoted 8bits and 16bits versions of the filter in the following.
30  - FILTER_TYPE specifies the filter type. LOWPASS, BANDPASS, HIGHPASS and NOTCH are available types.
31 
32 Two versions are available: the 8bits and 16bits versions (see above).
33 The 8bits version is an optimized version that uses 8bits values to set
34 the resonance and the cutoff_freq. It can works on 8bits samples only
35 on 8bits platforms.
36 The 16bits version consumes more CPU ressources but uses 16bits values
37 for resonance and cutoff_freq and can work on samples up to 16bits on
38 8bits platforms and up to 32 on 32bits platforms.
39 
40 The filter can be instanciated using the template version ResonantFilter<unsigned_t type, FILTER_TYPE>. For ease of use, the following types are also accepted:
41 
42 8bits versions: LowPassFilter, HighPassFilter, BandPassFilter, NotchFilter
43 16bits versions: LowPassFilter16, HighPassFilter16, BandPassFilter16, NotchFilter16
44 
45 
46 
47 //// ALGORITHM ////
48 // set feedback amount given f and q between 0 and 1
49 fb = q + q/(1.0 - f);
50 In order to avoid a slow division we use the use a Taylor expansion to approximate 1/(1.0 - f):
51 Close to f=0: 1/(1.0-f) approx 1.0+f.
52 Hence: fb = q + q * (1.0 + f)
53 This approximation is less and less valid with an increasing cutoff, leading to a reduction of the resonance of the filter at high cutoff frequencies.
54 
55 // for each sample...
56 buf0 = buf0 + f * (in - buf0 + fb * (buf0 - buf1));
57 buf1 = buf1 + f * (buf0 - buf1);
58 out = buf1; // LowPass
59 out = in - buf0; // HighPass
60 out = buf0 - buf1; // BandPass
61 out = in - buf0 + buf1; // Notch
62 
63 fixed point version of the filter
64 "dave's blog of art and programming" http://www.pawfal.org/dave/blog/2011/09/
65 */
66 
67 
68 
69 
70 
71 enum filter_types { LOWPASS, BANDPASS, HIGHPASS, NOTCH };
72 
73 /** A generic resonant filter for audio signals.
74  */
75 template<int8_t FILTER_TYPE, typename su=uint8_t>
77 {
78 
79 public:
80  /** Constructor.
81  */
83 
84 
85  /** deprecated. Use setCutoffFreqAndResonance(su cutoff, su
86  resonance).
87 
88  Set the cut off frequency,
89  @param cutoff use the range 0-255 to represent 0-8191 Hz (AUDIO_RATE/2) for ResonantFilter, cutoff use the range 0-65535 to represent 0-AUDIO_RATE/2.
90  Be careful of distortion at the lower end, especially with high resonance.
91  */
92  void setCutoffFreq(su cutoff)
93  {
94  f = cutoff;
95  fb = q + ucfxmul(q, (typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
96  }
97 
98  /** deprecated. Use setCutoffFreqAndResonance(su cutoff, su
99  resonance).
100 
101  Set the resonance. If you hear unwanted distortion, back off the resonance.
102  After setting resonance, you need to call setCuttoffFreq() to hear the change!
103  @param resonance in the range 0-255 for ResonantFilter, 0-65535 for ResonantFilter<FILTER_TYPE, uint16_t>, with 255/65535 being most resonant
104  @note Remember to call setCuttoffFreq() after resonance is changed!
105  */
106  void setResonance(su resonance) { q = resonance; }
107 
108  /**
109  Set the cut off frequency and resonance. Replaces setCutoffFreq() and
110  setResonance(). (Because the internal calculations need to be done whenever either parameter changes.)
111  @param cutoff range 0-255 represents 0-8191 Hz (AUDIO_RATE/2) for ResonantFilter, range 0-65535 for ResonantFilter16
112  Be careful of distortion at the lower end, especially with high resonance.
113  @param resonance range 0-255 for ResonantFilter, 0-65535 for ResonantFilter<FILTER_TYPE, uint16_t>, 255/65535 is most resonant.
114  */
115  void setCutoffFreqAndResonance(su cutoff, su resonance)
116  {
117  f = cutoff;
118  q = resonance; // hopefully optimised away when compiled, just here for
119  // backwards compatibility
120  fb = q + ucfxmul(q,(typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
121  }
122 
123  /** Calculate the next sample, given an input signal.
124  @param in the signal input. Should not be more than 8bits on 8bits platforms (Arduino) if using the 8bits version and not 16bits version.
125  @return the signal output.
126  @note Timing: about 11us.
127  */
128  // 10.5 to 12.5 us, mostly 10.5 us (was 14us)
130  {
131  advanceBuffers(in);
132  return current(in, Int2Type<FILTER_TYPE>());
133  }
134 
135 protected:
136  su q;
137  su f;
138  typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type fb;
139  AudioOutputStorage_t buf0, buf1;
140  const uint8_t FX_SHIFT = sizeof(su) << 3;
141  const uint8_t FX_SHIFT_M_1 = FX_SHIFT-1;
142  const su SHIFTED_1 = (1<<FX_SHIFT)-1;
143 
144  // // multiply two fixed point numbers (returns fixed point)
145  // inline
146  // long fxmul(long a, long b)
147  // {
148  // return (a*b)>>FX_SHIFT;
149  // }
150 
151  inline void advanceBuffers(AudioOutputStorage_t in)
152  {
153  buf0 += fxmul(((in - buf0) + fxmul(fb, buf0 - buf1)), f);
154  buf1 += ifxmul(buf0 - buf1, f); // could overflow if input changes fast
155  }
156 
157  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<LOWPASS>) {return buf1;}
158 
159  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<HIGHPASS>) {return in - buf0;}
160 
161  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<BANDPASS>) {return buf0-buf1;}
162 
163  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<NOTCH>) {return in - buf0 + buf1;}
164 
165  // multiply two fixed point numbers (returns fixed point)
166  inline typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type ucfxmul(su a, typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type b)
167  {
168  return (((typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type)a * (b >> 1)) >> (FX_SHIFT_M_1));
169  }
170 
171  // multiply two fixed point numbers (returns fixed point)
172  inline typename IntegerType<sizeof(AudioOutputStorage_t)+sizeof(su)-1>::signed_type ifxmul(typename IntegerType<sizeof(AudioOutputStorage_t )+sizeof(su)-1>::signed_type a, su b) { return ((a * b) >> FX_SHIFT); }
173 
174  // multiply two fixed point numbers (returns fixed point)
175  inline typename IntegerType<sizeof(AudioOutputStorage_t)+sizeof(AudioOutputStorage_t)>::signed_type fxmul(typename IntegerType<sizeof(AudioOutputStorage_t)+sizeof(AudioOutputStorage_t)>::signed_type a, typename IntegerType<sizeof(AudioOutputStorage_t)+sizeof(su)-1>::signed_type b) { return ((a * b) >> FX_SHIFT); }
176 };
177 
178 /** A generic filter for audio signals that can produce lowpass, highpass, bandpass and notch outputs at runtime.
179 Behaves like ResonantFilter for setting the resonance and cutoff frequency.
180 Like ResonantFilter, it can be used on different sample sizes: MultiResonantFilter<uint8_t> and MultiResonantFilter<uint16_t> have been tested.
181 For the former, both cutoff and resonance are uint8_t, hence between 0-255.
182 For the later, both cutoff and resonance are uint16_t, hence between 0-65535.
183  */
184 template<typename su=uint8_t>
185 class MultiResonantFilter: public ResonantFilter<LOWPASS,su>
186 {
187 public:
188  /** Compute the filters, given an input signal.
189  @param in the signal input. Should not be more than 8bits on 8bits platforms (Arduino) if using the 8bits version and not 16bits version.
190  */
191 inline void next (AudioOutputStorage_t in)
192  {
193  last_in = in;
194  ResonantFilter<LOWPASS,su>::advanceBuffers(in);
195  }
196  /** Return the input filtered with a lowpass filter
197  @return the filtered signal output.
198  */
199  inline AudioOutputStorage_t low() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<LOWPASS>());}
200  /** Return the input filtered with a highpass filter
201  @return the filtered signal output.
202  */
203  inline AudioOutputStorage_t high() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<HIGHPASS>());}
204  /** Return the input filtered with a bandpass filter
205  @return the filtered signal output.
206  */
207  inline AudioOutputStorage_t band() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<BANDPASS>());}
208  /** Return the input filtered with a notch filter
209  @return the filtered signal output.
210  */
211  inline AudioOutputStorage_t notch() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<NOTCH>());}
212 
213 private:
214  AudioOutputStorage_t last_in;
215 };
216 
217 
218 typedef ResonantFilter<LOWPASS> LowPassFilter;
219 typedef ResonantFilter<LOWPASS, uint16_t> LowPassFilter16;
220 /*
221 typedef ResonantFilter<uint8_t, HIGHPASS> HighPassFilter;
222 typedef ResonantFilter<uint16_t, HIGHPASS> HighPassFilter16;
223 typedef ResonantFilter<uint8_t, BANDPASS> BandPassFilter;
224 typedef ResonantFilter<uint16_t, BANDPASS> BandPassFilter16;
225 typedef ResonantFilter<uint8_t, NOTCH> NotchFilter;
226 typedef ResonantFilter<uint16_t, NOTCH> NotchFilter16;
227 */
228 
229 
230 /**
231 @example 10.Audio_Filters/ResonantFilter/ResonantFilter.ino
232 This example demonstrates the ResonantFilter specification of this class.
233 
234 @example 10.Audio_Filters/ResonantFilter16/ResonantFilter16.ino
235 This example demonstrates the ResonantFilter16 specification of this class.
236 
237 @example 10.Audio_Filters/MultiResonantFilter/MultiResonantFilter.ino
238 This example demonstrates the MultiResonantFilter specification of this class.
239 */
240 
241 #endif /* RESONANTFILTER_H_ */
void setCutoffFreqAndResonance(su cutoff, su resonance)
Set the cut off frequency and resonance.
AudioOutputStorage_t next(AudioOutputStorage_t in)
Calculate the next sample, given an input signal.
AudioOutputStorage_t notch()
Return the input filtered with a notch filter.
Enables you to instantiate a template based on an integer value.
Definition: meta.h:20
void next(AudioOutputStorage_t in)
Compute the filters, given an input signal.
A generic filter for audio signals that can produce lowpass, highpass, bandpass and notch outputs at ...
AudioOutputStorage_t low()
Return the input filtered with a lowpass filter.
AudioOutputStorage_t high()
Return the input filtered with a highpass filter.
AudioOutputStorage_t band()
Return the input filtered with a bandpass filter.
void setResonance(su resonance)
deprecated.
A generic resonant filter for audio signals.
void setCutoffFreq(su cutoff)
deprecated.
ResonantFilter()
Constructor.
#define AudioOutputStorage_t
The type used to store a single channel of a single frame, internally.
Definition: AudioOutput.h:46