1 //these extensions provide means to wrap Objects so that they
2 //make sense within the server bus system according to a node proxy.
4 ////////////////////// graphs, functions, numericals and arrays //////////////////
8 //objects can define their own wrapper classes dependant on
9 //how they play, stop, build, etc. see SynthDefControl for example
10 //the original (wrapped) object can be reached by the .source message
11 //for objects that only create ugen graphs, define prepareForProxySynthDef(proxy)
17 makeProxyControl { arg channelOffset=0;
18 ^this.proxyControlClass.new(this, channelOffset);
22 //any preparations that have to be done to prepare the object
23 //implement 'prepareForProxySynthDef' to return a ugen func
26 //this method is called from within the Control
27 buildForProxy { arg proxy, channelOffset=0, index;
29 argNames = this.argNames;
31 SystemSynthDefs.tempNamePrefix ++ proxy.generateUniqueName ++ index,
32 this.prepareForProxySynthDef(proxy),
33 proxy.nodeMap.ratesFor(argNames),
41 prepareForProxySynthDef { ^this.subclassResponsibility(thisMethod) }
46 //support for unop / binop proxy
55 prepareForProxySynthDef { ^this }
56 argNames { ^def.argNames }
57 defaultArgs { ^def.prototypeFrame }
61 prepareForProxySynthDef { ^{ this.value } }
66 prepareForProxySynthDef { arg proxy;
67 proxy.initBus(\control, 1);
68 ^{ÊDC.multiNewList([proxy.rate] ++ this) };
72 +Synth { // better information about common error
73 prepareForProxySynthDef { arg proxy;
75 "A synth is no valid source for a proxy.\n"
76 "For instance, ~out = { ... }.play would cause this and should be:\n"
77 "~out = { ... }; ~out.play; or (~out = { ... }).play;"
83 prepareForProxySynthDef { arg proxy;
84 proxy.initBus(\control, this.size);
85 ^{ÊDC.multiNewList([proxy.rate] ++ this) };
89 +SequenceableCollection {
90 prepareForProxySynthDef { arg proxy;
91 proxy.initBus(\control, this.size);
92 ^{ this.collect({ |el| el.prepareForProxySynthDef(proxy).value }) }
93 // could use SynthDef.wrap, but needs type check for function.
98 prepareForProxySynthDef { arg proxy;
99 proxy.initBus(this.rate, this.numChannels);
100 ^{ this.value(proxy) }
106 prepareForProxySynthDef { arg proxy;
107 proxy.initBus(this.rate, this.numChannels);
108 ^{ this.value(proxy) }
112 //needs a visit: lazy init + channelOffset
115 prepareForProxySynthDef { arg proxy;
116 ^BusPlug.for(this).prepareForProxySynthDef(proxy);
123 ///////////////////////////// SynthDefs and alike ////////////////////////////////////
128 numChannels { ^nil } //don't know
141 ///////////////////////////// Pattern - Streams ///////////////////////////////////
145 proxyControlClass { ^StreamControl }
146 buildForProxy { ^PauseStream.new(this) }
150 buildForProxy { ^this }
151 proxyControlClass { ^StreamControl }
155 buildForProxy { "a numerical pattern does not make sense here.".error; ^nil }
159 proxyControlClass { ^StreamControl }
161 buildForProxy { arg proxy, channelOffset=0;
162 ^PauseStream(this.endless.asStream
165 channelOffset: channelOffset,
166 server: { proxy.server },
167 out: { proxy.index },
168 group: { proxy.group }
175 proxyControlClass { ^PatternControl }
177 buildForProxy { arg proxy, channelOffset=0;
178 ^this.endless.buildForProxy(proxy, channelOffset)
184 proxyControlClass { ^PatternControl }
186 buildForProxy { arg proxy, channelOffset=0;
187 var player = this.asEventStreamPlayer;
188 var event = player.event.buildForProxy(proxy, channelOffset);
189 ^event !? { player };
194 proxyControlClass { ^StreamControl }
195 buildForProxy { arg proxy, channelOffset=0;
196 var ok, index, server, numChannels, rate, finish;
197 ok = if(proxy.isNeutral) {
198 rate = this.at(\rate) ? 'audio';
199 numChannels = this.at(\numChannels) ? NodeProxy.defaultNumAudio;
200 proxy.initBus(rate, numChannels);
202 rate = proxy.rate; // if proxy is initialized, it is user's responsibility
203 numChannels = proxy.numChannels;
208 server = proxy.server;
210 ~channelOffset = channelOffset; // default value
211 ~out = { ~channelOffset % numChannels + index };
212 ~server = server; // not safe for server changes yet
214 ~group = { proxy.group.asNodeID };
217 proxy.nodeMap.addToEvent(currentEnvironment);
218 ~group = ~group.value;
229 /////////// pluggable associations //////////////
233 buildForProxy { arg proxy, channelOffset=0, index;
234 ^AbstractPlayControl.buildMethods[key].value(value, proxy, channelOffset, index)
237 ^AbstractPlayControl.proxyControlClasses[key] ? SynthDefControl
241 +AbstractPlayControl {
242 makeProxyControl { ^this.deepCopy } //already wrapped, but needs to be copied
244 /* these adverbial extendible interfaces are for supporting different role schemes.
245 it is called by Association, so ~out = \filter -> ... will call this. The first arg passed is the value of the association */
248 proxyControlClasses = (
249 filter: SynthDefControl,
252 stream: PatternControl,
253 setbus: StreamControl,
254 setsrc: StreamControl
259 filter: #{ arg func, proxy, channelOffset=0, index;
261 if(proxy.isNeutral) {
262 ugen = func.value(Silent.ar);
263 ok = proxy.initBus(ugen.rate, ugen.numChannels);
264 if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw }
269 e = EnvGate.new * Control.names(["wet"++(index ? 0)]).kr(1.0);
270 if(proxy.rate === 'audio') {
271 XOut.ar(out, e, SynthDef.wrap(func, nil, [In.ar(out, proxy.numChannels)]))
273 XOut.kr(out, e, SynthDef.wrap(func, nil, [In.kr(out, proxy.numChannels)])) };
274 }.buildForProxy( proxy, channelOffset, index )
277 set: #{ arg pattern, proxy, channelOffset=0, index;
279 args = proxy.controlNames.collect(_.name);
283 \id, Pfunc { proxy.group.nodeID },
285 ).buildForProxy( proxy, channelOffset, index )
287 xset: #{ arg pattern, proxy, channelOffset=0, index;
290 \play, { proxy.xset(*proxy.controlNames.collect(_.name).envirPairs) }
291 ).buildForProxy( proxy, channelOffset, index )
293 setbus: #{ arg pattern, proxy, channelOffset=0, index;
294 var ok = proxy.initBus(\control);
295 if(ok.not) { Error("NodeProxy input: wrong rate").throw };
299 \id, Pfunc { proxy.group.nodeID },
300 \array, Pkey(\value).collect { |x| x.keep(proxy.numChannels) },
301 \out, Pfunc { proxy.index }
302 ).buildForProxy( proxy, channelOffset, index )
304 setsrc: #{ arg pattern, proxy, channelOffset=0, index=0;
305 pattern.collect { |event|
306 event[\type] = \rest;
307 proxy.put(index + 1, event[\source]);
309 }.buildForProxy( proxy, channelOffset, index );
311 control: #{ arg values, proxy, channelOffset=0, index;
312 { Control.kr(values) }.buildForProxy( proxy, channelOffset, index );
314 filterIn: #{ arg func, proxy, channelOffset=0, index;
316 if(proxy.isNeutral) {
317 ugen = func.value(Silent.ar);
318 ok = proxy.initBus(ugen.rate, ugen.numChannels);
319 if(ok.not) { Error("NodeProxy input: wrong rate/numChannels").throw }
324 var egate = EnvGate.new;
325 var wetamp = Control.names(["wet"++(index ? 0)]).kr(1.0);
326 var dryamp = 1 - wetamp;
327 if(proxy.rate === 'audio') {
328 in = In.ar(out, proxy.numChannels);
329 XOut.ar(out, egate, SynthDef.wrap(func, nil,
330 [in * wetamp]) + (dryamp * in))
332 in = In.kr(out, proxy.numChannels);
333 XOut.kr(out, egate, SynthDef.wrap(func, nil,
334 [in * wetamp]) + (dryamp * in))
336 }.buildForProxy( proxy, channelOffset, index )
339 mix: #{ arg func, proxy, channelOffset=0, index;
341 { var e = EnvGate.new * Control.names(["mix"++(index ? 0)]).kr(1.0);
342 e * SynthDef.wrap(func);
343 }.buildForProxy( proxy, channelOffset, index )