Mozzi  version v2.0
sound synthesis library for Arduino
StateVariable.h
1 /*
2  * StateVariable.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 /**
13 State Variable Filter (approximation of Chamberlin version)
14 Informed by pseudocode at http://www.musicdsp.org/showone.php?id=23 and
15 http://www.musicdsp.org/showone.php?id=142. Here's the original:
16 ---------------------
17 cutoff = cutoff freq in Hz
18 fs = sampling frequency //(e.g. 44100Hz)
19 f = 2 sin (pi * cutoff / fs) //[approximately]
20 q = resonance/bandwidth [0 < q <= 1] most res: q=1, less: q=0
21 low = lowpass output
22 high = highpass output
23 band = bandpass output
24 notch = notch output
25 
26 scale = q
27 
28 low=high=band=0;
29 
30 //--beginloop
31 low = low + f * band;
32 high = scale * input - low - q*band;
33 band = f * high + band;
34 notch = high + low;
35 //--endloop
36 ----------------------
37 References :
38 Hal Chamberlin, Musical Applications of Microprocessors, 2nd Ed, Hayden Book
39 Company 1985. pp 490-492. Jon Dattorro, Effect Design Part 1, J. Audio Eng.
40 Soc., Vol 45, No. 9, 1997 September
41 */
42 
43 #ifndef STATEVARIABLE_H_
44 #define STATEVARIABLE_H_
45 
46 #include "Arduino.h"
47 #include "math.h"
48 #include "meta.h"
49 #include "mozzi_fixmath.h"
50 #include "mozzi_utils.h"
51 #include "ResonantFilter.h"
52 
53 //enum filter_types { LOWPASS, BANDPASS, HIGHPASS, NOTCH };
54 
55 /** A State Variable filter which offers 12db resonant low, high, bandpass and
56 notch modes.
57 @tparam FILTER_TYPE choose between LOWPASS, BANDPASS, HIGHPASS and NOTCH.
58 @note To save processing time, this version of the filter does not saturate
59 internally, so any resonant peaks are unceremoniously truncated. It may be
60 worth adding code to constrain the internal variables to enable resonant
61 saturating effects.
62 @todo Try adding code to constrain the internal variables to enable resonant
63 saturating effects.
64 */
65 template <int8_t FILTER_TYPE> class StateVariable {
66 
67 public:
68  /** Constructor.
69  */
71 
72  /** Set how resonant the filter will be.
73  @param resonance a byte value between 1 and 255.
74  The lower this value is, the more resonant the filter.
75  At very low values, the filter can output loud peaks which can exceed
76  Mozzi's output range, so you may need to attenuate the output in your sketch.
77  @note Timing < 500 ns
78  */
79  void setResonance(Q0n8 resonance) {
80  // qvalue goes from 255 to 0, representing .999 to 0 in fixed point
81  // lower q, more resonance
82  q = resonance;
83  scale = (Q0n8)sqrt((unsigned int)resonance << 8);
84  }
85 
86  /** Set the centre or corner frequency of the filter.
87  @param centre_freq 20 - 4096 Hz (MOZZI_AUDIO_RATE/4).
88  This will be the cut-off frequency for LOWPASS and HIGHPASS, and the
89  centre frequency to pass or reduce for BANDPASS and NOTCH.
90  @note Timing 25-30us
91  @note The frequency calculation is VERY "approximate". This really needs to
92  be fixed.
93  */
94  void setCentreFreq(unsigned int centre_freq) {
95  // simple frequency tuning with error towards nyquist (reference? where did
96  // this come from?)
97  // f = (Q1n15)(((Q16n16_2PI*centre_freq)>>AUDIO_RATE_AS_LSHIFT)>>1);
98  f = (Q15n16)((Q16n16_2PI * centre_freq) >>
99  (AUDIO_RATE_AS_LSHIFT)); // this works best for now
100  // f = (Q15n16)(((Q16n16_2PI*centre_freq)<<(16-AUDIO_RATE_AS_LSHIFT))>>16);
101  // // a small shift left and a round 16 right is faster than big
102  // non-byte-aligned right in one go float ff =
103  // Q16n16_to_float(((Q16n16_PI*centre_freq))>>AUDIO_RATE_AS_LSHIFT); f =
104  // float_to_Q15n16(2.0f *sin(ff));
105  }
106 
107  /** Calculate the next sample, given an input signal.
108  @param input the signal input.
109  @return the signal output.
110  @note Timing: 16 - 20 us
111  */
112  inline int next(int input) {
113  // chooses a different next() function depending on whether the
114  // filter is declared as LOWPASS, BANDPASS, HIGHPASS or NOTCH.
115  // See meta.h.
116  return next(input, Int2Type<FILTER_TYPE>());
117  }
118 
119 private:
120  int low, band;
121  Q0n8 q, scale;
122  volatile Q15n16 f;
123 
124  /** Calculate the next sample, given an input signal.
125  @param in the signal input.
126  @return the signal output.
127  @note Timing: 16 - 20 us
128  */
129  inline int next(int input, Int2Type<LOWPASS>) {
130  // setPin13High();
131  low += ((f * band) >> 16);
132  int high = (((long)input - low - (((long)band * q) >> 8)) * scale) >> 8;
133  band += ((f * high) >> 16);
134  // int notch = high + low;
135  // setPin13Low();
136  return low;
137  }
138 
139  /** Calculate the next sample, given an input signal.
140  @param input the signal input.
141  @return the signal output.
142  @note Timing:
143  */
144  inline int next(int input, Int2Type<BANDPASS>) {
145  // setPin13High();
146  low += ((f * band) >> 16);
147  int high = (((long)input - low - (((long)band * q) >> 8)) * scale) >> 8;
148  band += ((f * high) >> 16);
149  // int notch = high + low;
150  // setPin13Low();
151  return band;
152  }
153 
154  /** Calculate the next sample, given an input signal.
155  @param input the signal input.
156  @return the signal output.
157  @note Timing:
158  */
159  inline int next(int input, Int2Type<HIGHPASS>) {
160  // setPin13High();
161  low += ((f * band) >> 16);
162  int high = (((long)input - low - (((long)band * q) >> 8)) * scale) >> 8;
163  band += ((f * high) >> 16);
164  // int notch = high + low;
165  // setPin13Low();
166  return high;
167  }
168 
169  /** Calculate the next sample, given an input signal.
170  @param input the signal input.
171  @return the signal output.
172  @note Timing: 16 - 20 us
173  */
174  inline int next(int input, Int2Type<NOTCH>) {
175  // setPin13High();
176  low += ((f * band) >> 16);
177  int high = (((long)input - low - (((long)band * q) >> 8)) * scale) >> 8;
178  band += ((f * high) >> 16);
179  int notch = high + low;
180  // setPin13Low();
181  return notch;
182  }
183 };
184 
185 /**
186 @example 11.Audio_Filters/StateVariableFilter/StateVariableFilter.ino
187 This example demonstrates the StateVariable class.
188 */
189 
190 #endif /* STATEVARIABLE_H_ */