Mozzi  version v2.0
sound synthesis library for Arduino
ResonantFilter.h
1 /*
2  * ResonantFilter.h
3  *
4  * This file is part of Mozzi.
5  *
6  * Copyright 2012-2024 Tim Barrass and the Mozzi Team
7  *
8  * Mozzi is licensed under the GNU Lesser General Public Licence (LGPL) Version 2.1 or later.
9  *
10  */
11 
12 #ifndef RESONANTFILTER_H_
13 #define RESONANTFILTER_H_
14 
15 #include "IntegerType.h"
16 #include "AudioOutput.h"
17 #include "meta.h"
18 
19 
20 
21 /*
22 simple resonant filter posted to musicdsp.org by Paul Kellett
23 http://www.musicdsp.org/archive.php?classid=3#259, applying the
24 modification from Peter Schoffhauzer to make it able to output
25 all filter types (LowPass, HighPass, Notch and BandPass).
26 
27 The generic filter is ResonantFilter<unsigned_t type, FILTER_TYPE>.
28  - 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.
29  - FILTER_TYPE specifies the filter type. LOWPASS, BANDPASS, HIGHPASS and NOTCH are available types.
30 
31 Two versions are available: the 8bits and 16bits versions (see above).
32 The 8bits version is an optimized version that uses 8bits values to set
33 the resonance and the cutoff_freq. It can works on 8bits samples only
34 on 8bits platforms.
35 The 16bits version consumes more CPU ressources but uses 16bits values
36 for resonance and cutoff_freq and can work on samples up to 16bits on
37 8bits platforms and up to 32 on 32bits platforms.
38 
39 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:
40 
41 8bits versions: LowPassFilter, HighPassFilter, BandPassFilter, NotchFilter
42 16bits versions: LowPassFilter16, HighPassFilter16, BandPassFilter16, NotchFilter16
43 
44 
45 
47 // set feedback amount given f and q between 0 and 1
48 fb = q + q/(1.0 - f);
49 In order to avoid a slow division we use the use a Taylor expansion to approximate 1/(1.0 - f):
50 Close to f=0: 1/(1.0-f) approx 1.0+f.
51 Hence: fb = q + q * (1.0 + f)
52 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.
53 
54 // for each sample...
55 buf0 = buf0 + f * (in - buf0 + fb * (buf0 - buf1));
56 buf1 = buf1 + f * (buf0 - buf1);
57 out = buf1; // LowPass
58 out = in - buf0; // HighPass
59 out = buf0 - buf1; // BandPass
60 out = in - buf0 + buf1; // Notch
61 
62 fixed point version of the filter
63 "dave's blog of art and programming" http://www.pawfal.org/dave/blog/2011/09/
64 */
65 
66 
67 
68 
69 
70 enum filter_types { LOWPASS, BANDPASS, HIGHPASS, NOTCH };
71 
74 template<int8_t FILTER_TYPE, typename su=uint8_t>
76 {
77 
78 public:
82 
83 
91  void setCutoffFreq(su cutoff)
92  {
93  f = cutoff;
94  fb = q + ucfxmul(q, (typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
95  }
96 
105  void setResonance(su resonance) { q = resonance; }
106 
114  void setCutoffFreqAndResonance(su cutoff, su resonance)
115  {
116  f = cutoff;
117  q = resonance; // hopefully optimised away when compiled, just here for
118  // backwards compatibility
119  fb = q + ucfxmul(q,(typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
120  }
121 
127  // 10.5 to 12.5 us, mostly 10.5 us (was 14us)
128  inline AudioOutputStorage_t next(AudioOutputStorage_t in)
129  {
130  advanceBuffers(in);
131  return current(in, Int2Type<FILTER_TYPE>());
132  }
133 
134 protected:
135  su q;
136  su f;
137  typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type fb;
138  AudioOutputStorage_t buf0, buf1;
139  const uint8_t FX_SHIFT = sizeof(su) << 3;
140  const uint8_t FX_SHIFT_M_1 = FX_SHIFT-1;
141  const su SHIFTED_1 = (1<<FX_SHIFT)-1;
142 
143  // // multiply two fixed point numbers (returns fixed point)
144  // inline
145  // long fxmul(long a, long b)
146  // {
147  // return (a*b)>>FX_SHIFT;
148  // }
149 
150  inline void advanceBuffers(AudioOutputStorage_t in)
151  {
152  buf0 += fxmul(((in - buf0) + fxmul(fb, buf0 - buf1)), f);
153  buf1 += ifxmul(buf0 - buf1, f); // could overflow if input changes fast
154  }
155 
156  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<LOWPASS>) {return buf1;}
157 
158  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<HIGHPASS>) {return in - buf0;}
159 
160  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<BANDPASS>) {return buf0-buf1;}
161 
162  inline AudioOutputStorage_t current(AudioOutputStorage_t in, Int2Type<NOTCH>) {return in - buf0 + buf1;}
163 
164  // multiply two fixed point numbers (returns fixed point)
165  inline typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type ucfxmul(su a, typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type b)
166  {
167  return (((typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type)a * (b >> 1)) >> (FX_SHIFT_M_1));
168  }
169 
170  // multiply two fixed point numbers (returns fixed point)
171  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); }
172 
173  // multiply two fixed point numbers (returns fixed point)
174  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); }
175 };
176 
183 template<typename su=uint8_t>
184 class MultiResonantFilter: public ResonantFilter<LOWPASS,su>
185 {
186 public:
190 inline void next (AudioOutputStorage_t in)
191  {
192  last_in = in;
194  }
198  inline AudioOutputStorage_t low() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<LOWPASS>());}
202  inline AudioOutputStorage_t high() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<HIGHPASS>());}
206  inline AudioOutputStorage_t band() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<BANDPASS>());}
210  inline AudioOutputStorage_t notch() {return ResonantFilter<LOWPASS,su>::current(last_in,Int2Type<NOTCH>());}
211 
212 private:
213  AudioOutputStorage_t last_in;
214 };
215 
216 
219 /*
220 typedef ResonantFilter<uint8_t, HIGHPASS> HighPassFilter;
221 typedef ResonantFilter<uint16_t, HIGHPASS> HighPassFilter16;
222 typedef ResonantFilter<uint8_t, BANDPASS> BandPassFilter;
223 typedef ResonantFilter<uint16_t, BANDPASS> BandPassFilter16;
224 typedef ResonantFilter<uint8_t, NOTCH> NotchFilter;
225 typedef ResonantFilter<uint16_t, NOTCH> NotchFilter16;
226 */
227 
228 
240 #endif /* RESONANTFILTER_H_ */
A generic filter for audio signals that can produce lowpass, highpass, bandpass and notch outputs at ...
AudioOutputStorage_t high()
Return the input filtered with a highpass filter.
void next(AudioOutputStorage_t in)
Compute the filters, given an input signal.
AudioOutputStorage_t notch()
Return the input filtered with a notch filter.
AudioOutputStorage_t band()
Return the input filtered with a bandpass filter.
AudioOutputStorage_t low()
Return the input filtered with a lowpass filter.
A generic resonant filter for audio signals.
AudioOutputStorage_t next(AudioOutputStorage_t in)
Calculate the next sample, given an input signal.
void setResonance(su resonance)
deprecated.
void setCutoffFreq(su cutoff)
deprecated.
void setCutoffFreqAndResonance(su cutoff, su resonance)
Set the cut off frequency and resonance.
ResonantFilter()
Constructor.
Enables you to instantiate a template based on an integer value.
Definition: meta.h:41
Provides appropriate integer types that can bit the given number of bytes on this platform (at most 6...
Definition: IntegerType.h:20