#lang scribble/manual @(require (for-label racket)) @title{Operators} @section{categories} Language, Common methods common unary and binary operators@section{related} Reference/Adverbs SuperCollider supports operator overloading. Operators can thus be applied to a variety of different objects; Numbers, Ugens, Collections, and so on. When operators are applied to ugens they result in link::Classes/BinaryOpUGen::s or link::Classes/UnaryOpUGen::s, through the methods of link::Classes/AbstractFunction::. This is a list of some of the common unary and binary operators that are implemented by several classes. See the specific classes for details and other operators. You can see which classes implements a specific operator by clicking on the method name. @section{section} Unary Operators Unary operators may be written in two ways: @racketblock[ a.operator operator(a) :: ] @section{subsection} Arithmetics @section{method} neg Inversion. @section{discussion} @racketblock[ { var a; a = FSinOsc.ar(300); [ a, a.neg ] }.plot :: ] @section{method} reciprocal Reciprocal (1/x). @section{method} abs Absolute value. @section{method} floor Next lower integer. @section{discussion} @racketblock[ { var a; a = Line.ar(-1, 1, 0.01); [ a, a.floor ] }.plot :: ] @section{method} ceil Next higher integer. @section{discussion} @racketblock[ { var a; a = Line.ar(-1, 1, 0.01); [ a, a.ceil ] }.plot :: ] @section{method} frac Fractional part. @section{method} sign Sign function. @section{returns} -1 when a < 0, +1 when a > 0, 0 when a is 0 @section{method} squared Squared value. @section{returns} @racketblock[ a*a :: ] @section{method} cubed Cubed value. @section{returns} @racketblock[ a*a*a :: ] @section{method} sqrt Square root. @section{discussion} The definition of square root is extended for signals so that sqrt(a) when a<0 returns -sqrt(-a). @section{method} exp Exponential. @section{subsection} Musical acoustics @section{method} midicps Convert MIDI note number to cycles per second. @section{discussion} @racketblock[ { Saw.ar(Line.kr(24,108,10).midicps, 0.2) }.play :: ] @section{method} cpsmidi Convert cycles per second to MIDI note. @section{method} midiratio Convert an interval in MIDI notes into a frequency ratio. @section{method} ratiomidi Convert a frequency ratio to an interval in MIDI notes. @section{method} dbamp Convert decibels to linear amplitude. @section{method} ampdb Convert linear amplitude to decibels. @section{method} octcps Convert decimal octaves to cycles per second. @section{method} cpsoct Convert cycles per second to decimal octaves. @section{subsection} Random operators See also link::Guides/Randomness:: @section{method} rand Returns an evenly distributed random value between this and zero. @racketblock[ 10.rand; { SinOsc.ar(110).rand }.plot; :: ] @section{method} rand2 Returns an evenly distributed random value between [+this ... - this]. @racketblock[ 10.rand2; { SinOsc.ar(110).rand2 }.plot; :: ] @section{method} linrand Returns a linearly distributed random value between this and zero. @racketblock[ 10.linrand; { SinOsc.ar(110).linrand }.plot; :: ] @section{method} bilinrand Returns a linearly distributed random value between [+this ... - this]. @racketblock[ 10.bilinrand; { SinOsc.ar(110).bilinrand }.plot; :: ] @section{method} sum3rand Returns a value from a gaussian-like random distribution between this and zero. Larry Polansky's poor man's gaussian generator, follows the formula: @racketblock[ { 1.0.rand }.dup(3).sum - 1.5 * (2/3) :: ] @racketblock[ 10.sum3rand; { SinOsc.ar(110).sum3rand }.plot; :: ] @section{method} coin Returns one or zero with the probability given by the argument. @racketblock[ 0.4.coin; { SinOsc.ar(110).coin }.plot; :: ] @section{subsection} Other @section{method} log Natural logarithm. @section{discussion} @racketblock[ { var a, e; e = exp(1); a = Line.ar(e, 1/e, 0.01); a.log }.plot :: ] @section{method} log2 Base 2 logarithm. @section{method} log10 Base 10 logarithm. @section{method} sin Sine. @section{method} cos Cosine. @section{method} tan Tangent. @section{method} asin Arcsine. @section{method} acos Arccosine. @section{method} atan Arctangent. @section{method} sinh Hyperbolic sine. @section{method} cosh Hyperbolic cosine. @section{method} tanh Hyperbolic tangent. @section{method} distort Nonlinear distortion. @section{discussion} @racketblock[ ( { var a; a = Line.ar(-4, 4, 0.01); a.distort }.plot ) { FSinOsc.ar(500, 0.0, XLine.kr(0.1, 10, 10)).distort * 0.25 }.scope; :: ] @section{method} softclip Nonlinear distortion. @section{discussion} Distortion with a perfectly linear region from -0.5 to +0.5 @racketblock[ ( { var a; a = Line.ar(-2, 2, 0.01); a.softclip }.plot ) { FSinOsc.ar(500,0.0, XLine.kr(0.1, 10, 10)).softclip * 0.25 }.scope(2); :: ] @section{method} isPositive Test if signal is >= 0. @section{method} isNegative Test if signal is < 0. @section{method} isStrictlyPositive Test if signal is > 0. @section{section} Binary Operators Three different syntaxes can be used for binary operators consisting of letters: @racketblock[ operator(a, b) a operator: b a.operator(b) :: Operators consisting of symbols are written like this: ] @racketblock[ a + b :: ] @section{subsection} Arithmetics @section{method} + Addition. @section{method} - Subtraction. @section{method} * Multiplication. @section{method} / Division. @section{method} % Floating point modulo. @section{method} ** Exponentiation. When used with UGens which produce a negative signal this function extends the usual definition of exponentiation and returns @racketblock[neg(neg(a) ** b)::. This allows exponentiation of negative signal values by noninteger exponents. For the normal behaviour use pow (see below). ] @section{method} pow Exponentiation. @section{method} lcm Least common multiple. This definition extends the usual definition and returns a negative number if strong::any of the operands:: is negative. This makes it consistent with the lattice-theoretical interpretation and its idempotency, commutative, associative, absorption laws. Following the example of the programming language J (see: link::Guides/J-concepts-in-SC::), lcm is analogous to logical strong::and:: (see also: link::http://www.jsoftware.com/papers/eem/gcd.htm::). @racketblock[ lcm(4, 6); lcm(1, 1); // and lcm(1624, 26); lcm(1624, -26); lcm(-1624, -26); lcm(513, gcd(513, 44)) // absorption law -> 513. :: ] @racketblock[ ( { var mx = MouseX.kr(-20, 20); var my = MouseY.kr(-20, 20); SinOsc.ar(SinOsc.kr(0.3) * 20 lcm: [mx, my] * 30 + 500) * 0.1 }.play; ) :: ] @section{method} gcd Greatest common divisor. This definition extends the usual definition and returns a negative number if strong::both operands:: are negative. This makes it consistent with the lattice-theoretical interpretation and its idempotency, commutative, associative, absorption laws. "greater" means "divisible by" in this interpretation, so @racketblock[gcd(-1, -1):: returns a negative number. This is necessary to make the whole system consistent (fundamental law of arithmetics, idempotency and absorption laws would fail). See examples below. Following the example of the programming language J (see: link::Guides/J-concepts-in-SC::), gcd is analogous to logical strong::or:: (see also: link::http://www.jsoftware.com/papers/eem/gcd.htm::). ] @racketblock[ gcd(4, 6); gcd(0, 1); // or gcd(1024, 256); gcd(1024, -256); gcd(-1024, -256); // "greater" means "divisible by" in this case, so this returns a negative number. gcd(-1024, lcm(-1024, 256)) // absorption law -> -1024. gcd(66, 54) * lcm(66, 54) == (66 * 54); // true :: ] @racketblock[ ( { var mx = MouseX.kr(-200, 200); var my = MouseY.kr(-200, 200); SinOsc.ar(SinOsc.kr(0.3) * 20 gcd: [mx, my] * 30 + 500) * 0.1 }.play; ) :: Here is an overview of how negative numbers are treated: ] @racketblock[ lcm(4, 6) // -> 12. "least multiple" interpreted as smallest in Z lcm(4, -6) // -> -12 "least multiple" interpreted as smallest in Z lcm(-4, -6) // -> -12 "least multiple" interpreted as smallest in Z gcd(4, 6) // -> 2 "greatest divisor" interpreted as highest in Z gcd(4, -6) // -> 2 "greatest divisor" is interpreted as highest in Z gcd(-4, -6) // -> -2 "greatest divisor" is interpreted as *inverse* in Z. This is the only necessary asymmetry. :: ] @section{subsection} Comparisons @section{method} < Less than. @section{method} <= Less than or equal. @section{method} > Greater than. @section{discussion} With UGens, this can be useful for triggering purposes, among other things: @racketblock[ ( { // trigger an envelope var trig; trig = SinOsc.ar(1) > 0; Out.ar(0, EnvGen.kr(Env.perc, trig, doneAction: Done.none) * SinOsc.ar(440,0,0.1) ) }.play ) // trigger a synth ( SynthDef("help-EnvGen",{ arg out=0; Out.ar(out, EnvGen.kr(Env.perc,1.0,doneAction: Done.freeSelf) * SinOsc.ar(440,0,0.1) ) }).add; // This synth has no output. It only checks amplitude of input and looks for a transition from < 0.2 // to > 0.2 { SendTrig.kr(Amplitude.kr(SoundIn.ar(0)) > 0.2) }.play; // OSCFunc to trigger synth OSCFunc({ "triggered".postln; Synth.new("help-EnvGen") },'/tr', s.addr); ) :: ] @section{method} >= Greater than or equal. @section{method} == Equal. @section{method} != Not equal. @section{subsection} Other @section{method} a 0 @racketblock[ { WhiteNoise.ar.amclip(FSinOsc.kr(1,0.2)) }.play; // makes a sine envelope :: ] @section{method} scaleneg Scale negative part of input. @section{discussion} a*b when a < 0, otherwise a. @racketblock[ { FSinOsc.ar(500).scaleneg(Line.ar(1,-1,4)) }.play; :: ] @section{method} clip2 Bilateral clipping. @section{discussion} clips input wave a to +/- b @racketblock[ ( { var a; a = Line.ar(-2, 2, 0.01); a.clip2 }.plot2 ) { FSinOsc.ar(400).clip2(0.2) }.scope; // clipping distortion { FSinOsc.ar(1000).clip2(Line.kr(0,1,8)) }.scope; :: ] @section{method} wrap2 Bilateral wrapping. @section{discussion} wraps input wave to +/- b @racketblock[ ( { var a; a = Line.ar(-2, 2, 0.01); a.wrap2 }.plot ) { FSinOsc.ar(1000).wrap2(Line.kr(0,1.01,8)) }.scope; :: ] @section{method} fold2 Bilateral folding. @section{discussion} folds input wave a to +/- b @racketblock[ ( { var a; a = Line.ar(-2, 2, 0.01); a.fold2 }.plot ) { FSinOsc.ar(1000).fold2(Line.kr(0,1,8)) }.scope; :: ] @section{method} excess Residual of clipping. @section{discussion} Returns the difference of the original signal and its clipped form: (a - clip2(a,b)). @racketblock[ ( { var a; a = Line.ar(-2, 2, 0.01); a.excess }.plot ) { FSinOsc.ar(1000).excess(Line.kr(0,1,8)) }.play; :: ]