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