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 /* 17 * This is a template class which encapsulates the SSE based SINC 18 * interpolation in COMBquad_SSE2,just made available for other uses 19 */ 20 21 #ifndef SURGE_SSESINCDELAYLINE_H 22 #define SURGE_SSESINCDELAYLINE_H 23 24 #include "SurgeStorage.h" 25 #include "basic_dsp.h" // for 'sum_ps_to_ss' 26 27 template <int COMB_SIZE> // power of two 28 struct SSESincDelayLine 29 { 30 static constexpr int comb_size = COMB_SIZE; 31 32 float buffer alignas(16)[COMB_SIZE + FIRipol_N]; 33 int wp = 0; 34 SSESincDelayLineSSESincDelayLine35 SSESincDelayLine() { memset((void *)buffer, 0, (COMB_SIZE + FIRipol_N) * sizeof(float)); } 36 writeSSESincDelayLine37 inline void write(float f) 38 { 39 buffer[wp] = f; 40 buffer[wp + (wp < FIRipol_N) * COMB_SIZE] = f; 41 wp = (wp + 1) & (COMB_SIZE - 1); 42 } 43 readSSESincDelayLine44 inline float read(float delay) 45 { 46 auto iDelay = (int)delay; 47 auto fracDelay = delay - iDelay; 48 auto sincTableOffset = (int)((1 - fracDelay) * FIRipol_M) * FIRipol_N * 2; 49 50 // So basically we interpolate around FIRipol_N (the 12 sample sinc) 51 // remembering that FIRoffset is the offset to center your table at 52 // a point ( it is FIRipol_N >> 1) 53 int readPtr = (wp - iDelay - (FIRipol_N >> 1)) & (COMB_SIZE - 1); 54 55 // And so now do what we do in COMBSSE2Quad 56 __m128 a = _mm_loadu_ps(&buffer[readPtr]); 57 __m128 b = _mm_loadu_ps(&sinctable[sincTableOffset]); 58 __m128 o = _mm_mul_ps(a, b); 59 60 a = _mm_loadu_ps(&buffer[readPtr + 4]); 61 b = _mm_loadu_ps(&sinctable[sincTableOffset + 4]); 62 o = _mm_add_ps(o, _mm_mul_ps(a, b)); 63 64 a = _mm_loadu_ps(&buffer[readPtr + 8]); 65 b = _mm_loadu_ps(&sinctable[sincTableOffset + 8]); 66 o = _mm_add_ps(o, _mm_mul_ps(a, b)); 67 68 float res; 69 _mm_store_ss(&res, sum_ps_to_ss(o)); 70 71 return res; 72 } 73 readLinearSSESincDelayLine74 inline float readLinear(float delay) 75 { 76 auto iDelay = (int)delay; 77 auto frac = delay - iDelay; 78 int RP = (wp - iDelay) & (COMB_SIZE - 1); 79 int RPP = RP == 0 ? COMB_SIZE - 1 : RP - 1; 80 return buffer[RP] * (1 - frac) + buffer[RPP] * frac; 81 } 82 clearSSESincDelayLine83 inline void clear() { memset((void *)buffer, 0, (COMB_SIZE + FIRipol_N) * sizeof(float)); } 84 }; 85 86 #endif // SURGE_SSESINCDELAYLINE_H 87