3 // function compositions
4 // override these in subclasses to perform different kinds of function compositions
5 composeUnaryOp { arg aSelector;
6 ^UnaryOpFunction.new(aSelector, this)
8 composeBinaryOp { arg aSelector, something, adverb;
9 ^BinaryOpFunction.new(aSelector, this, something, adverb);
11 reverseComposeBinaryOp { arg aSelector, something, adverb;
12 ^BinaryOpFunction.new(aSelector, something, this, adverb);
14 composeNAryOp { arg aSelector, anArgList;
15 ^NAryOpFunction.new(aSelector, this, anArgList)
18 // double dispatch for mixed operations
19 performBinaryOpOnSimpleNumber { arg aSelector, aNumber, adverb;
20 ^this.reverseComposeBinaryOp(aSelector, aNumber, adverb)
22 performBinaryOpOnSignal { arg aSelector, aSignal, adverb;
23 ^this.reverseComposeBinaryOp(aSelector, aSignal, adverb)
25 performBinaryOpOnComplex { arg aSelector, aComplex, adverb;
26 ^this.reverseComposeBinaryOp(aSelector, aComplex, adverb)
28 performBinaryOpOnSeqColl { arg aSelector, aSeqColl, adverb;
29 ^this.reverseComposeBinaryOp(aSelector, aSeqColl, adverb)
32 // respond to math operators
33 neg { ^this.composeUnaryOp('neg') }
34 reciprocal { ^this.composeUnaryOp('reciprocal') }
35 bitNot { ^this.composeUnaryOp('bitNot') }
36 abs { ^this.composeUnaryOp('abs') }
37 asFloat { ^this.composeUnaryOp('asFloat') }
38 asInteger { ^this.composeUnaryOp('asInteger') }
39 ceil { ^this.composeUnaryOp('ceil') }
40 floor { ^this.composeUnaryOp('floor') }
41 frac { ^this.composeUnaryOp('frac') }
42 sign { ^this.composeUnaryOp('sign') }
43 squared { ^this.composeUnaryOp('squared') }
44 cubed { ^this.composeUnaryOp('cubed') }
45 sqrt { ^this.composeUnaryOp('sqrt') }
46 exp { ^this.composeUnaryOp('exp') }
47 midicps { ^this.composeUnaryOp('midicps') }
48 cpsmidi { ^this.composeUnaryOp('cpsmidi') }
49 midiratio { ^this.composeUnaryOp('midiratio') }
50 ratiomidi { ^this.composeUnaryOp('ratiomidi') }
51 ampdb { ^this.composeUnaryOp('ampdb') }
52 dbamp { ^this.composeUnaryOp('dbamp') }
53 octcps { ^this.composeUnaryOp('octcps') }
54 cpsoct { ^this.composeUnaryOp('cpsoct') }
55 log { ^this.composeUnaryOp('log') }
56 log2 { ^this.composeUnaryOp('log2') }
57 log10 { ^this.composeUnaryOp('log10') }
58 sin { ^this.composeUnaryOp('sin') }
59 cos { ^this.composeUnaryOp('cos') }
60 tan { ^this.composeUnaryOp('tan') }
61 asin { ^this.composeUnaryOp('asin') }
62 acos { ^this.composeUnaryOp('acos') }
63 atan { ^this.composeUnaryOp('atan') }
64 sinh { ^this.composeUnaryOp('sinh') }
65 cosh { ^this.composeUnaryOp('cosh') }
66 tanh { ^this.composeUnaryOp('tanh') }
67 rand { ^this.composeUnaryOp('rand') }
68 rand2 { ^this.composeUnaryOp('rand2') }
69 linrand { ^this.composeUnaryOp('linrand') }
70 bilinrand { ^this.composeUnaryOp('bilinrand') }
71 sum3rand { ^this.composeUnaryOp('sum3rand') }
73 distort { ^this.composeUnaryOp('distort') }
74 softclip { ^this.composeUnaryOp('softclip') }
75 coin { ^this.composeUnaryOp('coin') }
76 even { ^this.composeUnaryOp('even') }
77 odd { ^this.composeUnaryOp('odd') }
79 rectWindow { ^this.composeUnaryOp('rectWindow') }
80 hanWindow { ^this.composeUnaryOp('hanWindow') }
81 welWindow { ^this.composeUnaryOp('welWindow') }
82 triWindow { ^this.composeUnaryOp('triWindow') }
84 scurve { ^this.composeUnaryOp('scurve') }
85 ramp { ^this.composeUnaryOp('ramp') }
87 isPositive { ^this.composeUnaryOp('isPositive') }
88 isNegative { ^this.composeUnaryOp('isNegative') }
89 isStrictlyPositive { ^this.composeUnaryOp('isStrictlyPositive') }
91 rho { ^this.composeUnaryOp('rho') }
92 theta { ^this.composeUnaryOp('theta') }
93 rotate { arg function; ^this.composeBinaryOp('rotate', function) }
94 dist { arg function; ^this.composeBinaryOp('dist', function) }
96 + { arg function, adverb; ^this.composeBinaryOp('+', function, adverb) }
97 - { arg function, adverb; ^this.composeBinaryOp('-', function, adverb) }
98 * { arg function, adverb; ^this.composeBinaryOp('*', function, adverb) }
99 / { arg function, adverb; ^this.composeBinaryOp('/', function, adverb) }
100 div { arg function, adverb; ^this.composeBinaryOp('div', function, adverb) }
101 mod { arg function, adverb; ^this.composeBinaryOp('mod', function, adverb) }
102 pow { arg function, adverb; ^this.composeBinaryOp('pow', function, adverb) }
103 min { arg function, adverb; ^this.composeBinaryOp('min', function, adverb) }
104 max { arg function=0, adverb; ^this.composeBinaryOp('max', function, adverb) }
106 < { arg function, adverb; ^this.composeBinaryOp('<', function, adverb) }
107 <= { arg function, adverb; ^this.composeBinaryOp('<=', function, adverb) }
108 > { arg function, adverb; ^this.composeBinaryOp('>', function, adverb) }
109 >= { arg function, adverb; ^this.composeBinaryOp('>=', function, adverb) }
111 bitAnd { arg function, adverb; ^this.composeBinaryOp('bitAnd', function, adverb) }
112 bitOr { arg function, adverb; ^this.composeBinaryOp('bitOr', function, adverb) }
113 bitXor { arg function, adverb; ^this.composeBinaryOp('bitXor', function, adverb) } bitHammingDistance { arg function, adverb; ^this.composeBinaryOp('hammingDistance', function, adverb) }
115 lcm { arg function, adverb; ^this.composeBinaryOp('lcm', function, adverb) }
116 gcd { arg function, adverb; ^this.composeBinaryOp('gcd', function, adverb) }
117 round { arg function=1, adverb; ^this.composeBinaryOp('round', function, adverb) }
118 roundUp { arg function=1, adverb; ^this.composeBinaryOp('roundUp', function, adverb) }
119 trunc { arg function=1, adverb; ^this.composeBinaryOp('trunc', function, adverb) }
120 atan2 { arg function, adverb; ^this.composeBinaryOp('atan2', function, adverb) }
121 hypot { arg function, adverb; ^this.composeBinaryOp('hypot', function, adverb) }
122 hypotApx { arg function, adverb; ^this.composeBinaryOp('hypotApx', function, adverb) }
123 leftShift { arg function, adverb; ^this.composeBinaryOp('leftShift', function, adverb) }
124 rightShift { arg function, adverb; ^this.composeBinaryOp('rightShift', function, adverb) }
125 unsignedRightShift { arg function, adverb; ^this.composeBinaryOp('unsignedRightShift', function, adverb) }
126 ring1 { arg function, adverb; ^this.composeBinaryOp('ring1', function, adverb) }
127 ring2 { arg function, adverb; ^this.composeBinaryOp('ring2', function, adverb) }
128 ring3 { arg function, adverb; ^this.composeBinaryOp('ring3', function, adverb) }
129 ring4 { arg function, adverb; ^this.composeBinaryOp('ring4', function, adverb) }
130 difsqr { arg function, adverb; ^this.composeBinaryOp('difsqr', function, adverb) }
131 sumsqr { arg function, adverb; ^this.composeBinaryOp('sumsqr', function, adverb) }
132 sqrsum { arg function, adverb; ^this.composeBinaryOp('sqrsum', function, adverb) }
133 sqrdif { arg function, adverb; ^this.composeBinaryOp('sqrdif', function, adverb) }
134 absdif { arg function, adverb; ^this.composeBinaryOp('absdif', function, adverb) }
135 thresh { arg function, adverb; ^this.composeBinaryOp('thresh', function, adverb) }
136 amclip { arg function, adverb; ^this.composeBinaryOp('amclip', function, adverb) }
137 scaleneg { arg function, adverb; ^this.composeBinaryOp('scaleneg', function, adverb) }
138 clip2 { arg function=1, adverb; ^this.composeBinaryOp('clip2', function, adverb) }
139 fold2 { arg function=1, adverb; ^this.composeBinaryOp('fold2', function, adverb) }
140 wrap2 { arg function=1, adverb; ^this.composeBinaryOp('wrap2', function, adverb) }
141 excess { arg function=1, adverb; ^this.composeBinaryOp('excess', function, adverb) }
142 firstArg { arg function, adverb; ^this.composeBinaryOp('firstArg', function, adverb) }
143 rrand { arg function, adverb; ^this.composeBinaryOp('rrand', function, adverb) }
144 exprand { arg function, adverb; ^this.composeBinaryOp('exprand', function, adverb) }
145 @ { arg function, adverb; ^this.composeBinaryOp('@', function, adverb) }
152 || { arg function, adverb; ^this.composeBinaryOp('||', function, adverb) }
153 && { arg function, adverb; ^this.composeBinaryOp('&&', function, adverb) }
154 xor { arg function, adverb; ^this.composeBinaryOp('xor', function, adverb) }
155 nand { arg function, adverb; ^this.composeBinaryOp('nand', function, adverb) }
156 not { ^this.composeUnaryOp('not') }
157 ref { ^this.composeUnaryOp('asRef') }
160 clip { arg lo, hi; ^this.composeNAryOp('clip', [lo,hi]) }
161 wrap { arg lo, hi; ^this.composeNAryOp('wrap', [lo,hi]) }
162 fold { arg lo, hi; ^this.composeNAryOp('fold', [lo,hi]) }
163 blend { arg that, blendFrac = 0.5; ^this.composeNAryOp('blend', [that, blendFrac]) }
165 linlin { arg inMin, inMax, outMin, outMax, clip=\minmax;
166 ^this.composeNAryOp('linlin', [inMin, inMax, outMin, outMax, clip])
168 linexp { arg inMin, inMax, outMin, outMax, clip=\minmax;
169 ^this.composeNAryOp('linexp', [inMin, inMax, outMin, outMax, clip])
171 explin { arg inMin, inMax, outMin, outMax, clip=\minmax;
172 ^this.composeNAryOp('explin', [inMin, inMax, outMin, outMax, clip])
174 expexp { arg inMin, inMax, outMin, outMax, clip=\minmax;
175 ^this.composeNAryOp('expexp', [inMin, inMax, outMin, outMax, clip])
178 degreeToKey { arg scale, stepsPerOctave=12;
179 ^this.composeNAryOp('degreeToKey', [scale, stepsPerOctave])
182 degrad { ^this.composeUnaryOp('degrad') }
183 raddeg { ^this.composeUnaryOp('raddeg') }
185 applyTo { arg ... args;
186 ^this.valueArray(args)
190 // function composition
191 ^{|...args| this.value(that.value(*args)) }
194 sampled{ |n=80,from=0.0,to=1.0|
196 valueArray = (from,(to-from)/(n-1) .. to).collect{|x| this.value(x) };
197 ^{ |x| valueArray.blendAt( ((x.clip(from,to)-from)/(to-from))*(n-1) ) }
200 // embed in ugen graph
201 asUGenInput { arg for; ^this.value(for) }
202 asAudioRateInput { |for|
203 var result = this.value(for);
204 ^if(result.rate != \audio) { K2A.ar(result) } { result }
206 // convert to control input
207 asControlInput { ^this.value }
208 isValidUGenInput { ^true }
212 UnaryOpFunction : AbstractFunction {
215 *new { arg selector, a;
216 ^super.newCopyArgs(selector, a)
218 value { arg ... args;
219 ^a.valueArray(args).perform(selector)
221 valueArray { arg args;
222 ^a.valueArray(args).perform(selector)
224 valueEnvir { arg ... args;
225 ^a.valueArrayEnvir(args).perform(selector)
227 valueArrayEnvir { arg ... args;
228 ^a.valueArrayEnvir(args).perform(selector)
230 functionPerformList { arg selector, arglist;
231 ^this.performList(selector, arglist)
233 storeOn { arg stream;
234 stream <<< a << "." << selector;
240 BinaryOpFunction : AbstractFunction {
241 var selector, a, b, adverb;
243 *new { arg selector, a, b, adverb;
244 ^super.newCopyArgs(selector, a, b, adverb)
246 value { arg ... args;
247 ^a.valueArray(args).perform(selector, b.valueArray(args), adverb)
249 valueArray { arg args;
250 ^a.valueArray(args).perform(selector, b.valueArray(args), adverb)
252 valueEnvir { arg ... args;
253 ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb)
255 valueArrayEnvir { arg ... args;
256 ^a.valueArrayEnvir(args).perform(selector, b.valueArrayEnvir(args), adverb)
258 functionPerformList { arg selector, arglist;
259 ^this.performList(selector, arglist)
261 storeOn { arg stream;
262 stream << "(" <<< a << " " << selector.asBinOpString;
263 if(adverb.notNil) { stream << "." << adverb };
264 stream << " " <<< b << ")"
269 NAryOpFunction : AbstractFunction {
270 var selector, a, arglist;
272 *new { arg selector, a, arglist;
273 ^super.newCopyArgs(selector, a, arglist)
275 value { arg ... args;
276 ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args)))
278 valueArray { arg args;
279 ^a.valueArray(args).performList(selector, arglist.collect(_.valueArray(args)))
281 valueEnvir { arg ... args;
282 ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args)))
284 valueArrayEnvir { arg ... args;
285 ^a.valueArrayEnvir(args).performList(selector, arglist.collect(_.valueArrayEnvir(args)))
287 functionPerformList { arg selector, arglist;
288 ^this.performList(selector, arglist)
290 storeOn { arg stream;
291 stream <<< a << "." << selector << "(" <<<* arglist << ")"
297 FunctionList : AbstractFunction {
298 var <>array, <flopped=false;
300 *new { arg functions;
301 ^super.newCopyArgs(functions)
303 addFunc { arg ... functions;
304 if(flopped) { Error("cannot add a function to a flopped FunctionList").throw };
305 array = array.addAll(functions)
307 removeFunc { arg function;
308 array.remove(function);
309 if(array.size < 2) { ^array[0] };
312 replaceFunc { arg find, replace;
313 array = array.replace(find, replace);
316 value { arg ... args;
317 var res = array.collect(_.valueArray(args));
318 ^if(flopped) { res.flop } { res }
320 valueArray { arg args;
321 var res = array.collect(_.valueArray(args));
322 ^if(flopped) { res.flop } { res }
324 valueEnvir { arg ... args;
325 var res = array.collect(_.valueArrayEnvir(args));
326 ^if(flopped) { res.flop } { res }
328 valueArrayEnvir { arg args;
329 var res = array.collect(_.valueArrayEnvir(args));
330 ^if(flopped) { res.flop } { res }
336 if(flopped.not) {array = array.collect(_.flop) }; flopped = true;
339 if(flopped.not) {array = array.collect(_.envirFlop) }; flopped = true;
341 storeArgs { ^[array] }