Audio/AudioControl: Lots of fixes
[audiocontrol.git] / OSC.py
1 import socket, struct
2 import Events, Logger
3
4 def osc_string(s) :
5     n = (len(s)+1)%4
6     if n : return s+'\0'*(5-n)
7     else : return s+'\0'
8
9
10 def osc_command(url,*args):
11     tag=","
12     argstring=""
13     for arg in args :
14         if type(arg) is int:
15             tag += 'i'
16             argstring += struct.pack(">I",arg)
17         elif type(arg) is str:
18             tag += 's'
19             argstring += osc_string(arg)
20         elif type(arg) is float:
21             tag += 'f'
22             argstring += struct.pack(">f",arg)
23         else:
24             raise RunstimeError, "Invalid OSC argument"
25     return osc_string(url) + osc_string(tag) + argstring
26
27
28 def osc_getstr(data):
29     i = data.index('\0')
30     s = data[:i]
31     n = (i+1)%4
32     if n : data = data[i+(5-n):]
33     else : data = data[i+1:]
34     return (s,data)
35
36
37 def osc_parse(data):
38     url,data = osc_getstr(data)
39     tag,data = osc_getstr(data)
40     values = []
41     for code in tag[1:]:
42         if code == 'i':
43             values.append(struct.unpack(">i",data[:4])[0])
44             data = data[4:]
45         elif code == 's':
46             v,data = osc_getstr(data)
47             values.append(v)
48         elif code == 'f':
49             values.append(struct.unpack(">f",data[:4])[0])
50             data = data[4:]
51         else:
52             raise RuntimeError, "Unknown OSC parameter type received"
53     return (url, values)
54
55
56 class OSCServer(Events.EventSource):
57
58     def __init__(self, addr, context):
59         Events.EventSource.__init__(self,
60                                     socket.socket(socket.AF_INET, socket.SOCK_DGRAM),
61                                     context)
62         self._addr = addr
63         self.fd().bind(addr)
64         self._handlers = {}
65
66     def registerHandler(self, addr, cb):
67         self._handlers[addr] = cb
68
69     def command(self, target, path, *args):
70         if args and type(args[0]) in (tuple, list) : args = args[0]
71         Logger.log('osc','osc://%s:%s%s %s'
72                    % (target[0], target[1], path,
73                       ' '.join(map(repr,args))))
74         self.fd().sendto(osc_command(path, *args),target)
75
76     def readEvents(self):
77         data, addr = self.fd().recvfrom(1024)
78         path, args = osc_parse(data)
79         Logger.log('oscrcv','osc://%s:%s%s %s' % (addr[0], addr[1], path,
80                                                   ' '.join(map(repr,args))))
81         handler = self._handlers.get(addr)
82         if handler:
83             return handler(path, args)
84         else:
85             return []
86
87     def localUrl(self):
88         return 'osc://%s:%s' % self._addr