1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25 """
26 Implementation of the OSC protocol for Twisted.
27
28 Server and clients use the pyliblo library to integrate well with a twisted
29 asynchronous networking application.
30
31 To use, install liblo from source (not from Ubuntu 8.10's package) and pyliblo.::
32
33 mkdir -p ~/src
34 pushd ~/src
35 svn co https://liblo.svn.sourceforge.net/svnroot/liblo/trunk liblo
36 pushd liblo
37 ./autogen.sh
38 make
39 sudo make install
40 popd
41 wget http://das.nasophon.de/download/pyliblo-0.8.0.tar.gz
42 tar -zxvf pyliblo-0.8.0.tar.gz
43 pushd pyliblo-0.8.0/
44 python setup.py build
45 sudo python setup.py install --prefix=/usr/local
46 popd
47 popd
48 """
49 import liblo
50 import sys
51 import time
52
53 from twisted.internet import reactor
54
55 VERBOSE = True
56
58 """
59 Raised when any OSC server error happens.
60 """
61 pass
62
64 """
65 Raised when any OSC client error happens.
66 """
67 pass
68
70 """
71 An OSC client can send OSC messages.
72 :param args: one or two arguments.
73 If one, it is either the port number or url.
74 If two, it is the host and the port.
75 [host], [port]
76 [addr | port]
77 """
79 self.args = args
80 if len(args) == 0:
81 args = 1234
82 self._target = None
83 self._setup()
84
86 try:
87 self._target = liblo.Address(*self.args)
88 except liblo.AddressError, e:
89 raise
90
92 """
93 Changes the port|host to send to.
94 """
95
96
97
98 self.args = args
99 self._setup()
100
102 """
103 See liblo.send : Simply omit the first argument.
104
105 :param addr: OSC address such as /foo/bar
106 Other args are arguments types and values.
107
108 You can use tuple of (type, value)
109 Types are "i", "s", "f", etc.
110 """
111 liblo.send(self._target, addr, *args)
112
114 """
115 An OSC server listens for incoming OSC messages.
116
117 The programmer must register callbacks in order to do something with the incoming data.
118 """
119 - def __init__(self, port=1234, interval=0.01):
120 """
121 :param interval: duration in seconds to wait between each poll
122 """
123 self.port = port
124 self._callbacks = []
125 self.interval = interval
126 self._server = None
127 self._delayed_id = None
128
129 self.started = False
130
132 """
133 Actually start the server.
134 """
135 self._setup()
136
138 """
139 Used to change the OSC port to listen to.
140 """
141 if port == self.port:
142 print "Port is already %d" % (port)
143 else:
144 self.port = port
145 if self.started:
146 self._setup()
147
149 """
150 Adds a callback for an OSC message.
151
152 :param addr: URL-like OSC address/pattern
153 :param type: string that enumerates the OSC types the method accepts
154 :param callback: pointer to a python function or method
155 :param args: List of any number of user data.
156
157 What liblo does is to check for matching callbacks in the order they
158 were registered, and when a match is found, the callback function is
159 called immediately. This means that, if the fallback is to be called
160 only when nothing else matches, it needs to be registered last.
161 """
162 global VERBOSE
163 for i in range(len(self._callbacks)):
164 if self._callbacks[i][0] == addr:
165 if VERBOSE:
166 print("Overriding the previous %s callback." % (addr))
167 self._callbacks[i] = [addr, types, callbacks, args]
168 return
169
170 self._callbacks.append([addr, types, callback, args])
171
173 """ Called once it is time to start the server or change the port to listen to. """
174 global VERBOSE
175 if VERBOSE:
176 print("STarting OSC server on port %d" % (self.port))
177 print("If you experience a long delay while the application is frozen, you might need to upgrade you liblo to the latest version instead of the version packaged with your operating system. Use the latest tarball instead of the .deb.")
178 try:
179 self._server = liblo.Server(self.port)
180 except liblo.ServerError, e:
181 raise
182 else:
183 for callback_list in self._callbacks:
184 addr, types, callback, args = callback_list
185 if VERBOSE:
186 print("Adding OSC method %s %s %s %s" % (addr, types, callback, args))
187 self._server.add_method(addr, types, callback, *args)
188 self.started = True
189 self._delayed_id = reactor.callLater(self.interval, self._poll)
190
192 """ Called often by twisted.reactor to poll the OSC server. """
193 self._server.recv(0)
194 if self.started:
195
196 self._delayed_id = reactor.callLater(self.interval, self._poll)
197
198 if __name__ == "__main__":
199
201 i, f = args
202 print "received message '%s' with arguments '%d' and '%f'" % (path, i, f)
203
205 i = args[0]
206 print "received message '%s' with argument '%d' " % (path, i)
207 print "user data : ", data
208 data.set_port(i)
209
211 print "received message '%s'" % path
212 print "blob contains %d bytes, user data was '%s'" % (len(args[0]), data)
213
215 print "got unknown message '%s' from '%s'" % (path, src.get_url())
216 for a, t in zip(args, types):
217 print "argument of type '%s': %s" % (t, a)
218
220 i, f, s = args
221 print "received message '%s' with arguments '%d', '%f' and '%s'" % (path, i, f, s)
222
226
227
228
229 client_addr = "osc.udp://127.0.0.1:1234"
230
231
232
233 s = OscServer(1234)
234 s.add_callback("/foo/bar", "if", foo_bar_callback)
235 s.add_callback("/set/port", "i", set_port_callback, s)
236 s.add_callback("/foo/baz", "b", foo_baz_callback, "blah")
237 s.add_callback("/ping", "ifs", ping_callback)
238 s.add_callback(None, None, fallback)
239 print("Will now start listening OSC server...")
240 s.start()
241 print("Server started. ")
242 reactor.callLater(1.0, send_something, client_addr)
243
244 try:
245 reactor.run()
246 except KeyboardInterrupt:
247 print("Exiting.")
248