3 var <>nodeID, <>server, <>group;
4 var <>isPlaying = false, <>isRunning = false;
16 // valid action numbers should stay the same
17 0: 0, 1: 1, 2: 2, 3: 3, 4: 4
21 *basicNew { arg server, nodeID;
22 server = server ? Server.default;
23 ^super.newCopyArgs(nodeID ?? { server.nextNodeID }, server)
26 *actionNumberFor { |addAction = (\addToHead)| ^addActions[addAction] }
28 free { arg sendFlag=true;
30 server.sendMsg(11, nodeID); //"/n_free"
36 freeMsg { ^[11, nodeID] }
39 server.sendMsg(12, nodeID,flag.binaryValue); //"/n_run"
42 runMsg { arg flag=true;
43 ^[12, nodeID,flag.binaryValue]; //"/n_run"
47 var bundle = this.mapMsg(*args);
48 if(bundle[0].isString) {
49 server.sendBundle(nil, bundle);
51 server.sendBundle(nil, *bundle);
55 mapMsg { arg ... args;
56 var krVals, arVals, result;
59 result = Array.new(2);
60 args.pairsDo({ arg control, bus;
64 krVals.addAll([control.asControlInput, bus.index, bus.numChannels])
67 arVals.addAll([control.asControlInput, bus.index, bus.numChannels])
69 // no default case, ignore others
71 if(krVals.size > 0, { result = result.add(["/n_mapn", nodeID] ++ krVals) });
72 if(arVals.size > 0, { result = result.add(["/n_mapan",nodeID] ++ arVals) });
73 if(result.size < 2, { result = result.flatten; });
77 server.sendMsg(48, nodeID, *(args.asControlInput)); //"/n_mapn"
79 mapnMsg { arg ... args;
80 ^[48, nodeID] ++ args.asControlInput; //"/n_mapn"
83 busMap { arg firstControl, aBus ... args;
85 this.deprecated(thisMethod, Node.findMethod(\map));
87 args.pairsDo({ arg control, bus; values.addAll([control, bus.index, bus.numChannels])});
88 server.sendMsg(48, nodeID, firstControl, aBus.index, aBus.numChannels, *values);
91 busMapMsg { arg firstControl, aBus ... args;
93 this.deprecated(thisMethod, Node.findMethod(\mapMsg));
95 args.pairsDo({ arg control, bus; values.addAll([control, bus.index, bus.numChannels])});
96 ^[48, nodeID, firstControl, aBus.index, aBus.numChannels] ++ values;
101 server.sendMsg(15, nodeID, *(args.asOSCArgArray)); //"/n_set"
104 setMsg { arg ... args;
105 // ^[15, nodeID] ++ args.unbubble.asControlInput;
106 ^[15, nodeID] ++ args.asOSCArgArray; //"/n_set"
110 server.sendMsg(*this.setnMsg(*args));
113 *setnMsgArgs{ arg ... args;
115 args = args.asControlInput;
116 args.pairsDo { arg control, moreVals;
117 if(moreVals.isArray,{
118 nargs.addAll([control, moreVals.size]++ moreVals);
120 nargs.addAll([control, 1, moreVals]);
126 setnMsg { arg ... args;
127 ^[16, nodeID] ++ Node.setnMsgArgs(*args);
131 fill { arg controlName, numControls, value ... args;
132 server.sendMsg(17, nodeID, controlName, numControls, value, *(args.asControlInput));//"n_fill"
135 fillMsg { arg controlName, numControls, value ... args;
136 ^[17, nodeID, controlName, numControls, value] ++ args.asControlInput; //"n_fill"
139 release { arg releaseTime;
140 server.sendMsg(*this.releaseMsg(releaseTime))
142 releaseMsg { arg releaseTime;
143 //assumes a control called 'gate' in the synth
144 if(releaseTime.isNil, {
147 releaseTime = -1.0 - releaseTime;
149 ^[15, nodeID, \gate, releaseTime]
152 server.sendMsg(10, nodeID);//"/n_trace"
156 var cmd,argnodeID,parent,prev,next,isGroup,head,tail;
157 # cmd,argnodeID,parent,prev,next,isGroup,head,tail = msg;
158 // assuming its me ... if(nodeID == argnodeID)
159 Post << if(isGroup == 1, "Group:" , "Synth:") << nodeID << Char.nl
160 << "parent : " << parent << Char.nl
161 << "prev : " << prev << Char.nl
162 << "next :" << next << Char.nl;
164 Post << "head :" << head << Char.nl
165 << "tail :" << tail << Char.nl << Char.nl;
167 }, '/n_info', server.addr).oneShot;
168 server.sendMsg(46, nodeID) //"/n_query"
170 register { arg assumePlaying=false;
171 NodeWatcher.register(this, assumePlaying)
178 this.removeDependant(f);
182 this.addDependant(f);
186 var c = Condition.new;
187 this.onFree({c.unhang});
191 moveBefore { arg aNode;
193 server.sendMsg(18, nodeID, aNode.nodeID); //"/n_before"
195 moveAfter { arg aNode;
197 server.sendMsg(19, nodeID, aNode.nodeID); //"/n_after"
199 moveToHead { arg aGroup;
200 (aGroup ? server.defaultGroup).moveNodeToHead(this);
202 moveToTail { arg aGroup;
203 (aGroup ? server.defaultGroup).moveNodeToTail(this);
206 // message creating methods
208 moveBeforeMsg { arg aNode;
210 ^[18, nodeID, aNode.nodeID];//"/n_before"
212 moveAfterMsg { arg aNode;
214 ^[19, nodeID, aNode.nodeID]; //"/n_after"
216 moveToHeadMsg { arg aGroup;
217 ^(aGroup ? server.defaultGroup).moveNodeToHeadMsg(this);
219 moveToTailMsg { arg aGroup;
220 ^(aGroup ? server.defaultGroup).moveNodeToTailMsg(this);
223 *orderNodesMsg { arg nodes;
224 var msg = [18]; // "/n_after"
225 nodes.doAdjacentPairs { |first, toMoveAfter|
226 msg = msg.add(toMoveAfter.nodeID);
227 msg = msg.add(first.nodeID);
232 hash { ^server.hash bitXor: nodeID.hash }
235 ^aNode respondsTo: #[\nodeID, \server]
236 and: { aNode.nodeID == nodeID and: { aNode.server === server }}
238 printOn { arg stream; stream << this.class.name << "(" << nodeID <<")" }
239 asUGenInput { Error("should not use a % inside a SynthDef".format(this.class.name)).throw }
240 asControlInput { ^this.nodeID }
244 // common base for Group and ParGroup classes
245 AbstractGroup : Node {
247 /** immediately sends **/
248 *new { arg target, addAction=\addToHead;
249 var group, server, addNum, inTarget;
250 inTarget = target.asTarget;
251 server = inTarget.server;
252 group = this.basicNew(server);
253 addNum = addActions[addAction];
254 if((addNum < 2), { group.group = inTarget; }, { group.group = inTarget.group; });
255 server.sendMsg(this.creationCmd, group.nodeID, addNum, inTarget.nodeID);
258 newMsg { arg target, addAction = \addToHead;
259 var addNum, inTarget;
260 // if target is nil set to default group of server specified when basicNew was called
261 inTarget = (target ? server.defaultGroup).asTarget;
262 addNum = addActions[addAction];
263 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
264 ^[this.class.creationCmd, nodeID, addNum, inTarget.nodeID]
268 addToHeadMsg { arg aGroup;
269 // if aGroup is nil set to default group of server specified when basicNew was called
270 group = (aGroup ? server.defaultGroup);
271 ^[this.class.creationCmd, nodeID, 0, group.nodeID]
273 addToTailMsg { arg aGroup;
274 // if aGroup is nil set to default group of server specified when basicNew was called
275 group = (aGroup ? server.defaultGroup);
276 ^[this.class.creationCmd, nodeID, 1, group.nodeID]
278 addAfterMsg { arg aNode;
280 ^[this.class.creationCmd, nodeID, 3, aNode.nodeID]
282 addBeforeMsg { arg aNode;
284 ^[this.class.creationCmd, nodeID, 2, aNode.nodeID]
286 addReplaceMsg { arg nodeToReplace;
287 group = nodeToReplace.group;
288 ^[this.class.creationCmd, nodeID, 4, nodeToReplace.nodeID]
292 *after { arg aNode; ^this.new(aNode, \addAfter) }
293 *before { arg aNode; ^this.new(aNode, \addBefore) }
294 *head { arg aGroup; ^this.new(aGroup, \addToHead) }
295 *tail { arg aGroup; ^this.new(aGroup, \addToTail) }
296 *replace { arg nodeToReplace; ^this.new(nodeToReplace, \addReplace) }
298 // move Nodes to this group
299 moveNodeToHead { arg aNode;
301 server.sendMsg(22, nodeID, aNode.nodeID); //"/g_head"
303 moveNodeToTail { arg aNode;
305 server.sendMsg(23, nodeID, aNode.nodeID); //"/g_tail"
307 moveNodeToHeadMsg { arg aNode;
309 ^[22, nodeID, aNode.nodeID]; //"/g_head"
311 moveNodeToTailMsg { arg aNode;
313 ^[23, nodeID, aNode.nodeID]; //g_tail
317 // free my children, but this node is still playing
318 server.sendMsg(24, nodeID); //"/g_freeAll"
321 // free my children, but this node is still playing
322 ^[24, nodeID]; //"/g_freeAll"
325 server.sendMsg(50, nodeID) //"/g_deepFree"
328 ^[50, nodeID] //"/g_deepFree"
332 dumpTree { arg postControls = false;
333 server.sendMsg("/g_dumpTree", nodeID, postControls.binaryValue)
336 queryTree { //|action|
337 var resp, done = false;
338 resp = OSCFunc({ arg msg;
339 var i = 2, tabs = 0, printControls = false, dumpFunc;
340 if(msg[1] != 0, {printControls = true});
341 ("NODE TREE Group" + msg[2]).postln;
343 dumpFunc = {|numChildren|
347 if(msg[i + 1] >=0, {i = i + 2}, {
348 i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0});
350 tabs.do({ " ".post });
351 msg[i].post; // nodeID
354 if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) });
356 (" " ++ msg[i + 2]).postln; // defname
360 tabs.do({ " ".post });
365 if(msg[i + 4 + j].isMemberOf(Symbol), {
366 (msg[i + 4 + j] ++ ": ").post;
377 dumpFunc.value(msg[3]);
380 // action.value(msg);
382 }, '/g_queryTree.reply', server.addr).oneShot;
383 server.sendMsg("/g_queryTree", nodeID);
384 SystemClock.sched(3, {
387 "Server failed to respond to Group:queryTree!".warn;
392 *creationCmd { ^this.subclassMustImplementThisMethod }
394 // queryTree { |action|
395 // var resp, done = false;
396 // resp = OSCresponderNode(server.addr, '/g_queryTree.reply', { arg time, responder, msg;
397 // action.value(msg);
399 // }).add.removeWhenDone;
400 // server.sendMsg("/g_queryTree", nodeID);
401 // SystemClock.sched(3, {
404 // "Server failed to respond to Group:queryTree!".warn;
410 Group : AbstractGroup {
411 *creationCmd { ^21 } //"/g_new"
418 /** immediately sends **/
419 *new { arg defName, args, target, addAction=\addToHead;
420 var synth, server, addNum, inTarget;
421 inTarget = target.asTarget;
422 server = inTarget.server;
423 addNum = addActions[addAction];
424 synth = this.basicNew(defName, server);
426 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
427 // server.sendMsg(59, //"s_newargs"
428 // defName, synth.nodeID, addNum, inTarget.nodeID,
429 // *Node.setnMsgArgs(*args));
430 server.sendMsg(9, //"s_new"
431 defName, synth.nodeID, addNum, inTarget.nodeID,
432 *(args.asOSCArgArray)
436 *newPaused { arg defName, args, target, addAction=\addToHead;
437 var synth, server, addNum, inTarget;
438 inTarget = target.asTarget;
439 server = inTarget.server;
440 addNum = addActions[addAction];
441 synth = this.basicNew(defName, server);
442 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
443 server.sendBundle(nil, [9, defName, synth.nodeID, addNum, inTarget.nodeID] ++
444 args.asOSCArgArray, [12, synth.nodeID, 0]); // "s_new" + "/n_run"
447 /** does not send (used for bundling) **/
448 *basicNew { arg defName, server, nodeID;
449 ^super.basicNew(server, nodeID).defName_(defName.asDefName)
452 newMsg { arg target, args, addAction = \addToHead;
453 var addNum, inTarget;
454 addNum = addActions[addAction];
455 // if target is nil set to default group of server specified when basicNew was called
456 inTarget = (target ? server.defaultGroup).asTarget;
457 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
458 ^[9, defName, nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray; //"/s_new"
460 *after { arg aNode, defName, args;
461 ^this.new(defName, args, aNode, \addAfter);
463 *before { arg aNode, defName, args;
464 ^this.new(defName, args, aNode, \addBefore);
466 *head { arg aGroup, defName, args;
467 ^this.new(defName, args, aGroup, \addToHead);
469 *tail { arg aGroup, defName, args;
470 ^this.new(defName, args, aGroup, \addToTail);
472 *replace { arg nodeToReplace, defName, args;
473 ^this.new(defName, args, nodeToReplace, \addReplace)
476 addToHeadMsg { arg aGroup, args;
477 // if aGroup is nil set to default group of server specified when basicNew was called
478 group = (aGroup ? server.defaultGroup);
479 ^[9, defName, nodeID, 0, group.nodeID] ++ args.asOSCArgArray // "/s_new"
481 addToTailMsg { arg aGroup, args;
482 // if aGroup is nil set to default group of server specified when basicNew was called
483 group = (aGroup ? server.defaultGroup);
484 ^[9, defName, nodeID, 1, group.nodeID] ++ args.asOSCArgArray // "/s_new"
486 addAfterMsg { arg aNode, args;
488 ^[9, defName, nodeID, 3, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
490 addBeforeMsg { arg aNode, args;
492 ^[9, defName, nodeID, 2, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
494 addReplaceMsg { arg nodeToReplace, args;
495 group = nodeToReplace.group;
496 ^[9, defName, nodeID, 4, nodeToReplace.nodeID] ++ args.asOSCArgArray // "/s_new"
500 *grain { arg defName, args, target, addAction=\addToHead;
502 target = target.asTarget;
503 server = target.server;
504 server.sendMsg(9, defName.asDefName, -1, addActions[addAction], target.nodeID,
505 *(args.asOSCArgArray)); //"/s_new"
509 get { arg index, action;
510 OSCpathResponder(server.addr,['/n_set',nodeID,index],{ arg time, r, msg;
511 action.value(msg.at(3)); r.remove }).add;
512 server.sendMsg(44, nodeID, index); //"/s_get"
515 ^[44, nodeID, index]; //"/s_get"
518 getn { arg index, count, action;
519 OSCpathResponder(server.addr,['/n_setn',nodeID,index],{arg time, r, msg;
520 action.value(msg.copyToEnd(4)); r.remove } ).add;
521 server.sendMsg(45, nodeID, index, count); //"/s_getn"
523 getnMsg { arg index, count;
524 ^[45, nodeID, index, count]; //"/s_getn"
527 printOn { arg stream; stream << this.class.name << "(" <<< defName << " : " << nodeID <<")" }
535 server = server ? Server.default;
536 ^(roots.at(server.name) ?? {
537 ^super.basicNew(server, 0).rninit
541 roots.put(server.name, this);
542 isPlaying = isRunning = true;
543 group = this; // self
545 *initClass { roots = IdentityDictionary.new; }
547 run { "run has no effect on RootNode".warn; }
548 free { "free has no effect on RootNode".warn; }
549 moveBefore { "moveBefore has no effect on RootNode".warn; }
550 moveAfter { "moveAfter has no effect on RootNode".warn; }
551 moveToHead { "moveToHead has no effect on RootNode".warn; }
552 moveToTail{ "moveToTail has no effect on RootNode".warn; }
555 roots.do({ arg rn; rn.freeAll })
559 ParGroup : AbstractGroup {
560 *creationCmd { ^63 } //"/p_new"