1 /*
2 ** Surge Synthesizer is Free and Open Source Software
3 **
4 ** Surge is made available under the Gnu General Public License, v3.0
5 ** https://www.gnu.org/licenses/gpl-3.0.en.html
6 **
7 ** Copyright 2004-2020 by various individuals as described by the Git transaction log
8 **
9 ** All source at: https://github.com/surge-synthesizer/surge.git
10 **
11 ** Surge was a commercial product from 2004-2018, with Copyright and ownership
12 ** in that period held by Claes Johanson at Vember Audio. Claes made Surge
13 ** open source in September 2018.
14 */
15 
16 #pragma once
17 #include <algorithm>
18 #include <memory>
19 #include <vt_dsp/basic_dsp.h>
20 #include <vt_dsp/halfratefilter.h>
21 
22 namespace chowdsp
23 {
24 
25 /*
26 ** Generalised oversampling class for use in effects processing.
27 ** Uses anti-imaging filters for upsampling, and anti-aliasing
28 ** filters for downsampling. Most of the oversampling parameters
29 ** are set as template parameters:
30 **
31 ** @param: OSFactor     sets the oversampling ratio as a power of two. i.e. Ratio = 2^OSFactor
32 ** @param: block_size   size of the blocks of audio before upsampling
33 ** @param: FilterOrd    sets the order of the anti-imaging/anti-aliasing filters
34 ** @param: steep        sets whether to use the filters in "steep" mode (see
35 *vt_dsp/halfratefilter.h)
36 **
37 ** The class should be used in the processign callback as follows:
38 ** Then use the following code to process samples:
39 ** @code
40 ** Ovsampling<2, BLOCK_SIZE> os;
41 ** void process(float* dataL, float* dataR)
42 ** {
43 **     os.upsample(dataL, dataR);
44 **     process_samples(os.leftUp, os.rightUp, os.getUpBLockSize());
45 **     os.downsample(dataL, dataR);
46 ** }
47 ** @endcode
48 */
49 template <size_t OSFactor, size_t block_size, size_t FilterOrd = 3, bool steep = false>
50 class Oversampling
51 {
52     std::unique_ptr<HalfRateFilter> hr_filts_up alignas(16)[OSFactor];
53     std::unique_ptr<HalfRateFilter> hr_filts_down alignas(16)[OSFactor];
54 
55     static constexpr size_t osRatio = 1 << OSFactor;
56     static constexpr size_t up_block_size = block_size * osRatio;
57     static constexpr size_t block_size_quad = block_size / 4;
58 
59   public:
Oversampling()60     Oversampling()
61     {
62         for (size_t i = 0; i < OSFactor; ++i)
63         {
64             hr_filts_up[i] = std::make_unique<HalfRateFilter>(FilterOrd, steep);
65             hr_filts_down[i] = std::make_unique<HalfRateFilter>(FilterOrd, steep);
66         }
67     }
68 
69     /** Resets the processing pipeline */
reset()70     void reset()
71     {
72         for (size_t i = 0; i < OSFactor; ++i)
73         {
74             hr_filts_up[i]->reset();
75             hr_filts_down[i]->reset();
76         }
77 
78         std::fill(leftUp, &leftUp[up_block_size], 0.0f);
79         std::fill(rightUp, &rightUp[up_block_size], 0.0f);
80     }
81 
82     /** Upsamples the audio in the input arrays, and stores the upsampled audio internally */
upsample(float * leftIn,float * rightIn)83     inline void upsample(float *leftIn, float *rightIn) noexcept
84     {
85         copy_block(leftIn, leftUp, block_size_quad);
86         copy_block(rightIn, rightUp, block_size_quad);
87 
88         for (size_t i = 0; i < OSFactor; ++i)
89         {
90             auto numSamples = block_size * (1 << (i + 1));
91             hr_filts_up[i]->process_block_U2(leftUp, rightUp, leftUp, rightUp, numSamples);
92         }
93     }
94 
95     /** Downsamples that audio in the internal buffers, and stores the downsampled audio in the
96      * input arrays */
downsample(float * leftOut,float * rightOut)97     inline void downsample(float *leftOut, float *rightOut) noexcept
98     {
99         for (size_t i = OSFactor; i > 0; --i)
100         {
101             auto numSamples = block_size * (1 << i);
102             hr_filts_down[i - 1]->process_block_D2(leftUp, rightUp, numSamples);
103         }
104 
105         copy_block(leftUp, leftOut, block_size_quad);
106         copy_block(rightUp, rightOut, block_size_quad);
107     }
108 
109     /** Returns the size of the upsampled blocks */
getUpBlockSize()110     inline constexpr size_t getUpBlockSize() const noexcept { return up_block_size; }
111 
112     /** Returns the oversampling ratio */
getOSRatio()113     inline constexpr size_t getOSRatio() const noexcept { return osRatio; }
114 
115     float leftUp alignas(16)[up_block_size];
116     float rightUp alignas(16)[up_block_size];
117 };
118 
119 } // namespace chowdsp
120