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 #include "SineOscillator.h"
17 #include "FastMath.h"
18 #include <algorithm>
19 
20 /*
21  * Sine Oscilator Optimization Strategy
22  *
23  * With Surge 1.9, we undertook a bunch of work to optimize the sine oscillator runtime at high
24  * unison count with odd shapes. Basicaly at high unison we were doing large numbers of loops,
25  * branches and so forth, and not using any of the advantage you could get by realizing the paralle
26  * structure of unison. So we fixed that.
27  *
28  * There's two core fixes.
29  *
30  * First, and you shouldn't need to touch this, the inner unison loop of ::process is now SSEified
31  * over unison. This means that we use parallel approximations of sine, we use parallel clamps and
32  * feedback application, the whole nine yards. You can see it in process_block_internal.
33  *
34  * But that's not all. The other key trick is that the shape modes added a massive amount of
35  * switching to the execution path. So we eliminated that completely. We did that with two tricks
36  *
37  * 1: Mode is a template applied at block level so there's no ifs inside the block
38  * 2: When possible, shape generation is coded as an SSE instruction.
39  *
40  * So #1 just means that process_block_internal has a <mode> template as do many other operators
41  * and we use template specialization. We are specializing the function
42  *
43  *   __m128 valueFromSineAndCosForMode<mode>(__m128 s, __m128 c, int maxc  )
44  *
45  * The default impleementation of this function calls
46  *
47  *    float valueForSineAndCosForModeAsScalar<mode>(s, c)
48  *
49  * on each SSE point in an unrolled SSE loop. But we also specialize it for many of the modes.
50  *
51  * The the original api point SineOscillator::valueFromSineAndCos (which is now only called by
52  * external APIs) calls into the appropriately templated function. Since our loop doesn't use that
53  * though we end up with our switch compile time inlined.
54  *
55  * So if you want to add a mode what does this mean? Well go update Parameter.cpp to extend the
56  * max of mode of course. But then you come back here and do the following
57  *
58  * 1. Assume that you know how to write your new mode as a scalar function. After the
59  * declaration of valueFromSineAndCosForMode as a template, specialize and put your scalar
60  * implementation in there. Add your mode to th switch statement in valueFromSinAndCos
61  * and into the DOCASE switch statement in process_block. Compile, run, test.
62  *
63  * 2. Then if that works, and you can code up your mode as an SSE function, remove that
64  * specialization and instead specialize the mode in teh SSE-named function.
65  *
66  * Should all be pretty clear.
67  */
68 
SineOscillator(SurgeStorage * storage,OscillatorStorage * oscdata,pdata * localcopy)69 SineOscillator::SineOscillator(SurgeStorage *storage, OscillatorStorage *oscdata, pdata *localcopy)
70     : Oscillator(storage, oscdata, localcopy), lp(storage), hp(storage)
71 {
72 }
73 
prepare_unison(int voices)74 void SineOscillator::prepare_unison(int voices)
75 {
76     auto us = Surge::Oscillator::UnisonSetup<float>(voices);
77 
78     out_attenuation_inv = us.attenuation_inv();
79     ;
80     out_attenuation = 1.0f / out_attenuation_inv;
81 
82     detune_bias = us.detuneBias();
83     detune_offset = us.detuneOffset();
84     for (int v = 0; v < voices; ++v)
85     {
86         us.panLaw(v, panL[v], panR[v]);
87     }
88 
89     // normalize to be sample rate independent amount of time for 50 44.1k samples
90     dplaying = 1.0 / 50.0 * 44100 / samplerate;
91     playingramp[0] = 1;
92     for (int i = 1; i < voices; ++i)
93         playingramp[i] = 0;
94 }
95 
init(float pitch,bool is_display,bool nonzero_init_drift)96 void SineOscillator::init(float pitch, bool is_display, bool nonzero_init_drift)
97 {
98     n_unison = limit_range(oscdata->p[sine_unison_voices].val.i, 1, MAX_UNISON);
99 
100     if (is_display)
101     {
102         n_unison = 1;
103     }
104 
105     prepare_unison(n_unison);
106 
107     for (int i = 0; i < n_unison; i++)
108     {
109         phase[i] = // phase in range -PI to PI
110             (oscdata->retrigger.val.b || is_display) ? 0.f : 2.0 * M_PI * storage->rand_01() - M_PI;
111         lastvalue[i] = 0.f;
112         driftLFO[i].init(nonzero_init_drift);
113         sine[i].set_phase(phase[i]);
114     }
115 
116     firstblock = (oscdata->retrigger.val.b || is_display);
117 
118     fb_val = 0.f;
119 
120     id_mode = oscdata->p[sine_shape].param_id_in_scene;
121     id_fb = oscdata->p[sine_feedback].param_id_in_scene;
122     id_fmlegacy = oscdata->p[sine_FMmode].param_id_in_scene;
123     id_detune = oscdata->p[sine_unison_detune].param_id_in_scene;
124 
125     hp.coeff_instantize();
126     lp.coeff_instantize();
127 
128     hp.coeff_HP(hp.calc_omega(oscdata->p[sine_lowcut].val.f / 12.0) / OSC_OVERSAMPLING, 0.707);
129     lp.coeff_LP2B(lp.calc_omega(oscdata->p[sine_highcut].val.f / 12.0) / OSC_OVERSAMPLING, 0.707);
130 
131     charFilt.init(storage->getPatch().character.val.i);
132     if (storage->getPatch().streamingRevision <= 15)
133     {
134         charFilt.doFilter = false;
135     }
136 }
137 
~SineOscillator()138 SineOscillator::~SineOscillator() {}
139 
calcquadrant(float sinx,float cosx)140 inline int calcquadrant(float sinx, float cosx)
141 {
142     int sxl0 = (sinx <= 0);
143     int cxl0 = (cosx <= 0);
144 
145     // quadrant
146     // 1: sin > cos > so this is 0 + 0 - 0 + 1 = 1
147     // 2: sin > cos < so this is 0 + 1 - 0 + 1 = 2
148     // 3: sin < cos < so this is 3 + 1 - 2 + 1 = 3
149     // 4: sin < cos > so this is 3 + 0 - 0 + 1 = 4
150     int quadrant = 3 * sxl0 + cxl0 - 2 * sxl0 * cxl0 + 1;
151     return quadrant;
152 }
153 
calcquadrant0(float sinx,float cosx)154 inline int calcquadrant0(float sinx, float cosx)
155 {
156     int sxl0 = (sinx <= 0);
157     int cxl0 = (cosx <= 0);
158 
159     // quadrant
160     // 1: sin > cos > so this is 0 + 0 - 0 = 0
161     // 2: sin > cos < so this is 0 + 1 - 0 = 1
162     // 3: sin < cos < so this is 3 + 1 - 2 = 2
163     // 4: sin < cos > so this is 3 + 0 - 0 = 3
164     int quadrant = 3 * sxl0 + cxl0 - 2 * sxl0 * cxl0;
165     return quadrant;
166 }
167 
calcquadrantSSE(__m128 sinx,__m128 cosx)168 inline __m128 calcquadrantSSE(__m128 sinx, __m128 cosx)
169 {
170     const auto mz = _mm_setzero_ps();
171     const auto m1 = _mm_set1_ps(1), m2 = _mm_set1_ps(2), m3 = _mm_set1_ps(3);
172     auto slt = _mm_and_ps(_mm_cmple_ps(sinx, mz), m1);
173     auto clt = _mm_and_ps(_mm_cmple_ps(cosx, mz), m1);
174 
175     // quadrant
176     // 1: sin > cos > so this is 0 + 0 - 0 + 1 = 1
177     // 2: sin > cos < so this is 0 + 1 - 0 + 1 = 2
178     // 3: sin < cos < so this is 3 + 1 - 2 + 1 = 3
179     // 4: sin < cos > so this is 3 + 0 - 0 + 1 = 4
180     // int quadrant = 3 * sxl0 + cxl0 - 2 * sxl0 * cxl0 + 1;
181     auto thsx = _mm_mul_ps(m3, slt);
182     auto twsc = _mm_mul_ps(m2, _mm_mul_ps(slt, clt));
183     auto r = _mm_add_ps(_mm_add_ps(thsx, clt), _mm_sub_ps(m1, twsc));
184     return r;
185 }
186 /*
187  * If you have a model you can't write as SSE and only as scalar, you can
188  * specialize this
189  */
valueFromSinAndCosForModeAsScalar(float s,float c)190 template <int mode> inline float valueFromSinAndCosForModeAsScalar(float s, float c) { return 0; }
191 
192 /*
193  * Otherwise, specialize this as an SSE operation. We have specialized the
194  * SSE version for every case to date.
195  */
196 template <int mode>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)197 inline __m128 valueFromSinAndCosForMode(__m128 svaluesse, __m128 cvaluesse, int maxc)
198 {
199     float res alignas(16)[4];
200     float sv alignas(16)[4], cv alignas(16)[4];
201     _mm_store_ps(sv, svaluesse);
202     _mm_store_ps(cv, cvaluesse);
203     for (int i = 0; i < maxc; ++i)
204         res[i] = valueFromSinAndCosForModeAsScalar<mode>(sv[i], cv[i]);
205     return _mm_load_ps(res);
206 }
207 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)208 template <> inline __m128 valueFromSinAndCosForMode<0>(__m128 svaluesse, __m128 cvaluesse, int maxc)
209 {
210     // mode zero is just sine obviously
211     return svaluesse;
212 }
213 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)214 template <> inline __m128 valueFromSinAndCosForMode<1>(__m128 svaluesse, __m128 cvaluesse, int maxc)
215 {
216     /*
217     switch (quadrant)
218     {
219     case 1:  pvalue = 1 - cosx;
220     case 2: pvalue = 1 + cosx;
221     case 3: pvalue = -1 - cosx;
222      case 4: pvalue = -1 + cosx;
223     }
224      */
225     const auto mz = _mm_setzero_ps();
226     const auto m1 = _mm_set1_ps(1);
227     const auto mm1 = _mm_set1_ps(-1);
228 
229     auto h1 = _mm_cmpge_ps(svaluesse, mz);
230     auto sw = _mm_sub_ps(_mm_and_ps(h1, m1), _mm_andnot_ps(h1, m1)); // this is now 1 1 -1 -1
231 
232     auto q24 = _mm_cmplt_ps(_mm_mul_ps(svaluesse, cvaluesse), mz);
233     auto pm = _mm_sub_ps(_mm_and_ps(q24, m1), _mm_andnot_ps(q24, m1)); // this is -1 1 -1 1
234     return _mm_add_ps(sw, _mm_mul_ps(pm, cvaluesse));
235 }
236 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)237 template <> inline __m128 valueFromSinAndCosForMode<2>(__m128 svaluesse, __m128 cvaluesse, int maxc)
238 {
239     // First half of sine.
240     const auto mz = _mm_setzero_ps();
241     return _mm_and_ps(svaluesse, _mm_cmpge_ps(svaluesse, mz));
242 }
243 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)244 template <> inline __m128 valueFromSinAndCosForMode<3>(__m128 svaluesse, __m128 cvaluesse, int maxc)
245 {
246     // 1 -/+ cosx in first half only
247     const auto mz = _mm_setzero_ps();
248     const auto m1 = _mm_set1_ps(1);
249     const auto mm1 = _mm_set1_ps(-1);
250     const auto m2 = _mm_set1_ps(2);
251 
252     auto h1 = _mm_cmpge_ps(svaluesse, mz);
253     auto q2 = _mm_and_ps(h1, _mm_cmple_ps(cvaluesse, mz));
254 
255     auto fh = _mm_and_ps(h1, m1);
256     auto cx =
257         _mm_mul_ps(fh, _mm_mul_ps(cvaluesse, _mm_add_ps(mm1, _mm_mul_ps(m2, _mm_and_ps(q2, m1)))));
258 
259     // return _mm_and_ps(svaluesse, _mm_cmpge_ps(svaluesse, mz));
260     return _mm_add_ps(fh, cx);
261 }
262 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)263 template <> inline __m128 valueFromSinAndCosForMode<4>(__m128 svaluesse, __m128 cvaluesse, int maxc)
264 {
265     // Sine 2x in first half
266     const auto mz = _mm_setzero_ps();
267     const auto m2 = _mm_set1_ps(2);
268 
269     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
270     return _mm_and_ps(s2x, _mm_cmpge_ps(svaluesse, mz));
271 }
272 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)273 template <> inline __m128 valueFromSinAndCosForMode<5>(__m128 svaluesse, __m128 cvaluesse, int maxc)
274 {
275     // This is basically a double frequency shape 0 in the first half only
276     const auto mz = _mm_setzero_ps();
277     const auto m1 = _mm_set1_ps(1);
278     const auto m2 = _mm_set1_ps(2);
279 
280     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
281     auto c2x = _mm_sub_ps(m1, _mm_mul_ps(m2, _mm_mul_ps(svaluesse, svaluesse)));
282 
283     auto v1 = valueFromSinAndCosForMode<1>(s2x, c2x, maxc);
284     return _mm_and_ps(_mm_cmpge_ps(svaluesse, mz), v1);
285 }
286 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)287 template <> inline __m128 valueFromSinAndCosForMode<6>(__m128 svaluesse, __m128 cvaluesse, int maxc)
288 {
289     // abs(Sine 2x in first half
290     const auto mz = _mm_setzero_ps();
291     const auto m2 = _mm_set1_ps(2);
292 
293     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
294     auto s2fh = _mm_and_ps(s2x, _mm_cmpge_ps(svaluesse, mz));
295     return abs_ps(s2fh);
296 }
297 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)298 template <> inline __m128 valueFromSinAndCosForMode<7>(__m128 svaluesse, __m128 cvaluesse, int maxc)
299 {
300     return abs_ps(valueFromSinAndCosForMode<5>(svaluesse, cvaluesse, maxc));
301 }
302 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)303 template <> inline __m128 valueFromSinAndCosForMode<8>(__m128 svaluesse, __m128 cvaluesse, int maxc)
304 {
305     // 2 * First half of sin - 1
306     const auto mz = _mm_setzero_ps();
307     const auto m2 = _mm_set1_ps(2);
308     const auto m1 = _mm_set1_ps(1);
309     auto fhs = _mm_and_ps(svaluesse, _mm_cmpge_ps(svaluesse, mz));
310     return _mm_sub_ps(_mm_mul_ps(m2, fhs), m1);
311 }
312 
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)313 template <> inline __m128 valueFromSinAndCosForMode<9>(__m128 svaluesse, __m128 cvaluesse, int maxc)
314 {
315     // zero out quadrant 1 and 3 which are quadrants where C and S have the same sign
316     const auto mz = _mm_setzero_ps();
317     const auto m2 = _mm_set1_ps(2);
318     const auto m1 = _mm_set1_ps(1);
319     auto css = _mm_mul_ps(svaluesse, cvaluesse);
320     return _mm_and_ps(svaluesse, _mm_cmple_ps(css, mz));
321 }
322 
323 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)324 inline __m128 valueFromSinAndCosForMode<10>(__m128 svaluesse, __m128 cvaluesse, int maxc)
325 {
326     // zero out quadrant 2 and 3 which are quadrants where C and S have the different sign
327     const auto mz = _mm_setzero_ps();
328     const auto m2 = _mm_set1_ps(2);
329     const auto m1 = _mm_set1_ps(1);
330     auto css = _mm_mul_ps(svaluesse, cvaluesse);
331     return _mm_and_ps(svaluesse, _mm_cmpge_ps(css, mz));
332 }
333 
334 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)335 inline __m128 valueFromSinAndCosForMode<11>(__m128 svaluesse, __m128 cvaluesse, int maxc)
336 {
337     auto q = valueFromSinAndCosForMode<3>(svaluesse, cvaluesse, maxc);
338     const auto m2 = _mm_set1_ps(2);
339     const auto m1 = _mm_set1_ps(1);
340     return _mm_sub_ps(_mm_mul_ps(m2, q), m1);
341 }
342 
343 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)344 inline __m128 valueFromSinAndCosForMode<12>(__m128 svaluesse, __m128 cvaluesse, int maxc)
345 {
346     // Flip sign of sin2x in quadrant 2 or 3 (when cosine is negative)
347     const auto mz = _mm_setzero_ps();
348     const auto m2 = _mm_set1_ps(2);
349     const auto m1 = _mm_set1_ps(1);
350     const auto mm1 = _mm_set1_ps(-1);
351 
352     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
353 
354     auto q23 = _mm_cmpge_ps(cvaluesse, mz);
355     auto mul = _mm_add_ps(_mm_and_ps(q23, m1), _mm_andnot_ps(q23, mm1));
356     return _mm_mul_ps(s2x, mul);
357 }
358 
359 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)360 inline __m128 valueFromSinAndCosForMode<13>(__m128 svaluesse, __m128 cvaluesse, int maxc)
361 {
362     // Flip sign of sin2x in quadrant 3  (when sine is negative)
363     // and zero it in quadrant 2 and 4 (when sine and cos have different signs or s2x is negative)
364     const auto mz = _mm_setzero_ps();
365     const auto m2 = _mm_set1_ps(2);
366     const auto m1 = _mm_set1_ps(1);
367     const auto mm1 = _mm_set1_ps(-1);
368 
369     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
370 
371     auto q13 = _mm_cmpge_ps(s2x, mz);
372     auto q2 = _mm_cmple_ps(svaluesse, mz);
373     auto signflip = _mm_sub_ps(m1, _mm_and_ps(q2, m2));
374 
375     return _mm_and_ps(q13, _mm_mul_ps(signflip, s2x));
376 }
377 
378 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)379 inline __m128 valueFromSinAndCosForMode<14>(__m128 svaluesse, __m128 cvaluesse, int maxc)
380 {
381     // abs of cos2x in the first half
382     const auto mz = _mm_setzero_ps();
383     const auto m1 = _mm_set1_ps(1);
384     const auto m2 = _mm_set1_ps(2);
385 
386     auto c2x = _mm_sub_ps(m1, _mm_mul_ps(m2, _mm_mul_ps(svaluesse, svaluesse)));
387     auto q23 = _mm_cmpge_ps(svaluesse, mz);
388     return _mm_and_ps(q23, abs_ps(c2x));
389 }
390 
391 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)392 inline __m128 valueFromSinAndCosForMode<15>(__m128 svaluesse, __m128 cvaluesse, int maxc)
393 {
394     // 1 - sinx in quadrant 1, -1-sinx in quadrant 4, zero otherwise
395 
396     const auto mz = _mm_setzero_ps();
397     const auto m1 = _mm_set1_ps(1);
398     const auto mm1 = _mm_set1_ps(-1);
399 
400     auto h1 = _mm_cmpge_ps(svaluesse, mz);
401     auto sig = _mm_add_ps(_mm_and_ps(h1, _mm_sub_ps(m1, svaluesse)),
402                           _mm_andnot_ps(h1, _mm_sub_ps(mm1, svaluesse)));
403 
404     auto q14 = _mm_cmpge_ps(cvaluesse, mz);
405     return _mm_and_ps(q14, sig);
406 }
407 
408 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)409 inline __m128 valueFromSinAndCosForMode<16>(__m128 svaluesse, __m128 cvaluesse, int maxc)
410 {
411     // 1 - sinx in quadrant 1, cosx - 1 in quadrant 4, zero otherwise
412 
413     const auto mz = _mm_setzero_ps();
414     const auto m1 = _mm_set1_ps(1);
415 
416     auto h1 = _mm_cmpge_ps(svaluesse, mz);
417     auto sig = _mm_add_ps(_mm_and_ps(h1, _mm_sub_ps(m1, svaluesse)),
418                           _mm_andnot_ps(h1, _mm_sub_ps(cvaluesse, m1)));
419 
420     auto q14 = _mm_cmpge_ps(cvaluesse, mz);
421     return _mm_and_ps(q14, sig);
422 }
423 
424 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)425 inline __m128 valueFromSinAndCosForMode<17>(__m128 svaluesse, __m128 cvaluesse, int maxc)
426 {
427     // 1-sinx in 1,2; -1-sinx in 3,4
428     const auto mz = _mm_setzero_ps();
429     const auto m1 = _mm_set1_ps(1);
430 
431     auto h1 = _mm_cmpge_ps(svaluesse, mz);
432     auto sw = _mm_sub_ps(_mm_and_ps(h1, m1), _mm_andnot_ps(h1, m1)); // this is now 1 1 -1 -1
433     return _mm_sub_ps(sw, svaluesse);
434 }
435 
436 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)437 inline __m128 valueFromSinAndCosForMode<18>(__m128 svaluesse, __m128 cvaluesse, int maxc)
438 {
439     // sin2x in 1, cosx in 23, -sin2x in 4
440     const auto mz = _mm_setzero_ps();
441     const auto m1 = _mm_set1_ps(1);
442     const auto m2 = _mm_set1_ps(2);
443 
444     auto h1 = _mm_cmpge_ps(svaluesse, mz);
445     auto sw = _mm_sub_ps(_mm_and_ps(h1, m1), _mm_andnot_ps(h1, m1)); // this is now 1 1 -1 -1
446 
447     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
448     auto q23 = _mm_cmple_ps(cvaluesse, mz);
449 
450     return _mm_add_ps(_mm_and_ps(q23, cvaluesse), _mm_andnot_ps(q23, _mm_mul_ps(sw, s2x)));
451 }
452 
453 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)454 inline __m128 valueFromSinAndCosForMode<19>(__m128 svaluesse, __m128 cvaluesse, int maxc)
455 {
456     // This is basically a double frequency shape 0 in the first half only
457     const auto mz = _mm_setzero_ps();
458     const auto m1 = _mm_set1_ps(1);
459     const auto m2 = _mm_set1_ps(2);
460 
461     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
462     auto c2x = _mm_sub_ps(m1, _mm_mul_ps(m2, _mm_mul_ps(svaluesse, svaluesse)));
463     auto s4x = _mm_mul_ps(m2, _mm_mul_ps(s2x, c2x));
464 
465     auto h1 = _mm_cmpge_ps(svaluesse, mz);
466     auto q23 = _mm_cmpge_ps(cvaluesse, mz);
467     auto fh = _mm_sub_ps(_mm_and_ps(q23, s2x), _mm_andnot_ps(q23, s4x));
468     auto res = _mm_add_ps(_mm_and_ps(h1, fh), _mm_andnot_ps(h1, svaluesse));
469 
470     return res;
471 }
472 
473 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)474 inline __m128 valueFromSinAndCosForMode<20>(__m128 svaluesse, __m128 cvaluesse, int maxc)
475 {
476     // Sine in quadrants 2 and 4; +/-1 in quadrants 1 and 3.
477     // quadrants 1 and 3 are when cos and sin have the same sign
478     const auto mz = _mm_setzero_ps();
479     const auto m1 = _mm_set1_ps(1);
480 
481     auto sbc = _mm_mul_ps(svaluesse, cvaluesse);
482     auto q13 = _mm_cmpge_ps(sbc, mz);
483     auto h12 = _mm_cmpge_ps(svaluesse, mz);
484     auto mv = _mm_sub_ps(_mm_and_ps(h12, m1), _mm_andnot_ps(h12, m1));
485     return _mm_add_ps(_mm_andnot_ps(q13, mv), _mm_and_ps(q13, svaluesse));
486 }
487 
488 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)489 inline __m128 valueFromSinAndCosForMode<21>(__m128 svaluesse, __m128 cvaluesse, int maxc)
490 {
491     // Sine in quadrants 2 and 4; +/-1 in quadrants 1 and 3.
492     // quadrants 1 and 3 are when cos and sin have the same sign
493     const auto mz = _mm_setzero_ps();
494     const auto m1 = _mm_set1_ps(1);
495 
496     auto sbc = _mm_mul_ps(svaluesse, cvaluesse);
497     auto q13 = _mm_cmpge_ps(sbc, mz);
498     auto h12 = _mm_cmpge_ps(svaluesse, mz);
499     auto mv = _mm_sub_ps(_mm_and_ps(h12, m1), _mm_andnot_ps(h12, m1));
500     return _mm_add_ps(_mm_and_ps(q13, mv), _mm_andnot_ps(q13, svaluesse));
501 }
502 
503 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)504 inline __m128 valueFromSinAndCosForMode<22>(__m128 svaluesse, __m128 cvaluesse, int maxc)
505 {
506     // first 2 quadrants are 1-sin
507     const auto mz = _mm_setzero_ps();
508     const auto m1 = _mm_set1_ps(1);
509 
510     auto sp = _mm_cmpge_ps(cvaluesse, mz);
511     return _mm_and_ps(sp, svaluesse);
512 }
513 
514 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)515 inline __m128 valueFromSinAndCosForMode<23>(__m128 svaluesse, __m128 cvaluesse, int maxc)
516 {
517     // first 2 quadrants are 1-sin
518     const auto mz = _mm_setzero_ps();
519     const auto m1 = _mm_set1_ps(1);
520 
521     auto sp = _mm_cmple_ps(cvaluesse, mz);
522     return _mm_and_ps(sp, svaluesse);
523 }
524 
525 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)526 inline __m128 valueFromSinAndCosForMode<24>(__m128 svaluesse, __m128 cvaluesse, int maxc)
527 {
528     // first 2 quadrants are 1-sin
529     const auto mz = _mm_setzero_ps();
530     const auto m1 = _mm_set1_ps(1);
531 
532     auto onems = _mm_sub_ps(m1, svaluesse);
533     auto sp = _mm_cmpge_ps(svaluesse, mz);
534     return _mm_add_ps(_mm_and_ps(sp, onems), _mm_andnot_ps(sp, svaluesse));
535 }
536 
537 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)538 inline __m128 valueFromSinAndCosForMode<26>(__m128 svaluesse, __m128 cvaluesse, int maxc)
539 {
540     // Zero out sine in quadrant 3 (which is cos and sin are both negative)
541     const auto mz = _mm_setzero_ps();
542     auto sl0 = _mm_cmple_ps(svaluesse, mz);
543     auto cl0 = _mm_cmple_ps(cvaluesse, mz);
544     return _mm_andnot_ps(_mm_and_ps(sl0, cl0), svaluesse);
545 }
546 
547 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)548 inline __m128 valueFromSinAndCosForMode<25>(__m128 svaluesse, __m128 cvaluesse, int maxc)
549 {
550     // Sine 2x in first half
551     const auto mz = _mm_setzero_ps();
552     const auto m2 = _mm_set1_ps(2);
553 
554     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
555     auto qv = calcquadrantSSE(svaluesse, cvaluesse);
556     auto h1 = _mm_cmpge_ps(svaluesse, mz);
557     return _mm_and_ps(h1, _mm_div_ps(s2x, qv));
558 }
559 
560 template <>
valueFromSinAndCosForMode(__m128 svaluesse,__m128 cvaluesse,int maxc)561 inline __m128 valueFromSinAndCosForMode<27>(__m128 svaluesse, __m128 cvaluesse, int maxc)
562 {
563     // Sine 2x in first half
564     const auto mz = _mm_setzero_ps();
565     const auto m2 = _mm_set1_ps(2);
566 
567     auto s2x = _mm_mul_ps(m2, _mm_mul_ps(svaluesse, cvaluesse));
568     auto qv = calcquadrantSSE(svaluesse, cvaluesse);
569     return _mm_div_ps(s2x, qv);
570 }
571 
572 // This is used by the legacy apis
singleValueFromSinAndCos(float sinx,float cosx)573 template <int mode> inline float singleValueFromSinAndCos(float sinx, float cosx)
574 {
575     auto s = _mm_set1_ps(sinx);
576     auto c = _mm_set1_ps(cosx);
577     auto r = valueFromSinAndCosForMode<mode>(s, c, 1);
578     float v;
579     _mm_store_ss(&v, r);
580     return v;
581 }
582 
583 template <int mode, bool stereo, bool FM>
process_block_internal(float pitch,float drift,float fmdepth)584 void SineOscillator::process_block_internal(float pitch, float drift, float fmdepth)
585 {
586     double detune;
587     double omega[MAX_UNISON];
588 
589     for (int l = 0; l < n_unison; l++)
590     {
591         detune = drift * driftLFO[l].next();
592 
593         if (n_unison > 1)
594         {
595             if (oscdata->p[sine_unison_detune].absolute)
596             {
597                 detune += oscdata->p[sine_unison_detune].get_extended(
598                               localcopy[oscdata->p[sine_unison_detune].param_id_in_scene].f) *
599                           storage->note_to_pitch_inv_ignoring_tuning(std::min(148.f, pitch)) * 16 /
600                           0.9443 * (detune_bias * float(l) + detune_offset);
601             }
602             else
603             {
604                 detune += oscdata->p[sine_unison_detune].get_extended(localcopy[id_detune].f) *
605                           (detune_bias * float(l) + detune_offset);
606             }
607         }
608 
609         omega[l] = std::min(M_PI, pitch_to_omega(pitch + detune));
610     }
611 
612     float fv = 32.0 * M_PI * fmdepth * fmdepth * fmdepth;
613 
614     /*
615     ** See issue 2619. At worst case we move phase by fv * 1. Since we
616     ** need phase to be in -Pi,Pi, that means if fv / Pi > 1e5 or so
617     ** we have float precision problems. So lets clamp fv.
618     */
619     fv = limit_range(fv, -1.0e6f, 1.0e6f);
620 
621     FMdepth.newValue(fv);
622     FB.newValue(abs(fb_val));
623 
624     float p alignas(16)[MAX_UNISON];
625     float sx alignas(16)[MAX_UNISON];
626     float cx alignas(16)[MAX_UNISON];
627     float olv alignas(16)[MAX_UNISON];
628     float orv alignas(16)[MAX_UNISON];
629 
630     for (int i = 0; i < MAX_UNISON; ++i)
631         p[i] = 0.0;
632 
633     auto outattensse = _mm_set1_ps(out_attenuation);
634     auto fbnegmask = _mm_cmplt_ps(_mm_set1_ps(fb_val), _mm_setzero_ps());
635     __m128 playramp[4], dramp[4];
636     if (firstblock)
637     {
638         for (int i = 0; i < 4; ++i)
639         {
640             playramp[i] = _mm_set1_ps(0.0);
641             dramp[i] = _mm_set1_ps(BLOCK_SIZE_OS_INV);
642         }
643         float tv alignas(16)[4];
644         _mm_store_ps(tv, playramp[0]);
645         tv[0] = 1.0;
646         playramp[0] = _mm_load_ps(tv);
647 
648         _mm_store_ps(tv, dramp[0]);
649         tv[0] = 0.0;
650         dramp[0] = _mm_load_ps(tv);
651     }
652     else
653     {
654         for (int i = 0; i < 4; ++i)
655         {
656             playramp[i] = _mm_set1_ps(1.0);
657             dramp[i] = _mm_setzero_ps();
658         }
659     }
660     firstblock = false;
661     for (int k = 0; k < BLOCK_SIZE_OS; k++)
662     {
663         float outL = 0.f, outR = 0.f;
664 
665         float fmpd = FM ? FMdepth.v * master_osc[k] : 0.f;
666         auto fmpds = _mm_set1_ps(fmpd);
667         auto fbv = _mm_set1_ps(FB.v);
668 
669         for (int u = 0; u < n_unison; u += 4)
670         {
671             float fph alignas(16)[4] = {(float)phase[u], (float)phase[u + 1], (float)phase[u + 2],
672                                         (float)phase[u + 3]};
673             auto ph = _mm_load_ps(&fph[0]);
674             auto lv = _mm_load_ps(&lastvalue[u]);
675             auto x = _mm_add_ps(_mm_add_ps(ph, lv), fmpds);
676 
677             x = Surge::DSP::clampToPiRangeSSE(x);
678 
679             auto sxl = Surge::DSP::fastsinSSE(x);
680             auto cxl = Surge::DSP::fastcosSSE(x);
681 
682             auto out_local = valueFromSinAndCosForMode<mode>(sxl, cxl, std::min(n_unison - u, 4));
683 
684             auto pl = _mm_load_ps(&panL[u]);
685             auto pr = _mm_load_ps(&panR[u]);
686 
687             auto ui = u >> 2;
688             auto ramp = playramp[ui];
689             auto olpr = _mm_mul_ps(out_local, ramp);
690             playramp[ui] = _mm_add_ps(playramp[ui], dramp[ui]);
691 
692             auto l = _mm_mul_ps(_mm_mul_ps(pl, olpr), outattensse);
693             auto r = _mm_mul_ps(_mm_mul_ps(pr, olpr), outattensse);
694             _mm_store_ps(&olv[u], l);
695             _mm_store_ps(&orv[u], r);
696 
697             auto lastv =
698                 _mm_mul_ps(_mm_add_ps(_mm_and_ps(fbnegmask, _mm_mul_ps(out_local, out_local)),
699                                       _mm_andnot_ps(fbnegmask, out_local)),
700                            fbv);
701             _mm_store_ps(&lastvalue[u], lastv);
702         }
703 
704         for (int u = 0; u < n_unison; ++u)
705         {
706             outL += olv[u];
707             outR += orv[u];
708 
709             // These are doubles and need to be so keep it unrolled
710             phase[u] += omega[u];
711             phase[u] -= (phase[u] > M_PI) * 2.0 * M_PI;
712         }
713 
714         FMdepth.process();
715         FB.process();
716 
717         if (stereo)
718         {
719             output[k] = outL;
720             outputR[k] = outR;
721         }
722         else
723             output[k] = (outL + outR) / 2;
724     }
725     applyFilter();
726 }
727 
applyFilter()728 void SineOscillator::applyFilter()
729 {
730     if (!oscdata->p[sine_lowcut].deactivated)
731     {
732         auto par = &(oscdata->p[sine_lowcut]);
733         auto pv = limit_range(localcopy[par->param_id_in_scene].f, par->val_min.f, par->val_max.f);
734         hp.coeff_HP(hp.calc_omega(pv / 12.0) / OSC_OVERSAMPLING, 0.707);
735     }
736 
737     if (!oscdata->p[sine_highcut].deactivated)
738     {
739         auto par = &(oscdata->p[sine_highcut]);
740         auto pv = limit_range(localcopy[par->param_id_in_scene].f, par->val_min.f, par->val_max.f);
741         lp.coeff_LP2B(lp.calc_omega(pv / 12.0) / OSC_OVERSAMPLING, 0.707);
742     }
743 
744     for (int k = 0; k < BLOCK_SIZE_OS; k += BLOCK_SIZE)
745     {
746         if (!oscdata->p[sine_lowcut].deactivated)
747             hp.process_block(&(output[k]), &(outputR[k]));
748         if (!oscdata->p[sine_highcut].deactivated)
749             lp.process_block(&(output[k]), &(outputR[k]));
750     }
751 }
752 
753 template <int mode>
process_block_legacy(float pitch,float drift,bool stereo,bool FM,float fmdepth)754 void SineOscillator::process_block_legacy(float pitch, float drift, bool stereo, bool FM,
755                                           float fmdepth)
756 {
757     double detune;
758     double omega[MAX_UNISON];
759 
760     if (FM)
761     {
762         for (int l = 0; l < n_unison; l++)
763         {
764             detune = drift * driftLFO[l].next();
765 
766             if (n_unison > 1)
767             {
768                 if (oscdata->p[sine_unison_detune].absolute)
769                 {
770                     detune += oscdata->p[sine_unison_detune].get_extended(
771                                   localcopy[oscdata->p[sine_unison_detune].param_id_in_scene].f) *
772                               storage->note_to_pitch_inv_ignoring_tuning(std::min(148.f, pitch)) *
773                               16 / 0.9443 * (detune_bias * float(l) + detune_offset);
774                 }
775                 else
776                 {
777                     detune += oscdata->p[sine_unison_detune].get_extended(localcopy[id_detune].f) *
778                               (detune_bias * float(l) + detune_offset);
779                 }
780             }
781 
782             omega[l] = std::min(M_PI, (double)pitch_to_omega(pitch + detune));
783         }
784 
785         FMdepth.newValue(fmdepth);
786 
787         for (int k = 0; k < BLOCK_SIZE_OS; k++)
788         {
789             float outL = 0.f, outR = 0.f;
790 
791             for (int u = 0; u < n_unison; u++)
792             {
793                 float out_local = singleValueFromSinAndCos<mode>(Surge::DSP::fastsin(phase[u]),
794                                                                  Surge::DSP::fastcos(phase[u]));
795 
796                 outL += (panL[u] * out_local) * out_attenuation * playingramp[u];
797                 outR += (panR[u] * out_local) * out_attenuation * playingramp[u];
798 
799                 if (playingramp[u] < 1)
800                     playingramp[u] += dplaying;
801                 if (playingramp[u] > 1)
802                     playingramp[u] = 1;
803 
804                 phase[u] += omega[u] + master_osc[k] * FMdepth.v;
805                 phase[u] = Surge::DSP::clampToPiRange(phase[u]);
806             }
807 
808             FMdepth.process();
809 
810             if (stereo)
811             {
812                 output[k] = outL;
813                 outputR[k] = outR;
814             }
815             else
816                 output[k] = (outL + outR) / 2;
817         }
818     }
819     else
820     {
821         for (int l = 0; l < n_unison; l++)
822         {
823             detune = drift * driftLFO[l].next();
824 
825             if (n_unison > 1)
826                 detune += oscdata->p[sine_unison_detune].get_extended(localcopy[id_detune].f) *
827                           (detune_bias * float(l) + detune_offset);
828 
829             omega[l] = std::min(M_PI, (double)pitch_to_omega(pitch + detune));
830             sine[l].set_rate(omega[l]);
831         }
832 
833         for (int k = 0; k < BLOCK_SIZE_OS; k++)
834         {
835             float outL = 0.f, outR = 0.f;
836 
837             for (int u = 0; u < n_unison; u++)
838             {
839                 sine[u].process();
840 
841                 float sinx = sine[u].r;
842                 float cosx = sine[u].i;
843 
844                 float out_local = singleValueFromSinAndCos<mode>(sinx, cosx);
845 
846                 outL += (panL[u] * out_local) * out_attenuation * playingramp[u];
847                 outR += (panR[u] * out_local) * out_attenuation * playingramp[u];
848 
849                 if (playingramp[u] < 1)
850                     playingramp[u] += dplaying;
851                 if (playingramp[u] > 1)
852                     playingramp[u] = 1;
853             }
854 
855             if (stereo)
856             {
857                 output[k] = outL;
858                 outputR[k] = outR;
859             }
860             else
861                 output[k] = (outL + outR) / 2;
862         }
863     }
864 }
865 
process_block(float pitch,float drift,bool stereo,bool FM,float fmdepth)866 void SineOscillator::process_block(float pitch, float drift, bool stereo, bool FM, float fmdepth)
867 {
868     auto mode = localcopy[id_mode].i;
869 
870     if (localcopy[id_fmlegacy].i == 0)
871     {
872 #define DOCASE(x)                                                                                  \
873     case x:                                                                                        \
874         process_block_legacy<x>(pitch, drift, stereo, FM, fmdepth);                                \
875         break;
876 
877         switch (mode)
878         {
879             DOCASE(0)
880             DOCASE(1)
881             DOCASE(2)
882             DOCASE(3)
883             DOCASE(4)
884             DOCASE(5)
885             DOCASE(6)
886             DOCASE(7)
887             DOCASE(8)
888             DOCASE(9)
889             DOCASE(10)
890 
891             DOCASE(11)
892             DOCASE(12)
893             DOCASE(13)
894             DOCASE(14)
895             DOCASE(15)
896             DOCASE(16)
897             DOCASE(17)
898             DOCASE(18)
899             DOCASE(19)
900             DOCASE(20)
901             DOCASE(21)
902             DOCASE(22)
903             DOCASE(23)
904             DOCASE(24)
905             DOCASE(25)
906             DOCASE(26)
907             DOCASE(27)
908         }
909 #undef DOCASE
910         applyFilter();
911 
912         if (charFilt.doFilter)
913         {
914             if (stereo)
915             {
916                 charFilt.process_block_stereo(output, outputR, BLOCK_SIZE_OS);
917             }
918             else
919             {
920                 charFilt.process_block(output, BLOCK_SIZE_OS);
921             }
922         }
923 
924         return;
925     }
926 
927     fb_val = oscdata->p[sine_feedback].get_extended(localcopy[id_fb].f);
928 
929 #define DOCASE(x)                                                                                  \
930     case x:                                                                                        \
931         if (stereo)                                                                                \
932             if (FM)                                                                                \
933                 process_block_internal<x, true, true>(pitch, drift, fmdepth);                      \
934             else                                                                                   \
935                 process_block_internal<x, true, false>(pitch, drift, fmdepth);                     \
936         else if (FM)                                                                               \
937             process_block_internal<x, false, true>(pitch, drift, fmdepth);                         \
938         else                                                                                       \
939             process_block_internal<x, false, false>(pitch, drift, fmdepth);                        \
940         break;
941 
942     switch (mode)
943     {
944         DOCASE(0)
945         DOCASE(1)
946         DOCASE(2)
947         DOCASE(3)
948         DOCASE(4)
949         DOCASE(5)
950         DOCASE(6)
951         DOCASE(7)
952         DOCASE(8)
953         DOCASE(9)
954         DOCASE(10)
955 
956         DOCASE(11)
957         DOCASE(12)
958         DOCASE(13)
959         DOCASE(14)
960         DOCASE(15)
961         DOCASE(16)
962         DOCASE(17)
963         DOCASE(18)
964         DOCASE(19)
965         DOCASE(20)
966         DOCASE(21)
967         DOCASE(22)
968         DOCASE(23)
969         DOCASE(24)
970         DOCASE(25)
971         DOCASE(26)
972         DOCASE(27)
973     }
974 #undef DOCASE
975 
976     if (charFilt.doFilter)
977     {
978         if (stereo)
979         {
980             charFilt.process_block_stereo(output, outputR, BLOCK_SIZE_OS);
981         }
982         else
983         {
984             charFilt.process_block(output, BLOCK_SIZE_OS);
985         }
986     }
987 }
988 
init_ctrltypes()989 void SineOscillator::init_ctrltypes()
990 {
991     oscdata->p[sine_shape].set_name("Shape");
992     oscdata->p[sine_shape].set_type(ct_sineoscmode);
993 
994     oscdata->p[sine_feedback].set_name("Feedback");
995     oscdata->p[sine_feedback].set_type(ct_osc_feedback_negative);
996 
997     oscdata->p[sine_FMmode].set_name("Behavior");
998     oscdata->p[sine_FMmode].set_type(ct_sinefmlegacy);
999 
1000     oscdata->p[sine_lowcut].set_name("Low Cut");
1001     oscdata->p[sine_lowcut].set_type(ct_freq_audible_deactivatable);
1002 
1003     oscdata->p[sine_highcut].set_name("High Cut");
1004     oscdata->p[sine_highcut].set_type(ct_freq_audible_deactivatable);
1005 
1006     oscdata->p[sine_unison_detune].set_name("Unison Detune");
1007     oscdata->p[sine_unison_detune].set_type(ct_oscspread);
1008 
1009     oscdata->p[sine_unison_voices].set_name("Unison Voices");
1010     oscdata->p[sine_unison_voices].set_type(ct_osccount);
1011 }
1012 
init_default_values()1013 void SineOscillator::init_default_values()
1014 {
1015     oscdata->p[sine_shape].val.i = 0;
1016     oscdata->p[sine_feedback].val.f = 0;
1017     oscdata->p[sine_FMmode].val.i = 1;
1018 
1019     oscdata->p[sine_lowcut].val.f = oscdata->p[sine_lowcut].val_min.f; // high cut at the bottom
1020     oscdata->p[sine_lowcut].deactivated = true;
1021     oscdata->p[sine_highcut].val.f = oscdata->p[sine_highcut].val_max.f; // low cut at the top
1022     oscdata->p[sine_highcut].deactivated = true;
1023 
1024     oscdata->p[sine_unison_detune].val.f = 0.1;
1025     oscdata->p[sine_unison_voices].val.i = 1;
1026 }
1027 
handleStreamingMismatches(int streamingRevision,int currentSynthStreamingRevision)1028 void SineOscillator::handleStreamingMismatches(int streamingRevision,
1029                                                int currentSynthStreamingRevision)
1030 {
1031     if (streamingRevision <= 9)
1032     {
1033         oscdata->p[sine_shape].val.i = oscdata->p[sine_shape].val_min.i;
1034     }
1035 
1036     if (streamingRevision <= 10)
1037     {
1038         oscdata->p[sine_feedback].val.f = 0;
1039         oscdata->p[sine_FMmode].val.i = 0;
1040     }
1041 
1042     if (streamingRevision <= 12)
1043     {
1044         oscdata->p[sine_lowcut].val.f = oscdata->p[sine_lowcut].val_min.f; // high cut at the bottom
1045         oscdata->p[sine_lowcut].deactivated = true;
1046         oscdata->p[sine_highcut].val.f = oscdata->p[sine_highcut].val_max.f; // low cut at the top
1047         oscdata->p[sine_highcut].deactivated = true;
1048         oscdata->p[sine_feedback].set_type(ct_osc_feedback);
1049 
1050         int wave_remap[] = {0, 8, 9, 10, 1, 11, 4, 12, 13, 2, 3, 5, 6, 7, 14, 15, 16, 17, 18, 19};
1051 
1052         // range checking for garbage data
1053         if (oscdata->p[sine_shape].val.i < 0 ||
1054             (oscdata->p[sine_shape].val.i >= (sizeof wave_remap) / sizeof *wave_remap))
1055             oscdata->p[sine_shape].val.i = oscdata->p[sine_shape].val_min.i;
1056         else
1057         {
1058             // make sure old patches still point to the correct waveforms
1059             oscdata->p[sine_shape].val.i = wave_remap[oscdata->p[sine_shape].val.i];
1060         }
1061     }
1062 
1063     if (streamingRevision <= 15)
1064     {
1065         oscdata->retrigger.val.b = true;
1066     }
1067 }
1068 
valueFromSinAndCos(float sinx,float cosx,int wfMode)1069 float SineOscillator::valueFromSinAndCos(float sinx, float cosx, int wfMode)
1070 {
1071     // As you port to SSE, put them here
1072     switch (wfMode)
1073     {
1074     case 0:
1075         return sinx;
1076     case 1:
1077         return singleValueFromSinAndCos<1>(sinx, cosx);
1078     case 2:
1079         return singleValueFromSinAndCos<2>(sinx, cosx);
1080     case 3:
1081         return singleValueFromSinAndCos<3>(sinx, cosx);
1082     case 4:
1083         return singleValueFromSinAndCos<4>(sinx, cosx);
1084     case 5:
1085         return singleValueFromSinAndCos<5>(sinx, cosx);
1086     case 6:
1087         return singleValueFromSinAndCos<6>(sinx, cosx);
1088     case 7:
1089         return singleValueFromSinAndCos<7>(sinx, cosx);
1090     case 8:
1091         return singleValueFromSinAndCos<8>(sinx, cosx);
1092     case 9:
1093         return singleValueFromSinAndCos<9>(sinx, cosx);
1094     case 10:
1095         return singleValueFromSinAndCos<10>(sinx, cosx);
1096     case 11:
1097         return singleValueFromSinAndCos<11>(sinx, cosx);
1098     case 12:
1099         return singleValueFromSinAndCos<12>(sinx, cosx);
1100     case 13:
1101         return singleValueFromSinAndCos<13>(sinx, cosx);
1102     case 14:
1103         return singleValueFromSinAndCos<14>(sinx, cosx);
1104     case 15:
1105         return singleValueFromSinAndCos<15>(sinx, cosx);
1106     case 16:
1107         return singleValueFromSinAndCos<16>(sinx, cosx);
1108     case 17:
1109         return singleValueFromSinAndCos<17>(sinx, cosx);
1110     case 18:
1111         return singleValueFromSinAndCos<18>(sinx, cosx);
1112     case 19:
1113         return singleValueFromSinAndCos<19>(sinx, cosx);
1114     case 20:
1115         return singleValueFromSinAndCos<20>(sinx, cosx);
1116     case 21:
1117         return singleValueFromSinAndCos<21>(sinx, cosx);
1118     case 22:
1119         return singleValueFromSinAndCos<22>(sinx, cosx);
1120     case 23:
1121         return singleValueFromSinAndCos<23>(sinx, cosx);
1122     case 24:
1123         return singleValueFromSinAndCos<24>(sinx, cosx);
1124     case 25:
1125         return singleValueFromSinAndCos<25>(sinx, cosx);
1126     case 26:
1127         return singleValueFromSinAndCos<26>(sinx, cosx);
1128     case 27:
1129         return singleValueFromSinAndCos<27>(sinx, cosx);
1130     }
1131 
1132     return 0;
1133 }
1134