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 #pragma once
22 
23 #include "SC_BoundsMacros.h"
24 #include "SC_InlineUnaryOp.h"
25 #include <cmath>
26 
sc_mod(float in,float hi)27 inline float sc_mod(float in, float hi) {
28     // avoid the divide if possible
29     const float lo = (float)0.;
30     if (in >= hi) {
31         in -= hi;
32         if (in < hi)
33             return in;
34     } else if (in < lo) {
35         in += hi;
36         if (in >= lo)
37             return in;
38     } else
39         return in;
40 
41     if (hi == lo)
42         return lo;
43     return in - hi * sc_floor(in / hi);
44 }
45 
sc_mod(double in,double hi)46 inline double sc_mod(double in, double hi) {
47     // avoid the divide if possible
48     const double lo = (double)0.;
49     if (in >= hi) {
50         in -= hi;
51         if (in < hi)
52             return in;
53     } else if (in < lo) {
54         in += hi;
55         if (in >= lo)
56             return in;
57     } else
58         return in;
59 
60     if (hi == lo)
61         return lo;
62     return in - hi * sc_floor(in / hi);
63 }
64 
sc_wrap(float in,float lo,float hi)65 inline float sc_wrap(float in, float lo, float hi) {
66     float range;
67     // avoid the divide if possible
68     if (in >= hi) {
69         range = hi - lo;
70         in -= range;
71         if (in < hi)
72             return in;
73     } else if (in < lo) {
74         range = hi - lo;
75         in += range;
76         if (in >= lo)
77             return in;
78     } else
79         return in;
80 
81     if (hi == lo)
82         return lo;
83     return in - range * sc_floor((in - lo) / range);
84 }
85 
sc_wrap(double in,double lo,double hi)86 inline double sc_wrap(double in, double lo, double hi) {
87     double range;
88     // avoid the divide if possible
89     if (in >= hi) {
90         range = hi - lo;
91         in -= range;
92         if (in < hi)
93             return in;
94     } else if (in < lo) {
95         range = hi - lo;
96         in += range;
97         if (in >= lo)
98             return in;
99     } else
100         return in;
101 
102     if (hi == lo)
103         return lo;
104     return in - range * sc_floor((in - lo) / range);
105 }
106 
sc_wrap(double in,double lo,double hi,double range)107 inline double sc_wrap(double in, double lo, double hi, double range) {
108     // avoid the divide if possible
109     if (in >= hi) {
110         in -= range;
111         if (in < hi)
112             return in;
113     } else if (in < lo) {
114         in += range;
115         if (in >= lo)
116             return in;
117     } else
118         return in;
119 
120     if (hi == lo)
121         return lo;
122     return in - range * sc_floor((in - lo) / range);
123 }
124 
sc_wrap(float in,float lo,float hi,float range)125 inline double sc_wrap(float in, float lo, float hi, float range) {
126     // avoid the divide if possible
127     if (in >= hi) {
128         in -= range;
129         if (in < hi)
130             return in;
131     } else if (in < lo) {
132         in += range;
133         if (in >= lo)
134             return in;
135     } else
136         return in;
137 
138     if (hi == lo)
139         return lo;
140     return in - range * sc_floor((in - lo) / range);
141 }
142 
sc_fold(float in,float lo,float hi)143 inline float sc_fold(float in, float lo, float hi) {
144     float x, c, range, range2;
145     x = in - lo;
146 
147     // avoid the divide if possible
148     if (in >= hi) {
149         in = hi + hi - in;
150         if (in >= lo)
151             return in;
152     } else if (in < lo) {
153         in = lo + lo - in;
154         if (in < hi)
155             return in;
156     } else
157         return in;
158 
159     if (hi == lo)
160         return lo;
161     // ok do the divide
162     range = hi - lo;
163     range2 = range + range;
164     c = x - range2 * sc_floor(x / range2);
165     if (c >= range)
166         c = range2 - c;
167     return c + lo;
168 }
169 
sc_fold(double in,double lo,double hi)170 inline double sc_fold(double in, double lo, double hi) {
171     double x, c, range, range2;
172     x = in - lo;
173 
174     // avoid the divide if possible
175     if (in >= hi) {
176         in = hi + hi - in;
177         if (in >= lo)
178             return in;
179     } else if (in < lo) {
180         in = lo + lo - in;
181         if (in < hi)
182             return in;
183     } else
184         return in;
185 
186     if (hi == lo)
187         return lo;
188     // ok do the divide
189     range = hi - lo;
190     range2 = range + range;
191     c = x - range2 * sc_floor(x / range2);
192     if (c >= range)
193         c = range2 - c;
194     return c + lo;
195 }
196 
sc_fold(float in,float lo,float hi,float range,float range2)197 inline double sc_fold(float in, float lo, float hi, float range, float range2) {
198     float x, c;
199     x = in - lo;
200 
201     // avoid the divide if possible
202     if (in >= hi) {
203         in = hi + hi - in;
204         if (in >= lo)
205             return in;
206     } else if (in < lo) {
207         in = lo + lo - in;
208         if (in < hi)
209             return in;
210     } else
211         return in;
212 
213     if (hi == lo)
214         return lo;
215     // ok do the divide
216     c = x - range2 * sc_floor(x / range2);
217     if (c >= range)
218         c = range2 - c;
219     return c + lo;
220 }
221 
sc_fold(double in,double lo,double hi,double range,double range2)222 inline double sc_fold(double in, double lo, double hi, double range, double range2) {
223     double x, c;
224     x = in - lo;
225 
226     // avoid the divide if possible
227     if (in >= hi) {
228         in = hi + hi - in;
229         if (in >= lo)
230             return in;
231     } else if (in < lo) {
232         in = lo + lo - in;
233         if (in < hi)
234             return in;
235     } else
236         return in;
237 
238     if (hi == lo)
239         return lo;
240     // ok do the divide
241     c = x - range2 * sc_floor(x / range2);
242     if (c >= range)
243         c = range2 - c;
244     return c + lo;
245 }
246 
sc_pow(float a,float b)247 inline float sc_pow(float a, float b) { return a >= 0.f ? std::pow(a, b) : -std::pow(-a, b); }
248 
sc_pow(double a,double b)249 inline double sc_pow(double a, double b) { return a >= 0.f ? std::pow(a, b) : -std::pow(-a, b); }
250 
sc_round(float x,float quant)251 inline float sc_round(float x, float quant) { return quant == 0. ? x : sc_floor(x / quant + .5f) * quant; }
252 
sc_round(double x,double quant)253 inline double sc_round(double x, double quant) { return quant == 0. ? x : sc_floor(x / quant + .5) * quant; }
254 
sc_roundUp(float x,float quant)255 inline float sc_roundUp(float x, float quant) { return quant == 0. ? x : sc_ceil(x / quant) * quant; }
256 
sc_roundUp(double x,double quant)257 inline double sc_roundUp(double x, double quant) { return quant == 0. ? x : sc_ceil(x / quant) * quant; }
258 
sc_trunc(float x,float quant)259 inline float sc_trunc(float x, float quant) { return quant == 0. ? x : sc_floor(x / quant) * quant; }
260 
sc_trunc(double x,double quant)261 inline double sc_trunc(double x, double quant) { return quant == 0. ? x : sc_floor(x / quant) * quant; }
262 
sc_atan2(float a,float b)263 inline float sc_atan2(float a, float b) { return std::atan2(a, b); }
264 
265 const float kFSQRT2M1 = static_cast<float32>(sqrt(2.) - 1.);
266 const double kDSQRT2M1 = sqrt(2.) - 1.;
267 
sc_hypotx(float x,float y)268 inline float sc_hypotx(float x, float y) {
269     float minxy;
270 
271     x = std::abs(x);
272     y = std::abs(y);
273 
274     minxy = sc_min(x, y);
275 
276     return x + y - kFSQRT2M1 * minxy;
277 }
278 
sc_hypotx(double x,double y)279 inline double sc_hypotx(double x, double y) {
280     double minxy;
281 
282     x = std::abs(x);
283     y = std::abs(y);
284 
285     minxy = sc_min(x, y);
286 
287     return x + y - kDSQRT2M1 * minxy;
288 }
289 
sc_div(int a,int b)290 inline int sc_div(int a, int b) {
291     int c;
292     if (b) {
293         if (a < 0)
294             c = (a + 1) / b - 1;
295         else
296             c = a / b;
297     } else
298         c = a;
299     return c;
300 }
301 
302 /*
303 inline int sc_mod(int a, int b)
304 {
305     long c;
306     c = a % b;
307     if (c<0) c += b;
308     return c;
309 }
310 */
311 
sc_mod(int in,int hi)312 inline int sc_mod(int in, int hi) {
313     // avoid the divide if possible
314     const int lo = 0;
315     if (in >= hi) {
316         in -= hi;
317         if (in < hi)
318             return in;
319     } else if (in < lo) {
320         in += hi;
321         if (in >= lo)
322             return in;
323     } else
324         return in;
325 
326     if (hi == lo)
327         return lo;
328 
329     int c;
330     c = in % hi;
331     if (c < 0)
332         c += hi;
333     return c;
334 }
335 
sc_wrap(int in,int lo,int hi)336 inline int sc_wrap(int in, int lo, int hi) { return sc_mod(in - lo, hi - lo + 1) + lo; }
337 
sc_fold(int in,int lo,int hi)338 inline int sc_fold(int in, int lo, int hi) {
339     int b = hi - lo;
340     int b2 = b + b;
341     int c = sc_mod(in - lo, b2);
342     if (c > b)
343         c = b2 - c;
344     return c + lo;
345 }
346 
347 
sc_gcd(int a,int b)348 inline int sc_gcd(int a, int b) {
349     if (a == 0)
350         return b;
351 
352     if (b == 0)
353         return a;
354 
355     const bool negative = (a <= 0 && b <= 0);
356 
357     a = sc_abs(a);
358     b = sc_abs(b);
359 
360     if (a == 1 || b == 1) {
361         if (negative) {
362             return -1;
363         } else {
364             return 1;
365         }
366     }
367 
368     if (a < b) {
369         int t = a;
370         a = b;
371         b = t;
372     }
373 
374     while (b > 0) {
375         int t = a % b;
376         a = b;
377         b = t;
378     }
379 
380     if (negative) {
381         a = 0 - a;
382     }
383 
384     return a;
385 }
386 
387 
sc_lcm(int a,int b)388 inline int sc_lcm(int a, int b) {
389     if (a == 0 || b == 0)
390         return 0;
391     else
392         return (a * b) / sc_gcd(a, b);
393 }
394 
395 
sc_gcd(long a,long b)396 inline long sc_gcd(long a, long b) {
397     if (a == 0)
398         return b;
399 
400     if (b == 0)
401         return a;
402 
403     const bool negative = (a <= 0 && b <= 0);
404 
405     a = sc_abs(a);
406     b = sc_abs(b);
407 
408     if (a == 1 || b == 1) {
409         if (negative) {
410             return (long)-1;
411         } else {
412             return (long)1;
413         }
414     }
415 
416     if (a < b) {
417         long t = a;
418         a = b;
419         b = t;
420     }
421 
422     while (b > 0) {
423         long t = a % b;
424         a = b;
425         b = t;
426     }
427 
428     if (negative) {
429         a = 0 - a;
430     }
431 
432     return a;
433 }
434 
435 
sc_lcm(long a,long b)436 inline long sc_lcm(long a, long b) {
437     if (a == 0 || b == 0)
438         return (long)0;
439     else
440         return (a * b) / sc_gcd(a, b);
441 }
442 
443 
sc_gcd(float u,float v)444 inline float sc_gcd(float u, float v) { return (float)sc_gcd((long)std::trunc(u), (long)std::trunc(v)); }
445 
446 
sc_lcm(float u,float v)447 inline float sc_lcm(float u, float v) { return (float)sc_lcm((long)std::trunc(u), (long)std::trunc(v)); }
448 
449 
sc_bitAnd(int a,int b)450 inline int sc_bitAnd(int a, int b) { return a & b; }
451 
sc_bitOr(int a,int b)452 inline int sc_bitOr(int a, int b) { return a | b; }
453 
sc_leftShift(int a,int b)454 inline int sc_leftShift(int a, int b) { return a << b; }
455 
sc_rightShift(int a,int b)456 inline int sc_rightShift(int a, int b) { return a >> b; }
457 
sc_unsignedRightShift(int a,int b)458 inline int sc_unsignedRightShift(int a, int b) { return (int)((uint32)a >> b); }
459 
sc_round(int x,int quant)460 inline int sc_round(int x, int quant) { return quant == 0 ? x : sc_div(x + quant / 2, quant) * quant; }
461 
462 
sc_roundUp(int x,int quant)463 inline int sc_roundUp(int x, int quant) { return quant == 0 ? x : sc_div(x + quant - 1, quant) * quant; }
464 
sc_trunc(int x,int quant)465 inline int sc_trunc(int x, int quant) { return quant == 0 ? x : sc_div(x, quant) * quant; }
466 
sc_powi(F x,unsigned int n)467 template <typename F> inline F sc_powi(F x, unsigned int n) {
468     F z = 1;
469     while (n != 0) {
470         if ((n & 1) != 0) {
471             z *= x;
472         }
473         n >>= 1;
474         x *= x;
475     }
476 
477     return z;
478 }
479 
sc_thresh(T a,U b)480 template <typename T, typename U> inline T sc_thresh(T a, U b) { return a < b ? (T)0 : a; }
481 
sc_clip2(T a,T b)482 template <typename T> inline T sc_clip2(T a, T b) { return sc_clip(a, -b, b); }
483 
sc_wrap2(T a,T b)484 template <typename T> inline T sc_wrap2(T a, T b) { return sc_wrap(a, -b, b); }
485 
sc_fold2(T a,T b)486 template <typename T> inline T sc_fold2(T a, T b) { return sc_fold(a, -b, b); }
487 
sc_excess(T a,T b)488 template <typename T> inline T sc_excess(T a, T b) { return a - sc_clip(a, -b, b); }
489 
sc_scaleneg(T a,T b)490 template <typename T> inline T sc_scaleneg(T a, T b) {
491     if (a < 0)
492         return a * b;
493     else
494         return a;
495 }
496 
497 template <> inline float sc_scaleneg<float>(float a, float b) {
498     b = 0.5f * b + 0.5f;
499     return (std::abs(a) - a) * b + a;
500 }
501 
502 template <> inline double sc_scaleneg<double>(double a, double b) {
503     b = 0.5 * b + 0.5;
504     return (std::abs(a) - a) * b + a;
505 }
506 
sc_amclip(T a,T b)507 template <typename T> inline T sc_amclip(T a, T b) {
508     if (b < 0)
509         return 0;
510     else
511         return a * b;
512 }
513 
514 template <> inline float sc_amclip<float>(float a, float b) { return a * 0.5f * (b + std::abs(b)); }
515 
516 template <> inline double sc_amclip<double>(double a, double b) { return a * 0.5 * (b + std::abs(b)); }
517 
sc_ring1(T a,T b)518 template <typename T> inline T sc_ring1(T a, T b) { return a * b + a; }
519 
sc_ring2(T a,T b)520 template <typename T> inline T sc_ring2(T a, T b) { return a * b + a + b; }
521 
sc_ring3(T a,T b)522 template <typename T> inline T sc_ring3(T a, T b) { return a * a * b; }
523 
sc_ring4(T a,T b)524 template <typename T> inline T sc_ring4(T a, T b) { return a * a * b - a * b * b; }
525 
sc_difsqr(T a,T b)526 template <typename T> inline T sc_difsqr(T a, T b) { return a * a - b * b; }
527 
sc_sumsqr(T a,T b)528 template <typename T> inline T sc_sumsqr(T a, T b) { return a * a + b * b; }
529 
sc_sqrsum(T a,T b)530 template <typename T> inline T sc_sqrsum(T a, T b) {
531     T z = a + b;
532     return z * z;
533 }
534 
sc_sqrdif(T a,T b)535 template <typename T> inline T sc_sqrdif(T a, T b) {
536     T z = a - b;
537     return z * z;
538 }
539 
540 #if 0
541 
542 inline long sc_div(long a, long b)
543 {
544 	int c;
545 	if (b) {
546 		if (a<0) c = (a+1)/b - 1;
547 		else c = a/b;
548 	} else c = a;
549 	return c;
550 }
551 
552 
553 inline long sc_wrap(long in, long lo, long hi)
554 {
555 	return sc_mod(in - lo, hi - lo + 1) + lo;
556 }
557 
558 inline long sc_fold(long in, long lo, long hi)
559 {
560 	long b = hi - lo;
561 	int b2 = b+b;
562 	long c = sc_mod(in - lo, b2);
563 	if (c>b) c = b2-c;
564 	return c + lo;
565 }
566 
567 inline long sc_bitAnd(long a, long b)
568 {
569 	return a & b;
570 }
571 
572 inline long sc_bitOr(long a, long b)
573 {
574 	return a | b;
575 }
576 
577 inline long sc_leftShift(long a, long b)
578 {
579 	return a << b;
580 }
581 
582 inline long sc_rightShift(long a, long b)
583 {
584 	return a >> b;
585 }
586 
587 inline long sc_unsignedRightShift(long a, long b)
588 {
589 	return (unsigned long)a >> b;
590 }
591 
592 inline long sc_round(long x, long quant)
593 {
594 	return quant==0 ? x : sc_div(x + quant/2, quant) * quant;
595 }
596 
597 #endif
598