2 BusPlug : AbstractFunction {
5 var <>monitor, <>parentGroup; // if nil, uses default group
6 var busArg; // cache for "/s_new" bus arg
9 classvar <>defaultNumAudio=2, <>defaultNumControl=1;
13 ^super.newCopyArgs(server ? Server.default);
18 ^this.new(bus.server).bus_(bus)
21 *audio { arg server, numChannels;
22 ^this.new(server).defineBus(\audio, numChannels);
25 *control { arg server, numChannels;
26 ^this.new(server).defineBus(\control, numChannels);
37 //////// bus definitions //////////////////////////////////////////
45 busLoaded = bus.server.serverRunning;
49 initBus { arg rate, numChannels;
50 if(rate.isNil or: { rate === 'scalar' }) { ^true }; // this is no problem
52 this.defineBus(rate, numChannels);
55 numChannels = numChannels ? this.numChannels;
56 ^(bus.rate === rate) and: { numChannels <= bus.numChannels }
60 defineBus { arg rate=\audio, numChannels;
61 if(numChannels.isNil, {
62 numChannels = if(rate === \audio) {
63 this.class.defaultNumAudio
65 this.class.defaultNumControl }
67 this.bus = Bus.alloc(rate, server, numChannels);
74 if(bus.rate === \control) { bus.setAll(0) }; // clean up
82 busArg { ^busArg ?? { this.makeBusArg } }
85 var index, numChannels, prefix;
86 if(bus.isNil) { ^busArg = "" }; // still neutral
87 prefix = if(this.rate == \audio) { "\a" } { "\c" };
89 numChannels = this.numChannels;
90 ^busArg = if(numChannels == 1) {
93 { |i| prefix ++ (index + i) }.dup(numChannels)
98 asBus { ^if(this.isNeutral) { nil } { bus } }
99 asNodeArg { ^if(this.isNeutral) { nil } { this.busArg } }
102 //////////// playing and access /////////////////////////////////////////////
105 rate { ^if(bus.isNil) { \scalar } { bus.rate } }
106 numChannels { ^if(bus.isNil) { nil } { bus.numChannels } }
107 index { ^if(bus.isNil) { nil } { bus.index } }
111 ^bus.isNil or: { bus.index.isNil and: { bus.numChannels.isNil } }
114 prepareOutput { } // see subclass
117 ar { arg numChannels, offset=0;
119 this.defineBus(\audio, numChannels)
122 ^InBus.ar(bus, numChannels ? bus.numChannels, offset)
125 kr { arg numChannels, offset=0;
127 this.defineBus(\control, numChannels)
130 ^InBus.kr(bus, numChannels ? bus.numChannels, offset)
133 // for now, force multichannel expansion in streams early.
134 embedInStream { arg inval;
135 ^this.asControlInput.embedInStream(inval);
139 if(this.isPlaying.not) {
140 if(this.isNeutral) { this.defineBus(\control, 1) };
150 ///// math support /////////
152 value { arg something;
154 if(UGen.buildSynthDef.isNil) { ^this }; // only return when in ugen graph.
155 something !? { n = something.numChannels };
156 ^if(something.rate == 'audio') { this.ar(n) } { this.kr(n) }
159 composeUnaryOp { arg aSelector;
160 ^UnaryOpPlug.new(aSelector, this)
162 composeBinaryOp { arg aSelector, something;
163 ^BinaryOpPlug.new(aSelector, this, something)
165 reverseComposeBinaryOp { arg aSelector, something;
166 ^BinaryOpPlug.new(aSelector, something, this)
168 composeNAryOp { arg aSelector, anArgList;
169 ^thisMethod.notYetImplemented
170 //^NAryOpPlug.new(aSelector, [this]++anArgList) // nary op ugens are not yet implemented
175 ///// monitoring //////////////
178 play { arg out, numChannels, group, multi=false, vol, fadeTime, addAction;
179 var bundle = MixedBundle.new;
180 if(this.homeServer.serverRunning.not) {
181 ("server not running:" + this.homeServer).warn;
184 this.playToBundle(bundle, out, numChannels, group, multi, vol, fadeTime, addAction);
185 // homeServer: multi client support: monitor only locally
186 bundle.schedSend(this.homeServer, this.clock, this.quant)
189 playN { arg outs, amps, ins, vol, fadeTime, group, addAction;
190 var bundle = MixedBundle.new;
191 if(this.homeServer.serverRunning.not) {
192 ("server not running:" + this.homeServer).warn;
195 this.playNToBundle(bundle, outs, amps, ins, vol, fadeTime, group, addAction);
196 bundle.schedSend(this.homeServer, this.clock, this.quant)
203 vol { ^if(monitor.isNil) { 1.0 }{ monitor.vol } }
204 vol_ { arg val; this.initMonitor(val) }
206 monitorIndex { ^if(monitor.isNil) { nil }{ monitor.out } }
207 monitorGroup { ^if(monitor.isNil) { nil } { monitor.group } }
209 initMonitor { arg vol;
210 if(this.rate !== 'audio') { Error("can only monitor audio proxy").throw };
211 if(monitor.isNil) { monitor = Monitor.new };
212 if (vol.notNil) { monitor.vol_(vol) };
216 stop { arg fadeTime=0.1, reset=false; monitor.stop(fadeTime); if(reset) { monitor = nil }; }
218 scope { arg bufsize = 4096, zoom; if(this.isNeutral.not) { ^bus.scope(bufsize, zoom) } }
220 record { arg path, headerFormat="aiff", sampleFormat="int16", numChannels;
222 if(server.serverRunning.not) { "server not running".inform; ^nil };
223 rec = RecNodeProxy.newFrom(this, numChannels);
224 rec.open(path, headerFormat, sampleFormat);
229 // shared node proxy support
232 homeServer { ^server }
234 printOn { arg stream;
235 stream << this.class.name << "." << bus.rate << "("
236 << server << ", " << bus.numChannels <<")";
242 playToBundle { arg bundle, out, numChannels,
243 group, multi=false, vol, fadeTime, addAction;
244 this.newMonitorToBundle(bundle, numChannels);
245 group = group ?? { if(parentGroup.isPlaying) { parentGroup } { this.homeServer.asGroup } };
246 monitor.playToBundle(bundle, bus.index, bus.numChannels, out, numChannels, group,
247 multi, vol, fadeTime, addAction);
250 playNToBundle { arg bundle, outs, amps, ins, vol, fadeTime, group, addAction;
251 this.newMonitorToBundle(bundle); // todo: numChannels
252 group = group ?? { if(parentGroup.isPlaying) {parentGroup}{this.homeServer.asGroup} };
253 monitor.playNBusToBundle(bundle, outs, amps, ins, bus, vol, fadeTime, group, addAction);
257 newMonitorToBundle { arg bundle, numChannels;
258 this.initBus(\audio, numChannels);
260 if(this.isPlaying.not) { this.wakeUpToBundle(bundle) };
268 //////////////////////////////////////////////////////////////
269 // a bus plug that holds synths or client side players ///////
272 NodeProxy : BusPlug {
275 var <group, <objects, <nodeMap;
276 var <loaded=false, <>awake=true, <paused=false;
277 var <>clock, <>quant;
278 classvar <>buildProxyControl;
281 *new { arg server, rate, numChannels, inputs;
283 res = super.new(server).init;
284 res.initBus(rate, numChannels);
285 inputs.do { arg o; res.add(o) };
290 nodeMap = ProxyNodeMap.new;
295 clear { arg fadeTime=0;
296 this.free(fadeTime, true); // free group and objects
297 this.removeAll; // take out all objects
298 this.stop(fadeTime, true); // stop any monitor
300 this.freeBus; // free the bus from the server allocator
301 this.init; // reset the environment
305 end { arg fadeTime, reset=false;
307 dt = fadeTime ? this.fadeTime;
310 (dt + (server.latency ? 0)).wait;
316 if(this.isPlaying) { objects.do { |item| item.pause(clock, quant) } };
322 if(this.isPlaying) { objects.do { |item| item.resume(clock, quant) } };
326 if(t.isNil) { this.unset(\fadeTime) } { this.set(\fadeTime, t) };
329 ^nodeMap.at(\fadeTime).value ? 0.02;
331 prFadeTime { ^nodeMap.at(\fadeTime).value }
333 asGroup { ^group.asGroup }
334 asTarget { ^group.asGroup }
335 asNodeID { ^group.asNodeID }
337 parentGroup_ {arg node;
338 if(node.isPlaying.not) { "node not playing and registered: % \n".postf(node); ^this };
340 if(group.isPlaying) { group.moveToHead(parentGroup) }
344 //////////// set the source to anything that returns a valid ugen input ////////////
346 add { arg obj, channelOffset=0, extraArgs, now = true;
347 this.put(objects.pos, obj, channelOffset, extraArgs, now)
351 this.put(nil, obj, 0)
357 source { ^objects.at(0).source }
358 sources {^objects.array.collect(_.source) }
360 this.put(nil, obj, 0, nil, false);
364 "info: node proxy 'at' was changed to return source. "
365 "use proxy.objects.at to access control object".postln;
366 ^objects.at(index).source
369 put { arg index, obj, channelOffset = 0, extraArgs, now = true; var container, bundle, orderIndex;
370 if(obj.isNil) { this.removeAt(index); ^this };
371 if(index.isSequenceableCollection) { ^this.putAll(obj.asArray, index, channelOffset)
374 orderIndex = index ? 0;
375 container = obj.makeProxyControl(channelOffset, this);
376 container.build(this, orderIndex); // bus allocation happens here
378 if(this.shouldAddObject(container, index)) {
379 bundle = MixedBundle.new;
381 { this.removeAllToBundle(bundle) }
382 { this.removeToBundle(bundle, index) };
383 objects = objects.put(orderIndex, container);
385 format("failed to add % to node proxy: %", obj, this).inform;
389 if(server.serverRunning) {
392 this.prepareToBundle(nil, bundle);
394 container.loadToBundle(bundle, server);
397 container.wakeUpParentsToBundle(bundle);
398 this.sendObjectToBundle(bundle, container, extraArgs, index);
400 bundle.schedSend(server, clock, quant);
407 putAll { arg list, index=(0), channelOffset = 0;
408 channelOffset = channelOffset.asArray;
409 if(index.isSequenceableCollection) {
410 max(list.size, index.size).do { |i|
411 this.put(index.wrapAt(i), list.wrapAt(i), channelOffset.wrapAt(i))
414 list.do { |item, i| this.put(i + index, item, channelOffset.wrapAt(i)) } }
417 putSeries { arg first, second, last, value;
418 last = last ?? { max(1, max(objects.size, value.size)) - 1 };
419 this.putAll(value.asArray, (first, second..last))
422 shouldAddObject { arg obj; ^obj.readyForPlay } // shared node proxy overrides this
424 removeLast { this.removeAt(objects.indices.last) }
425 removeAll { this.removeAt(nil) }
426 removeAt { arg index;
428 bundle = MixedBundle.new;
430 { this.removeAllToBundle(bundle) }
431 { this.removeToBundle(bundle, index) };
432 bundle.schedSend(server);
436 nodeMap.setRates(args);
440 setRates { arg ... args;
441 nodeMap.setRates(args);
445 defineBus { arg rate=\audio, numChannels;
446 super.defineBus(rate, numChannels);
453 if(index.notNil) { nodeMap.set(\out, index, \i_out, index) };
454 nodeMap.proxy = this;
457 server_ { arg inServer;
458 if(this.isNeutral.not) {
459 // Error("can't change the server").throw
467 if(server != inBus.server) { Error("can't change the server").throw };
475 if(agroup.server !== server, { Error("cannot move to another server").throw });
476 NodeWatcher.register(agroup.isPlaying_(true)); // assume it is playing
478 { bundle = MixedBundle.new;
479 this.stopAllToBundle(bundle);
481 this.sendAllToBundle(bundle);
482 bundle.schedSend(server, clock, 0.0);
483 } { group = agroup };
486 // applying the settings to nodes //
489 this.setNodeMap(map, false)
492 // unsetArgsToBundle does not work.
493 setNodeMap { arg map, xfade=true;
494 var bundle, old, fadeTime;
495 map.set(\fadeTime, this.fadeTime); // keep old fadeTime
496 bundle = MixedBundle.new;
501 if(xfade) { this.sendEach(nil,true) }
503 this.unsetToBundle(bundle); // unmap old
504 nodeMap.addToBundle(bundle, group); // map new
505 bundle.schedSend(server, clock, quant);
514 bundle = MixedBundle.new;
515 this.stopAllToBundle(bundle);
516 bundle.schedSend(server, clock, quant);
517 bundle = MixedBundle.new;
519 this.loadToBundle(bundle);
520 this.sendAllToBundle(bundle);
521 bundle.schedSend(server, clock, quant);
528 controlNames { arg except = #[\out, \i_out, \gate, \fadeTime];
529 var all = Array.new; // Set doesn't work, because equality undefined for ControlName
531 el.controlNames.do { |item|
532 if(except.includes(item.name).not and: {
533 all.every { |cn| cn.name !== item.name }
542 controlKeys { |except, noInternalKeys = true|
543 var list = Array.new;
544 if (noInternalKeys) { except = except ++ this.internalKeys; };
545 this.controlNames.do { |el, i|
546 if(except.includes(el.name).not)
547 { list = list.add(el.name) }
552 ^#[\out, \i_out, \gate, \fadeTime];
554 getKeysValues { |keys, except, withDefaults = true, noInternalKeys = true|
555 var pairs, result = [], myKeys, defaults, mapSettings;
556 if (noInternalKeys) { except = except ++ this.internalKeys; };
558 pairs = this.controlKeysValues(keys, except).clump(2);
559 #myKeys, defaults = pairs.flop;
561 mapSettings = nodeMap.settings;
562 myKeys.collect { |key, i|
564 val = mapSettings[key];
565 doAdd = withDefaults or: val.notNil;
567 result = result.add([ key, (val ? defaults[i]).value ]);
573 // controlPairs, gets default values
574 controlKeysValues { arg keys, except = #[\out, \i_out, \gate, \fadeTime];
575 var list, fullList = this.controlNames(except);
576 if(keys.isNil or: { keys.isEmpty }) {
577 list = Array(fullList.size * 2);
578 fullList.do { |cn| list.add(cn.name).add(cn.defaultValue) }
580 list = Array(keys.size * 2);
582 var val = fullList.detect { |cn| cn.name == key };
583 val = if(val.isNil) { 0 } { val.defaultValue };
584 list.add(key).add(val)
590 // derive names and default args from synthDefs
591 supplementNodeMap { arg keys, replaceOldKeys=false;
592 this.controlNames.do { |el|
596 ( replaceOldKeys or: { nodeMap.at(key).isNil } )
598 { keys.isNil or: { keys.includes(key) } }
599 ) { nodeMap.set(key, el.defaultValue) }
605 ^server.clientID.asString ++ this.identityHash.abs
610 /////////// filtering within one proxy /////////////////
612 filter { arg i, func; this.put(i, \filter -> func) }
614 /////////// shortcuts for efficient bus input //////////////
616 readFromBus { arg busses;
618 busses = busses.asCollection;
619 n = this.numChannels;
620 busses.do { arg item, i;
621 x = min(item.numChannels ? n, n);
623 SynthControl.new("system_link_" ++ this.rate ++ "_" ++ x),
625 ["in", item.index, "out", this.index]
631 proxies = proxies.asCollection;
632 proxies.do { arg item; item.wakeUp };
633 this.readFromBus(proxies)
637 /////// send and spawn //////////
642 bundle = MixedBundle.new;
643 this.prepareToBundle(nil, bundle);
647 spawn { arg extraArgs, index=0;
649 obj = objects.at(index);
652 bundle = this.getBundle;
653 obj.spawnToBundle(bundle, extraArgs, this);
654 nodeMap.addToBundle(bundle, -1);
655 bundle.schedSend(server);
660 send { arg extraArgs, index, freeLast=true;
662 if(objects.isEmpty) { ^this };
664 bundle = this.getBundle;
665 if(freeLast) { this.stopAllToBundle(bundle) };
666 this.sendAllToBundle(bundle, extraArgs);
667 bundle.schedSend(server);
670 obj = objects.at(index);
672 bundle = this.getBundle;
673 if(freeLast) { obj.stopToBundle(bundle) };
675 this.sendObjectToBundle(bundle, obj, extraArgs, index);
676 bundle.schedSend(server);
681 sendAll { arg extraArgs, freeLast=true;
682 this.send(extraArgs, nil, freeLast);
685 sendEach { arg extraArgs, freeLast=true;
687 bundle = this.getBundle;
688 if(freeLast, { this.stopAllToBundle(bundle) });
689 this.sendEachToBundle(bundle, extraArgs);
690 bundle.schedSend(server);
694 quantize { arg ... proxies;
695 var quant = this.quant ? 1.0;
696 ([this]++proxies).do { |x|
702 wakeUp { if(this.isPlaying.not) { this.deepWakeUp } } // do not touch internal state if playing
706 bundle = MixedBundle.new;
707 this.wakeUpToBundle(bundle);
708 bundle.schedSend(server, clock, quant)
712 /////// append to bundle commands
715 defaultGroupID { ^server.nextNodeID } //shared proxy support
717 prepareToBundle { arg argGroup, bundle, addAction=\addToTail;
718 if(this.isPlaying.not) {
719 group = Group.basicNew(server, this.defaultGroupID);
720 NodeWatcher.register(group);
721 group.isPlaying = server.serverRunning;
722 if(argGroup.isNil and: { parentGroup.isPlaying }) { argGroup = parentGroup };
723 bundle.addPrepare(group.newMsg(argGroup ?? { server.asGroup }, addAction));
727 //apply the node map settings to the entire group
728 sendAllToBundle { arg bundle, extraArgs;
729 objects.do { arg item;
730 item.playToBundle(bundle, extraArgs.value, this);
732 if(objects.notEmpty) { nodeMap.addToBundle(bundle, group) };
735 //apply the node map settings to each synth separately
736 sendEachToBundle { arg bundle, extraArgs;
737 objects.do { arg item;
738 this.sendObjectToBundle(bundle, item, extraArgs.value)
743 sendObjectToBundle { arg bundle, object, extraArgs, index;
744 var synthID, target, nodes;
745 synthID = object.playToBundle(bundle, extraArgs.value, this);
747 if(index.notNil and: { objects.size > 1 }) { // if nil, all are sent anyway
748 // make list of nodeIDs following the index
750 objects.doRange({ arg obj;
752 if(id.notNil and: { id != synthID }) { nodes = nodes ++ id ++ synthID };
754 if(nodes.size > 0) { bundle.add(["/n_before"] ++ nodes.reverse) };
756 nodeMap.addToBundle(bundle, synthID)
760 removeToBundle { arg bundle, index;
761 var obj, dt, playing;
762 playing = this.isPlaying;
763 obj = objects.removeAt(index);
767 if(playing) { obj.stopToBundle(bundle, dt) };
768 obj.freeToBundle(bundle, dt);
773 removeAllToBundle { arg bundle;
776 playing = this.isPlaying;
777 objects.do { arg obj;
778 if(playing) { obj.stopToBundle(bundle, dt) };
779 obj.freeToBundle(bundle, dt);
784 stopAllToBundle { arg bundle;
787 if(this.isPlaying) { objects.do { arg obj; obj.stopToBundle(bundle, dt) } };
790 reallocBusIfNeeded { // bus is reallocated only if the server was not booted on creation.
791 if(busLoaded.not and: { bus.notNil }) {
797 loadToBundle { arg bundle;
798 this.reallocBusIfNeeded;
799 objects.do { arg item, i;
801 item.loadToBundle(bundle, server);
807 wakeUpToBundle { arg bundle, checkedAlready;
808 if(checkedAlready.isNil) { checkedAlready = IdentitySet.new };
809 if(checkedAlready.includes(this).not) {
810 checkedAlready.add(this);
811 this.wakeUpParentsToBundle(bundle, checkedAlready);
812 if(loaded.not) { this.loadToBundle(bundle) };
813 if(awake and: { this.isPlaying.not }) {
814 this.prepareToBundle(nil, bundle, \addToHead);
815 this.sendAllToBundle(bundle)
821 wakeUpParentsToBundle { arg bundle, checkedAlready;
822 nodeMap.wakeUpParentsToBundle(bundle, checkedAlready);
823 objects.do{ arg item; item.wakeUpParentsToBundle(bundle, checkedAlready) };
826 // used in 'garbage collector'
828 getFamily { arg set, alreadyAsked;
830 parents = IdentitySet.new;
831 alreadyAsked = alreadyAsked ?? { IdentitySet.new };
832 if(alreadyAsked.includes(this).not) {
833 alreadyAsked.add(this);
834 objects.do { arg obj; parents.addAll(obj.parents) };
835 parents.addAll(nodeMap.parents);
836 parents.do { arg proxy; proxy.getFamily(parents, alreadyAsked) };
843 getStructure { arg alreadyAsked;
844 var parents, substructure;
846 alreadyAsked = alreadyAsked ?? { IdentitySet.new };
847 if(alreadyAsked.includes(this).not) {
848 alreadyAsked.add(this);
849 objects.do { arg obj; parents.addAll(obj.parents) };
850 parents.addAll(nodeMap.parents);
851 substructure = parents.collect { arg proxy; proxy.getStructure(alreadyAsked) };
852 ^[this, substructure.flatten(1)];
865 parentPlaying = this.addToChild;
866 if(parentPlaying) { this.deepWakeUp };
871 child = buildProxyControl;
872 if(child.notNil) { child.addParent(this) };
878 ////////////behave like my group////////////
880 isPlaying { ^group.isPlaying }
882 free { arg fadeTime, freeGroup = true;
885 bundle = MixedBundle.new;
886 if(fadeTime.notNil) { bundle.add([15, group.nodeID, "fadeTime", fadeTime]) };
887 this.stopAllToBundle(bundle);
889 bundle.sched((fadeTime ? this.fadeTime) + (server.latency ? 0), { group.free });
895 release { arg fadeTime; this.free(fadeTime, false) }
898 set { arg ... args; // pairs of keys or indices and value
901 server.sendBundle(server.latency, [15, group.nodeID] ++ args);
908 server.sendBundle(server.latency, group.setnMsg(*args));
912 setGroup { arg args, useLatency=false;
914 server.sendBundle(if(useLatency) { server.latency }, [15, group.nodeID] ++ args);
918 // map to a control proxy
920 map { arg ... args; // key, proxy ... args;
924 nodeMap.unmapArgsToBundle(bundle, group.nodeID, args[0,2..args.size-2]);
925 nodeMap.map(*args).updateBundle;
926 nodeMap.addToBundle(bundle, group.nodeID);
927 server.listSendBundle(server.latency, bundle);
928 } { nodeMap.map(*args) }
931 mapn { arg ... args; // for now, avoid errors.
935 // map to current environment
936 mapEnvir { arg ... keys;
937 nodeMap.mapEnvir(*keys);
939 nodeMap.sendToNode(group);
944 unset { arg ... keys;
945 var bundle = List.new;
946 this.unsetToBundle(bundle, keys);
947 if(bundle.notEmpty) {
948 server.listSendBundle(server.latency, bundle)
953 unmap { arg ... keys;
955 if(keys.isEmpty) { keys = nodeMap.mappingKeys; if(keys.isEmpty) { ^this } };
958 nodeMap.unmapArgsToBundle(bundle, group.nodeID, keys);
959 if(bundle.notEmpty) { server.listSendBundle(server.latency, bundle) };
961 nodeMap.unmap(*keys);
964 unsetToBundle { arg bundle, keys;
965 var pairs = this.controlKeysValues(keys);
968 bundle.add([15, group.nodeID] ++ pairs);
971 nodeMap.unset(*pairs[0,2..]);
978 this.xFadePerform(\set, args);
981 this.xFadePerform(\map, args);
983 xsetn { arg ... args;
984 this.xFadePerform(\setn, args);
986 xmapn { arg ... args;
987 this.xFadePerform(\map, args); // for now, avoid errors.
989 xunset { arg ... args;
990 this.xFadePerform(\unset, args);
993 xFadePerform { arg selector, args;
995 nodeMap.performList(selector, args);
997 { this.sendEach(nil, true) }
998 { "not playing".inform }
1002 var bundle = MixedBundle.new;
1003 this.source = proxy;
1005 if(proxy.monitorGroup.isPlaying) {
1006 proxy.stop(fadeTime: 0.5);
1007 if(this.monitorGroup.isPlaying.not) {
1008 this.playToBundle(bundle, fadeTime:0.1)
1011 bundle.add(proxy.moveBeforeMsg(this));
1012 bundle.send(server, server.latency);
1015 moveBeforeMsg { arg ... proxies;
1017 ([this] ++ proxies).do { |el|
1019 list = list.add(el.group);
1020 if(el.monitor.isPlaying) {
1021 list = list.add(el.monitor.group) // debatable. maybe check whether special
1025 ^list !? { Node.orderNodesMsg(list) }
1028 orderNodes { arg ... proxies;
1029 var msg = this.moveBeforeMsg(*proxies);
1031 server.sendBundle(nil, msg)
1039 classvar <>defaultServer, <>all;
1042 *initClass { all = () }
1044 *new { arg key, object;
1045 // key may be simply a symbol, or an association of a symbol and a server name
1046 var res, server, dict;
1048 if(key.isKindOf(Association)) {
1049 server = Server.named.at(key.value);
1051 Error("Ndef(%): no server found with this name.".format(key)).throw
1055 server = Server.default;
1058 dict = this.dictFor(server);
1059 res = dict.envir.at(key);
1061 res = super.new(server).key_(key);
1062 dict.envir.put(key, res)
1065 object !? { res.source = object };
1069 *ar { arg key, numChannels, offset=0;
1070 ^this.new(key).ar(numChannels, offset)
1073 *kr { arg key, numChannels, offset=0;
1074 ^this.new(key).kr(numChannels, offset)
1077 *dictFor { arg server;
1078 var dict = all.at(server.name);
1080 dict = ProxySpace.new(server); // use a proxyspace for ease of access.
1081 all.put(server.name, dict)
1087 all.do { arg dict; dict.do { arg item; item.clear } };
1091 storeOn { arg stream;
1092 this.printOn(stream);
1094 printOn { arg stream;
1095 stream << this.class.name << "(" <<< this.key << ")"