iPlug2 - C++ Audio Plug-in Framework
Loading...
Searching...
No Matches
SVF.h
Go to the documentation of this file.
1/*
2 ==============================================================================
3
4 This file is part of the iPlug 2 library. Copyright (C) the iPlug 2 developers.
5
6 See LICENSE.txt for more info.
7
8 ==============================================================================
9*/
10
11#pragma once
12
19#include <complex>
20
21#include "IPlugPlatform.h"
22
23BEGIN_IPLUG_NAMESPACE
24
25#define SVFMODES_VALIST "LowPass", "HighPass", "BandPass", "Notch", "Peak", "Bell", "LowPassShelf", "HighPassShelf"
26
27template<typename T = double, int NC = 1>
28class SVF
29{
30public:
31
32 enum EMode
33 {
34 kLowPass = 0,
35 kHighPass,
36 kBandPass,
37 kNotch,
38 kPeak,
39 kBell,
40 kLowPassShelf,
41 kHighPassShelf,
42 kNumModes
43 };
44
45 SVF(EMode mode = kLowPass, double freqCPS = 1000.)
46 {
47 mNewState.mode = mState.mode = mode;
48 mNewState.freq = mState.freq = freqCPS;
49 UpdateCoefficients();
50 }
51
52 static double PlotResponse(double freqCPS, double Q, EMode mode, double x, double gain = 0., double minHz = 1., double maxHz = 20000)
53 {
54 using cdouble = std::complex<double>;
55
56 const double g = freqCPS;
57 const double k = 1.0 / Q;
58// const double A = std::pow(10., gain / 40.);
59
60 static double minLogHz = std::log10(minHz);
61 static double maxLogHz = std::log10(maxHz);
62 static const cdouble _1j = std::sqrt(cdouble(-1, 0));
63
64 const double w = std::pow(10., (x * (maxLogHz - minLogHz)) + minHz);
65 const cdouble s = _1j * w;
66 cdouble result;
67
68 switch (mode)
69 {
70 case kLowPass: result = g * g / (g * g + g * k * s + s * s); break;
71 case kBandPass: result = g * s / (g * g + g * k * s + s * s); break;
72 case kHighPass: result = s * s / (g * g + g * k * s + s * s); break;
73 // case kNotch: result = (g * g) + (s * s) / (g * g + g * k * s + s * s); break;
74 case kPeak: result = (g - s) * (g + s) / (g * g + g * k * s + s * s); break;
75 // case kBell: result = A * (1. + A * k * s + (s * s)) / A + k * s + A * (s * s); break;
76 // case kLowPassShelf: result = A * (A + std::sqrt(A) * k * s + (s * s)) / 1. + std::sqrt(A) * k * s + A * (s * s); break;
77 // case kHighPassShelf: result = A * (1. + std::sqrt(A) * k * s + A * (s * s)) / A + std::sqrt(A) * k * s + (s * s); break;
78 default: return 0.;
79 }
80
81 const double magnitude = 20. * std::log10(std::abs(std::real(result)));
82
83 //DBGMSG("%f\n", magnitude);
84
85 return magnitude;
86 }
87
88 void SetFreqCPS(double freqCPS) { mNewState.freq = Clip(freqCPS, 10.0, 20000.); }
89
90 void SetQ(double Q) { mNewState.Q = Clip(Q, 0.1, 100.0); }
91
92 void SetGain(double gainDB) { mNewState.gain = Clip(gainDB, -36.0, 36.0); }
93
94 void SetMode(EMode mode) { mNewState.mode = mode; }
95
96 void SetSampleRate(double sampleRate) { mNewState.sampleRate = sampleRate; }
97
98 void ProcessBlock(T** inputs, T** outputs, int nChans, int nFrames)
99 {
100 assert(nChans <= NC);
101
102 if(mState != mNewState)
103 UpdateCoefficients();
104
105 for (auto c = 0; c < nChans; c++)
106 {
107 for (auto s = 0; s < nFrames; s++)
108 {
109 const double v0 = static_cast<double>(inputs[c][s]);
110
111 mV3[c] = v0 - mIc2eq[c];
112 mV1[c] = m_a1 * mIc1eq[c] + m_a2*mV3[c];
113 mV2[c] = mIc2eq[c] + m_a2 * mIc1eq[c] + m_a3 * mV3[c];
114 mIc1eq[c] = 2.0 * mV1[c] - mIc1eq[c];
115 mIc2eq[c] = 2.0 * mV2[c] - mIc2eq[c];
116
117 outputs[c][s] = static_cast<T>(m_m0) * static_cast<T>(v0) +
118 static_cast<T>(m_m1) * static_cast<T>(mV1[c]) +
119 static_cast<T>(m_m2) * static_cast<T>(mV2[c]);
120 }
121 }
122 }
123
124 void Reset()
125 {
126 for (auto c = 0; c < NC; c++)
127 {
128 mV1[c] = 0.;
129 mV2[c] = 0.;
130 mV3[c] = 0.;
131 mIc1eq[c] = 0.;
132 mIc2eq[c] = 0.;
133 }
134 }
135
136private:
137 void UpdateCoefficients()
138 {
139 mState = mNewState;
140
141 const double w = std::tan(PI * mState.freq/mState.sampleRate);
142
143 switch(mState.mode)
144 {
145 case kLowPass:
146 {
147 const double g = w;
148 const double k = 1. / mState.Q;
149 m_a1 = 1./(1. + g * (g + k));
150 m_a2 = g * m_a1;
151 m_a3 = g * m_a2;
152 m_m0 = 0;
153 m_m1 = 0;
154 m_m2 = 1.;
155 break;
156 }
157 case kHighPass:
158 {
159 const double g = w;
160 const double k = 1. / mState.Q;
161 m_a1 = 1./(1. + g * (g + k));
162 m_a2 = g * m_a1;
163 m_a3 = g * m_a2;
164 m_m0 = 1.;
165 m_m1 = -k;
166 m_m2 = -1.;
167 break;
168 }
169 case kBandPass:
170 {
171 const double g = w;
172 const double k = 1. / mState.Q;
173 m_a1 = 1./(1. + g * (g + k));
174 m_a2 = g * m_a1;
175 m_a3 = g * m_a2;
176 m_m0 = 0.;
177 m_m1 = 1.;
178 m_m2 = 0.;
179 break;
180 }
181 case kNotch:
182 {
183 const double g = w;
184 const double k = 1. / mState.Q;
185 m_a1 = 1./(1. + g * (g + k));
186 m_a2 = g * m_a1;
187 m_a3 = g * m_a2;
188 m_m0 = 1.;
189 m_m1 = -k;
190 m_m2 = 0.;
191 break;
192 }
193 case kPeak:
194 {
195 const double g = w;
196 const double k = 1. / mState.Q;
197 m_a1 = 1./(1. + g * (g + k));
198 m_a2 = g * m_a1;
199 m_a3 = g * m_a2;
200 m_m0 = 1.;
201 m_m1 = -k;
202 m_m2 = -2.;
203 break;
204 }
205 case kBell:
206 {
207 const double A = std::pow(10., mState.gain/40.);
208 const double g = w;
209 const double k = 1 / mState.Q;
210 m_a1 = 1./(1. + g * (g + k));
211 m_a2 = g * m_a1;
212 m_a3 = g * m_a2;
213 m_m0 = 1.;
214 m_m1 = k * (A * A - 1.);
215 m_m2 = 0.;
216 break;
217 }
218 case kLowPassShelf:
219 {
220 const double A = std::pow(10., mState.gain/40.);
221 const double g = w / std::sqrt(A);
222 const double k = 1. / mState.Q;
223 m_a1 = 1./(1. + g * (g + k));
224 m_a2 = g * m_a1;
225 m_a3 = g * m_a2;
226 m_m0 = 1.;
227 m_m1 = k * (A - 1.);
228 m_m2 = (A * A - 1.);
229 break;
230 }
231 case kHighPassShelf:
232 {
233 const double A = std::pow(10., mState.gain/40.);
234 const double g = w / std::sqrt(A);
235 const double k = 1. / mState.Q;
236 m_a1 = 1./(1. + g * (g + k));
237 m_a2 = g * m_a1;
238 m_a3 = g * m_a2;
239 m_m0 = A*A;
240 m_m1 = k*(1. - A)*A;
241 m_m2 = (1. - A*A);
242 break;
243 }
244 default:
245 break;
246 }
247 }
248
249private:
250 double mV1[NC] = {};
251 double mV2[NC] = {};
252 double mV3[NC] = {};
253 double mIc1eq[NC] = {};
254 double mIc2eq[NC] = {};
255 double m_a1 = 0.;
256 double m_a2 = 0.;
257 double m_a3 = 0.;
258 double m_m0 = 0.;
259 double m_m1 = 0.;
260 double m_m2 = 0.;
261
262 struct Settings
263 {
264 EMode mode;
265 double freq = 1000.;
266 double Q = 0.1;
267 double gain = 1.;
268 double sampleRate = 44100.;
269
270 bool operator != (const Settings &other) const
271 {
272 return !(mode == other.mode && freq == other.freq && Q == other.Q && gain == other.gain && sampleRate == other.sampleRate);
273 }
274 } WDL_FIXALIGN;
275
276 Settings mState, mNewState;
277} WDL_FIXALIGN;
278
279END_IPLUG_NAMESPACE
Include to get consistently named preprocessor macros for different platforms and logging functionali...
Definition: SVF.h:29
BEGIN_IPLUG_NAMESPACE T Clip(T x, T lo, T hi)
Clips the value x between lo and hi.