Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / server / plugins / MulAddUGens.cpp
blob2b80fc3a64396d068a5425a5d103cd8fec7d5379
1 /*
2 SuperCollider real time audio synthesis system
3 Copyright (c) 2002 James McCartney. All rights reserved.
4 http://www.audiosynth.com
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.
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.
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
22 #include "SC_PlugIn.hpp"
23 #include "SIMD_Unit.hpp"
25 static InterfaceTable *ft;
27 namespace {
29 struct MulAdd:
30 SIMD_Unit
32 ControlRateInput<1> mMul;
33 ControlRateInput<2> mAdd;
35 #define MULADD_CALCFUNC(METHOD_NAME) \
36 do { \
37 set_unrolled_calc_function<MulAdd, \
38 &MulAdd::METHOD_NAME<unrolled_64>, \
39 &MulAdd::METHOD_NAME<unrolled>, \
40 &MulAdd::METHOD_NAME<scalar> >(); \
41 return; \
42 } while (0)
44 MulAdd(void)
46 mMul.init(this);
47 mAdd.init(this);
49 if (mCalcRate != calc_FullRate) {
50 set_calc_function<MulAdd, &MulAdd::next_scalar>();
51 return;
54 assert(inRate(0) == calc_FullRate);
56 switch (inRate(1)) {
57 case calc_FullRate:
58 switch (inRate(2)) {
59 case calc_FullRate:
60 MULADD_CALCFUNC(next_aa);
62 case calc_BufRate:
63 MULADD_CALCFUNC(next_ak);
65 case calc_ScalarRate:
66 if (mAdd == 0.f)
67 MULADD_CALCFUNC(next_a0);
68 else
69 MULADD_CALCFUNC(next_ai);
71 default:
72 assert(false);
75 case calc_BufRate:
76 switch (inRate(2)) {
77 case calc_FullRate:
78 MULADD_CALCFUNC(next_ka);
80 case calc_BufRate:
81 MULADD_CALCFUNC(next_kk);
83 case calc_ScalarRate:
84 if (mAdd == 0.f)
85 MULADD_CALCFUNC(next_k0);
86 else
87 MULADD_CALCFUNC(next_ki);
89 default:
90 assert(false);
93 case calc_ScalarRate:
94 switch (inRate(2)) {
95 case calc_FullRate:
96 if (mMul == 1.0)
97 MULADD_CALCFUNC(next_1a);
98 else if (mMul == 0.f)
99 MULADD_CALCFUNC(next_0a);
100 else
101 MULADD_CALCFUNC(next_ia);
103 case calc_BufRate:
104 if (mMul == 1.0)
105 MULADD_CALCFUNC(next_1k);
106 else if (mMul == 0.f)
107 MULADD_CALCFUNC(next_0k);
108 else
109 MULADD_CALCFUNC(next_ik);
111 case calc_ScalarRate:
112 if (mMul == 1.0) {
113 if (mAdd == 0)
114 MULADD_CALCFUNC(next_10);
115 else
116 MULADD_CALCFUNC(next_1i);
119 else if (mMul == 0.f) {
120 if (mAdd == 0.f)
121 MULADD_CALCFUNC(next_00);
122 else
123 MULADD_CALCFUNC(next_0i);
125 else {
126 if (mAdd == 0.f)
127 MULADD_CALCFUNC(next_i0);
128 else
129 MULADD_CALCFUNC(next_ii);
132 default:
133 assert(false);
136 default:
137 assert(false);
141 inline bool mulChanged(void) const
143 return mMul.changed(this);
146 inline bool addChanged(void) const
148 return mAdd.changed(this);
151 #if __cplusplus <= 199711L
152 nova::detail::scalar_ramp_argument<float> mulSlope(void)
153 #else
154 decltype(nova::slope_argument(0.f, 0.f)) mulSlope(void)
155 #endif
157 return mMul.slope(this);
160 #if __cplusplus <= 199711L
161 nova::detail::scalar_ramp_argument<float> addSlope(void)
162 #else
163 decltype(nova::slope_argument(0.f, 0.f)) addSlope(void)
164 #endif
166 return mAdd.slope(this);
169 void next_scalar(int inNumSamples)
171 out0(0) = (in0(0) * in0(1)) + in0(2);
174 template <int SIMD>
175 void next_aa(int inNumSamples)
177 muladd<SIMD>(out(0), in(0), in(1), in(2), inNumSamples);
180 template <int SIMD>
181 void next_ak(int inNumSamples)
183 if (addChanged())
184 muladd<SIMD>(out(0), in(0), in(1), addSlope(), inNumSamples);
185 else {
186 if (mAdd == 0.f)
187 times_vec<SIMD>(out(0), in(0), in(1), inNumSamples);
188 else
189 next_ai<SIMD>(inNumSamples);
193 template <int SIMD>
194 void next_ai(int inNumSamples)
196 muladd<SIMD>(out(0), in(0), in(1), mAdd, inNumSamples);
199 template <int SIMD>
200 void next_ka(int inNumSamples)
202 if (mulChanged())
203 muladd<SIMD>(out(0), in(0), mulSlope(), in(2), inNumSamples);
204 else
205 next_ia<SIMD>(inNumSamples);
208 template <int SIMD>
209 void next_kk(int inNumSamples)
211 if (addChanged()) {
212 if (mulChanged())
213 muladd<SIMD>(out(0), in(0), mulSlope(), addSlope(), inNumSamples);
214 else {
215 if (mMul == 0)
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);
222 } else
223 next_ki<SIMD>(inNumSamples);
226 template <int SIMD>
227 void next_ki(int inNumSamples)
229 if (mulChanged())
230 muladd<SIMD>(out(0), in(0), mulSlope(), mAdd, inNumSamples);
231 else
232 next_ii<SIMD>(inNumSamples);
235 template <int SIMD>
236 void next_ia(int inNumSamples)
238 if (mMul == 0)
239 next_0a<SIMD>(inNumSamples);
240 else if (mMul == 1.0)
241 next_1a<SIMD>(inNumSamples);
242 else
243 muladd<SIMD>(out(0), in(0), mMul, in(2), inNumSamples);
246 template <int SIMD>
247 void next_ik(int inNumSamples)
249 if (addChanged()) {
250 if (mMul == 0.f)
251 slope_vec<SIMD>(out(0), addSlope(), inNumSamples);
252 else if (mMul == 1.f)
253 plus_vec<SIMD>(out(0), in(0), addSlope(), inNumSamples);
254 else
255 muladd<SIMD>(out(0), in(0), mMul, addSlope(), inNumSamples);
256 } else
257 next_ii<SIMD>(inNumSamples);
260 template <int SIMD>
261 void next_ii(int inNumSamples)
263 if (mMul == 0)
264 next_0i<SIMD>(inNumSamples);
265 else if (mMul == 1.f) {
266 next_1i<SIMD>(inNumSamples);
267 } else {
268 if (mAdd == 0)
269 times_vec<SIMD>(out(0), in(0), mMul, inNumSamples);
270 else
271 muladd<SIMD>(out(0), in(0), mMul, mAdd, inNumSamples);
275 template <int SIMD>
276 void next_1a(int inNumSamples)
278 plus_vec<SIMD>(out(0), in(0), in(2), inNumSamples);
281 template <int SIMD>
282 void next_1k(int inNumSamples)
284 if (addChanged())
285 plus_vec<SIMD>(out(0), in(0), addSlope(), inNumSamples);
286 else
287 next_1i<SIMD>(inNumSamples);
290 template <int SIMD>
291 void next_1i(int inNumSamples)
293 if (mAdd == 0)
294 copy_vec<SIMD>(out(0), in(0), inNumSamples);
295 else
296 plus_vec<SIMD>(out(0), in(0), mAdd, inNumSamples);
299 template <int SIMD>
300 void next_0a(int inNumSamples)
302 copy_vec<SIMD>(out(0), in(2), inNumSamples);
305 template <int SIMD>
306 void next_0k(int inNumSamples)
308 if (addChanged())
309 slope_vec<SIMD>(out(0), addSlope(), inNumSamples);
310 else
311 next_0i<SIMD>(inNumSamples);
314 template <int SIMD>
315 void next_0i(int inNumSamples)
317 set_vec<SIMD>(out(0), mAdd, inNumSamples);
320 template <int SIMD>
321 void next_a0(int inNumSamples)
323 times_vec<SIMD>(out(0), in(0), in(1), inNumSamples);
326 template <int SIMD>
327 void next_k0(int inNumSamples)
329 if (mulChanged())
330 times_vec<SIMD>(out(0), in(0), mulSlope(), inNumSamples);
331 else
332 next_ik<SIMD>(inNumSamples);
335 template <int SIMD>
336 void next_i0(int inNumSamples)
338 if (mMul == 0.f)
339 next_00<SIMD>(inNumSamples);
340 else if (mMul == 1.f)
341 next_10<SIMD>(inNumSamples);
342 else
343 times_vec<SIMD>(out(0), in(0), mMul, inNumSamples);
346 template <int SIMD>
347 void next_10(int inNumSamples)
349 copy_vec<SIMD>(out(0), in(0), inNumSamples);
352 template <int SIMD>
353 void next_00(int inNumSamples)
355 set_vec<SIMD>(out(0), 0.f, inNumSamples);
359 DEFINE_XTORS(MulAdd)
361 struct Sum3:
362 SIMD_Unit
364 ControlRateInput<1> in1;
365 ControlRateInput<2> in2;
367 Sum3(void)
369 in1.init(this);
370 in2.init(this);
372 if (mCalcRate != calc_FullRate) {
373 set_calc_function<Sum3, &Sum3::next_scalar>();
374 return;
377 assert(inRate(0) == calc_FullRate);
379 switch (inRate(1)) {
380 case calc_FullRate:
381 switch (inRate(2)) {
382 case calc_FullRate:
383 set_vector_calc_function<Sum3, &Sum3::next_aaa<true>, &Sum3::next_aaa<false> >();
384 return;
386 case calc_BufRate:
387 set_vector_calc_function<Sum3, &Sum3::next_aak<true>, &Sum3::next_aak<false> >();
388 return;
390 case calc_ScalarRate:
391 set_vector_calc_function<Sum3, &Sum3::next_aai<true>, &Sum3::next_aai<false> >();
392 return;
394 default:
395 assert(false);
398 case calc_BufRate:
399 switch (inRate(2)) {
400 case calc_BufRate:
401 set_vector_calc_function<Sum3, &Sum3::next_akk<true>, &Sum3::next_akk<false> >();
402 return;
404 case calc_ScalarRate:
405 set_vector_calc_function<Sum3, &Sum3::next_aki<true>, &Sum3::next_aki<false> >();
406 return;
408 default:
409 assert(false);
412 case calc_ScalarRate:
413 assert (inRate(2) == calc_ScalarRate);
414 set_vector_calc_function<Sum3, &Sum3::next_aii<true>, &Sum3::next_aii<false> >();
415 return;
417 default:
418 assert(false);
422 template <bool SIMD, typename Arg1, typename Arg2, typename Arg3>
423 static void sum_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, Arg3 const & arg3, int inNumSamples)
425 if (SIMD)
426 nova::sum_vec_simd(out, arg1, arg2, arg3, inNumSamples);
427 else
428 nova::sum_vec(out, arg1, arg2, arg3, inNumSamples);
431 void next_scalar(int inNumSamples)
433 out0(0) = in0(0) + in0(1) + in0(2);
436 template <bool SIMD>
437 void next_aaa(int inNumSamples)
439 sum_vec<SIMD>(out(0), in(0), in(1), in(2), inNumSamples);
442 template <bool SIMD>
443 void next_aak(int inNumSamples)
445 if (in2.changed(this))
446 sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), inNumSamples);
447 else
448 next_aai<SIMD>(inNumSamples);
451 template <bool SIMD>
452 void next_aai(int inNumSamples)
454 sum_vec<SIMD>(out(0), in(0), in(1), in2, inNumSamples);
457 template <bool SIMD>
458 void next_aki(int inNumSamples)
460 if (in1.changed(this))
461 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, inNumSamples);
462 else
463 next_aii<SIMD>(inNumSamples);
466 template <bool SIMD>
467 void next_akk(int inNumSamples)
469 if (in2.changed(this)) {
470 if (in1.changed(this))
471 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), inNumSamples);
472 else
473 sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), inNumSamples);
474 } else
475 next_aki<SIMD>(inNumSamples);
478 template <bool SIMD>
479 void next_aii(int inNumSamples)
481 sum_vec<SIMD>(out(0), in(0), in0(1), in0(2), inNumSamples);
485 DEFINE_XTORS(Sum3)
487 struct Sum4:
488 SIMD_Unit
490 ControlRateInput<1> in1;
491 ControlRateInput<2> in2;
492 ControlRateInput<3> in3;
494 Sum4(void)
496 in1.init(this);
497 in2.init(this);
498 in3.init(this);
500 if (mCalcRate != calc_FullRate) {
501 set_calc_function<Sum4, &Sum4::next_scalar>();
502 return;
505 assert(inRate(0) == calc_FullRate);
507 switch (inRate(1)) {
508 case calc_FullRate:
509 switch (inRate(2)) {
510 case calc_FullRate:
511 switch (inRate(3)) {
512 case calc_FullRate:
513 set_vector_calc_function<Sum4, &Sum4::next_aaaa<true>, &Sum4::next_aaaa<false> >();
514 return;
516 case calc_BufRate:
517 set_vector_calc_function<Sum4, &Sum4::next_aaak<true>, &Sum4::next_aaak<false> >();
518 return;
520 case calc_ScalarRate:
521 set_vector_calc_function<Sum4, &Sum4::next_aaai<true>, &Sum4::next_aaai<false> >();
522 return;
524 default:
525 assert(false);
528 case calc_BufRate:
529 switch (inRate(3)) {
530 case calc_BufRate:
531 set_vector_calc_function<Sum4, &Sum4::next_aakk<true>, &Sum4::next_aakk<false> >();
532 return;
534 case calc_ScalarRate:
535 set_vector_calc_function<Sum4, &Sum4::next_aaki<true>, &Sum4::next_aaki<false> >();
536 return;
538 default:
539 assert(false);
542 case calc_ScalarRate:
543 switch (inRate(3)) {
544 case calc_ScalarRate:
545 set_vector_calc_function<Sum4, &Sum4::next_aaii<true>, &Sum4::next_aaii<false> >();
546 return;
548 default:
549 assert(false);
552 case calc_BufRate:
553 switch (inRate(2)) {
554 case calc_BufRate:
555 switch (inRate(3)) {
556 case calc_BufRate:
557 set_vector_calc_function<Sum4, &Sum4::next_akkk<true>, &Sum4::next_akkk<false> >();
558 return;
560 case calc_ScalarRate:
561 set_vector_calc_function<Sum4, &Sum4::next_akki<true>, &Sum4::next_akki<false> >();
562 return;
564 default:
565 assert(false);
568 case calc_ScalarRate:
569 switch (inRate(3)) {
570 case calc_ScalarRate:
571 set_vector_calc_function<Sum4, &Sum4::next_akii<true>, &Sum4::next_akii<false> >();
572 return;
574 default:
575 assert(false);
579 case calc_ScalarRate:
580 switch (inRate(2)) {
581 case calc_ScalarRate:
582 switch (inRate(3)) {
583 case calc_ScalarRate:
584 set_vector_calc_function<Sum4, &Sum4::next_aiii<true>, &Sum4::next_aiii<false> >();
585 return;
587 default:
588 assert(false);
591 default:
592 assert(false);
595 default:
596 assert(false);
600 void next_scalar(int inNumSamples)
602 out0(0) = in0(0) + in0(1) + in0(2) + in0(3);
605 template <bool SIMD, typename Arg1, typename Arg2, typename Arg3, typename Arg4>
606 static void sum_vec(float * out, Arg1 const & arg1, Arg2 const & arg2, Arg3 const & arg3, Arg4 const & arg4, int inNumSamples)
608 if (SIMD)
609 nova::sum_vec_simd(out, arg1, arg2, arg3, arg4, inNumSamples);
610 else
611 nova::sum_vec(out, arg1, arg2, arg3, arg4, inNumSamples);
614 template <bool SIMD>
615 void next_aaaa(int inNumSamples)
617 sum_vec<SIMD>(out(0), in(0), in(1), in(2), in(3), inNumSamples);
620 template <bool SIMD>
621 void next_aaak(int inNumSamples)
623 if (in3.changed(this))
624 sum_vec<SIMD>(out(0), in(0), in(1), in(2), in3.slope(this), inNumSamples);
625 else
626 next_aaai<SIMD>(inNumSamples);
629 template <bool SIMD>
630 void next_aaai(int inNumSamples)
632 sum_vec<SIMD>(out(0), in(0), in(1), in(2), in3, inNumSamples);
635 template <bool SIMD>
636 void next_aakk(int inNumSamples)
638 if (in3.changed(this)) {
639 if (in2.changed(this))
640 sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), in3.slope(this), inNumSamples);
641 else
642 sum_vec<SIMD>(out(0), in(0), in(1), in2, in3.slope(this), inNumSamples);
643 } else
644 next_aaki<SIMD>(inNumSamples);
647 template <bool SIMD>
648 void next_aaki(int inNumSamples)
650 if (in2.changed(this))
651 sum_vec<SIMD>(out(0), in(0), in(1), in2.slope(this), in3, inNumSamples);
652 else
653 next_aaii<SIMD>(inNumSamples);
656 template <bool SIMD>
657 void next_aaii(int inNumSamples)
659 sum_vec<SIMD>(out(0), in(0), in(1), in2, in3, inNumSamples);
662 template <bool SIMD>
663 void next_akkk(int inNumSamples)
665 if (in3.changed(this)) {
666 if (in2.changed(this)) {
667 if (in1.changed(this))
668 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), in3.slope(this), inNumSamples);
669 else
670 sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), in3.slope(this), inNumSamples);
671 } else {
672 if (in1.changed(this))
673 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, in3.slope(this), inNumSamples);
674 else
675 sum_vec<SIMD>(out(0), in(0), in1, in2, in3.slope(this), inNumSamples);
677 } else
678 next_akki<SIMD>(inNumSamples);
681 template <bool SIMD>
682 void next_akki(int inNumSamples)
684 if (in2.changed(this)) {
685 if (in1.changed(this))
686 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2.slope(this), in3, inNumSamples);
687 else
688 sum_vec<SIMD>(out(0), in(0), in1, in2.slope(this), in3, inNumSamples);
689 } else
690 next_akii<SIMD>(inNumSamples);
693 template <bool SIMD>
694 void next_akii(int inNumSamples)
696 if (in1.changed(this))
697 sum_vec<SIMD>(out(0), in(0), in1.slope(this), in2, in3, inNumSamples);
698 else
699 next_aiii<SIMD>(inNumSamples);
702 template <bool SIMD>
703 void next_aiii(int inNumSamples)
705 sum_vec<SIMD>(out(0), in(0), in1, in2, in3, inNumSamples);
709 DEFINE_XTORS(Sum4)
713 ////////////////////////////////////////////////////////////////////////////////////////////////////////
715 PluginLoad(MulAdd)
717 ft = inTable;
719 DefineSimpleUnit(MulAdd);
720 DefineSimpleUnit(Sum3);
721 DefineSimpleUnit(Sum4);