Merge pull request #506 from andrewcsmith/patch-2
[supercollider.git] / SCClassLibrary / Common / Control / OSC.sc
blob4d27c4fc65cf9f13da5f178b79af3f3fafb466cd
1 // this is probably not working anymore. see NetAddr.sc instead for the newer way.
3 /*
4 // Open Sound Control support
6 OSCNode {
7         classvar <>sc; // this contains the "/sc" default behaviour for all input ports.
9         // a not-very-secure password for access to the compiler
10         // setting password to a Symbol opens SC to potential hacking
11         classvar <>password;
13         var <name, <>children, <>function, <>value, <port;
15         *new { arg name, function, children, value;
16                 ^super.newCopyArgs(name, children, function ? { arg node, x; x }, value);
17         }
18         *tree { arg children, argName, argValue;
19                 children = children.collect({ arg subtree;
20                         var name, thing, value;
21                         #name, thing, value = subtree;
22                         if (thing.isArray, {
23                                 this.tree(thing, name, value);
24                         },{
25                                 OSCNode(name, thing, nil, value);
26                         });
27                 });
28                 ^OSCNode(argName, nil, children, argValue);
29         }
30         add { arg child;
31                 if (children.isNil, { children = Array.new(4) });
32                 children = children.add(child);
33         }
34         remove { arg child;
35                 if (children.notNil, { children.take(child); });
36         }
37         empty {
38                 children = nil;
39         }
40         name_ { arg theName; name = theName.asSymbol; }
42         // these are for send and reply on the same machine.
43         send { arg oscAddress ... args;
44                 _OSCNode_Send
45                 ^this.primitiveFailed;
46         }
47         reply { arg oscAddress ... args;
48                 _OSCNode_Send
49                 ^this.primitiveFailed;
50         }
52         *initClass {
53                 // Build the default behaviour for all input ports.
54                 // You might want to comment some or all of this out for installations
55                 // so you can't be hacked..
56                 sc = this.tree([
57                         [\interpreter, [
58                                 // Warning: the 'run' method makes SC vulnerable executing any
59                                 // code sent to it over the net. If you don't want to worry about it
60                                 // then never set the password and you'll be safe.
61                                 [\run, { arg node, msgPassword, string;
62                                         if (password.isKindOf(Symbol) and: { password === msgPassword },
63                                         {
64                                                 string.interpret; // a powerful tool for both Good and Evil...
65                                         })
66                                 }],
67                                 [\set, { arg node, varName, value; // set one of the variables a-z in the interpreter
68                                         thisProcess.interpreter.perform(varName.asSetter, value);
69                                 }],
70                                 [\clearAll, { thisProcess.interpreter.clearAll; }],
71                                 [\executeFile, { arg node, pathname; thisProcess.interpreter.executeFile(pathname); }]
72                         ]],
74                         [\library, [
75                                 [\choose, { arg node, names; Library.prLibMenuChoose(names); }],
76                                 [\perform, { arg node, names, selector ... args;
77                                         var obj;
78                                         obj = Library.at(names);
79                                         if (obj.notNil, {
80                                                 obj.performList(selector, args);
81                                         });
82                                 }]
83                         ]],
85                         [\obj, [
86                                 [\perform, { arg node, id, selector ... args;
87                                         var obj;
88                                         obj = ObjectTable.at(id);
89                                         if (obj.notNil, {
90                                                 obj.performList(selector, args);
91                                         });
92                                 }],
94                                 // a function cannot be sent via the OSC, so 'put' only works using
95                                 // inter-VM-messaging on the same machine.
96                                 [\put, { arg node, id, function; ObjectTable.put(id, function.value); }],
98                                 [\remove, { arg node, id; ObjectTable.remove(id); }]
99                         ]],
100                         [\sound, [
101                                 [\play, { arg node, pathName, duration, loop=false;
102                                         SoundFile.play(pathName, duration: duration, loop: loop);
103                                 }]
104                         ]],
105                         [\mixer, [
106                                 [\stop, { arg node, channel;
107                                         MixerPlayer.forInput(channel, { arg input;
108                                                 input.killBox.value = 0;
109                                                 input.killBox.doAction;
110                                         });
111                                 }],
112                                 [\copy, { arg node, channel;
113                                         MixerPlayer.forInput(channel, { arg input;
114                                                 input.copyBtn.doAction;
115                                         });
116                                 }],
117                                 [\volume, { arg node, channel, volume = 0.0;
118                                         MixerPlayer.forInput(channel, { arg input;
119                                                 input.volumeSlider.value = volume;
120                                         });
121                                 }],
122                                 [\close, { arg node;
123                                         MixerPlayer.mixer.notNil.if({
124                                                 MixerPlayer.mixer.close;
125                                         });
126                                 }]
127                         ]],
128                         [\ping, { arg node; node.port.reply("/sc/postln", "I'm listening") }],
129                         [\run, { thisProcess.run }],
130                         [\stop, { Synth.stop }],
131                         [\post, { arg node ... args; args.do({ arg item; item.post; " ".post; }); "\n".post; }],
132                         [\postln, { arg node ... args; args.do({ arg item; item.postln; });}]
133                 ]);
134         }
136         // PRIVATE
137         call { arg rcvPort ... args;
138                 port = rcvPort;
139                 value = function.valueArray(this, args);
140                 port = nil;
141         }
144 ////////////////////////////
146 // UDP support
148 OSCPort {
149         classvar <openPorts; // keep track of all open ports
150         var <portID, udpPort, <>oscNode;
152         *closeAll {
153                 if (openPorts.notNil, {
154                         openPorts.copy.do({ arg port; port.close; });
155                 });
156         }
157         close {
158                 openPorts.remove(this);
159                 this.prClose;
160         }
162         // PRIVATE
163         prClose {
164                 _OSCPort_Close
165                 ^this.primitiveFailed;
166         }
167         addOpenPort {
168                 if (openPorts.isNil, { openPorts = Array.new(4); });
169                 openPorts = openPorts.add(this);
170         }
173 OSCInPort : OSCPort {
174         // UDP port for incoming OSC messages
176         *new { arg portID, oscNode;
177                 ^super.new.init(portID, oscNode)
178         }
179         reply { arg oscAddress ... args;
180                 _OSCInPort_Reply
181                 ^this.primitiveFailed;
182         }
184         // PRIVATE
185         init { arg argPortID, argOSCNode;
186                 portID = argPortID;
187                 oscNode = argOSCNode;
188                 this.addOpenPort;
189                 this.prInit
190         }
191         prInit {
192                 _OSCInPort_Init
193                 ^this.primitiveFailed;
194         }
198 OSCOutPort : OSCPort {
199         // UDP port for outgoing OSC messages
200         var <hostname;
202         *new { arg portID, hostname, oscNode;
203                 ^super.new.init(portID, hostname, oscNode)
204         }
206         send { arg oscAddress ... args;
207                 _OSCOutPort_Send
208                 ^this.primitiveFailed;
209         }
210         sendNoTags { arg oscAddress ... args;
211                 _OSCOutPort_SendNoTags
212                 ^this.primitiveFailed;
213         }
214         sendRaw { arg rawArray;
215                 _OSCOutPort_SendRaw
216                 ^this.primitiveFailed;
217         }
219         sendArray { arg array;
220                 this.performList(\send, array);
221         }
223         // PRIVATE
224         init { arg argPortID, argHostname, argOSCNode;
225                 portID = argPortID;
226                 hostname = argHostname;
227                 oscNode = argOSCNode;
228                 this.addOpenPort;
229                 this.prInit
230         }
231         prInit {
232                 _OSCOutPort_Init
233                 ^this.primitiveFailed;
234         }