cmake build system: visiblity support for clang
[supercollider.git] / SCClassLibrary / Common / Control / NodeWatcher.sc
blobffced2498a4650b2c52d2d62f99e33dd75aed142
1 //watches a server address for node-related messages
3 AbstractNodeWatcher {
5         var <server, <responders;
6         var <isWatching=false;
8         *new { arg server;
9                 ^super.new.ninit(server)
10         }
12         ninit { arg argServer;
13                 var cmds;
14                 server = argServer;
15                 this.clear;
16                 responders = [];
17                 server.addr.asArray.do({ arg addrItem; //support for multiple addresses
18                         this.cmds.do({ arg cmd;
19                                 var method;
20                                 method = cmd.copyToEnd(1).asSymbol;
21                                 responders = responders.add(
22                                         OSCFunc({ arg msg; this.respond(method, msg) }, cmd, addrItem)
23                                                 .permanent_(true)
24                                                 .disable
25                                 )
26                         });
27                 });
28         }
30         clear {}
32         cmds { ^nil }
34         respond { arg method, msg;
35                 this.performList(method, msg.drop(1))
36         }
38         start {
39                 if(isWatching.not, {
40                         responders.do({ arg item; item.enable });
41                         isWatching = true;
42                 })
43         }
44         stop {
45                 if(isWatching, {
46                         responders.do({ arg item; item.free });
47                         isWatching = false;
48                         this.free;
49                 })
50         }
56 BasicNodeWatcher : AbstractNodeWatcher {
57         var <nodes;
59         nodeIsPlaying { arg nodeID;
60                 ^nodes.includes(nodeID);
61         }
62         nodeIsPlaying_ { arg nodeID;
63                 //sometimes it is needed to set this before the server reply
64                 ^nodes.add(nodeID);
65         }
67         clear {
68                 nodes = IdentitySet.new;
69         }
71         cmds {  ^#["/n_go", "/n_end"] }
73         n_end { arg nodeID;
74                 nodes.remove(nodeID);
75         }
76         n_go { arg nodeID;
77                 nodes.add(nodeID);
78         }
84 ///////////////////////////////////
85 //watches registered nodes and sets their isPlaying/isRunning flag.
86 //a node needs to be  registered to be addressed, other nodes are ignored.
88 NodeWatcher : BasicNodeWatcher {
90         classvar <>all;
92         *initClass {
93                 all = IdentityDictionary.new;
94                 CmdPeriod.add(this);
95         }
97         *cmdPeriod { all.do { arg item; item.clear } }
99         *newFrom { arg server;
100                 var res;
101                 res = all.at(server.name);
102                 if(res.isNil, {
103                         res = this.new(server);
104                         res.start;
105                         all.put(server.name, res)
106                 });
107                 ^res
108         }
110         *register { arg node, assumePlaying=false;
111                 var watcher;
112                 watcher = this.newFrom(node.server);
113                 watcher.register(node, assumePlaying);
114         }
116         *unregister { arg node;
117                 var watcher;
118                 watcher = this.newFrom(node.server);
119                 watcher.unregister(node);
120         }
122         cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] }
123         respond { arg method, msg;
124                 var node, group;
125                 node = nodes.at(msg.at(1));
126                 if(node.notNil, {
127                                 group = nodes.at(msg.at(2));
128                                 this.performList(method, node, group)
129                 })
130         }
132         clear {
133                 // we must copy 'nodes'
134                 // b/c a /n_end dependant might add or remove nodes
135                 // from the collection
136                 // NEVER iterate over a collection that might change
137                 nodes.copy.do({ arg node;
138                         node.isPlaying = false;
139                         node.isRunning = false;
140                         node.changed(\n_end);
141                 });
142                 nodes = IdentityDictionary.new
143         }
145         register { arg node, assumePlaying=false;
146                 if(server.serverRunning.not) { nodes.removeAll; ^this };
147                 if(isWatching) {
148                         if(assumePlaying and: { nodes.at(node.nodeID).isNil }) { node.isPlaying = true };
149                         nodes.put(node.nodeID, node);
150                 };
151         }
153         unregister { arg node;
154                 nodes.removeAt(node.nodeID);
155         }
158         //////////////private implementation//////////////
160         n_go { arg node;
161                 node.isPlaying = true;
162                 node.isRunning = true;
163                 node.changed(\n_go);  // notify all the node's dependents of the change
164         }
166         n_end { arg node;
167                 this.unregister(node);
168                 node.isPlaying = false;
169                 node.isRunning = false;
170                 node.changed(\n_end);
171         }
173         n_off { arg node;
174                 node.isRunning = false;
175                 node.changed(\n_off);
176         }
178         n_on { arg node;
179                 node.isRunning = true;
180                 node.changed(\n_on);
181         }
186 DebugNodeWatcher : BasicNodeWatcher {
188         cmds { ^#["/n_go", "/n_end", "/n_off", "/n_on"] }
190         //////////////private implementation//////////////
192         doPost { arg action, nodeID, groupID, prevID, nextID;
193                 Post << ("[ server: " + server.name + "]" +
194                 action + nodeID + "in group" + groupID + "between nodes" + prevID + "and" + nextID
195                 ) << Char.nl
196         }
198         n_go { arg nodeID, groupID, prevID, nextID;
199                 this.doPost("started", nodeID, groupID, prevID, nextID);
200                 nodes.add(nodeID);
201         }
203         n_end { arg nodeID, groupID, prevID, nextID;
204                 nodes.remove(nodeID);
205                 this.doPost("ended", nodeID, groupID, prevID, nextID);
206         }
208         n_off { arg nodeID, groupID, prevID, nextID;
209                 this.doPost("turned off", nodeID, groupID, prevID, nextID);
210         }
212         n_on { arg nodeID, groupID, prevID, nextID;
213                 this.doPost("turned on", nodeID, prevID, nextID);
214         }