1 /*
2   ==============================================================================
3 
4    This file is part of the JUCE library.
5    Copyright (c) 2020 - Raw Material Software Limited
6 
7    JUCE is an open source library subject to commercial or open-source
8    licensing.
9 
10    The code included in this file is provided under the terms of the ISC license
11    http://www.isc.org/downloads/software-support-policy/isc-license. Permission
12    To use, copy, modify, and/or distribute this software for any purpose with or
13    without fee is hereby granted provided that the above copyright notice and
14    this permission notice appear in all copies.
15 
16    JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
17    EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
18    DISCLAIMED.
19 
20   ==============================================================================
21 */
22 
23 namespace juce
24 {
25 
IIRCoefficients()26 IIRCoefficients::IIRCoefficients() noexcept
27 {
28     zeromem (coefficients, sizeof (coefficients));
29 }
30 
~IIRCoefficients()31 IIRCoefficients::~IIRCoefficients() noexcept {}
32 
IIRCoefficients(const IIRCoefficients & other)33 IIRCoefficients::IIRCoefficients (const IIRCoefficients& other) noexcept
34 {
35     memcpy (coefficients, other.coefficients, sizeof (coefficients));
36 }
37 
operator =(const IIRCoefficients & other)38 IIRCoefficients& IIRCoefficients::operator= (const IIRCoefficients& other) noexcept
39 {
40     memcpy (coefficients, other.coefficients, sizeof (coefficients));
41     return *this;
42 }
43 
IIRCoefficients(double c1,double c2,double c3,double c4,double c5,double c6)44 IIRCoefficients::IIRCoefficients (double c1, double c2, double c3,
45                                   double c4, double c5, double c6) noexcept
46 {
47     auto a = 1.0 / c4;
48 
49     coefficients[0] = (float) (c1 * a);
50     coefficients[1] = (float) (c2 * a);
51     coefficients[2] = (float) (c3 * a);
52     coefficients[3] = (float) (c5 * a);
53     coefficients[4] = (float) (c6 * a);
54 }
55 
makeLowPass(double sampleRate,double frequency)56 IIRCoefficients IIRCoefficients::makeLowPass (double sampleRate,
57                                               double frequency) noexcept
58 {
59     return makeLowPass (sampleRate, frequency, 1.0 / MathConstants<double>::sqrt2);
60 }
61 
makeLowPass(double sampleRate,double frequency,double Q)62 IIRCoefficients IIRCoefficients::makeLowPass (double sampleRate,
63                                               double frequency,
64                                               double Q) noexcept
65 {
66     jassert (sampleRate > 0.0);
67     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
68     jassert (Q > 0.0);
69 
70     auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
71     auto nSquared = n * n;
72     auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
73 
74     return IIRCoefficients (c1,
75                             c1 * 2.0,
76                             c1,
77                             1.0,
78                             c1 * 2.0 * (1.0 - nSquared),
79                             c1 * (1.0 - 1.0 / Q * n + nSquared));
80 }
81 
makeHighPass(double sampleRate,double frequency)82 IIRCoefficients IIRCoefficients::makeHighPass (double sampleRate,
83                                                double frequency) noexcept
84 {
85     return makeHighPass (sampleRate, frequency, 1.0 / std::sqrt(2.0));
86 }
87 
makeHighPass(double sampleRate,double frequency,double Q)88 IIRCoefficients IIRCoefficients::makeHighPass (double sampleRate,
89                                                double frequency,
90                                                double Q) noexcept
91 {
92     jassert (sampleRate > 0.0);
93     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
94     jassert (Q > 0.0);
95 
96     auto n = std::tan (MathConstants<double>::pi * frequency / sampleRate);
97     auto nSquared = n * n;
98     auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
99 
100     return IIRCoefficients (c1,
101                             c1 * -2.0,
102                             c1,
103                             1.0,
104                             c1 * 2.0 * (nSquared - 1.0),
105                             c1 * (1.0 - 1.0 / Q * n + nSquared));
106 }
107 
makeBandPass(double sampleRate,double frequency)108 IIRCoefficients IIRCoefficients::makeBandPass (double sampleRate,
109                                                double frequency) noexcept
110 {
111     return makeBandPass (sampleRate, frequency, 1.0 / MathConstants<double>::sqrt2);
112 }
113 
makeBandPass(double sampleRate,double frequency,double Q)114 IIRCoefficients IIRCoefficients::makeBandPass (double sampleRate,
115                                                double frequency,
116                                                double Q) noexcept
117 {
118     jassert (sampleRate > 0.0);
119     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
120     jassert (Q > 0.0);
121 
122     auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
123     auto nSquared = n * n;
124     auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
125 
126     return IIRCoefficients (c1 * n / Q,
127                             0.0,
128                             -c1 * n / Q,
129                             1.0,
130                             c1 * 2.0 * (1.0 - nSquared),
131                             c1 * (1.0 - 1.0 / Q * n + nSquared));
132 }
133 
makeNotchFilter(double sampleRate,double frequency)134 IIRCoefficients IIRCoefficients::makeNotchFilter (double sampleRate,
135                                                   double frequency) noexcept
136 {
137     return makeNotchFilter (sampleRate, frequency, 1.0 / MathConstants<double>::sqrt2);
138 }
139 
makeNotchFilter(double sampleRate,double frequency,double Q)140 IIRCoefficients IIRCoefficients::makeNotchFilter (double sampleRate,
141                                                   double frequency,
142                                                   double Q) noexcept
143 {
144     jassert (sampleRate > 0.0);
145     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
146     jassert (Q > 0.0);
147 
148     auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
149     auto nSquared = n * n;
150     auto c1 = 1.0 / (1.0 + n / Q + nSquared);
151 
152     return IIRCoefficients (c1 * (1.0 + nSquared),
153                             2.0 * c1 * (1.0 - nSquared),
154                             c1 * (1.0 + nSquared),
155                             1.0,
156                             c1 * 2.0 * (1.0 - nSquared),
157                             c1 * (1.0 - n / Q + nSquared));
158 }
159 
makeAllPass(double sampleRate,double frequency)160 IIRCoefficients IIRCoefficients::makeAllPass (double sampleRate,
161                                               double frequency) noexcept
162 {
163     return makeAllPass (sampleRate, frequency, 1.0 / MathConstants<double>::sqrt2);
164 }
165 
makeAllPass(double sampleRate,double frequency,double Q)166 IIRCoefficients IIRCoefficients::makeAllPass (double sampleRate,
167                                               double frequency,
168                                               double Q) noexcept
169 {
170     jassert (sampleRate > 0.0);
171     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
172     jassert (Q > 0.0);
173 
174     auto n = 1.0 / std::tan (MathConstants<double>::pi * frequency / sampleRate);
175     auto nSquared = n * n;
176     auto c1 = 1.0 / (1.0 + 1.0 / Q * n + nSquared);
177 
178     return IIRCoefficients (c1 * (1.0 - n / Q + nSquared),
179                             c1 * 2.0 * (1.0 - nSquared),
180                             1.0,
181                             1.0,
182                             c1 * 2.0 * (1.0 - nSquared),
183                             c1 * (1.0 - n / Q + nSquared));
184 }
185 
makeLowShelf(double sampleRate,double cutOffFrequency,double Q,float gainFactor)186 IIRCoefficients IIRCoefficients::makeLowShelf (double sampleRate,
187                                                double cutOffFrequency,
188                                                double Q,
189                                                float gainFactor) noexcept
190 {
191     jassert (sampleRate > 0.0);
192     jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5);
193     jassert (Q > 0.0);
194 
195     auto A = jmax (0.0f, std::sqrt (gainFactor));
196     auto aminus1 = A - 1.0;
197     auto aplus1 = A + 1.0;
198     auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
199     auto coso = std::cos (omega);
200     auto beta = std::sin (omega) * std::sqrt (A) / Q;
201     auto aminus1TimesCoso = aminus1 * coso;
202 
203     return IIRCoefficients (A * (aplus1 - aminus1TimesCoso + beta),
204                             A * 2.0 * (aminus1 - aplus1 * coso),
205                             A * (aplus1 - aminus1TimesCoso - beta),
206                             aplus1 + aminus1TimesCoso + beta,
207                             -2.0 * (aminus1 + aplus1 * coso),
208                             aplus1 + aminus1TimesCoso - beta);
209 }
210 
makeHighShelf(double sampleRate,double cutOffFrequency,double Q,float gainFactor)211 IIRCoefficients IIRCoefficients::makeHighShelf (double sampleRate,
212                                                 double cutOffFrequency,
213                                                 double Q,
214                                                 float gainFactor) noexcept
215 {
216     jassert (sampleRate > 0.0);
217     jassert (cutOffFrequency > 0.0 && cutOffFrequency <= sampleRate * 0.5);
218     jassert (Q > 0.0);
219 
220     auto A = jmax (0.0f, std::sqrt (gainFactor));
221     auto aminus1 = A - 1.0;
222     auto aplus1 = A + 1.0;
223     auto omega = (MathConstants<double>::twoPi * jmax (cutOffFrequency, 2.0)) / sampleRate;
224     auto coso = std::cos (omega);
225     auto beta = std::sin (omega) * std::sqrt (A) / Q;
226     auto aminus1TimesCoso = aminus1 * coso;
227 
228     return IIRCoefficients (A * (aplus1 + aminus1TimesCoso + beta),
229                             A * -2.0 * (aminus1 + aplus1 * coso),
230                             A * (aplus1 + aminus1TimesCoso - beta),
231                             aplus1 - aminus1TimesCoso + beta,
232                             2.0 * (aminus1 - aplus1 * coso),
233                             aplus1 - aminus1TimesCoso - beta);
234 }
235 
makePeakFilter(double sampleRate,double frequency,double Q,float gainFactor)236 IIRCoefficients IIRCoefficients::makePeakFilter (double sampleRate,
237                                                  double frequency,
238                                                  double Q,
239                                                  float gainFactor) noexcept
240 {
241     jassert (sampleRate > 0.0);
242     jassert (frequency > 0.0 && frequency <= sampleRate * 0.5);
243     jassert (Q > 0.0);
244 
245     auto A = jmax (0.0f, std::sqrt (gainFactor));
246     auto omega = (MathConstants<double>::twoPi * jmax (frequency, 2.0)) / sampleRate;
247     auto alpha = 0.5 * std::sin (omega) / Q;
248     auto c2 = -2.0 * std::cos (omega);
249     auto alphaTimesA = alpha * A;
250     auto alphaOverA = alpha / A;
251 
252     return IIRCoefficients (1.0 + alphaTimesA,
253                             c2,
254                             1.0 - alphaTimesA,
255                             1.0 + alphaOverA,
256                             c2,
257                             1.0 - alphaOverA);
258 }
259 
260 //==============================================================================
IIRFilter()261 IIRFilter::IIRFilter() noexcept
262 {
263 }
264 
IIRFilter(const IIRFilter & other)265 IIRFilter::IIRFilter (const IIRFilter& other) noexcept  : active (other.active)
266 {
267     const SpinLock::ScopedLockType sl (other.processLock);
268     coefficients = other.coefficients;
269 }
270 
~IIRFilter()271 IIRFilter::~IIRFilter() noexcept
272 {
273 }
274 
275 //==============================================================================
makeInactive()276 void IIRFilter::makeInactive() noexcept
277 {
278     const SpinLock::ScopedLockType sl (processLock);
279     active = false;
280 }
281 
setCoefficients(const IIRCoefficients & newCoefficients)282 void IIRFilter::setCoefficients (const IIRCoefficients& newCoefficients) noexcept
283 {
284     const SpinLock::ScopedLockType sl (processLock);
285     coefficients = newCoefficients;
286     active = true;
287 }
288 
289 //==============================================================================
reset()290 void IIRFilter::reset() noexcept
291 {
292     const SpinLock::ScopedLockType sl (processLock);
293     v1 = v2 = 0.0;
294 }
295 
processSingleSampleRaw(float in)296 float IIRFilter::processSingleSampleRaw (float in) noexcept
297 {
298     auto out = coefficients.coefficients[0] * in + v1;
299 
300     JUCE_SNAP_TO_ZERO (out);
301 
302     v1 = coefficients.coefficients[1] * in - coefficients.coefficients[3] * out + v2;
303     v2 = coefficients.coefficients[2] * in - coefficients.coefficients[4] * out;
304 
305     return out;
306 }
307 
processSamples(float * const samples,const int numSamples)308 void IIRFilter::processSamples (float* const samples, const int numSamples) noexcept
309 {
310     const SpinLock::ScopedLockType sl (processLock);
311 
312     if (active)
313     {
314         auto c0 = coefficients.coefficients[0];
315         auto c1 = coefficients.coefficients[1];
316         auto c2 = coefficients.coefficients[2];
317         auto c3 = coefficients.coefficients[3];
318         auto c4 = coefficients.coefficients[4];
319         auto lv1 = v1, lv2 = v2;
320 
321         for (int i = 0; i < numSamples; ++i)
322         {
323             auto in = samples[i];
324             auto out = c0 * in + lv1;
325             samples[i] = out;
326 
327             lv1 = c1 * in - c3 * out + lv2;
328             lv2 = c2 * in - c4 * out;
329         }
330 
331         JUCE_SNAP_TO_ZERO (lv1);  v1 = lv1;
332         JUCE_SNAP_TO_ZERO (lv2);  v2 = lv2;
333     }
334 }
335 
336 } // namespace juce
337