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);
185 var c = Condition.new;
186 this.onFree({c.unhang});
190 moveBefore { arg aNode;
192 server.sendMsg(18, nodeID, aNode.nodeID); //"/n_before"
194 moveAfter { arg aNode;
196 server.sendMsg(19, nodeID, aNode.nodeID); //"/n_after"
198 moveToHead { arg aGroup;
199 (aGroup ? server.defaultGroup).moveNodeToHead(this);
201 moveToTail { arg aGroup;
202 (aGroup ? server.defaultGroup).moveNodeToTail(this);
205 // message creating methods
207 moveBeforeMsg { arg aNode;
209 ^[18, nodeID, aNode.nodeID];//"/n_before"
211 moveAfterMsg { arg aNode;
213 ^[19, nodeID, aNode.nodeID]; //"/n_after"
215 moveToHeadMsg { arg aGroup;
216 ^(aGroup ? server.defaultGroup).moveNodeToHeadMsg(this);
218 moveToTailMsg { arg aGroup;
219 ^(aGroup ? server.defaultGroup).moveNodeToTailMsg(this);
222 *orderNodesMsg { arg nodes;
223 var msg = [18]; // "/n_after"
224 nodes.doAdjacentPairs { |first, toMoveAfter|
225 msg = msg.add(toMoveAfter.nodeID);
226 msg = msg.add(first.nodeID);
231 hash { ^server.hash bitXor: nodeID.hash }
234 ^aNode respondsTo: #[\nodeID, \server]
235 and: { aNode.nodeID == nodeID and: { aNode.server === server }}
237 printOn { arg stream; stream << this.class.name << "(" << nodeID <<")" }
238 asUGenInput { Error("should not use a % inside a SynthDef".format(this.class.name)).throw }
239 asControlInput { ^this.nodeID }
243 // common base for Group and ParGroup classes
244 AbstractGroup : Node {
246 /** immediately sends **/
247 *new { arg target, addAction=\addToHead;
248 var group, server, addNum, inTarget;
249 inTarget = target.asTarget;
250 server = inTarget.server;
251 group = this.basicNew(server);
252 addNum = addActions[addAction];
253 if((addNum < 2), { group.group = inTarget; }, { group.group = inTarget.group; });
254 server.sendMsg(this.creationCmd, group.nodeID, addNum, inTarget.nodeID);
257 newMsg { arg target, addAction = \addToHead;
258 var addNum, inTarget;
259 // if target is nil set to default group of server specified when basicNew was called
260 inTarget = (target ? server.defaultGroup).asTarget;
261 addNum = addActions[addAction];
262 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
263 ^[this.class.creationCmd, nodeID, addNum, inTarget.nodeID]
267 addToHeadMsg { arg aGroup;
268 // if aGroup is nil set to default group of server specified when basicNew was called
269 group = (aGroup ? server.defaultGroup);
270 ^[this.class.creationCmd, nodeID, 0, group.nodeID]
272 addToTailMsg { arg aGroup;
273 // if aGroup is nil set to default group of server specified when basicNew was called
274 group = (aGroup ? server.defaultGroup);
275 ^[this.class.creationCmd, nodeID, 1, group.nodeID]
277 addAfterMsg { arg aNode;
279 ^[this.class.creationCmd, nodeID, 3, aNode.nodeID]
281 addBeforeMsg { arg aNode;
283 ^[this.class.creationCmd, nodeID, 2, aNode.nodeID]
285 addReplaceMsg { arg nodeToReplace;
286 group = nodeToReplace.group;
287 ^[this.class.creationCmd, nodeID, 4, nodeToReplace.nodeID]
291 *after { arg aNode; ^this.new(aNode, \addAfter) }
292 *before { arg aNode; ^this.new(aNode, \addBefore) }
293 *head { arg aGroup; ^this.new(aGroup, \addToHead) }
294 *tail { arg aGroup; ^this.new(aGroup, \addToTail) }
295 *replace { arg nodeToReplace; ^this.new(nodeToReplace, \addReplace) }
297 // move Nodes to this group
298 moveNodeToHead { arg aNode;
300 server.sendMsg(22, nodeID, aNode.nodeID); //"/g_head"
302 moveNodeToTail { arg aNode;
304 server.sendMsg(23, nodeID, aNode.nodeID); //"/g_tail"
306 moveNodeToHeadMsg { arg aNode;
308 ^[22, nodeID, aNode.nodeID]; //"/g_head"
310 moveNodeToTailMsg { arg aNode;
312 ^[23, nodeID, aNode.nodeID]; //g_tail
316 // free my children, but this node is still playing
317 server.sendMsg(24, nodeID); //"/g_freeAll"
320 // free my children, but this node is still playing
321 ^[24, nodeID]; //"/g_freeAll"
324 server.sendMsg(50, nodeID) //"/g_deepFree"
327 ^[50, nodeID] //"/g_deepFree"
331 dumpTree { arg postControls = false;
332 server.sendMsg("/g_dumpTree", nodeID, postControls.binaryValue)
335 queryTree { //|action|
336 var resp, done = false;
337 resp = OSCFunc({ arg msg;
338 var i = 2, tabs = 0, printControls = false, dumpFunc;
339 if(msg[1] != 0, {printControls = true});
340 ("NODE TREE Group" + msg[2]).postln;
342 dumpFunc = {|numChildren|
346 if(msg[i + 1] >=0, {i = i + 2}, {
347 i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0});
349 tabs.do({ " ".post });
350 msg[i].post; // nodeID
353 if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) });
355 (" " ++ msg[i + 2]).postln; // defname
359 tabs.do({ " ".post });
364 if(msg[i + 4 + j].isMemberOf(Symbol), {
365 (msg[i + 4 + j] ++ ": ").post;
376 dumpFunc.value(msg[3]);
379 // action.value(msg);
381 }, '/g_queryTree.reply', server.addr).oneShot;
382 server.sendMsg("/g_queryTree", nodeID);
383 SystemClock.sched(3, {
386 "Server failed to respond to Group:queryTree!".warn;
391 *creationCmd { ^this.subclassMustImplementThisMethod }
393 // queryTree { |action|
394 // var resp, done = false;
395 // resp = OSCresponderNode(server.addr, '/g_queryTree.reply', { arg time, responder, msg;
396 // action.value(msg);
398 // }).add.removeWhenDone;
399 // server.sendMsg("/g_queryTree", nodeID);
400 // SystemClock.sched(3, {
403 // "Server failed to respond to Group:queryTree!".warn;
409 Group : AbstractGroup {
410 *creationCmd { ^21 } //"/g_new"
417 /** immediately sends **/
418 *new { arg defName, args, target, addAction=\addToHead;
419 var synth, server, addNum, inTarget;
420 inTarget = target.asTarget;
421 server = inTarget.server;
422 addNum = addActions[addAction];
423 synth = this.basicNew(defName, server);
425 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
426 // server.sendMsg(59, //"s_newargs"
427 // defName, synth.nodeID, addNum, inTarget.nodeID,
428 // *Node.setnMsgArgs(*args));
429 server.sendMsg(9, //"s_new"
430 defName, synth.nodeID, addNum, inTarget.nodeID,
431 *(args.asOSCArgArray)
435 *newPaused { arg defName, args, target, addAction=\addToHead;
436 var synth, server, addNum, inTarget;
437 inTarget = target.asTarget;
438 server = inTarget.server;
439 addNum = addActions[addAction];
440 synth = this.basicNew(defName, server);
441 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
442 server.sendBundle(nil, [9, defName, synth.nodeID, addNum, inTarget.nodeID] ++
443 args.asOSCArgArray, [12, synth.nodeID, 0]); // "s_new" + "/n_run"
446 /** does not send (used for bundling) **/
447 *basicNew { arg defName, server, nodeID;
448 ^super.basicNew(server, nodeID).defName_(defName.asDefName)
451 newMsg { arg target, args, addAction = \addToHead;
452 var addNum, inTarget;
453 addNum = addActions[addAction];
454 // if target is nil set to default group of server specified when basicNew was called
455 inTarget = (target ? server.defaultGroup).asTarget;
456 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
457 ^[9, defName, nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray; //"/s_new"
459 *after { arg aNode, defName, args;
460 ^this.new(defName, args, aNode, \addAfter);
462 *before { arg aNode, defName, args;
463 ^this.new(defName, args, aNode, \addBefore);
465 *head { arg aGroup, defName, args;
466 ^this.new(defName, args, aGroup, \addToHead);
468 *tail { arg aGroup, defName, args;
469 ^this.new(defName, args, aGroup, \addToTail);
471 *replace { arg nodeToReplace, defName, args;
472 ^this.new(defName, args, nodeToReplace, \addReplace)
475 addToHeadMsg { arg aGroup, args;
476 // if aGroup is nil set to default group of server specified when basicNew was called
477 group = (aGroup ? server.defaultGroup);
478 ^[9, defName, nodeID, 0, group.nodeID] ++ args.asOSCArgArray // "/s_new"
480 addToTailMsg { arg aGroup, args;
481 // if aGroup is nil set to default group of server specified when basicNew was called
482 group = (aGroup ? server.defaultGroup);
483 ^[9, defName, nodeID, 1, group.nodeID] ++ args.asOSCArgArray // "/s_new"
485 addAfterMsg { arg aNode, args;
487 ^[9, defName, nodeID, 3, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
489 addBeforeMsg { arg aNode, args;
491 ^[9, defName, nodeID, 2, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
493 addReplaceMsg { arg nodeToReplace, args;
494 group = nodeToReplace.group;
495 ^[9, defName, nodeID, 4, nodeToReplace.nodeID] ++ args.asOSCArgArray // "/s_new"
499 *grain { arg defName, args, target, addAction=\addToHead;
501 target = target.asTarget;
502 server = target.server;
503 server.sendMsg(9, defName.asDefName, -1, addActions[addAction], target.nodeID,
504 *(args.asOSCArgArray)); //"/s_new"
508 get { arg index, action;
509 OSCpathResponder(server.addr,['/n_set',nodeID,index],{ arg time, r, msg;
510 action.value(msg.at(3)); r.remove }).add;
511 server.sendMsg(44, nodeID, index); //"/s_get"
514 ^[44, nodeID, index]; //"/s_get"
517 getn { arg index, count, action;
518 OSCpathResponder(server.addr,['/n_setn',nodeID,index],{arg time, r, msg;
519 action.value(msg.copyToEnd(4)); r.remove } ).add;
520 server.sendMsg(45, nodeID, index, count); //"/s_getn"
522 getnMsg { arg index, count;
523 ^[45, nodeID, index, count]; //"/s_getn"
526 printOn { arg stream; stream << this.class.name << "(" <<< defName << " : " << nodeID <<")" }
534 server = server ? Server.default;
535 ^(roots.at(server.name) ?? {
536 ^super.basicNew(server, 0).rninit
540 roots.put(server.name, this);
541 isPlaying = isRunning = true;
542 group = this; // self
544 *initClass { roots = IdentityDictionary.new; }
546 run { "run has no effect on RootNode".warn; }
547 free { "free has no effect on RootNode".warn; }
548 moveBefore { "moveBefore has no effect on RootNode".warn; }
549 moveAfter { "moveAfter has no effect on RootNode".warn; }
550 moveToHead { "moveToHead has no effect on RootNode".warn; }
551 moveToTail{ "moveToTail has no effect on RootNode".warn; }
554 roots.do({ arg rn; rn.freeAll })
558 ParGroup : AbstractGroup {
559 *creationCmd { ^63 } //"/p_new"