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