Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Math / SimpleNumber.sc
blobc5e4acde75c70adaa5a0b14f2bad045b4ca58b6f
1 SimpleNumber : Number {
3         *new { ^this.shouldNotImplement(thisMethod) }
5         isValidUGenInput { ^this.isNaN.not }
6         numChannels { ^1 }
8         magnitude { ^this.abs }
9         angle { if (this >= 0, {^0.0}, {^pi} ) }
12         neg { _Neg; ^this.primitiveFailed }
13         bitNot { _BitNot; ^this.primitiveFailed }
14         abs { _Abs; ^this.primitiveFailed }
15         ceil { _Ceil; ^this.primitiveFailed }
16         floor { _Floor; ^this.primitiveFailed }
17         frac { _Frac; ^this.primitiveFailed }
18         sign { _Sign; ^this.primitiveFailed }
19         squared { _Squared; ^this.primitiveFailed }
20         cubed { _Cubed; ^this.primitiveFailed }
21         sqrt { _Sqrt; ^this.primitiveFailed }
22         exp { _Exp; ^this.primitiveFailed }
23         reciprocal { _Recip; ^this.primitiveFailed }
24         midicps { _MIDICPS; ^this.primitiveFailed }
25         cpsmidi { _CPSMIDI; ^this.primitiveFailed }
26         midiratio { _MIDIRatio; ^this.primitiveFailed }
27         ratiomidi { _RatioMIDI; ^this.primitiveFailed }
28         ampdb { _AmpDb; ^this.primitiveFailed }
29         dbamp { _DbAmp; ^this.primitiveFailed }
30         octcps { _OctCPS; ^this.primitiveFailed }
31         cpsoct { _CPSOct; ^this.primitiveFailed }
32         log { _Log; ^this.primitiveFailed }
33         log2 { _Log2; ^this.primitiveFailed }
34         log10 { _Log10; ^this.primitiveFailed }
35         sin { _Sin; ^this.primitiveFailed }
36         cos { _Cos; ^this.primitiveFailed }
37         tan { _Tan; ^this.primitiveFailed }
38         asin { _ArcSin; ^this.primitiveFailed }
39         acos { _ArcCos; ^this.primitiveFailed }
40         atan { _ArcTan; ^this.primitiveFailed }
41         sinh { _SinH; ^this.primitiveFailed }
42         cosh { _CosH; ^this.primitiveFailed }
43         tanh { _TanH; ^this.primitiveFailed }
44         rand { _Rand; ^this.primitiveFailed }
45         rand2 { _Rand2; ^this.primitiveFailed }
46         linrand { _LinRand; ^this.primitiveFailed }
47         bilinrand { _BiLinRand; ^this.primitiveFailed }
48         sum3rand { _Sum3Rand; ^this.primitiveFailed }
50         distort { _Distort; ^this.primitiveFailed }
51         softclip { _SoftClip; ^this.primitiveFailed }
52         coin { _Coin; ^this.primitiveFailed }
53         isPositive { ^this >= 0 }
54         isNegative { ^this < 0 }
55         isStrictlyPositive { ^this > 0 }
56         isNaN { ^(this >= 0 or: { this <= 0 }).not }
57         asBoolean    { ^this > 0 }
58         booleanValue { ^this > 0 } // TODO in the long-run, deprecate for asBoolean
59         binaryValue { ^this.sign.max(0) } // TODO in the long-run, deprecate for asInteger
61         rectWindow { _RectWindow; ^this.primitiveFailed }
62         hanWindow { _HanWindow; ^this.primitiveFailed }
63         welWindow { _WelchWindow; ^this.primitiveFailed }
64         triWindow { _TriWindow; ^this.primitiveFailed }
66         scurve { _SCurve; ^this.primitiveFailed }
67         ramp { _Ramp; ^this.primitiveFailed }
69         + { arg aNumber, adverb; _Add; ^aNumber.performBinaryOpOnSimpleNumber('+', this, adverb) }
70         - { arg aNumber, adverb; _Sub; ^aNumber.performBinaryOpOnSimpleNumber('-', this, adverb) }
71         * { arg aNumber, adverb; _Mul; ^aNumber.performBinaryOpOnSimpleNumber('*', this, adverb) }
72         / { arg aNumber, adverb; _FDiv; ^aNumber.performBinaryOpOnSimpleNumber('/', this, adverb) }
73         mod { arg aNumber, adverb; _Mod; ^aNumber.performBinaryOpOnSimpleNumber('mod', this, adverb) }
74         div { arg aNumber, adverb; _IDiv; ^aNumber.performBinaryOpOnSimpleNumber('div', this, adverb) }
75         pow { arg aNumber, adverb; _Pow; ^aNumber.performBinaryOpOnSimpleNumber('pow', this, adverb) }
76         min { arg aNumber, adverb; _Min; ^aNumber.performBinaryOpOnSimpleNumber('min', this, adverb) }
77         max { arg aNumber=0.0, adverb; _Max; ^aNumber.performBinaryOpOnSimpleNumber('max', this, adverb) }
78         bitAnd { arg aNumber, adverb; _BitAnd; ^aNumber.performBinaryOpOnSimpleNumber('bitAnd', this, adverb) }
79         bitOr { arg aNumber, adverb; _BitOr; ^aNumber.performBinaryOpOnSimpleNumber('bitOr', this, adverb) }
80         bitXor { arg aNumber, adverb; _BitXor; ^aNumber.performBinaryOpOnSimpleNumber('bitXor', this, adverb) }
81         bitHammingDistance { arg aNumber, adverb; _HammingDistance  ^aNumber.performBinaryOpOnSimpleNumber('hammingDistance', this, adverb) }
82         bitTest { arg bit; ^( (this & 1.leftShift(bit)) != 0) }
83         lcm { arg aNumber, adverb; _LCM; ^aNumber.performBinaryOpOnSimpleNumber('lcm', this, adverb) }
84         gcd { arg aNumber, adverb; _GCD; ^aNumber.performBinaryOpOnSimpleNumber('gcd', this, adverb) }
85         round { arg aNumber=1.0, adverb; _Round; ^aNumber.performBinaryOpOnSimpleNumber('round', this, adverb) }
86         roundUp { arg aNumber=1.0, adverb; _RoundUp; ^aNumber.performBinaryOpOnSimpleNumber('roundUp', this, adverb) }
87         trunc { arg aNumber=1.0, adverb; _Trunc; ^aNumber.performBinaryOpOnSimpleNumber('trunc', this, adverb) }
88         atan2 { arg aNumber, adverb; _Atan2; ^aNumber.performBinaryOpOnSimpleNumber('atan2', this, adverb) }
89         hypot { arg aNumber, adverb; _Hypot; ^aNumber.performBinaryOpOnSimpleNumber('hypot', this, adverb) }
90         hypotApx { arg aNumber, adverb; _HypotApx; ^aNumber.performBinaryOpOnSimpleNumber('hypotApx', this, adverb) }
91         leftShift { arg aNumber=1, adverb; _ShiftLeft; ^aNumber.performBinaryOpOnSimpleNumber('leftShift', this, adverb) }
92         rightShift { arg aNumber=1, adverb; _ShiftRight; ^aNumber.performBinaryOpOnSimpleNumber('rightShift', this, adverb) }
93         unsignedRightShift { arg aNumber, adverb; _UnsignedShift; ^aNumber.performBinaryOpOnSimpleNumber('unsignedRightShift', this, adverb) }
94         ring1 { arg aNumber, adverb; _Ring1; ^aNumber.performBinaryOpOnSimpleNumber('ring1', this, adverb) }
95         ring2 { arg aNumber, adverb; _Ring2; ^aNumber.performBinaryOpOnSimpleNumber('ring2', this, adverb) }
96         ring3 { arg aNumber, adverb; _Ring3; ^aNumber.performBinaryOpOnSimpleNumber('ring3', this, adverb) }
97         ring4 { arg aNumber, adverb; _Ring4; ^aNumber.performBinaryOpOnSimpleNumber('ring4', this, adverb) }
98         difsqr { arg aNumber, adverb; _DifSqr; ^aNumber.performBinaryOpOnSimpleNumber('difsqr', this, adverb) }
99         sumsqr { arg aNumber, adverb; _SumSqr; ^aNumber.performBinaryOpOnSimpleNumber('sumsqr', this, adverb) }
100         sqrsum { arg aNumber, adverb; _SqrSum; ^aNumber.performBinaryOpOnSimpleNumber('sqrsum', this, adverb) }
101         sqrdif { arg aNumber, adverb; _SqrDif; ^aNumber.performBinaryOpOnSimpleNumber('sqrdif', this, adverb) }
102         absdif { arg aNumber, adverb; _AbsDif; ^aNumber.performBinaryOpOnSimpleNumber('absdif', this, adverb) }
103         thresh { arg aNumber, adverb; _Thresh; ^aNumber.performBinaryOpOnSimpleNumber('thresh', this, adverb) }
104         amclip { arg aNumber, adverb; _AMClip; ^aNumber.performBinaryOpOnSimpleNumber('amclip', this, adverb) }
105         scaleneg { arg aNumber, adverb; _ScaleNeg; ^aNumber.performBinaryOpOnSimpleNumber('scaleneg', this, adverb) }
106         clip2 { arg aNumber, adverb; _Clip2; ^aNumber.performBinaryOpOnSimpleNumber('clip2', this, adverb) }
107         fold2 { arg aNumber, adverb; _Fold2; ^aNumber.performBinaryOpOnSimpleNumber('fold2', this, adverb) }
108         wrap2 { arg aNumber, adverb; _Wrap2; ^aNumber.performBinaryOpOnSimpleNumber('wrap2', this, adverb) }
110         excess { arg aNumber, adverb; _Excess; ^aNumber.performBinaryOpOnSimpleNumber('excess', this, adverb) }
111         firstArg { arg aNumber, adverb; _FirstArg; ^aNumber.performBinaryOpOnSimpleNumber('firstArg', this, adverb) }
112         rrand { arg aNumber, adverb; _RandRange; ^aNumber.performBinaryOpOnSimpleNumber('rrand', this, adverb) }
113         exprand { arg aNumber, adverb; _ExpRandRange; ^aNumber.performBinaryOpOnSimpleNumber('exprand', this, adverb) }
115         == { arg aNumber, adverb; _EQ; ^aNumber.perform('==', this, adverb) }
116         != { arg aNumber, adverb; _NE; ^aNumber.perform('!=', this, adverb) }
117         < { arg aNumber, adverb; _LT; ^aNumber.performBinaryOpOnSimpleNumber('<', this, adverb) }
118         > { arg aNumber, adverb; _GT; ^aNumber.performBinaryOpOnSimpleNumber('>', this, adverb) }
119         <= { arg aNumber, adverb; _LE; ^aNumber.performBinaryOpOnSimpleNumber('<=', this, adverb) }
120         >= { arg aNumber, adverb; _GE; ^aNumber.performBinaryOpOnSimpleNumber('>=', this, adverb) }
122         equalWithPrecision { arg that, precision=0.0001;
123                 ^absdif(this, that) < precision
124         }
126         hash { _ObjectHash; ^this.primitiveFailed }
128         asInteger { _AsInt; ^this.primitiveFailed }
129         asFloat { _AsFloat; ^this.primitiveFailed }
130         asComplex { ^Complex.new(this, 0.0) }
131         asRect { ^Rect(this, this, this, this) }
133         degrad { ^this*pi/180 }
134         raddeg { ^this*180/pi }
136         performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb;
137                  BinaryOpFailureError(this, aSelector, [aNumber, adverb]).throw;
138         }
139         performBinaryOpOnComplex { arg aSelector, aComplex, adverb; ^aComplex.perform(aSelector, this.asComplex, adverb) }
140         performBinaryOpOnSignal { arg aSelector, aSignal, adverb;
141                 BinaryOpFailureError(this, aSelector, [aSignal, adverb]).throw;
142         }
144         nextPowerOfTwo { ^this.nextPowerOf(2) }
145         nextPowerOf { arg base; ^pow(base, ceil(log(this) / log(base))) }
146         nextPowerOfThree { ^pow(3, ceil(log(this) / log(3))) }
147         previousPowerOf { arg base; ^pow(base, ceil(log(this) / log(base)) - 1) }
149         quantize { arg quantum = 1.0, tolerance = 0.05, strength = 1.0;
150                 var round = round(this, quantum);
151                 var diff = round - this;
152                 if (abs(diff) < tolerance) {
153                         ^this + (strength * diff)
154                 }{
155                         ^this
156                 }
157         }
160         linlin { arg inMin, inMax, outMin, outMax, clip=\minmax;
161                 // linear to linear mapping
162                 switch(clip,
163                         \minmax, {
164                                 if (this <= inMin, { ^outMin });
165                                 if (this >= inMax, { ^outMax });
166                         },
167                         \min, {
168                                 if (this <= inMin, { ^outMin });
169                         },
170                         \max, {
171                                 if (this >= inMax, { ^outMax });
172                         }
173                 );
174                 ^(this-inMin)/(inMax-inMin) * (outMax-outMin) + outMin;
175         }
177         linexp { arg inMin, inMax, outMin, outMax, clip=\minmax;
178                 // linear to exponential mapping
179                 switch(clip,
180                         \minmax, {
181                                 if (this <= inMin, { ^outMin });
182                                 if (this >= inMax, { ^outMax });
183                         },
184                         \min, {
185                                 if (this <= inMin, { ^outMin });
186                         },
187                         \max, {
188                                 if (this >= inMax, { ^outMax });
189                         }
190                 );
191                 ^pow(outMax/outMin, (this-inMin)/(inMax-inMin)) * outMin
192         }
194         explin { arg inMin, inMax, outMin, outMax, clip=\minmax;
195                 // exponential to linear mapping
196                 switch(clip,
197                         \minmax, {
198                                 if (this <= inMin, { ^outMin });
199                                 if (this >= inMax, { ^outMax });
200                         },
201                         \min, {
202                                 if (this <= inMin, { ^outMin });
203                         },
204                         \max, {
205                                 if (this >= inMax, { ^outMax });
206                         }
207                 );
208                 ^(log(this/inMin)) / (log(inMax/inMin)) * (outMax-outMin) + outMin;
209         }
211         expexp { arg inMin, inMax, outMin, outMax, clip=\minmax;
212                 // exponential to exponential mapping
213                 switch(clip,
214                         \minmax, {
215                                 if (this <= inMin, { ^outMin });
216                                 if (this >= inMax, { ^outMax });
217                         },
218                         \min, {
219                                 if (this <= inMin, { ^outMin });
220                         },
221                         \max, {
222                                 if (this >= inMax, { ^outMax });
223                         }
224                 );
225                 ^pow(outMax/outMin, log(this/inMin) / log(inMax/inMin)) * outMin;
226         }
228         lincurve { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax;
229                 var grow, a, b, scaled;
230                 switch(clip,
231                         \minmax, {
232                                 if (this <= inMin, { ^outMin });
233                                 if (this >= inMax, { ^outMax });
234                         },
235                         \min, {
236                                 if (this <= inMin, { ^outMin });
237                         },
238                         \max, {
239                                 if (this >= inMax, { ^outMax });
240                         }
241                 );
242                 if (abs(curve) < 0.001) { ^this.linlin(inMin, inMax, outMin, outMax) };
244                 grow = exp(curve);
245                 a = outMax - outMin / (1.0 - grow);
246                 b = outMin + a;
247                 scaled = (this - inMin) / (inMax - inMin);
249                 ^b - (a * pow(grow, scaled));
250         }
252         curvelin { arg inMin = 0, inMax = 1, outMin = 0, outMax = 1, curve = -4, clip = \minmax;
253                 var grow, a, b, scaled;
254                 switch(clip,
255                         \minmax, {
256                                 if (this <= inMin, { ^outMin });
257                                 if (this >= inMax, { ^outMax });
258                         },
259                         \min, {
260                                 if (this <= inMin, { ^outMin });
261                         },
262                         \max, {
263                                 if (this >= inMax, { ^outMax });
264                         }
265                 );
266                 if (abs(curve) < 0.001) { ^this.linlin(inMin, inMax, outMin, outMax) };
268                 grow = exp(curve);
269                 a = outMax - outMin / (1.0 - grow);
270                 b = outMin + a;
271                 scaled = (this - inMin) / (inMax - inMin);
273                 ^log((b - scaled) / a) / curve
274         }
276         bilin { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax;
277                 // triangular linear mapping
278                 switch(clip,
279                         \minmax, {
280                                 if (this <= inMin, { ^outMin });
281                                 if (this >= inMax, { ^outMax });
282                         },
283                         \min, {
284                                 if (this <= inMin, { ^outMin });
285                         },
286                         \max, {
287                                 if (this >= inMax, { ^outMax });
288                         }
289                 );
290                 ^if (this >= inCenter) {
291                         this.linlin(inCenter, inMax, outCenter, outMax, \none);
292                 } {
293                         this.linlin(inMin, inCenter, outMin, outCenter, \none);
294                 }
295         }
297         biexp { arg inCenter, inMin, inMax, outCenter, outMin, outMax, clip=\minmax;
298                 // triangular exponential mapping
299                 switch(clip,
300                         \minmax, {
301                                 if (this <= inMin, { ^outMin });
302                                 if (this >= inMax, { ^outMax });
303                         },
304                         \min, {
305                                 if (this <= inMin, { ^outMin });
306                         },
307                         \max, {
308                                 if (this >= inMax, { ^outMax });
309                         }
310                 );
311                 if (this >= inCenter) {
312                         this.explin(inCenter, inMax, outCenter, outMax, \none);
313                 } {
314                         this.explin(inMin, inCenter, outMin, outCenter, \none);
315                 }
316         }
317         lcurve { arg a = 1.0, m = 0.0, n = 1.0, tau = 1.0;
318                 var rTau, x = this.neg;
319                 ^if(tau == 1.0) {
320                         a * (m * exp(x) + 1) / (n * exp(x) + 1)
321                 } {
322                         rTau = tau.reciprocal;
323                         a * (m * exp(x) * rTau + 1) / (n * exp(x) * rTau + 1)
324                 }
325         }
326         gauss { arg standardDeviation;
327                 ^((((-2*log(1.0.rand)).sqrt * sin(2pi.rand)) * standardDeviation) + this)
328         }
329         gaussCurve { arg a = 1.0, b = 0.0, c = 1.0;
330                 ^a * (exp(squared(this - b) / (-2.0 * squared(c))))
331         }
333         asPoint { ^Point.new(this, this) }
335         asWarp { arg spec; ^CurveWarp.new(spec, this) }
337         // scheduled Routine support
338         wait { ^this.yield }
339         waitUntil { ^(this - thisThread.beats).max(0).yield }
340         sleep {
341                 var thread = thisThread;
342                 thread.clock.sched(this, { thread.next; nil });
343                 nil.yield;
344         }
346         printOn { arg stream;
347                 stream.putAll(this.asString);
348         }
349         storeOn { arg stream;
350                 stream.putAll(this.asString);
351         }
354         rate { ^'scalar' } // scalarRate constant
355         asAudioRateInput { ^if(this == 0) { Silent.ar } { DC.ar(this) } }
357         madd   { arg mul, add; ^(this * mul) + add; }
359         lag    { ^this }
360         lag2   { ^this }
361         lag3   { ^this }
362         lagud  { ^this }
363         lag2ud { ^this }
364         lag3ud { ^this }
365         varlag { ^this }
366         slew   { ^this }
368         // support for writing synth defs
369         writeInputSpec { arg file, synth;
370                 var constIndex = synth.constants.at(this.asFloat);
371                 if (constIndex.isNil) {
372                         Error("SimpleNumber-writeInputSpec constant not found: " ++ this.asFloat).throw;
373                 };
374                 file.putInt32(-1);
375                 file.putInt32(constIndex);
376         }
378         series { arg second, last;
379                 _SimpleNumberSeries
380                 ^this.primitiveFailed
381                 /* var step, size;
382                 second = second ?? { if (this < last) { this + 1 } { this - 1 } };
383                 step = second - this;
384                 size = floor((last - this) / step + 0.001).asInteger + 1;
385                 ^Array.series(size, this, step) */
386         }
387         seriesIter { arg second, last;
388                 var step, size;
389                 if (second.isNil) {
390                         last = last ? inf;
391                         step = if (this < last, 1, -1);
392                 }{
393                         last ?? { last = if (second < this, -inf, inf) };
394                         step = second - this;
395                 };
396                 ^if (step < 0) {
397                         r {
398                                 var val = this;
399                                 while {
400                                         val >= last;
401                                 }{
402                                         val.yield;
403                                         val = val + step;
404                                 };
405                         }
406                 }{
407                         r {
408                                 var val = this;
409                                 while {
410                                         val <= last;
411                                 }{
412                                         val.yield;
413                                         val = val + step;
414                                 };
415                         }
416                 }
417         }
420         degreeToKey { arg scale, stepsPerOctave = 12;
421                 var scaleDegree = this.round.asInteger;
422                 var accidental = (this - scaleDegree) * 10.0;
423                 ^scale.performDegreeToKey(scaleDegree, stepsPerOctave, accidental)
424         }
426         keyToDegree { arg scale, stepsPerOctave=12;
427                 ^scale.performKeyToDegree(this, stepsPerOctave)
428         }
430         nearestInList { arg list;  // collection is sorted
431                 ^list.performNearestInList(this);
432         }
434         nearestInScale { arg scale, stepsPerOctave=12; // collection is sorted
435                 ^scale.performNearestInScale(this, stepsPerOctave);
436         }
438         partition { arg parts=2, min=1;
439                 // randomly partition a number into parts of at least min size :
440                 var n = this - (min - 1 * parts);
441                 ^(1..n-1).scramble.keep(parts-1).sort.add(n).differentiate + (min - 1)
442         }
444         nextTimeOnGrid { arg clock;
445                 ^clock.nextTimeOnGrid(this, 0);
446         }
448         playAndDelta {}
450         asQuant { ^Quant(this) }
452         // a clock format inspired by ISO 8601 time interval display (truncated representation)
453         // receiver is a time in seconds, returns string "ddd:hh:mm:ss:ttt" where t is milliseconds
454         // see String:asSecs for complement
456         asTimeString { arg precision = 0.001, maxDays = 365, dropDaysIfPossible = true;
457                 var decimal, days, hours, minutes, seconds, mseconds;
458                 decimal = this.asInteger;
459                 days = decimal.div(86400).min(maxDays);
460                 days = if(dropDaysIfPossible and: { days == 0 }) {
461                         days = ""
462                 } {
463                         days.asString.padLeft(3, "0").add($:);
464                 };
465                 hours = (decimal.div(3600) % 24).asString.padLeft(2, "0").add($:);
466                 minutes = (decimal.div(60) % 60).asString.padLeft(2, "0").add($:);
467                 seconds = (decimal % 60).asString.padLeft(2, "0").add($:);
468                 mseconds = (this.frac / precision).round(precision).asInteger.asString.padLeft(3, "0");
469                 ^days ++ hours ++ minutes ++ seconds ++ mseconds
470         }
472         asFraction {|denominator=100, fasterBetter=true|
473                 _AsFraction
474                 // asFraction will return a fraction that is the best approximation up to the given
475                 // denominator.
476                 // if fasterBetter is true it may find a much closer approximation and do it faster.
477                 ^this.primitiveFailed
478         }
479         prSimpleNumberSeries { arg second, last;
480                 _SimpleNumberSeries
481                 ^this.primitiveFailed
482         }
484         asBufWithValues {
485                 ^this
486         }
488         schedBundleArrayOnClock { |clock, bundleArray, lag = 0, server, latency|
489                 clock.sched(this, {
490                                         if (lag != 0) {
491                                                 SystemClock.sched(lag, {
492                                                         server.sendBundle(latency ? server.latency, *bundleArray)
493                                                 })
494                                         } {
495                                                 server.sendBundle(latency ? server.latency, *bundleArray)
496                                         }
497                 })
498         }