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