OpenShot Library | OpenShotAudio 0.2.2
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
27namespace juce
28{
29namespace dsp
30{
31
32/** Abstract class for the provided oversampling stages used internally in
33 the Oversampling class.
34*/
35template <typename SampleType>
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;
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*/
73template <typename SampleType>
74struct 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*/
113template <typename SampleType>
114struct 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
249private:
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*/
265template <typename SampleType>
266struct 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
455private:
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//==============================================================================
531template <typename SampleType>
533 : numChannels (newNumChannels)
534{
535 jassert (numChannels > 0);
536
538}
539
540template <typename SampleType>
541Oversampling<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
587template <typename SampleType>
589{
590 stages.clear();
591}
592
593//==============================================================================
594template <typename SampleType>
596{
597 stages.add (new OversamplingDummy<SampleType> (numChannels));
598}
599
600template <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
623template <typename SampleType>
625{
626 stages.clear();
627 factorOversampling = 1u;
628}
629
630//==============================================================================
631template <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
646template <typename SampleType>
648{
649 return factorOversampling;
650}
651
652//==============================================================================
653template <typename SampleType>
654void 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
669template <typename SampleType>
671{
672 jassert (! stages.isEmpty());
673
674 if (isReady)
675 for (auto* stage : stages)
676 stage->reset();
677}
678
679template <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
700template <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
725template class Oversampling<float>;
726template class Oversampling<double>;
727
728} // namespace dsp
729} // namespace juce
void setUnchecked(int indexToChange, ParameterType newValue)
Replaces an element with a new value without doing any bounds-checking.
Definition: juce_Array.h:572
ElementType getUnchecked(int index) const
Returns one of the elements in the array, without checking the index passed in.
Definition: juce_Array.h:256
int size() const noexcept
Returns the current number of elements in the array.
Definition: juce_Array.h:219
void fill(const ParameterType &newValue) noexcept
Fills the Array with the provided value.
Definition: juce_Array.h:209
ElementType * getRawDataPointer() noexcept
Returns a pointer to the actual array data.
Definition: juce_Array.h:314
void add(const ElementType &newElement)
Appends a new element at the end of the array.
Definition: juce_Array.h:422
void resize(int targetNumItems)
This will enlarge or shrink the array to the given number of elements, by adding or removing items fr...
Definition: juce_Array.h:674
void clear()
Removes all elements from the array.
Definition: juce_Array.h:192
void setSize(int newNumChannels, int newNumSamples, bool keepExistingContent=false, bool clearExtraSpace=false, bool avoidReallocating=false)
Changes the buffer's size or number of channels.
Type * getWritePointer(int channelNumber) noexcept
Returns a writeable pointer to one of the buffer's channels.
void clear() noexcept
Clears all the samples in all channels.
Minimal and lightweight data-structure which contains a list of pointers to channels containing some ...
AudioBlock getSubBlock(size_t newOffset, size_t newLength) const noexcept
Return a new AudioBlock pointing to a sub-block inside this block.
constexpr size_t getNumChannels() const noexcept
Returns the number of channels referenced by this block.
SampleType * getChannelPointer(size_t channel) const noexcept
Returns a raw pointer into one of the channels in this block.
AudioBlock & copyFrom(const AudioBlock< OtherSampleType > &src) noexcept
Copies the values in src to this block.
constexpr size_t getNumSamples() const noexcept
Returns the number of samples referenced by this block.
A processing class performing multi-channel oversampling.
void processSamplesDown(AudioBlock< SampleType > &outputBlock) noexcept
Must be called to perform the downsampling, after the upsampling and the non-linear processing.
FilterType
The type of filter that can be used for the oversampling processing.
void clearOversamplingStages()
Removes all the previously registered oversampling stages, so you can add your own from scratch.
void initProcessing(size_t maximumNumberOfSamplesBeforeOversampling)
Must be called before any processing, to set the buffer sizes of the internal buffers of the oversamp...
Oversampling(size_t numChannels, size_t factor, FilterType type, bool isMaxQuality=true)
Constructor of the oversampling class.
SampleType getLatencyInSamples() noexcept
Returns the latency in samples of the whole processing.
AudioBlock< SampleType > processSamplesUp(const AudioBlock< const SampleType > &inputBlock) noexcept
Must be called to perform the upsampling, prior to any oversampled processing.
size_t getOversamplingFactor() noexcept
Returns the current oversampling factor.
void reset() noexcept
Resets the processing pipeline, ready to oversample a new stream of data.
void addDummyOversamplingStage()
Adds a new "dummy" oversampling stage, which does nothing to the signal.
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 ...
A class representing a polynomial.
Polynomial< FloatingType > getProductWith(const Polynomial< FloatingType > &other) const
computes the product of two polynomials and return the result
The structure returned by the function designIIRLowpassHalfBandPolyphaseAllpassMethod.
Commonly used mathematical constants.
size_t getFilterOrder() const noexcept
Returns the filter order associated with the coefficients.
NumericType * getRawCoefficients() noexcept
Returns a raw data pointer to the coefficients.
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...
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...
A set of coefficients for use in an Filter object.
Array< NumericType > coefficients
The raw coefficients.
Oversampling stage class performing 2 times oversampling using the Filter Design FIR Equiripple metho...
Oversampling stage class performing 2 times oversampling using the Filter Design IIR Polyphase Allpas...
Dummy oversampling stage class which simply copies and pastes the input signal, which could be equiva...
Abstract class for the provided oversampling stages used internally in the Oversampling class.