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 
31 namespace juce
32 {
33 namespace dsp
34 {
35 
36 /**
37  Classes for state variable filter processing.
38 */
39 namespace 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>
195  struct Parameters : public ProcessorState
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.
Commonly used mathematical constants.
This structure is passed into a DSP algorithm's prepare() method, and contains information about vari...
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.