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"
84 server.sendMsg(15, nodeID, *(args.asOSCArgArray)); //"/n_set"
87 setMsg { arg ... args;
88 // ^[15, nodeID] ++ args.unbubble.asControlInput;
89 ^[15, nodeID] ++ args.asOSCArgArray; //"/n_set"
93 server.sendMsg(*this.setnMsg(*args));
96 *setnMsgArgs{ arg ... args;
98 args = args.asControlInput;
99 args.pairsDo { arg control, moreVals;
100 if(moreVals.isArray,{
101 nargs.addAll([control, moreVals.size]++ moreVals);
103 nargs.addAll([control, 1, moreVals]);
109 setnMsg { arg ... args;
110 ^[16, nodeID] ++ Node.setnMsgArgs(*args);
114 fill { arg controlName, numControls, value ... args;
115 server.sendMsg(17, nodeID, controlName, numControls, value, *(args.asControlInput));//"n_fill"
118 fillMsg { arg controlName, numControls, value ... args;
119 ^[17, nodeID, controlName, numControls, value] ++ args.asControlInput; //"n_fill"
122 release { arg releaseTime;
123 server.sendMsg(*this.releaseMsg(releaseTime))
125 releaseMsg { arg releaseTime;
126 //assumes a control called 'gate' in the synth
127 if(releaseTime.isNil, {
130 releaseTime = -1.0 - releaseTime;
132 ^[15, nodeID, \gate, releaseTime]
135 server.sendMsg(10, nodeID);//"/n_trace"
139 var cmd,argnodeID,parent,prev,next,isGroup,head,tail;
140 # cmd,argnodeID,parent,prev,next,isGroup,head,tail = msg;
141 // assuming its me ... if(nodeID == argnodeID)
142 Post << if(isGroup == 1, "Group:" , "Synth:") << nodeID << Char.nl
143 << "parent : " << parent << Char.nl
144 << "prev : " << prev << Char.nl
145 << "next :" << next << Char.nl;
147 Post << "head :" << head << Char.nl
148 << "tail :" << tail << Char.nl << Char.nl;
150 }, '/n_info', server.addr).oneShot;
151 server.sendMsg(46, nodeID) //"/n_query"
153 register { arg assumePlaying=false;
154 NodeWatcher.register(this, assumePlaying)
161 this.removeDependant(f);
165 this.addDependant(f);
168 var c = Condition.new;
169 this.onFree({c.unhang});
173 moveBefore { arg aNode;
175 server.sendMsg(18, nodeID, aNode.nodeID); //"/n_before"
177 moveAfter { arg aNode;
179 server.sendMsg(19, nodeID, aNode.nodeID); //"/n_after"
181 moveToHead { arg aGroup;
182 (aGroup ? server.defaultGroup).moveNodeToHead(this);
184 moveToTail { arg aGroup;
185 (aGroup ? server.defaultGroup).moveNodeToTail(this);
188 // message creating methods
190 moveBeforeMsg { arg aNode;
192 ^[18, nodeID, aNode.nodeID];//"/n_before"
194 moveAfterMsg { arg aNode;
196 ^[19, nodeID, aNode.nodeID]; //"/n_after"
198 moveToHeadMsg { arg aGroup;
199 ^(aGroup ? server.defaultGroup).moveNodeToHeadMsg(this);
201 moveToTailMsg { arg aGroup;
202 ^(aGroup ? server.defaultGroup).moveNodeToTailMsg(this);
205 *orderNodesMsg { arg nodes;
206 var msg = [18]; // "/n_after"
207 nodes.doAdjacentPairs { |first, toMoveAfter|
208 msg = msg.add(toMoveAfter.nodeID);
209 msg = msg.add(first.nodeID);
215 ^this.compareObject(that, #[\nodeID, \server])
219 ^this.instVarHash(#[\nodeID, \server])
222 printOn { arg stream; stream << this.class.name << "(" << nodeID <<")" }
223 asUGenInput { Error("should not use a % inside a SynthDef".format(this.class.name)).throw }
224 asControlInput { ^this.nodeID }
228 // common base for Group and ParGroup classes
229 AbstractGroup : Node {
231 /** immediately sends **/
232 *new { arg target, addAction=\addToHead;
233 var group, server, addNum, inTarget;
234 inTarget = target.asTarget;
235 server = inTarget.server;
236 group = this.basicNew(server);
237 addNum = addActions[addAction];
238 if((addNum < 2), { group.group = inTarget; }, { group.group = inTarget.group; });
239 server.sendMsg(this.creationCmd, group.nodeID, addNum, inTarget.nodeID);
242 newMsg { arg target, addAction = \addToHead;
243 var addNum, inTarget;
244 // if target is nil set to default group of server specified when basicNew was called
245 inTarget = (target ? server.defaultGroup).asTarget;
246 addNum = addActions[addAction];
247 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
248 ^[this.class.creationCmd, nodeID, addNum, inTarget.nodeID]
252 addToHeadMsg { arg aGroup;
253 // if aGroup is nil set to default group of server specified when basicNew was called
254 group = (aGroup ? server.defaultGroup);
255 ^[this.class.creationCmd, nodeID, 0, group.nodeID]
257 addToTailMsg { arg aGroup;
258 // if aGroup is nil set to default group of server specified when basicNew was called
259 group = (aGroup ? server.defaultGroup);
260 ^[this.class.creationCmd, nodeID, 1, group.nodeID]
262 addAfterMsg { arg aNode;
264 ^[this.class.creationCmd, nodeID, 3, aNode.nodeID]
266 addBeforeMsg { arg aNode;
268 ^[this.class.creationCmd, nodeID, 2, aNode.nodeID]
270 addReplaceMsg { arg nodeToReplace;
271 group = nodeToReplace.group;
272 ^[this.class.creationCmd, nodeID, 4, nodeToReplace.nodeID]
276 *after { arg aNode; ^this.new(aNode, \addAfter) }
277 *before { arg aNode; ^this.new(aNode, \addBefore) }
278 *head { arg aGroup; ^this.new(aGroup, \addToHead) }
279 *tail { arg aGroup; ^this.new(aGroup, \addToTail) }
280 *replace { arg nodeToReplace; ^this.new(nodeToReplace, \addReplace) }
282 // move Nodes to this group
283 moveNodeToHead { arg aNode;
285 server.sendMsg(22, nodeID, aNode.nodeID); //"/g_head"
287 moveNodeToTail { arg aNode;
289 server.sendMsg(23, nodeID, aNode.nodeID); //"/g_tail"
291 moveNodeToHeadMsg { arg aNode;
293 ^[22, nodeID, aNode.nodeID]; //"/g_head"
295 moveNodeToTailMsg { arg aNode;
297 ^[23, nodeID, aNode.nodeID]; //g_tail
301 // free my children, but this node is still playing
302 server.sendMsg(24, nodeID); //"/g_freeAll"
305 // free my children, but this node is still playing
306 ^[24, nodeID]; //"/g_freeAll"
309 server.sendMsg(50, nodeID) //"/g_deepFree"
312 ^[50, nodeID] //"/g_deepFree"
316 dumpTree { arg postControls = false;
317 server.sendMsg("/g_dumpTree", nodeID, postControls.binaryValue)
320 queryTree { //|action|
321 var resp, done = false;
322 resp = OSCFunc({ arg msg;
323 var i = 2, tabs = 0, printControls = false, dumpFunc;
324 if(msg[1] != 0, {printControls = true});
325 ("NODE TREE Group" + msg[2]).postln;
327 dumpFunc = {|numChildren|
331 if(msg[i + 1] >=0, {i = i + 2}, {
332 i = i + 3 + if(printControls, {msg[i + 3] * 2 + 1}, {0});
334 tabs.do({ " ".post });
335 msg[i].post; // nodeID
338 if(msg[i + 1] > 0, { dumpFunc.value(msg[i + 1]) });
340 (" " ++ msg[i + 2]).postln; // defname
344 tabs.do({ " ".post });
349 if(msg[i + 4 + j].isMemberOf(Symbol), {
350 (msg[i + 4 + j] ++ ": ").post;
361 dumpFunc.value(msg[3]);
364 // action.value(msg);
366 }, '/g_queryTree.reply', server.addr).oneShot;
367 server.sendMsg("/g_queryTree", nodeID);
368 SystemClock.sched(3, {
371 "Server failed to respond to Group:queryTree!".warn;
376 *creationCmd { ^this.subclassMustImplementThisMethod }
378 // queryTree { |action|
379 // var resp, done = false;
380 // resp = OSCresponderNode(server.addr, '/g_queryTree.reply', { arg time, responder, msg;
381 // action.value(msg);
383 // }).add.removeWhenDone;
384 // server.sendMsg("/g_queryTree", nodeID);
385 // SystemClock.sched(3, {
388 // "Server failed to respond to Group:queryTree!".warn;
394 Group : AbstractGroup {
395 *creationCmd { ^21 } //"/g_new"
402 /** immediately sends **/
403 *new { arg defName, args, target, addAction=\addToHead;
404 var synth, server, addNum, inTarget;
405 inTarget = target.asTarget;
406 server = inTarget.server;
407 addNum = addActions[addAction];
408 synth = this.basicNew(defName, server);
410 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
411 // server.sendMsg(59, //"s_newargs"
412 // defName, synth.nodeID, addNum, inTarget.nodeID,
413 // *Node.setnMsgArgs(*args));
414 server.sendMsg(9, //"s_new"
415 defName, synth.nodeID, addNum, inTarget.nodeID,
416 *(args.asOSCArgArray)
420 *newPaused { arg defName, args, target, addAction=\addToHead;
421 var synth, server, addNum, inTarget;
422 inTarget = target.asTarget;
423 server = inTarget.server;
424 addNum = addActions[addAction];
425 synth = this.basicNew(defName, server);
426 if((addNum < 2), { synth.group = inTarget; }, { synth.group = inTarget.group; });
427 server.sendBundle(nil, [9, defName, synth.nodeID, addNum, inTarget.nodeID] ++
428 args.asOSCArgArray, [12, synth.nodeID, 0]); // "s_new" + "/n_run"
431 /** does not send (used for bundling) **/
432 *basicNew { arg defName, server, nodeID;
433 ^super.basicNew(server, nodeID).defName_(defName.asDefName)
436 newMsg { arg target, args, addAction = \addToHead;
437 var addNum, inTarget;
438 addNum = addActions[addAction];
439 // if target is nil set to default group of server specified when basicNew was called
440 inTarget = (target ? server.defaultGroup).asTarget;
441 (addNum < 2).if({ group = inTarget; }, { group = inTarget.group; });
442 ^[9, defName, nodeID, addNum, inTarget.nodeID] ++ args.asOSCArgArray; //"/s_new"
444 *after { arg aNode, defName, args;
445 ^this.new(defName, args, aNode, \addAfter);
447 *before { arg aNode, defName, args;
448 ^this.new(defName, args, aNode, \addBefore);
450 *head { arg aGroup, defName, args;
451 ^this.new(defName, args, aGroup, \addToHead);
453 *tail { arg aGroup, defName, args;
454 ^this.new(defName, args, aGroup, \addToTail);
456 *replace { arg nodeToReplace, defName, args;
457 ^this.new(defName, args, nodeToReplace, \addReplace)
460 addToHeadMsg { arg aGroup, args;
461 // if aGroup is nil set to default group of server specified when basicNew was called
462 group = (aGroup ? server.defaultGroup);
463 ^[9, defName, nodeID, 0, group.nodeID] ++ args.asOSCArgArray // "/s_new"
465 addToTailMsg { arg aGroup, args;
466 // if aGroup is nil set to default group of server specified when basicNew was called
467 group = (aGroup ? server.defaultGroup);
468 ^[9, defName, nodeID, 1, group.nodeID] ++ args.asOSCArgArray // "/s_new"
470 addAfterMsg { arg aNode, args;
472 ^[9, defName, nodeID, 3, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
474 addBeforeMsg { arg aNode, args;
476 ^[9, defName, nodeID, 2, aNode.nodeID] ++ args.asOSCArgArray // "/s_new"
478 addReplaceMsg { arg nodeToReplace, args;
479 group = nodeToReplace.group;
480 ^[9, defName, nodeID, 4, nodeToReplace.nodeID] ++ args.asOSCArgArray // "/s_new"
484 *grain { arg defName, args, target, addAction=\addToHead;
486 target = target.asTarget;
487 server = target.server;
488 server.sendMsg(9, defName.asDefName, -1, addActions[addAction], target.nodeID,
489 *(args.asOSCArgArray)); //"/s_new"
493 get { arg index, action;
494 OSCpathResponder(server.addr,['/n_set',nodeID,index],{ arg time, r, msg;
495 action.value(msg.at(3)); r.remove }).add;
496 server.sendMsg(44, nodeID, index); //"/s_get"
500 ^[44, nodeID, index]; //"/s_get"
503 getn { arg index, count, action;
504 OSCpathResponder(server.addr,['/n_setn',nodeID,index],{arg time, r, msg;
505 action.value(msg.copyToEnd(4)); r.remove } ).add;
506 server.sendMsg(45, nodeID, index, count); //"/s_getn"
509 getnMsg { arg index, count;
510 ^[45, nodeID, index, count]; //"/s_getn"
513 seti { arg ... args; // args are [key, index, value, key, index, value ...]
514 var msg = Array.new(args.size div: 3 * 2);
515 var synthDesc = SynthDescLib.at(defName.asSymbol);
516 if(synthDesc.isNil) {
517 "message seti failed, because SynthDef % was not added.".format(defName).warn;
520 forBy(0, args.size-1, 3, { |i|
521 var key = args[i], offset = args[i+1], value = args[i+2];
522 var controlName = synthDesc.controlDict[key];
523 if(controlName.notNil and: { offset < controlName.numChannels }) {
524 msg.add(controlName.index+offset);
526 msg.add(value.keep(controlName.numChannels - offset))
532 server.sendMsg("/n_set", nodeID, *msg.asOSCArgArray);
535 printOn { arg stream; stream << this.class.name << "(" <<< defName << " : " << nodeID <<")" }
543 server = server ? Server.default;
544 ^(roots.at(server.name) ?? {
545 ^super.basicNew(server, 0).rninit
549 roots.put(server.name, this);
550 isPlaying = isRunning = true;
551 group = this; // self
553 *initClass { roots = IdentityDictionary.new; }
555 run { "run has no effect on RootNode".warn; }
556 free { "free has no effect on RootNode".warn; }
557 moveBefore { "moveBefore has no effect on RootNode".warn; }
558 moveAfter { "moveAfter has no effect on RootNode".warn; }
559 moveToHead { "moveToHead has no effect on RootNode".warn; }
560 moveToTail{ "moveToTail has no effect on RootNode".warn; }
563 roots.do({ arg rn; rn.freeAll })
567 ParGroup : AbstractGroup {
568 *creationCmd { ^63 } //"/p_new"