root/trunk/libffado/support/mixer/osc.py

Revision 459, 6.9 kB (checked in by ppalmers, 17 years ago)

- Add basic OSC mixer control for Phase88

Line 
1 # ======================================================================
2 # file:         OSC.py
3 # author:       stefan kersten <steve@k-hornz.de>
4 # contents:     OSC client module for python
5 # license:      public domain
6 # ======================================================================
7 # $Id: osc.py,v 1.1 2005/03/01 14:36:21 nebogeo Exp $
8 # ======================================================================
9 # copyright (c) 2000 stefan kersten
10 # ======================================================================
11 # this module provides simple OSC client functionality
12 # usage examples down at the end of the file
13 # ======================================================================
14
15 __revision__ = "$Revision: 1.1 $"
16
17 # ======================================================================
18 # imports
19
20 import cStringIO, exceptions, math, socket, struct, time, types
21
22 # ======================================================================
23 # constants
24
25 SECONDS_UTC_TO_UNIX_EPOCH = 2208988800.0
26 FLOAT_TO_INT_SCALE = pow(2.0, 32.0)
27
28 # ======================================================================
29 # types
30
31 class Value:
32     """Abstract OSC value."""
33     def __init__(self, value):
34         self.value = value
35
36     def binary_value(self):
37         pass
38
39     def type_tag(self):
40         pass
41
42 class Int(Value):
43     """32 bit integer value."""
44     def __init__(self, value):
45         Value.__init__(self, long(value))
46        
47     def binary_value(self):
48         return struct.pack('!l', self.value)
49
50     def type_tag(self):
51         return 'i'
52
53 class Float(Value):
54     """32 bit floating point value."""
55     def __init__(self, value):
56         Value.__init__(self, float(value))
57        
58     def binary_value(self):
59         return struct.pack('!f', self.value)
60
61     def type_tag(self):
62         return 'f'
63
64 class String(Value):
65     """Null-terminated string padded to multiples of 4 byte."""
66     def __init__(self, value):
67         Value.__init__(self, str(value))
68        
69     def binary_value(self):
70         v = self.value
71         l = len(v)
72         return struct.pack('%ds%dx' % (l, self.pad_amount(l)), v)
73
74     def type_tag(self):
75         return 's'
76    
77     def pad_amount(self, len):
78         return 4 - (len % 4)
79
80 class Time(Value):
81     """64 bit timetag in NTP format."""
82     def __init__(self, value):
83         Value.__init__(self, float(value))
84        
85     def __add__(self, time):
86         return Time(float(self.value + time.value))
87
88     def binary_value(self):
89         t = self.value
90         # FIXME: how to convert without overflows?
91         s = long(t)
92         f = long(math.fmod(t, 1.0)*FLOAT_TO_INT_SCALE)
93         return struct.pack('!LL', s, f)
94
95 # ======================================================================
96 # utilities
97
98 time_module = time
99 def time():
100     """Return current time as float in OSC format."""
101     return SECONDS_UTC_TO_UNIX_EPOCH + time_module.time()
102
103 # ======================================================================
104 # classes
105
106 class Packet:
107     """Abstract base class for all OSC-related containers.
108
109     Has methods for retrieving the proper binary representation
110     and its size.
111     """
112     def __init__(self, packets):
113         stream = cStringIO.StringIO()
114         self._write_contents(packets, stream)
115         self._data = stream.getvalue()
116
117     def get_packet(self):
118         """Return the binary representation of the receiver's contents.
119
120         This data is in the proper OSC format and can be sent over a
121         socket.
122         """
123         return self._data
124
125     def get_size(self):
126         """Return the size of the receiver's binary data."""
127         return len(self._data)
128    
129     def _write_contents(self, packets, stream):
130         """Write packets on stream.
131
132         Private.
133
134         Override in subclasses for specific behavior.
135         """
136         pass
137
138     def __repr__(self):
139         return '<' + \
140                str(self.__class__.__name__) + \
141                ' instance, size=' + \
142                str(self.get_size()) + \
143                '>'
144
145     def sendto(self, host, port):
146         """Send the receiver's data through a UDP socket."""
147         s = socket.socket(socket.SOCK_DGRAM, socket.AF_INET)
148         packet = self.get_packet()
149         s.sendto(packet, (host, port))
150         s.close()
151
152     def sendlocal(self, port):
153         """Send the receiver's data through a UDP socket locally."""
154         self.sendto('localhost', port)
155
156 def _value(x):
157     """Convert x(int, float or string) to an OSC object."""
158     t = type(x)
159     if t == types.FloatType:
160         return Float(x)
161     if t == types.IntType or t == types.LongType:
162         return Int(x)
163     # return string representation as default
164     return String(str(x))
165
166 class Message(Packet):
167     """Single OSC message with arguments.
168
169     Message(address, *args) -> Message
170    
171     address     -- OSC address string
172     *args       -- message argument list
173     """
174     def __init__(self, address, args=[]):
175         Packet.__init__(self, [String(address)] + map(lambda x: _value(x), args))
176
177     def _write_contents(self, args, stream):
178         t_stream = cStringIO.StringIO() # tag stream
179         v_stream = cStringIO.StringIO() # value stream
180         # open signature string
181         t_stream.write(',')
182         # collect tags and arguments
183         for v in args[1:]:
184             t_stream.write(v.type_tag())
185             v_stream.write(v.binary_value())
186         # write address
187         stream.write(args[0].binary_value())
188         # write signature
189         stream.write(String(t_stream.getvalue()).binary_value())
190         # write arguments
191         stream.write(v_stream.getvalue())
192
193 class Bundle(Packet):
194     """OSC container type with timing information.
195
196     Bundle(time, packets) -> Bundle
197
198     time        -- floating point timetag in OSC units
199     packets     -- array of Packet(s)
200     """
201     def __init__(self, time, packets):
202         Packet.__init__(self, [Time(time)] + packets)
203
204     def _write_contents(self, args, stream):
205         # write '#bundle' preamble
206         stream.write(String('#bundle').binary_value())
207         # write timetag
208         stream.write(args[0].binary_value())
209         # write packets, prefixed with a byte count
210         for packet in args[1:]:
211             data = packet.get_packet()
212             size = len(data)
213             stream.write(Int(size).binary_value())
214             stream.write(data)
215
216 def test(port):
217     """Some example messages and bundles, sent to port."""
218     Message("/filter/cutoff", [145.1232]).sendlocal(port)
219     Message("/http", ["www dot k-hornz dot de", 12, 3.41, "bulb"]).sendlocal(port)
220     # print Int(len(Message("/msg").get_packet())).binary_value()
221     Bundle(0.1, [Message("/fubar")]).sendlocal(port)
222     Bundle(time(), [Message("/msg", [1.0, "+", 1, 61, "0"]), Message("/bang!")]).sendlocal(port)
223
224 def test2():
225     """Some example messages and bundles, sent to port."""
226     Message("/noisepattern/start", ["hello"]).sendlocal(9898989)
227     Message("/noisepattern/modify", [1, "hello", "two"]).sendlocal(9898989)
228     print("/noisepattern/start")
229
230 if __name__ == "__main__":
231     """Run dump on port 10000."""
232     #test(10000)
233     test2()
234
235 # EOF
236 # ======================================================================
Note: See TracBrowser for help on using the browser.