HelpBrowser: path box becomes a more conventional search box
[supercollider.git] / SCClassLibrary / JITLib / ProxySpace / ProxySpace.sc
blob1be76565b3e11770e3463da3b336391c91ca1ec2
1 ProxySpace : LazyEnvir {
3         classvar <>all;
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)
12         }
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;
18         }
20         init { arg argServer, argName, argClock;
21                 server = argServer;
22                 clock = argClock;
23                 name = argName;
24                 if(clock.notNil) { this.quant = 1.0 };
25                 if(argName.notNil) { this.add };
26         }
29         makeProxy {
30                         var proxy = NodeProxy.new;
31                         this.initProxy(proxy);
32                         ^proxy
33         }
35         initProxy { arg proxy;
36                 proxy.server = server;
37                 proxy.clock = clock;
38                 proxy.awake = awake;
39                 if(fadeTime.notNil) { proxy.fadeTime = fadeTime };
40                 if(group.isPlaying) { proxy.parentGroup = group };
41                 if(quant.notNil) { proxy.quant = quant };
42         }
45         // access and control
47         clock_ { arg aClock;
48                 clock = aClock;
49                 this.do { arg item; item.clock = aClock };
50         }
52         fadeTime_ { arg dt;
53                 fadeTime = dt;
54                 this.do { arg item; item.fadeTime = dt };
55         }
57         group_ { arg node;
58                 node = node.asGroup;
59                 NodeWatcher.register(node, true);
60                 if(node.isPlaying.not) { "group % not playing!".postf(node); ^this };
61                 group = node;
62                 this.do { arg item; item.parentGroup = node };
63         }
65         quant_ { arg val;
66                 quant = val;
67                 this.do { arg item; item.quant = val };
68         }
70         awake_ { arg flag;
71                 this.do(_.awake_(flag));
72                 awake = flag;
73         }
75         makeTempoClock { arg tempo=1.0, beats, seconds;
76                 var clock, proxy;
77                 proxy = envir[\tempo];
78                 if(proxy.isNil) { proxy = NodeProxy.control(server, 1); envir.put(\tempo, proxy); };
79                 proxy.fadeTime = 0.0;
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 };
83         }
86         play { arg key=\out, out=0, numChannels=2;
87                 ^this.use({ arg envir;
88                         this.at(key).play(out, numChannels);
89                 });
90         }
92         stop { arg fadeTime;
93                 this.do({ arg proxy; proxy.stop(fadeTime) })
94         }
96         record { arg key, path, headerFormat="aiff", sampleFormat="int16";
97                 ^this.use({ arg envir;
98                         this.at(key).record(path, headerFormat="aiff", sampleFormat);
99                 });
100         }
102         ar { arg key=\out, numChannels, offset=0;
103                 ^this.use({ arg envir;
104                         this.at(key).ar(numChannels, offset)
105                 })
106         }
108         kr { arg key=\out, numChannels, offset=0;
109                 ^this.use({ arg envir;
110                         this.at(key).kr(numChannels, offset)
111                 })
112         }
114         free { arg fadeTime;
115                 this.do { arg proxy; proxy.free(fadeTime) };
116                 tempoProxy.free;
117         }
119         clear { arg fadeTime=0.0;
120                 this.do({ arg proxy; proxy.clear(fadeTime) });
121                 tempoProxy !? { tempoProxy.clear };
122                 this.unregisterServer;
123                 super.clear;
124         }
126         end { arg fadeTime;
127                 this.do({ arg proxy; proxy.end(fadeTime) });
128                 tempoProxy.free;
129         }
131         release { arg fadeTime;
132                 this.do({ arg proxy; proxy.release(fadeTime) });
133                 tempoProxy.free;
134         }
136         wakeUp {
137                 this.use({ arg envir;
138                         this.do({ arg proxy;
139                                 proxy.deepWakeUp;
140                         });
141                 });
142         }
144         // maintaining state
146         registerServer {
147                 ServerQuit.add(this, server);
148                 ServerBoot.add(this, server);
149         }
151         unregisterServer {
152                 ServerQuit.remove(this, server);
153                 ServerBoot.remove(this, server);
154         }
156         doOnServerBoot { arg server;
157                 this.do(_.freeBus);
158         }
160         doOnServerQuit { arg server;
161                 this.do(_.freeBus);
162         }
164         // garbage collector
166         // ends all proxies that are not needed
167         reduce { arg excluding, method=\end;
168                 this.gcList(excluding).do { arg proxy; proxy.perform(method) };
169         }
171         // removes all proxies that are not needed
172         clean { arg excluding;
173                 this.reduce(nil, \clear);
174                 this.removeNeutral;
175         }
177         removeNeutral {
178                 envir.copy.keysValuesDo { arg key, val; if(val.isNeutral) { envir.removeAt(key) } };
179         }
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;
186                 res = List.new;
187                 monitors.do { arg proxy; proxy.getFamily(toBeKept) };
188                 envir.do { arg proxy; if(toBeKept.includes(proxy).not) { res.add(proxy) } };
189                 ^res
190         }
191         monitors {
192                 var monitors;
193                 monitors = Array.new;
194                 envir.do { arg proxy;
195                         if(proxy.monitor.isPlaying) { monitors =  monitors.add(proxy) }
196                 };
197                 ^monitors
198         }
200         getStructure { arg keys, excluding;
201                 ^keys.collect { |key|
202                         var proxy = envir.at(key);
203                         var structure;
204                         proxy !? {
205                                 structure = proxy.getStructure(excluding);
206                                 structure.deepCollect(inf, { |px|
207                                         px !? { envir.findKeyForValue(px) -> px }
208                                 });
209                         }
210                 }
211         }
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|
223                 var pxs;
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) })
228                         }
229                 });
230                 ^pxs;
231         }
233         doFunctionPerform { arg selector; ^this[selector] }
235         // global access
237         add {
238                 if(name.notNil) {
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 }
243         }
245         remove {
246                 this.class.all.removeAt(name)
247         }
250         *clearAll {
251                 this.all.do({ arg item; item.clear });
252         }
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" })
263                                         }
264                         << "(" << item.numChannels << ")   " << if(i.even) { "\t\t" } { "\n" };
265                 };
266                 stream << "\n)\n"
268         }
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 };
284                         // none found
285                 ^nil
286         }