OpenShot Library | OpenShotAudio 0.2.2
juce_StateVariableFilter.h
1
2/** @weakgroup juce_dsp-processors
3 * @{
4 */
5/*
6 ==============================================================================
7
8 This file is part of the JUCE library.
9 Copyright (c) 2017 - ROLI Ltd.
10
11 JUCE is an open source library subject to commercial or open-source
12 licensing.
13
14 By using JUCE, you agree to the terms of both the JUCE 5 End-User License
15 Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
16 27th April 2017).
17
18 End User License Agreement: www.juce.com/juce-5-licence
19 Privacy Policy: www.juce.com/juce-5-privacy-policy
20
21 Or: You may also use this code under the terms of the GPL v3 (see
22 www.gnu.org/licenses).
23
24 JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
25 EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
26 DISCLAIMED.
27
28 ==============================================================================
29*/
30
31namespace juce
32{
33namespace dsp
34{
35
36/**
37 Classes for state variable filter processing.
38*/
39namespace StateVariableFilter
40{
41 template <typename NumericType>
42 struct Parameters;
43
44 /**
45 An IIR filter that can perform low, band and high-pass filtering on an audio
46 signal, with 12 dB of attenuation / octave, using a TPT structure, designed
47 for fast modulation (see Vadim Zavalishin's documentation about TPT
48 structures for more information). Its behaviour is based on the analog
49 state variable filter circuit.
50
51 Note: The bandpass here is not the one in the RBJ CookBook, its gain can be
52 higher than 0 dB. For the classic 0 dB bandpass, we need to multiply the
53 result with R2
54
55 @tags{DSP}
56 */
57 template <typename SampleType>
58 class Filter
59 {
60 public:
61 //==============================================================================
62 /** The NumericType is the underlying primitive type used by the SampleType (which
63 could be either a primitive or vector)
64 */
65 using NumericType = typename SampleTypeHelpers::ElementType<SampleType>::Type;
66
67 /** A typedef for a ref-counted pointer to the coefficients object */
69
70 //==============================================================================
71 /** Creates a filter with default parameters. */
73
74 Filter (ParametersPtr parametersToUse) : parameters (std::move (parametersToUse)) { reset(); }
75
76 /** Creates a copy of another filter. */
77 Filter (const Filter&) = default;
78
79 /** Move constructor */
80 Filter (Filter&&) = default;
81
82 //==============================================================================
83 /** Initialization of the filter */
84 void prepare (const ProcessSpec&) noexcept { reset(); }
85
86 /** Resets the filter's processing pipeline. */
87 void reset() noexcept { s1 = s2 = SampleType {0}; }
88
89 /** Ensure that the state variables are rounded to zero if the state
90 variables are denormals. This is only needed if you are doing
91 sample by sample processing.
92 */
93 void snapToZero() noexcept { util::snapToZero (s1); util::snapToZero (s2); }
94
95 //==============================================================================
96 /** The parameters of the state variable filter. It's up to the caller to ensure
97 that these parameters are modified in a thread-safe way. */
99
100 //==============================================================================
101 template <typename ProcessContext>
102 void process (const ProcessContext& context) noexcept
103 {
104 static_assert (std::is_same<typename ProcessContext::SampleType, SampleType>::value,
105 "The sample-type of the filter must match the sample-type supplied to this process callback");
106
107 if (context.isBypassed)
108 processInternal<true, ProcessContext> (context);
109 else
110 processInternal<false, ProcessContext> (context);
111 }
112
113 /** Processes a single sample, without any locking or checking.
114 Use this if you need processing of a single value. */
115 SampleType JUCE_VECTOR_CALLTYPE processSample (SampleType sample) noexcept
116 {
117 switch (parameters->type)
118 {
119 case Parameters<NumericType>::Type::lowPass: return processLoop<false, Parameters<NumericType>::Type::lowPass> (sample, *parameters); break;
120 case Parameters<NumericType>::Type::bandPass: return processLoop<false, Parameters<NumericType>::Type::bandPass> (sample, *parameters); break;
121 case Parameters<NumericType>::Type::highPass: return processLoop<false, Parameters<NumericType>::Type::highPass> (sample, *parameters); break;
122 default: jassertfalse;
123 }
124
125 return SampleType{0};
126 }
127
128 private:
129 //==============================================================================
130 template <bool isBypassed, typename Parameters<NumericType>::Type type>
131 SampleType JUCE_VECTOR_CALLTYPE processLoop (SampleType sample, Parameters<NumericType>& state) noexcept
132 {
133 y[2] = (sample - s1 * state.R2 - s1 * state.g - s2) * state.h;
134
135 y[1] = y[2] * state.g + s1;
136 s1 = y[2] * state.g + y[1];
137
138 y[0] = y[1] * state.g + s2;
139 s2 = y[1] * state.g + y[0];
140
141 return isBypassed ? sample : y[static_cast<size_t> (type)];
142 }
143
144 template <bool isBypassed, typename Parameters<NumericType>::Type type>
145 void processBlock (const SampleType* input, SampleType* output, size_t n) noexcept
146 {
147 auto state = *parameters;
148
149 for (size_t i = 0 ; i < n; ++i)
150 output[i] = processLoop<isBypassed, type> (input[i], state);
151
152 snapToZero();
153 *parameters = state;
154 }
155
156 template <bool isBypassed, typename ProcessContext>
157 void processInternal (const ProcessContext& context) noexcept
158 {
159 auto&& inputBlock = context.getInputBlock();
160 auto&& outputBlock = context.getOutputBlock();
161
162 // This class can only process mono signals. Use the ProcessorDuplicator class
163 // to apply this filter on a multi-channel audio stream.
164 jassert (inputBlock.getNumChannels() == 1);
165 jassert (outputBlock.getNumChannels() == 1);
166
167 auto n = inputBlock.getNumSamples();
168 auto* src = inputBlock .getChannelPointer (0);
169 auto* dst = outputBlock.getChannelPointer (0);
170
171 switch (parameters->type)
172 {
173 case Parameters<NumericType>::Type::lowPass: processBlock<isBypassed, Parameters<NumericType>::Type::lowPass> (src, dst, n); break;
174 case Parameters<NumericType>::Type::bandPass: processBlock<isBypassed, Parameters<NumericType>::Type::bandPass> (src, dst, n); break;
175 case Parameters<NumericType>::Type::highPass: processBlock<isBypassed, Parameters<NumericType>::Type::highPass> (src, dst, n); break;
176 default: jassertfalse;
177 }
178 }
179
180 //==============================================================================
181 std::array<SampleType, 3> y;
182 SampleType s1, s2;
183
184 //==============================================================================
185 JUCE_LEAK_DETECTOR (Filter)
186 };
187
188 //==============================================================================
189 /**
190 Structure used for the state variable filter parameters.
191
192 @tags{DSP}
193 */
194 template <typename NumericType>
196 {
197 //==============================================================================
198 enum class Type
199 {
200 lowPass,
201 bandPass,
202 highPass
203 };
204
205 //==============================================================================
206 /** The type of the IIR filter */
207 Type type = Type::lowPass;
208
209 /** Sets the cutoff frequency and resonance of the IIR filter.
210
211 Note: The bandwidth of the resonance increases with the value of the
212 parameter. To have a standard 12 dB/octave filter, the value must be set
213 at 1 / sqrt(2).
214 */
215 void setCutOffFrequency (double sampleRate, NumericType frequency,
216 NumericType resonance = static_cast<NumericType> (1.0 / MathConstants<double>::sqrt2)) noexcept
217 {
218 jassert (sampleRate > 0);
219 jassert (resonance > NumericType (0));
220 jassert (frequency > NumericType (0) && frequency <= NumericType (sampleRate * 0.5));
221
222 g = static_cast<NumericType> (std::tan (MathConstants<double>::pi * frequency / sampleRate));
223 R2 = static_cast<NumericType> (1.0 / resonance);
224 h = static_cast<NumericType> (1.0 / (1.0 + R2 * g + g * g));
225 }
226
227 //==============================================================================
228 /** The Coefficients structure is ref-counted, so this is a handy type that can be used
229 as a pointer to one.
230 */
232
233 //==============================================================================
234 Parameters() = default;
235 Parameters (const Parameters& o) : g (o.g), R2 (o.R2), h (o.h) {}
236 Parameters& operator= (const Parameters& o) noexcept { g = o.g; R2 = o.R2; h = o.h; return *this; }
237
238 //==============================================================================
239 NumericType g = static_cast<NumericType> (std::tan (MathConstants<double>::pi * 200.0 / 44100.0));
240 NumericType R2 = static_cast<NumericType> (MathConstants<double>::sqrt2);
241 NumericType h = static_cast<NumericType> (1.0 / (1.0 + R2 * g + g * g));
242 };
243}
244
245} // namespace dsp
246} // namespace juce
247
248/** @}*/
A smart-pointer class which points to a reference-counted object.
An IIR filter that can perform low, band and high-pass filtering on an audio signal,...
Filter()
Creates a filter with default parameters.
Parameters< NumericType >::Ptr parameters
The parameters of the state variable filter.
typename Parameters< NumericType >::Ptr ParametersPtr
A typedef for a ref-counted pointer to the coefficients object.
void prepare(const ProcessSpec &) noexcept
Initialization of the filter.
void reset() noexcept
Resets the filter's processing pipeline.
SampleType JUCE_VECTOR_CALLTYPE processSample(SampleType sample) noexcept
Processes a single sample, without any locking or checking.
Filter(const Filter &)=default
Creates a copy of another filter.
void snapToZero() noexcept
Ensure that the state variables are rounded to zero if the state variables are denormals.
typename SampleTypeHelpers::ElementType< SampleType >::Type NumericType
The NumericType is the underlying primitive type used by the SampleType (which could be either a prim...
Filter(Filter &&)=default
Move constructor.
This structure is passed into a DSP algorithm's prepare() method, and contains information about vari...
Commonly used mathematical constants.
This is a handy base class for the state of a processor (such as parameter values) which is typically...
Structure used for the state variable filter parameters.
void setCutOffFrequency(double sampleRate, NumericType frequency, NumericType resonance=static_cast< NumericType >(1.0/MathConstants< double >::sqrt2)) noexcept
Sets the cutoff frequency and resonance of the IIR filter.