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