Skip to content

Commit e642c01

Browse files
authored
Merge pull request #165 from tomcombriat/ResonantFilter
Mutation of the LowPassFilter into a generic filter
2 parents 0aa195e + 00dc12f commit e642c01

File tree

7 files changed

+369
-157
lines changed

7 files changed

+369
-157
lines changed

LowPassFilter.h

Lines changed: 2 additions & 141 deletions
Original file line numberDiff line numberDiff line change
@@ -13,146 +13,7 @@
1313
#ifndef LOWPASS_H_
1414
#define LOWPASS_H_
1515

16-
#include "IntegerType.h"
17-
#include "AudioOutput.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
24-
25-
Two versions are available: LowPassFilter and LowPassFilter16.
26-
LowPassFilter is an optimized version that uses 8bits values to set
27-
the resonance and the cutoff_freq. It can works on 8bits samples only
28-
on 8bits platforms.
29-
LowPassFilter16 consumes more CPU ressources but uses 16bits values
30-
for resonance and cutoff_freq and can work on samples up to 16bits on
31-
8bits platforms and up to 32 on 32bits platforms.
32-
33-
// set feedback amount given f and q between 0 and 1
34-
fb = q + q/(1.0 - f);
35-
In order to avoid a slow division we use the use a Taylor expansion to approximate 1/(1.0 - f):
36-
Close to f=0: 1/(1.0-f) approx 1.0+f.
37-
Hence: fb = q + q * (1.0 + f)
38-
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.
39-
40-
// for each sample...
41-
buf0 = buf0 + f * (in - buf0 + fb * (buf0 - buf1));
42-
buf1 = buf1 + f * (buf0 - buf1);
43-
out = buf1;
44-
45-
fixed point version of the filter
46-
"dave's blog of art and programming" http://www.pawfal.org/dave/blog/2011/09/
47-
*/
48-
49-
// we are using .n fixed point (n bits for the fractional part)
50-
//#define FX_SHIFT 8
51-
//#define SHIFTED_1 ((uint8_t)255)
52-
53-
/** A resonant low pass filter for audio signals.
54-
*/
55-
template<typename su=uint8_t>
56-
class LowPassFilterNbits
57-
{
58-
59-
public:
60-
/** Constructor.
61-
*/
62-
LowPassFilterNbits() { ; }
63-
64-
65-
/** deprecated. Use setCutoffFreqAndResonance(su cutoff, su
66-
resonance).
67-
68-
Set the cut off frequency,
69-
@param cutoff use the range 0-255 to represent 0-8191 Hz (AUDIO_RATE/2) for LowPassFilter, cutoff use the range 0-65535 to represent 0-AUDIO_RATE/2.
70-
Be careful of distortion at the lower end, especially with high resonance.
71-
*/
72-
void setCutoffFreq(su cutoff)
73-
{
74-
f = cutoff;
75-
fb = q + ucfxmul(q, (typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
76-
}
77-
78-
/** deprecated. Use setCutoffFreqAndResonance(su cutoff, su
79-
resonance).
80-
81-
Set the resonance. If you hear unwanted distortion, back off the resonance.
82-
After setting resonance, you need to call setCuttoffFreq() to hear the change!
83-
@param resonance in the range 0-255 for LowPassFilter, 0-65535 for LowPassFilter16, with 255/65535 being most resonant
84-
@note Remember to call setCuttoffFreq() after resonance is changed!
85-
*/
86-
void setResonance(su resonance) { q = resonance; }
87-
88-
/**
89-
Set the cut off frequency and resonance. Replaces setCutoffFreq() and
90-
setResonance(). (Because the internal calculations need to be done whenever either parameter changes.)
91-
@param cutoff range 0-255 represents 0-8191 Hz (AUDIO_RATE/2) for LowPassFilter, range 0-65535 for LowPassFilter16
92-
Be careful of distortion at the lower end, especially with high resonance.
93-
@param resonance range 0-255 for LowPassFilter, 0-65535 for LowPassFilter16, 255/65535 is most resonant.
94-
*/
95-
void setCutoffFreqAndResonance(su cutoff, su resonance)
96-
{
97-
f = cutoff;
98-
q = resonance; // hopefully optimised away when compiled, just here for
99-
// backwards compatibility
100-
fb = q + ucfxmul(q,(typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type) SHIFTED_1 + cutoff);
101-
}
102-
103-
/** Calculate the next sample, given an input signal.
104-
@param in the signal input. Should not be more than 8bits on 8bits platforms (Arduino) if using LowPassFilter and not LowPassFilter16.
105-
@return the signal output.
106-
@note Timing: about 11us.
107-
*/
108-
// 10.5 to 12.5 us, mostly 10.5 us (was 14us)
109-
inline AudioOutputStorage_t next(AudioOutputStorage_t in)
110-
{
111-
// setPin13High();
112-
buf0 += fxmul(((in - buf0) + fxmul(fb, buf0 - buf1)), f);
113-
buf1 += ifxmul(buf0 - buf1, f); // could overflow if input changes fast
114-
return buf1;
115-
}
116-
117-
private:
118-
su q;
119-
su f;
120-
typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type fb;
121-
AudioOutputStorage_t buf0, buf1;
122-
const uint8_t FX_SHIFT = sizeof(su) << 3;
123-
const uint8_t FX_SHIFT_M_1 = FX_SHIFT-1;
124-
const su SHIFTED_1 = (1<<FX_SHIFT)-1;
125-
126-
// // multiply two fixed point numbers (returns fixed point)
127-
// inline
128-
// long fxmul(long a, long b)
129-
// {
130-
// return (a*b)>>FX_SHIFT;
131-
// }
132-
133-
// multiply two fixed point numbers (returns fixed point)
134-
inline typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type ucfxmul(su a, typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type b)
135-
{
136-
return (((typename IntegerType<sizeof(su)+sizeof(su)>::unsigned_type)a * (b >> 1)) >> (FX_SHIFT_M_1));
137-
}
138-
139-
// multiply two fixed point numbers (returns fixed point)
140-
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); }
141-
142-
// multiply two fixed point numbers (returns fixed point)
143-
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); }
144-
};
145-
146-
typedef LowPassFilterNbits<> LowPassFilter;
147-
typedef LowPassFilterNbits<uint16_t> LowPassFilter16;
148-
149-
150-
/**
151-
@example 10.Audio_Filters/LowPassFilter/LowPassFilter.ino
152-
This example demonstrates the LowPassFilter class.
153-
154-
@example 10.Audio_Filters/LowPassFilter/LowPassFilter16.ino
155-
This example demonstrates the LowPassFilter16 class.
156-
*/
16+
#include<ResonantFilter.h>
17+
#warning This header is deprecated, please use ResonantFilter.h instead.
15718

15819
#endif /* LOWPASS_H_ */

ResonantFilter.h

Lines changed: 241 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,241 @@
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>
76+
class ResonantFilter
77+
{
78+
79+
public:
80+
/** Constructor.
81+
*/
82+
ResonantFilter() { ; }
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)
129+
inline AudioOutputStorage_t next(AudioOutputStorage_t in)
130+
{
131+
advanceBuffers(in);
132+
return next(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 next(AudioOutputStorage_t in, Int2Type<LOWPASS>) {return buf1;}
158+
159+
inline AudioOutputStorage_t next(AudioOutputStorage_t in, Int2Type<HIGHPASS>) {return in - buf0;}
160+
161+
inline AudioOutputStorage_t next(AudioOutputStorage_t in, Int2Type<BANDPASS>) {return buf0-buf1;}
162+
163+
inline AudioOutputStorage_t next(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>::next(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>::next(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>::next(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>::next(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_ */

0 commit comments

Comments
 (0)