OpenShot Library | OpenShotAudio  0.2.1
juce_Oversampling.cpp
1 /*
2  ==============================================================================
3 
4  This file is part of the JUCE library.
5  Copyright (c) 2017 - ROLI Ltd.
6 
7  JUCE is an open source library subject to commercial or open-source
8  licensing.
9 
10  By using JUCE, you agree to the terms of both the JUCE 5 End-User License
11  Agreement and JUCE 5 Privacy Policy (both updated and effective as of the
12  27th April 2017).
13 
14  End User License Agreement: www.juce.com/juce-5-licence
15  Privacy Policy: www.juce.com/juce-5-privacy-policy
16 
17  Or: You may also use this code under the terms of the GPL v3 (see
18  www.gnu.org/licenses).
19 
20  JUCE IS PROVIDED "AS IS" WITHOUT ANY WARRANTY, AND ALL WARRANTIES, WHETHER
21  EXPRESSED OR IMPLIED, INCLUDING MERCHANTABILITY AND FITNESS FOR PURPOSE, ARE
22  DISCLAIMED.
23 
24  ==============================================================================
25 */
26 
27 namespace juce
28 {
29 namespace dsp
30 {
31 
32 /** Abstract class for the provided oversampling stages used internally in
33  the Oversampling class.
34 */
35 template <typename SampleType>
36 struct Oversampling<SampleType>::OversamplingStage
37 {
38  OversamplingStage (size_t numChans, size_t newFactor) : numChannels (numChans), factor (newFactor) {}
39  virtual ~OversamplingStage() {}
40 
41  //==============================================================================
42  virtual SampleType getLatencyInSamples() = 0;
43 
44  virtual void initProcessing (size_t maximumNumberOfSamplesBeforeOversampling)
45  {
46  buffer.setSize (static_cast<int> (numChannels),
47  static_cast<int> (maximumNumberOfSamplesBeforeOversampling * factor),
48  false, false, true);
49  }
50 
51  virtual void reset()
52  {
53  buffer.clear();
54  }
55 
56  AudioBlock<SampleType> getProcessedSamples (size_t numSamples)
57  {
58  return AudioBlock<SampleType> (buffer).getSubBlock (0, numSamples);
59  }
60 
61  virtual void processSamplesUp (const AudioBlock<const SampleType>&) = 0;
62  virtual void processSamplesDown (AudioBlock<SampleType>&) = 0;
63 
65  size_t numChannels, factor;
66 };
67 
68 
69 //==============================================================================
70 /** Dummy oversampling stage class which simply copies and pastes the input
71  signal, which could be equivalent to a "one time" oversampling processing.
72 */
73 template <typename SampleType>
74 struct OversamplingDummy : public Oversampling<SampleType>::OversamplingStage
75 {
76  using ParentType = typename Oversampling<SampleType>::OversamplingStage;
77 
78  OversamplingDummy (size_t numChans) : ParentType (numChans, 1) {}
79 
80  //==============================================================================
81  SampleType getLatencyInSamples() override
82  {
83  return 0;
84  }
85 
86  void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
87  {
88  jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
89  jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
90 
91  for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
92  ParentType::buffer.copyFrom (static_cast<int> (channel), 0,
93  inputBlock.getChannelPointer (channel), static_cast<int> (inputBlock.getNumSamples()));
94  }
95 
96  void processSamplesDown (AudioBlock<SampleType>& outputBlock) override
97  {
98  jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
99  jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
100 
101  outputBlock.copyFrom (ParentType::getProcessedSamples (outputBlock.getNumSamples()));
102  }
103 
104  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (OversamplingDummy)
105 };
106 
107 //==============================================================================
108 /** Oversampling stage class performing 2 times oversampling using the Filter
109  Design FIR Equiripple method. The resulting filter is linear phase,
110  symmetric, and has every two samples but the middle one equal to zero,
111  leading to specific processing optimizations.
112 */
113 template <typename SampleType>
114 struct Oversampling2TimesEquirippleFIR : public Oversampling<SampleType>::OversamplingStage
115 {
116  using ParentType = typename Oversampling<SampleType>::OversamplingStage;
117 
118  Oversampling2TimesEquirippleFIR (size_t numChans,
119  SampleType normalisedTransitionWidthUp,
120  SampleType stopbandAmplitudedBUp,
121  SampleType normalisedTransitionWidthDown,
122  SampleType stopbandAmplitudedBDown)
123  : ParentType (numChans, 2)
124  {
125  coefficientsUp = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);
126  coefficientsDown = *FilterDesign<SampleType>::designFIRLowpassHalfBandEquirippleMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);
127 
128  auto N = coefficientsUp.getFilterOrder() + 1;
129  stateUp.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
130 
131  N = coefficientsDown.getFilterOrder() + 1;
132  auto Ndiv2 = N / 2;
133  auto Ndiv4 = Ndiv2 / 2;
134 
135  stateDown.setSize (static_cast<int> (this->numChannels), static_cast<int> (N));
136  stateDown2.setSize (static_cast<int> (this->numChannels), static_cast<int> (Ndiv4 + 1));
137 
138  position.resize (static_cast<int> (this->numChannels));
139  }
140 
141  //==============================================================================
142  SampleType getLatencyInSamples() override
143  {
144  return static_cast<SampleType> (coefficientsUp.getFilterOrder() + coefficientsDown.getFilterOrder()) * 0.5f;
145  }
146 
147  void reset() override
148  {
149  ParentType::reset();
150 
151  stateUp.clear();
152  stateDown.clear();
153  stateDown2.clear();
154 
155  position.fill (0);
156  }
157 
158  void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
159  {
160  jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
161  jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
162 
163  // Initialization
164  auto fir = coefficientsUp.getRawCoefficients();
165  auto N = coefficientsUp.getFilterOrder() + 1;
166  auto Ndiv2 = N / 2;
167  auto numSamples = inputBlock.getNumSamples();
168 
169  // Processing
170  for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
171  {
172  auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
173  auto buf = stateUp.getWritePointer (static_cast<int> (channel));
174  auto samples = inputBlock.getChannelPointer (channel);
175 
176  for (size_t i = 0; i < numSamples; ++i)
177  {
178  // Input
179  buf[N - 1] = 2 * samples[i];
180 
181  // Convolution
182  auto out = static_cast<SampleType> (0.0);
183 
184  for (size_t k = 0; k < Ndiv2; k += 2)
185  out += (buf[k] + buf[N - k - 1]) * fir[k];
186 
187  // Outputs
188  bufferSamples[i << 1] = out;
189  bufferSamples[(i << 1) + 1] = buf[Ndiv2 + 1] * fir[Ndiv2];
190 
191  // Shift data
192  for (size_t k = 0; k < N - 2; k += 2)
193  buf[k] = buf[k + 2];
194  }
195  }
196  }
197 
198  void processSamplesDown (AudioBlock<SampleType>& outputBlock) override
199  {
200  jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
201  jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
202 
203  // Initialization
204  auto fir = coefficientsDown.getRawCoefficients();
205  auto N = coefficientsDown.getFilterOrder() + 1;
206  auto Ndiv2 = N / 2;
207  auto Ndiv4 = Ndiv2 / 2;
208  auto numSamples = outputBlock.getNumSamples();
209 
210  // Processing
211  for (size_t channel = 0; channel < outputBlock.getNumChannels(); ++channel)
212  {
213  auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
214  auto buf = stateDown.getWritePointer (static_cast<int> (channel));
215  auto buf2 = stateDown2.getWritePointer (static_cast<int> (channel));
216  auto samples = outputBlock.getChannelPointer (channel);
217  auto pos = position.getUnchecked (static_cast<int> (channel));
218 
219  for (size_t i = 0; i < numSamples; ++i)
220  {
221  // Input
222  buf[N - 1] = bufferSamples[i << 1];
223 
224  // Convolution
225  auto out = static_cast<SampleType> (0.0);
226 
227  for (size_t k = 0; k < Ndiv2; k += 2)
228  out += (buf[k] + buf[N - k - 1]) * fir[k];
229 
230  // Output
231  out += buf2[pos] * fir[Ndiv2];
232  buf2[pos] = bufferSamples[(i << 1) + 1];
233 
234  samples[i] = out;
235 
236  // Shift data
237  for (size_t k = 0; k < N - 2; ++k)
238  buf[k] = buf[k + 2];
239 
240  // Circular buffer
241  pos = (pos == 0 ? Ndiv4 : pos - 1);
242  }
243 
244  position.setUnchecked (static_cast<int> (channel), pos);
245  }
246 
247  }
248 
249 private:
250  //==============================================================================
251  FIR::Coefficients<SampleType> coefficientsUp, coefficientsDown;
252  AudioBuffer<SampleType> stateUp, stateDown, stateDown2;
253  Array<size_t> position;
254 
255  //==============================================================================
256  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling2TimesEquirippleFIR)
257 };
258 
259 
260 //==============================================================================
261 /** Oversampling stage class performing 2 times oversampling using the Filter
262  Design IIR Polyphase Allpass Cascaded method. The resulting filter is minimum
263  phase, and provided with a method to get the exact resulting latency.
264 */
265 template <typename SampleType>
266 struct Oversampling2TimesPolyphaseIIR : public Oversampling<SampleType>::OversamplingStage
267 {
268  using ParentType = typename Oversampling<SampleType>::OversamplingStage;
269 
270  Oversampling2TimesPolyphaseIIR (size_t numChans,
271  SampleType normalisedTransitionWidthUp,
272  SampleType stopbandAmplitudedBUp,
273  SampleType normalisedTransitionWidthDown,
274  SampleType stopbandAmplitudedBDown)
275  : ParentType (numChans, 2)
276  {
277  auto structureUp = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthUp, stopbandAmplitudedBUp);
278  auto coeffsUp = getCoefficients (structureUp);
279  latency = static_cast<SampleType> (-(coeffsUp.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));
280 
281  auto structureDown = FilterDesign<SampleType>::designIIRLowpassHalfBandPolyphaseAllpassMethod (normalisedTransitionWidthDown, stopbandAmplitudedBDown);
282  auto coeffsDown = getCoefficients (structureDown);
283  latency += static_cast<SampleType> (-(coeffsDown.getPhaseForFrequency (0.0001, 1.0)) / (0.0001 * MathConstants<double>::twoPi));
284 
285  for (auto i = 0; i < structureUp.directPath.size(); ++i)
286  coefficientsUp.add (structureUp.directPath.getObjectPointer (i)->coefficients[0]);
287 
288  for (auto i = 1; i < structureUp.delayedPath.size(); ++i)
289  coefficientsUp.add (structureUp.delayedPath.getObjectPointer (i)->coefficients[0]);
290 
291  for (auto i = 0; i < structureDown.directPath.size(); ++i)
292  coefficientsDown.add (structureDown.directPath.getObjectPointer (i)->coefficients[0]);
293 
294  for (auto i = 1; i < structureDown.delayedPath.size(); ++i)
295  coefficientsDown.add (structureDown.delayedPath.getObjectPointer (i)->coefficients[0]);
296 
297  v1Up.setSize (static_cast<int> (this->numChannels), coefficientsUp.size());
298  v1Down.setSize (static_cast<int> (this->numChannels), coefficientsDown.size());
299  delayDown.resize (static_cast<int> (this->numChannels));
300  }
301 
302  //==============================================================================
303  SampleType getLatencyInSamples() override
304  {
305  return latency;
306  }
307 
308  void reset() override
309  {
310  ParentType::reset();
311  v1Up.clear();
312  v1Down.clear();
313  delayDown.fill (0);
314  }
315 
316  void processSamplesUp (const AudioBlock<const SampleType>& inputBlock) override
317  {
318  jassert (inputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
319  jassert (inputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
320 
321  // Initialization
322  auto coeffs = coefficientsUp.getRawDataPointer();
323  auto numStages = coefficientsUp.size();
324  auto delayedStages = numStages / 2;
325  auto directStages = numStages - delayedStages;
326  auto numSamples = inputBlock.getNumSamples();
327 
328  // Processing
329  for (size_t channel = 0; channel < inputBlock.getNumChannels(); ++channel)
330  {
331  auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
332  auto lv1 = v1Up.getWritePointer (static_cast<int> (channel));
333  auto samples = inputBlock.getChannelPointer (channel);
334 
335  for (size_t i = 0; i < numSamples; ++i)
336  {
337  // Direct path cascaded allpass filters
338  auto input = samples[i];
339 
340  for (auto n = 0; n < directStages; ++n)
341  {
342  auto alpha = coeffs[n];
343  auto output = alpha * input + lv1[n];
344  lv1[n] = input - alpha * output;
345  input = output;
346  }
347 
348  // Output
349  bufferSamples[i << 1] = input;
350 
351  // Delayed path cascaded allpass filters
352  input = samples[i];
353 
354  for (auto n = directStages; n < numStages; ++n)
355  {
356  auto alpha = coeffs[n];
357  auto output = alpha * input + lv1[n];
358  lv1[n] = input - alpha * output;
359  input = output;
360  }
361 
362  // Output
363  bufferSamples[(i << 1) + 1] = input;
364  }
365  }
366 
367  // Snap To Zero
368  snapToZero (true);
369  }
370 
371  void processSamplesDown (AudioBlock<SampleType>& outputBlock) override
372  {
373  jassert (outputBlock.getNumChannels() <= static_cast<size_t> (ParentType::buffer.getNumChannels()));
374  jassert (outputBlock.getNumSamples() * ParentType::factor <= static_cast<size_t> (ParentType::buffer.getNumSamples()));
375 
376  // Initialization
377  auto coeffs = coefficientsDown.getRawDataPointer();
378  auto numStages = coefficientsDown.size();
379  auto delayedStages = numStages / 2;
380  auto directStages = numStages - delayedStages;
381  auto numSamples = outputBlock.getNumSamples();
382 
383  // Processing
384  for (size_t channel = 0; channel < outputBlock.getNumChannels(); ++channel)
385  {
386  auto bufferSamples = ParentType::buffer.getWritePointer (static_cast<int> (channel));
387  auto lv1 = v1Down.getWritePointer (static_cast<int> (channel));
388  auto samples = outputBlock.getChannelPointer (channel);
389  auto delay = delayDown.getUnchecked (static_cast<int> (channel));
390 
391  for (size_t i = 0; i < numSamples; ++i)
392  {
393  // Direct path cascaded allpass filters
394  auto input = bufferSamples[i << 1];
395 
396  for (auto n = 0; n < directStages; ++n)
397  {
398  auto alpha = coeffs[n];
399  auto output = alpha * input + lv1[n];
400  lv1[n] = input - alpha * output;
401  input = output;
402  }
403 
404  auto directOut = input;
405 
406  // Delayed path cascaded allpass filters
407  input = bufferSamples[(i << 1) + 1];
408 
409  for (auto n = directStages; n < numStages; ++n)
410  {
411  auto alpha = coeffs[n];
412  auto output = alpha * input + lv1[n];
413  lv1[n] = input - alpha * output;
414  input = output;
415  }
416 
417  // Output
418  samples[i] = (delay + directOut) * static_cast<SampleType> (0.5);
419  delay = input;
420  }
421 
422  delayDown.setUnchecked (static_cast<int> (channel), delay);
423  }
424 
425  // Snap To Zero
426  snapToZero (false);
427  }
428 
429  void snapToZero (bool snapUpProcessing)
430  {
431  if (snapUpProcessing)
432  {
433  for (auto channel = 0; channel < ParentType::buffer.getNumChannels(); ++channel)
434  {
435  auto lv1 = v1Up.getWritePointer (channel);
436  auto numStages = coefficientsUp.size();
437 
438  for (auto n = 0; n < numStages; ++n)
439  util::snapToZero (lv1[n]);
440  }
441  }
442  else
443  {
444  for (auto channel = 0; channel < ParentType::buffer.getNumChannels(); ++channel)
445  {
446  auto lv1 = v1Down.getWritePointer (channel);
447  auto numStages = coefficientsDown.size();
448 
449  for (auto n = 0; n < numStages; ++n)
450  util::snapToZero (lv1[n]);
451  }
452  }
453  }
454 
455 private:
456  //==============================================================================
457  /** This function calculates the equivalent high order IIR filter of a given
458  polyphase cascaded allpass filters structure.
459  */
461  {
462  constexpr auto one = static_cast<SampleType> (1.0);
463 
464  Polynomial<SampleType> numerator1 ({ one }), denominator1 ({ one }),
465  numerator2 ({ one }), denominator2 ({ one });
466 
467  for (auto* i : structure.directPath)
468  {
469  auto coeffs = i->getRawCoefficients();
470 
471  if (i->getFilterOrder() == 1)
472  {
473  numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));
474  denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));
475  }
476  else
477  {
478  numerator1 = numerator1 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));
479  denominator1 = denominator1.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));
480  }
481  }
482 
483  for (auto* i : structure.delayedPath)
484  {
485  auto coeffs = i->getRawCoefficients();
486 
487  if (i->getFilterOrder() == 1)
488  {
489  numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1] }));
490  denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[2] }));
491  }
492  else
493  {
494  numerator2 = numerator2 .getProductWith (Polynomial<SampleType> ({ coeffs[0], coeffs[1], coeffs[2] }));
495  denominator2 = denominator2.getProductWith (Polynomial<SampleType> ({ one, coeffs[3], coeffs[4] }));
496  }
497  }
498 
499  auto numeratorf1 = numerator1.getProductWith (denominator2);
500  auto numeratorf2 = numerator2.getProductWith (denominator1);
501  auto numerator = numeratorf1.getSumWith (numeratorf2);
502  auto denominator = denominator1.getProductWith (denominator2);
503 
505 
506  coeffs.coefficients.clear();
507  auto inversion = one / denominator[0];
508 
509  for (auto i = 0; i <= numerator.getOrder(); ++i)
510  coeffs.coefficients.add (numerator[i] * inversion);
511 
512  for (auto i = 1; i <= denominator.getOrder(); ++i)
513  coeffs.coefficients.add (denominator[i] * inversion);
514 
515  return coeffs;
516  }
517 
518  //==============================================================================
519  Array<SampleType> coefficientsUp, coefficientsDown;
520  SampleType latency;
521 
522  AudioBuffer<SampleType> v1Up, v1Down;
523  Array<SampleType> delayDown;
524 
525  //==============================================================================
526  JUCE_DECLARE_NON_COPYABLE_WITH_LEAK_DETECTOR (Oversampling2TimesPolyphaseIIR)
527 };
528 
529 
530 //==============================================================================
531 template <typename SampleType>
533  : numChannels (newNumChannels)
534 {
535  jassert (numChannels > 0);
536 
538 }
539 
540 template <typename SampleType>
541 Oversampling<SampleType>::Oversampling (size_t newNumChannels, size_t newFactor,
542  FilterType newType, bool isMaximumQuality)
543  : numChannels (newNumChannels)
544 {
545  jassert (isPositiveAndBelow (newFactor, 5) && numChannels > 0);
546 
547  if (newFactor == 0)
548  {
550  }
551  else if (newType == FilterType::filterHalfBandPolyphaseIIR)
552  {
553  for (size_t n = 0; n < newFactor; ++n)
554  {
555  auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
556  auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
557 
558  auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
559  auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
560  auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
561  auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
562 
563  addOversamplingStage (FilterType::filterHalfBandPolyphaseIIR,
564  twUp, gaindBStartUp + gaindBFactorUp * n,
565  twDown, gaindBStartDown + gaindBFactorDown * n);
566  }
567  }
568  else if (newType == FilterType::filterHalfBandFIREquiripple)
569  {
570  for (size_t n = 0; n < newFactor; ++n)
571  {
572  auto twUp = (isMaximumQuality ? 0.10f : 0.12f) * (n == 0 ? 0.5f : 1.0f);
573  auto twDown = (isMaximumQuality ? 0.12f : 0.15f) * (n == 0 ? 0.5f : 1.0f);
574 
575  auto gaindBStartUp = (isMaximumQuality ? -90.0f : -70.0f);
576  auto gaindBStartDown = (isMaximumQuality ? -75.0f : -60.0f);
577  auto gaindBFactorUp = (isMaximumQuality ? 10.0f : 8.0f);
578  auto gaindBFactorDown = (isMaximumQuality ? 10.0f : 8.0f);
579 
580  addOversamplingStage (FilterType::filterHalfBandFIREquiripple,
581  twUp, gaindBStartUp + gaindBFactorUp * n,
582  twDown, gaindBStartDown + gaindBFactorDown * n);
583  }
584  }
585 }
586 
587 template <typename SampleType>
589 {
590  stages.clear();
591 }
592 
593 //==============================================================================
594 template <typename SampleType>
596 {
597  stages.add (new OversamplingDummy<SampleType> (numChannels));
598 }
599 
600 template <typename SampleType>
602  float normalisedTransitionWidthUp,
603  float stopbandAmplitudedBUp,
604  float normalisedTransitionWidthDown,
605  float stopbandAmplitudedBDown)
606 {
607  if (type == FilterType::filterHalfBandPolyphaseIIR)
608  {
609  stages.add (new Oversampling2TimesPolyphaseIIR<SampleType> (numChannels,
610  normalisedTransitionWidthUp, stopbandAmplitudedBUp,
611  normalisedTransitionWidthDown, stopbandAmplitudedBDown));
612  }
613  else
614  {
615  stages.add (new Oversampling2TimesEquirippleFIR<SampleType> (numChannels,
616  normalisedTransitionWidthUp, stopbandAmplitudedBUp,
617  normalisedTransitionWidthDown, stopbandAmplitudedBDown));
618  }
619 
620  factorOversampling *= 2;
621 }
622 
623 template <typename SampleType>
625 {
626  stages.clear();
627  factorOversampling = 1u;
628 }
629 
630 //==============================================================================
631 template <typename SampleType>
633 {
634  auto latency = static_cast<SampleType> (0);
635  size_t order = 1;
636 
637  for (auto* stage : stages)
638  {
639  order *= stage->factor;
640  latency += stage->getLatencyInSamples() / static_cast<SampleType> (order);
641  }
642 
643  return latency;
644 }
645 
646 template <typename SampleType>
648 {
649  return factorOversampling;
650 }
651 
652 //==============================================================================
653 template <typename SampleType>
654 void Oversampling<SampleType>::initProcessing (size_t maximumNumberOfSamplesBeforeOversampling)
655 {
656  jassert (! stages.isEmpty());
657  auto currentNumSamples = maximumNumberOfSamplesBeforeOversampling;
658 
659  for (auto* stage : stages)
660  {
661  stage->initProcessing (currentNumSamples);
662  currentNumSamples *= stage->factor;
663  }
664 
665  isReady = true;
666  reset();
667 }
668 
669 template <typename SampleType>
671 {
672  jassert (! stages.isEmpty());
673 
674  if (isReady)
675  for (auto* stage : stages)
676  stage->reset();
677 }
678 
679 template <typename SampleType>
681 {
682  jassert (! stages.isEmpty());
683 
684  if (! isReady)
685  return {};
686 
687  auto* firstStage = stages.getUnchecked (0);
688  firstStage->processSamplesUp (inputBlock);
689  auto block = firstStage->getProcessedSamples (inputBlock.getNumSamples() * firstStage->factor);
690 
691  for (int i = 1; i < stages.size(); ++i)
692  {
693  stages[i]->processSamplesUp (block);
694  block = stages[i]->getProcessedSamples (block.getNumSamples() * stages[i]->factor);
695  }
696 
697  return block;
698 }
699 
700 template <typename SampleType>
702 {
703  jassert (! stages.isEmpty());
704 
705  if (! isReady)
706  return;
707 
708  auto currentNumSamples = outputBlock.getNumSamples();
709 
710  for (int n = 0; n < stages.size() - 1; ++n)
711  currentNumSamples *= stages.getUnchecked(n)->factor;
712 
713  for (int n = stages.size() - 1; n > 0; --n)
714  {
715  auto& stage = *stages.getUnchecked(n);
716  auto audioBlock = stages.getUnchecked (n - 1)->getProcessedSamples (currentNumSamples);
717  stage.processSamplesDown (audioBlock);
718 
719  currentNumSamples /= stage.factor;
720  }
721 
722  stages.getFirst()->processSamplesDown (outputBlock);
723 }
724 
725 template class Oversampling<float>;
726 template class Oversampling<double>;
727 
728 } // namespace dsp
729 } // namespace juce
void addDummyOversamplingStage()
Adds a new "dummy" oversampling stage, which does nothing to the signal.
Abstract class for the provided oversampling stages used internally in the Oversampling class...
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
Copies the values in src to this block.
static IIRPolyphaseAllpassStructure designIIRLowpassHalfBandPolyphaseAllpassMethod(FloatType normalisedTransitionWidth, FloatType stopbandAmplitudedB)
This method generates arrays of IIR::Coefficients for a low-pass filter, with a cutoff frequency at h...
Array< NumericType > coefficients
The raw coefficients.
Oversampling stage class performing 2 times oversampling using the Filter Design IIR Polyphase Allpas...
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:422
void initProcessing(size_t maximumNumberOfSamplesBeforeOversampling)
Must be called before any processing, to set the buffer sizes of the internal buffers of the oversamp...
Minimal and lightweight data-structure which contains a list of pointers to channels containing some ...
AudioBlock< SampleType > processSamplesUp(const AudioBlock< const SampleType > &inputBlock) noexcept
Must be called to perform the upsampling, prior to any oversampled processing.
constexpr size_t getNumSamples() const noexcept
Returns the number of samples referenced by this block.
size_t getOversamplingFactor() noexcept
Returns the current oversampling factor.
A set of coefficients for use in an Filter object.
void reset() noexcept
Resets the processing pipeline, ready to oversample a new stream of data.
Oversampling stage class performing 2 times oversampling using the Filter Design FIR Equiripple metho...
void clear()
Removes all elements from the array.
Definition: juce_Array.h:192
static FIRCoefficientsPtr designFIRLowpassHalfBandEquirippleMethod(FloatType normalisedTransitionWidth, FloatType amplitudedB)
This method generates a FIR::Coefficients for a low-pass filter, with a cutoff frequency at half band...
SampleType getLatencyInSamples() noexcept
Returns the latency in samples of the whole processing.
void processSamplesDown(AudioBlock< SampleType > &outputBlock) noexcept
Must be called to perform the downsampling, after the upsampling and the non-linear processing...
void clearOversamplingStages()
Removes all the previously registered oversampling stages, so you can add your own from scratch...
A processing class performing multi-channel oversampling.
void addOversamplingStage(FilterType, float normalisedTransitionWidthUp, float stopbandAmplitudedBUp, float normalisedTransitionWidthDown, float stopbandAmplitudedBDown)
Adds a new oversampling stage to the Oversampling class, multiplying the current oversampling factor ...
The structure returned by the function designIIRLowpassHalfBandPolyphaseAllpassMethod.
SampleType * getChannelPointer(size_t channel) const noexcept
Returns a raw pointer into one of the channels in this block.
Oversampling(size_t numChannels, size_t factor, FilterType type, bool isMaxQuality=true)
Constructor of the oversampling class.
Commonly used mathematical constants.
Dummy oversampling stage class which simply copies and pastes the input signal, which could be equiva...
constexpr size_t getNumChannels() const noexcept
Returns the number of channels referenced by this block.
Polynomial< FloatingType > getProductWith(const Polynomial< FloatingType > &other) const
computes the product of two polynomials and return the result
A class representing a polynomial.
FilterType
The type of filter that can be used for the oversampling processing.