Audio/AudioControl: Commit loads of long uncommited changes
[audiocontrol.git] / OSC.py
diff --git a/OSC.py b/OSC.py
new file mode 100644 (file)
index 0000000..e248b47
--- /dev/null
+++ b/OSC.py
@@ -0,0 +1,88 @@
+import socket, struct
+import Events, Logger
+
+def osc_string(s) :
+    n = (len(s)+1)%4
+    if n : return s+'\0'*(5-n)
+    else : return s+'\0'
+
+
+def osc_command(url,*args):
+    tag=","
+    argstring=""
+    for arg in args :
+        if type(arg) is int:
+            tag += 'i'
+            argstring += struct.pack(">I",arg)
+        elif type(arg) is str:
+            tag += 's'
+            argstring += osc_string(arg)
+        elif type(arg) is float:
+            tag += 'f'
+            argstring += struct.pack(">f",arg)
+        else:
+            raise RunstimeError, "Invalid OSC argument"
+    return osc_string(url) + osc_string(tag) + argstring
+
+
+def osc_getstr(data):
+    i = data.index('\0')
+    s = data[:i]
+    n = (i+1)%4
+    if n : data = data[i+(5-n):]
+    else : data = data[i+1:]
+    return (s,data)
+
+
+def osc_parse(data):
+    url,data = osc_getstr(data)
+    tag,data = osc_getstr(data)
+    values = []
+    for code in tag[1:]:
+        if code == 'i':
+            values.append(struct.unpack(">i",data[:4])[0])
+            data = data[4:]
+        elif code == 's':
+            v,data = osc_getstr(data)
+            values.append(v)
+        elif code == 'f':
+            values.append(struct.unpack(">f",data[:4])[0])
+            data = data[4:]
+        else:
+            raise RuntimeError, "Unknown OSC parameter type received"
+    return (url, values)
+
+
+class OSCServer(Events.EventSource):
+
+    def __init__(self, addr, context):
+        Events.EventSource.__init__(self,
+                                    socket.socket(socket.AF_INET, socket.SOCK_DGRAM),
+                                    context)
+        self._addr = addr
+        self.fd().bind(addr)
+        self._handlers = {}
+
+    def registerHandler(self, addr, cb):
+        self._handlers[addr] = cb
+
+    def command(self, target, path, *args):
+        if args and type(args[0]) in (tuple, list) : args = args[0]
+        Logger.log('osc','osc://%s:%s%s %s'
+                   % (target[0], target[1], path,
+                      ' '.join(map(repr,args))))
+        self.fd().sendto(osc_command(path, *args),target)
+
+    def readEvents(self):
+        data, addr = self.fd().recvfrom(1024)
+        path, args = osc_parse(data)
+        Logger.log('oscrcv','osc://%s:%s%s %s' % (addr[0], addr[1], path,
+                                                  ' '.join(map(repr,args))))
+        handler = self._handlers.get(addr)
+        if handler:
+            return handler(path, args)
+        else:
+            return []
+
+    def localUrl(self):
+        return 'osc://%s:%s' % self._addr