OpenShot Audio Library | OpenShotAudio  0.3.0
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 
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 //==============================================================================
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 //==============================================================================
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 //==============================================================================
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  //==============================================================================
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 setUnchecked(int indexToChange, ParameterType newValue)
Definition: juce_Array.h:568
ElementType getUnchecked(int index) const
Definition: juce_Array.h:252
int size() const noexcept
Definition: juce_Array.h:215
void fill(const ParameterType &newValue) noexcept
Definition: juce_Array.h:205
void add(const ElementType &newElement)
Definition: juce_Array.h:418
ElementType * getRawDataPointer() noexcept
Definition: juce_Array.h:310
void resize(int targetNumItems)
Definition: juce_Array.h:670
void clear()
Definition: juce_Array.h:188
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Type * getWritePointer(int channelNumber) noexcept
AudioBlock getSubBlock(size_t newOffset, size_t newLength) const noexcept
SampleType * getChannelPointer(size_t channel) const noexcept
constexpr size_t getNumChannels() const noexcept
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
constexpr size_t getNumSamples() const noexcept
void processSamplesDown(AudioBlock< SampleType > &outputBlock) noexcept
void initProcessing(size_t maximumNumberOfSamplesBeforeOversampling)
Oversampling(size_t numChannels, size_t factor, FilterType type, bool isMaxQuality=true)
SampleType getLatencyInSamples() noexcept
AudioBlock< SampleType > processSamplesUp(const AudioBlock< const SampleType > &inputBlock) noexcept
size_t getOversamplingFactor() noexcept
void addOversamplingStage(FilterType, float normalisedTransitionWidthUp, float stopbandAmplitudedBUp, float normalisedTransitionWidthDown, float stopbandAmplitudedBDown)
Polynomial< FloatingType > getProductWith(const Polynomial< FloatingType > &other) const
NumericType * getRawCoefficients() noexcept
size_t getFilterOrder() const noexcept
static IIRPolyphaseAllpassStructure designIIRLowpassHalfBandPolyphaseAllpassMethod(FloatType normalisedTransitionWidth, FloatType stopbandAmplitudedB)
static FIRCoefficientsPtr designFIRLowpassHalfBandEquirippleMethod(FloatType normalisedTransitionWidth, FloatType amplitudedB)