1 ProxySpace : LazyEnvir {
5 var <name, <server, <clock, <fadeTime, <quant;
6 var <awake=true, tempoProxy, <group;
8 *initClass { all = IdentityDictionary.new }
10 *new { arg server, name, clock;
11 ^super.new.init(server ? Server.default, name, clock)
14 *push { arg server, name, clock;
15 if(name.isNil and: { currentEnvironment.isKindOf(this) })
16 { currentEnvironment.clear.pop }; // avoid nesting
17 ^this.new(server, name, clock).push;
20 init { arg argServer, argName, argClock;
24 if(clock.notNil) { this.quant = 1.0 };
25 if(argName.notNil) { this.add };
30 var proxy = NodeProxy.new;
31 this.initProxy(proxy);
35 initProxy { arg proxy;
36 proxy.server = server;
39 if(fadeTime.notNil) { proxy.fadeTime = fadeTime };
40 if(group.isPlaying) { proxy.parentGroup = group };
41 if(quant.notNil) { proxy.quant = quant };
49 this.do { arg item; item.clock = aClock };
54 this.do { arg item; item.fadeTime = dt };
59 NodeWatcher.register(node, true);
60 if(node.isPlaying.not) { "group % not playing!".postf(node); ^this };
62 this.do { arg item; item.parentGroup = node };
67 this.do { arg item; item.quant = val };
71 this.do(_.awake_(flag));
75 makeTempoClock { arg tempo=1.0, beats, seconds;
77 proxy = envir[\tempo];
78 if(proxy.isNil) { proxy = NodeProxy.control(server, 1); envir.put(\tempo, proxy); };
80 proxy.put(0, { |tempo = 1.0| tempo }, 0, [\tempo, tempo]);
81 this.clock = TempoBusClock.new(proxy, tempo, beats, seconds).permanent_(true);
82 if(quant.isNil) { this.quant = 1.0 };
86 play { arg key=\out, out=0, numChannels=2;
87 ^this.use({ arg envir;
88 this.at(key).play(out, numChannels);
93 this.do({ arg proxy; proxy.stop(fadeTime) })
96 record { arg key, path, headerFormat="aiff", sampleFormat="int16";
97 ^this.use({ arg envir;
98 this.at(key).record(path, headerFormat="aiff", sampleFormat);
102 ar { arg key=\out, numChannels, offset=0;
103 ^this.use({ arg envir;
104 this.at(key).ar(numChannels, offset)
108 kr { arg key=\out, numChannels, offset=0;
109 ^this.use({ arg envir;
110 this.at(key).kr(numChannels, offset)
115 this.do { arg proxy; proxy.free(fadeTime) };
119 clear { arg fadeTime=0.0;
120 this.do({ arg proxy; proxy.clear(fadeTime) });
121 tempoProxy !? { tempoProxy.clear };
122 this.unregisterServer;
127 this.do({ arg proxy; proxy.end(fadeTime) });
131 release { arg fadeTime;
132 this.do({ arg proxy; proxy.release(fadeTime) });
137 this.use({ arg envir;
147 ServerQuit.add(this, server);
148 ServerBoot.add(this, server);
152 ServerQuit.remove(this, server);
153 ServerBoot.remove(this, server);
156 doOnServerBoot { arg server;
160 doOnServerQuit { arg server;
166 // ends all proxies that are not needed
167 reduce { arg excluding, method=\end;
168 this.gcList(excluding).do { arg proxy; proxy.perform(method) };
171 // removes all proxies that are not needed
172 clean { arg excluding;
173 this.reduce(nil, \clear);
178 envir.copy.keysValuesDo { arg key, val; if(val.isNeutral) { envir.removeAt(key) } };
180 // get a list of all proxies that are not reached either by the list passed in
181 // or (if nil) by the monitoring proxies
182 gcList { arg excluding;
183 var monitors, all, toBeKept, res;
184 monitors = excluding ?? { this.monitors };
185 toBeKept = IdentitySet.new;
187 monitors.do { arg proxy; proxy.getFamily(toBeKept) };
188 envir.do { arg proxy; if(toBeKept.includes(proxy).not) { res.add(proxy) } };
193 monitors = Array.new;
194 envir.do { arg proxy;
195 if(proxy.monitor.isPlaying) { monitors = monitors.add(proxy) }
200 getStructure { arg keys, excluding;
201 ^keys.collect { |key|
202 var proxy = envir.at(key);
205 structure = proxy.getStructure(excluding);
206 structure.deepCollect(inf, { |px|
207 px !? { envir.findKeyForValue(px) -> px }
213 activeProxies { ^this.arProxyNames({ |px, key| px.isPlaying }) }
215 playingProxies { ^this.arProxyNames({ |px, key| px.monitor.isPlaying }) }
217 existingProxies { ^this.arProxyNames }
219 arProxyNames { |func=true| ^this.proxyNames(\audio, func) }
220 krProxyNames { |func=true| ^this.proxyNames(\control, func) }
222 proxyNames { |rate, func=true|
224 pxs = SortedList(8, { |a,b| a < b });
225 this.keysValuesDo({ arg key, px;
226 if (px.rate === rate) {
227 if (func.value(px, key), { pxs.add(key) })
233 doFunctionPerform { arg selector; ^this[selector] }
239 if(this.class.all[name].isNil)
240 { this.class.all.put(name, this) }
241 { "there is already an environment with this name".warn };
242 } { "a ProxySpace with no name cannot be added to the repository".warn }
246 this.class.all.removeAt(name)
251 this.all.do({ arg item; item.clear });
255 printOn { arg stream;
256 stream << this.class.name;
257 if(envir.isEmpty) { stream << " ()\n"; ^this };
258 stream << " ( " << (name ? "") << Char.nl;
259 this.keysValuesDo { arg key, item, i;
260 stream << "~" << key << " - ";
261 stream << if(item.rate === 'audio') { "ar" } {
262 if(item.rate === 'control', { "kr" }, { "ir" })
264 << "(" << item.numChannels << ") " << if(i.even) { "\t\t" } { "\n" };
270 postln { Post << this }
272 includes { |proxy| ^envir.includes(proxy) }
274 *findSpace { |proxy, getCode = false|
275 var space = [ currentEnvironment, thisProcess.interpreter.p ]
276 .detect { |cand| cand.isKindOf(this) and: { cand.includes(proxy) } };
277 if (space.notNil) { ^space };
279 space = ProxySpace.all.detect(_.includes(proxy));
280 if (space.notNil) { ^space };
282 space = Ndef.all.detect(_.includes(proxy));
283 if (space.notNil) { ^space };