1 /*
2     SuperCollider real time audio synthesis system
3     Copyright (c) 2002 James McCartney. All rights reserved.
4     http://www.audiosynth.com
5 
6     This program is free software; you can redistribute it and/or modify
7     it under the terms of the GNU General Public License as published by
8     the Free Software Foundation; either version 2 of the License, or
9     (at your option) any later version.
10 
11     This program is distributed in the hope that it will be useful,
12     but WITHOUT ANY WARRANTY; without even the implied warranty of
13     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14     GNU General Public License for more details.
15 
16     You should have received a copy of the GNU General Public License
17     along with this program; if not, write to the Free Software
18     Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301  USA
19 */
20 
21 
22 #include "SC_PlugIn.hpp"
23 #include "SIMD_Unit.hpp"
24 
25 static InterfaceTable* ft;
26 
27 namespace {
28 
29 struct MulAdd : SIMD_Unit {
30     ControlRateInput<1> mMul;
31     ControlRateInput<2> mAdd;
32 
33 #define MULADD_CALCFUNC(METHOD_NAME)                                                                                   \
34     do {                                                                                                               \
35         set_unrolled_calc_function<MulAdd, &MulAdd::METHOD_NAME<unrolled_64>, &MulAdd::METHOD_NAME<unrolled>,          \
36                                    &MulAdd::METHOD_NAME<scalar>>();                                                    \
37         return;                                                                                                        \
38     } while (0)
39 
MulAdd__anon2eabe8300111::MulAdd40     MulAdd(void) {
41         mMul.init(this);
42         mAdd.init(this);
43 
44         if (mCalcRate != calc_FullRate) {
45             set_calc_function<MulAdd, &MulAdd::next_scalar>();
46             return;
47         }
48 
49         assert(inRate(0) == calc_FullRate);
50 
51         switch (inRate(1)) {
52         case calc_FullRate:
53             switch (inRate(2)) {
54             case calc_FullRate:
55                 MULADD_CALCFUNC(next_aa);
56 
57             case calc_BufRate:
58                 MULADD_CALCFUNC(next_ak);
59 
60             case calc_ScalarRate:
61                 if (mAdd == 0.f)
62                     MULADD_CALCFUNC(next_a0);
63                 else
64                     MULADD_CALCFUNC(next_ai);
65 
66             default:
67                 assert(false);
68             }
69 
70         case calc_BufRate:
71             switch (inRate(2)) {
72             case calc_FullRate:
73                 MULADD_CALCFUNC(next_ka);
74 
75             case calc_BufRate:
76                 MULADD_CALCFUNC(next_kk);
77 
78             case calc_ScalarRate:
79                 if (mAdd == 0.f)
80                     MULADD_CALCFUNC(next_k0);
81                 else
82                     MULADD_CALCFUNC(next_ki);
83 
84             default:
85                 assert(false);
86             }
87 
88         case calc_ScalarRate:
89             switch (inRate(2)) {
90             case calc_FullRate:
91                 if (mMul == 1.0)
92                     MULADD_CALCFUNC(next_1a);
93                 else if (mMul == 0.f)
94                     MULADD_CALCFUNC(next_0a);
95                 else
96                     MULADD_CALCFUNC(next_ia);
97 
98             case calc_BufRate:
99                 if (mMul == 1.0)
100                     MULADD_CALCFUNC(next_1k);
101                 else if (mMul == 0.f)
102                     MULADD_CALCFUNC(next_0k);
103                 else
104                     MULADD_CALCFUNC(next_ik);
105 
106             case calc_ScalarRate:
107                 if (mMul == 1.0) {
108                     if (mAdd == 0)
109                         MULADD_CALCFUNC(next_10);
110                     else
111                         MULADD_CALCFUNC(next_1i);
112                 }
113 
114                 else if (mMul == 0.f) {
115                     if (mAdd == 0.f)
116                         MULADD_CALCFUNC(next_00);
117                     else
118                         MULADD_CALCFUNC(next_0i);
119                 } else {
120                     if (mAdd == 0.f)
121                         MULADD_CALCFUNC(next_i0);
122                     else
123                         MULADD_CALCFUNC(next_ii);
124                 }
125 
126             default:
127                 assert(false);
128             }
129 
130         default:
131             assert(false);
132         }
133     }
134 
mulChanged__anon2eabe8300111::MulAdd135     inline bool mulChanged(void) const { return mMul.changed(this); }
136 
addChanged__anon2eabe8300111::MulAdd137     inline bool addChanged(void) const { return mAdd.changed(this); }
138 
139 #if __cplusplus <= 199711L
mulSlope__anon2eabe8300111::MulAdd140     nova::detail::scalar_ramp_argument<float> mulSlope(void)
141 #else
142     decltype(nova::slope_argument(0.f, 0.f)) mulSlope(void)
143 #endif
144     {
145         return mMul.slope(this);
146     }
147 
148 #if __cplusplus <= 199711L
addSlope__anon2eabe8300111::MulAdd149     nova::detail::scalar_ramp_argument<float> addSlope(void)
150 #else
151     decltype(nova::slope_argument(0.f, 0.f)) addSlope(void)
152 #endif
153     {
154         return mAdd.slope(this);
155     }
156 
next_scalar__anon2eabe8300111::MulAdd157     void next_scalar(int inNumSamples) { out0(0) = (in0(0) * in0(1)) + in0(2); }
158 
next_aa__anon2eabe8300111::MulAdd159     template <int SIMD> void next_aa(int inNumSamples) { muladd<SIMD>(out(0), in(0), in(1), in(2), inNumSamples); }
160 
next_ak__anon2eabe8300111::MulAdd161     template <int SIMD> void next_ak(int inNumSamples) {
162         if (addChanged())
163             muladd<SIMD>(out(0), in(0), in(1), addSlope(), inNumSamples);
164         else {
165             if (mAdd == 0.f)
166                 times_vec<SIMD>(out(0), in(0), in(1), inNumSamples);
167             else
168                 next_ai<SIMD>(inNumSamples);
169         }
170     }
171 
next_ai__anon2eabe8300111::MulAdd172     template <int SIMD> void next_ai(int inNumSamples) { muladd<SIMD>(out(0), in(0), in(1), mAdd, inNumSamples); }
173 
next_ka__anon2eabe8300111::MulAdd174     template <int SIMD> void next_ka(int inNumSamples) {
175         if (mulChanged())
176             muladd<SIMD>(out(0), in(0), mulSlope(), in(2), inNumSamples);
177         else
178             next_ia<SIMD>(inNumSamples);
179     }
180 
next_kk__anon2eabe8300111::MulAdd181     template <int SIMD> void next_kk(int inNumSamples) {
182         if (addChanged()) {
183             if (mulChanged())
184                 muladd<SIMD>(out(0), in(0), mulSlope(), addSlope(), inNumSamples);
185             else {
186                 if (mMul == 0)
187                     slope_vec<SIMD>(out(0), addSlope(), inNumSamples);
188                 else if (mMul == 1.f)
189                     plus_vec<SIMD>(out(0), in(0), addSlope(), inNumSamples);
190                 else
191                     muladd<SIMD>(out(0), in(0), mMul, addSlope(), inNumSamples);
192             }
193         } else
194             next_ki<SIMD>(inNumSamples);
195     }
196 
next_ki__anon2eabe8300111::MulAdd197     template <int SIMD> void next_ki(int inNumSamples) {
198         if (mulChanged())
199             muladd<SIMD>(out(0), in(0), mulSlope(), mAdd, inNumSamples);
200         else
201             next_ii<SIMD>(inNumSamples);
202     }
203 
next_ia__anon2eabe8300111::MulAdd204     template <int SIMD> void next_ia(int inNumSamples) {
205         if (mMul == 0)
206             next_0a<SIMD>(inNumSamples);
207         else if (mMul == 1.0)
208             next_1a<SIMD>(inNumSamples);
209         else
210             muladd<SIMD>(out(0), in(0), mMul, in(2), inNumSamples);
211     }
212 
next_ik__anon2eabe8300111::MulAdd213     template <int SIMD> void next_ik(int inNumSamples) {
214         if (addChanged()) {
215             if (mMul == 0.f)
216                 slope_vec<SIMD>(out(0), addSlope(), inNumSamples);
217             else if (mMul == 1.f)
218                 plus_vec<SIMD>(out(0), in(0), addSlope(), inNumSamples);
219             else
220                 muladd<SIMD>(out(0), in(0), mMul, addSlope(), inNumSamples);
221         } else
222             next_ii<SIMD>(inNumSamples);
223     }
224 
next_ii__anon2eabe8300111::MulAdd225     template <int SIMD> void next_ii(int inNumSamples) {
226         if (mMul == 0)
227             next_0i<SIMD>(inNumSamples);
228         else if (mMul == 1.f) {
229             next_1i<SIMD>(inNumSamples);
230         } else {
231             if (mAdd == 0)
232                 times_vec<SIMD>(out(0), in(0), mMul, inNumSamples);
233             else
234                 muladd<SIMD>(out(0), in(0), mMul, mAdd, inNumSamples);
235         }
236     }
237 
next_1a__anon2eabe8300111::MulAdd238     template <int SIMD> void next_1a(int inNumSamples) { plus_vec<SIMD>(out(0), in(0), in(2), inNumSamples); }
239 
next_1k__anon2eabe8300111::MulAdd240     template <int SIMD> void next_1k(int inNumSamples) {
241         if (addChanged())
242             plus_vec<SIMD>(out(0), in(0), addSlope(), inNumSamples);
243         else
244             next_1i<SIMD>(inNumSamples);
245     }
246 
next_1i__anon2eabe8300111::MulAdd247     template <int SIMD> void next_1i(int inNumSamples) {
248         if (mAdd == 0)
249             copy_vec<SIMD>(out(0), in(0), inNumSamples);
250         else
251             plus_vec<SIMD>(out(0), in(0), mAdd, inNumSamples);
252     }
253 
next_0a__anon2eabe8300111::MulAdd254     template <int SIMD> void next_0a(int inNumSamples) { copy_vec<SIMD>(out(0), in(2), inNumSamples); }
255 
next_0k__anon2eabe8300111::MulAdd256     template <int SIMD> void next_0k(int inNumSamples) {
257         if (addChanged())
258             slope_vec<SIMD>(out(0), addSlope(), inNumSamples);
259         else
260             next_0i<SIMD>(inNumSamples);
261     }
262 
next_0i__anon2eabe8300111::MulAdd263     template <int SIMD> void next_0i(int inNumSamples) { set_vec<SIMD>(out(0), mAdd, inNumSamples); }
264 
next_a0__anon2eabe8300111::MulAdd265     template <int SIMD> void next_a0(int inNumSamples) { times_vec<SIMD>(out(0), in(0), in(1), inNumSamples); }
266 
next_k0__anon2eabe8300111::MulAdd267     template <int SIMD> void next_k0(int inNumSamples) {
268         if (mulChanged())
269             times_vec<SIMD>(out(0), in(0), mulSlope(), inNumSamples);
270         else
271             next_ik<SIMD>(inNumSamples);
272     }
273 
next_i0__anon2eabe8300111::MulAdd274     template <int SIMD> void next_i0(int inNumSamples) {
275         if (mMul == 0.f)
276             next_00<SIMD>(inNumSamples);
277         else if (mMul == 1.f)
278             next_10<SIMD>(inNumSamples);
279         else
280             times_vec<SIMD>(out(0), in(0), mMul, inNumSamples);
281     }
282 
next_10__anon2eabe8300111::MulAdd283     template <int SIMD> void next_10(int inNumSamples) { copy_vec<SIMD>(out(0), in(0), inNumSamples); }
284 
next_00__anon2eabe8300111::MulAdd285     template <int SIMD> void next_00(int inNumSamples) { set_vec<SIMD>(out(0), 0.f, inNumSamples); }
286 };
287 
288 struct Sum3 : SIMD_Unit {
289     ControlRateInput<1> in1;
290     ControlRateInput<2> in2;
291 
Sum3__anon2eabe8300111::Sum3292     Sum3(void) {
293         in1.init(this);
294         in2.init(this);
295 
296         if (mCalcRate != calc_FullRate) {
297             set_calc_function<Sum3, &Sum3::next_scalar>();
298             return;
299         }
300 
301         assert(inRate(0) == calc_FullRate);
302 
303         switch (inRate(1)) {
304         case calc_FullRate:
305             switch (inRate(2)) {
306             case calc_FullRate:
307                 set_vector_calc_function<Sum3, &Sum3::next_aaa<true>, &Sum3::next_aaa<false>>();
308                 return;
309 
310             case calc_BufRate:
311                 set_vector_calc_function<Sum3, &Sum3::next_aak<true>, &Sum3::next_aak<false>>();
312                 return;
313 
314             case calc_ScalarRate:
315                 set_vector_calc_function<Sum3, &Sum3::next_aai<true>, &Sum3::next_aai<false>>();
316                 return;
317 
318             default:
319                 assert(false);
320             }
321 
322         case calc_BufRate:
323             switch (inRate(2)) {
324             case calc_BufRate:
325                 set_vector_calc_function<Sum3, &Sum3::next_akk<true>, &Sum3::next_akk<false>>();
326                 return;
327 
328             case calc_ScalarRate:
329                 set_vector_calc_function<Sum3, &Sum3::next_aki<true>, &Sum3::next_aki<false>>();
330                 return;
331 
332             default:
333                 assert(false);
334             }
335 
336         case calc_ScalarRate:
337             assert(inRate(2) == calc_ScalarRate);
338             set_vector_calc_function<Sum3, &Sum3::next_aii<true>, &Sum3::next_aii<false>>();
339             return;
340 
341         default:
342             assert(false);
343         }
344     }
345 
346     template <bool SIMD, typename Arg1, typename Arg2, typename Arg3>
sum_vec__anon2eabe8300111::Sum3347     static void sum_vec(float* out, Arg1 const& arg1, Arg2 const& arg2, Arg3 const& arg3, int inNumSamples) {
348         if (SIMD)
349             nova::sum_vec_simd(out, arg1, arg2, arg3, inNumSamples);
350         else
351             nova::sum_vec(out, arg1, arg2, arg3, inNumSamples);
352     }
353 
next_scalar__anon2eabe8300111::Sum3354     void next_scalar(int inNumSamples) { out0(0) = in0(0) + in0(1) + in0(2); }
355 
next_aaa__anon2eabe8300111::Sum3356     template <bool SIMD> void next_aaa(int inNumSamples) { sum_vec<SIMD>(out(0), in(0), in(1), in(2), inNumSamples); }
357 
next_aak__anon2eabe8300111::Sum3358     template <bool SIMD> void next_aak(int inNumSamples) {
359         if (in2.changed(this))
360             sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), inNumSamples);
361         else
362             next_aai<SIMD>(inNumSamples);
363     }
364 
next_aai__anon2eabe8300111::Sum3365     template <bool SIMD> void next_aai(int inNumSamples) { sum_vec<SIMD>(out(0), in(0), in(1), in2, inNumSamples); }
366 
next_aki__anon2eabe8300111::Sum3367     template <bool SIMD> void next_aki(int inNumSamples) {
368         if (in1.changed(this))
369             sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, inNumSamples);
370         else
371             next_aii<SIMD>(inNumSamples);
372     }
373 
next_akk__anon2eabe8300111::Sum3374     template <bool SIMD> void next_akk(int inNumSamples) {
375         if (in2.changed(this)) {
376             if (in1.changed(this))
377                 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), inNumSamples);
378             else
379                 sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), inNumSamples);
380         } else
381             next_aki<SIMD>(inNumSamples);
382     }
383 
next_aii__anon2eabe8300111::Sum3384     template <bool SIMD> void next_aii(int inNumSamples) { sum_vec<SIMD>(out(0), in(0), in0(1), in0(2), inNumSamples); }
385 };
386 
387 struct Sum4 : SIMD_Unit {
388     ControlRateInput<1> in1;
389     ControlRateInput<2> in2;
390     ControlRateInput<3> in3;
391 
Sum4__anon2eabe8300111::Sum4392     Sum4(void) {
393         in1.init(this);
394         in2.init(this);
395         in3.init(this);
396 
397         if (mCalcRate != calc_FullRate) {
398             set_calc_function<Sum4, &Sum4::next_scalar>();
399             return;
400         }
401 
402         assert(inRate(0) == calc_FullRate);
403 
404         switch (inRate(1)) {
405         case calc_FullRate:
406             switch (inRate(2)) {
407             case calc_FullRate:
408                 switch (inRate(3)) {
409                 case calc_FullRate:
410                     set_vector_calc_function<Sum4, &Sum4::next_aaaa<true>, &Sum4::next_aaaa<false>>();
411                     return;
412 
413                 case calc_BufRate:
414                     set_vector_calc_function<Sum4, &Sum4::next_aaak<true>, &Sum4::next_aaak<false>>();
415                     return;
416 
417                 case calc_ScalarRate:
418                     set_vector_calc_function<Sum4, &Sum4::next_aaai<true>, &Sum4::next_aaai<false>>();
419                     return;
420 
421                 default:
422                     assert(false);
423                 }
424 
425             case calc_BufRate:
426                 switch (inRate(3)) {
427                 case calc_BufRate:
428                     set_vector_calc_function<Sum4, &Sum4::next_aakk<true>, &Sum4::next_aakk<false>>();
429                     return;
430 
431                 case calc_ScalarRate:
432                     set_vector_calc_function<Sum4, &Sum4::next_aaki<true>, &Sum4::next_aaki<false>>();
433                     return;
434 
435                 default:
436                     assert(false);
437                 }
438 
439             case calc_ScalarRate:
440                 switch (inRate(3)) {
441                 case calc_ScalarRate:
442                     set_vector_calc_function<Sum4, &Sum4::next_aaii<true>, &Sum4::next_aaii<false>>();
443                     return;
444 
445                 default:
446                     assert(false);
447                 }
448             }
449         case calc_BufRate:
450             switch (inRate(2)) {
451             case calc_BufRate:
452                 switch (inRate(3)) {
453                 case calc_BufRate:
454                     set_vector_calc_function<Sum4, &Sum4::next_akkk<true>, &Sum4::next_akkk<false>>();
455                     return;
456 
457                 case calc_ScalarRate:
458                     set_vector_calc_function<Sum4, &Sum4::next_akki<true>, &Sum4::next_akki<false>>();
459                     return;
460 
461                 default:
462                     assert(false);
463                 }
464 
465             case calc_ScalarRate:
466                 switch (inRate(3)) {
467                 case calc_ScalarRate:
468                     set_vector_calc_function<Sum4, &Sum4::next_akii<true>, &Sum4::next_akii<false>>();
469                     return;
470 
471                 default:
472                     assert(false);
473                 }
474             }
475 
476         case calc_ScalarRate:
477             switch (inRate(2)) {
478             case calc_ScalarRate:
479                 switch (inRate(3)) {
480                 case calc_ScalarRate:
481                     set_vector_calc_function<Sum4, &Sum4::next_aiii<true>, &Sum4::next_aiii<false>>();
482                     return;
483 
484                 default:
485                     assert(false);
486                 }
487 
488             default:
489                 assert(false);
490             }
491 
492         default:
493             assert(false);
494         }
495     }
496 
next_scalar__anon2eabe8300111::Sum4497     void next_scalar(int inNumSamples) { out0(0) = in0(0) + in0(1) + in0(2) + in0(3); }
498 
499     template <bool SIMD, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
sum_vec__anon2eabe8300111::Sum4500     static void sum_vec(float* out, Arg1 const& arg1, Arg2 const& arg2, Arg3 const& arg3, Arg4 const& arg4,
501                         int inNumSamples) {
502         if (SIMD)
503             nova::sum_vec_simd(out, arg1, arg2, arg3, arg4, inNumSamples);
504         else
505             nova::sum_vec(out, arg1, arg2, arg3, arg4, inNumSamples);
506     }
507 
next_aaaa__anon2eabe8300111::Sum4508     template <bool SIMD> void next_aaaa(int inNumSamples) {
509         sum_vec<SIMD>(out(0), in(0), in(1), in(2), in(3), inNumSamples);
510     }
511 
next_aaak__anon2eabe8300111::Sum4512     template <bool SIMD> void next_aaak(int inNumSamples) {
513         if (in3.changed(this))
514             sum_vec<SIMD>(out(0), in(0), in(1), in(2), in3.slope(this), inNumSamples);
515         else
516             next_aaai<SIMD>(inNumSamples);
517     }
518 
next_aaai__anon2eabe8300111::Sum4519     template <bool SIMD> void next_aaai(int inNumSamples) {
520         sum_vec<SIMD>(out(0), in(0), in(1), in(2), in3, inNumSamples);
521     }
522 
next_aakk__anon2eabe8300111::Sum4523     template <bool SIMD> void next_aakk(int inNumSamples) {
524         if (in3.changed(this)) {
525             if (in2.changed(this))
526                 sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), in3.slope(this), inNumSamples);
527             else
528                 sum_vec<SIMD>(out(0), in(0), in(1), in2, in3.slope(this), inNumSamples);
529         } else
530             next_aaki<SIMD>(inNumSamples);
531     }
532 
next_aaki__anon2eabe8300111::Sum4533     template <bool SIMD> void next_aaki(int inNumSamples) {
534         if (in2.changed(this))
535             sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), in3, inNumSamples);
536         else
537             next_aaii<SIMD>(inNumSamples);
538     }
539 
next_aaii__anon2eabe8300111::Sum4540     template <bool SIMD> void next_aaii(int inNumSamples) {
541         sum_vec<SIMD>(out(0), in(0), in(1), in2, in3, inNumSamples);
542     }
543 
next_akkk__anon2eabe8300111::Sum4544     template <bool SIMD> void next_akkk(int inNumSamples) {
545         if (in3.changed(this)) {
546             if (in2.changed(this)) {
547                 if (in1.changed(this))
548                     sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), in3.slope(this), inNumSamples);
549                 else
550                     sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), in3.slope(this), inNumSamples);
551             } else {
552                 if (in1.changed(this))
553                     sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, in3.slope(this), inNumSamples);
554                 else
555                     sum_vec<SIMD>(out(0), in(0), in1, in2, in3.slope(this), inNumSamples);
556             }
557         } else
558             next_akki<SIMD>(inNumSamples);
559     }
560 
next_akki__anon2eabe8300111::Sum4561     template <bool SIMD> void next_akki(int inNumSamples) {
562         if (in2.changed(this)) {
563             if (in1.changed(this))
564                 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), in3, inNumSamples);
565             else
566                 sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), in3, inNumSamples);
567         } else
568             next_akii<SIMD>(inNumSamples);
569     }
570 
next_akii__anon2eabe8300111::Sum4571     template <bool SIMD> void next_akii(int inNumSamples) {
572         if (in1.changed(this))
573             sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, in3, inNumSamples);
574         else
575             next_aiii<SIMD>(inNumSamples);
576     }
577 
next_aiii__anon2eabe8300111::Sum4578     template <bool SIMD> void next_aiii(int inNumSamples) { sum_vec<SIMD>(out(0), in(0), in1, in2, in3, inNumSamples); }
579 };
580 
581 }
582 
583 ////////////////////////////////////////////////////////////////////////////////////////////////////////
584 
PluginLoad(MulAdd)585 PluginLoad(MulAdd) {
586     ft = inTable;
587 
588     registerUnit<MulAdd>(ft, "MulAdd");
589     registerUnit<Sum3>(ft, "Sum3");
590     registerUnit<Sum4>(ft, "Sum4");
591 }
592