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