0
# Message Handling
1
2
Core OSC message and bundle construction, parsing, and manipulation capabilities. This module provides the fundamental building blocks for creating and processing OSC messages and bundles with full support for all standard OSC data types.
3
4
## Capabilities
5
6
### Message Creation
7
8
Build OSC messages with typed arguments using the builder pattern or convenience functions.
9
10
```python { .api }
11
class OscMessageBuilder:
12
"""Builds arbitrary OSC messages with typed arguments."""
13
14
def __init__(self, address: Optional[str] = None):
15
"""Initialize builder with optional OSC address pattern."""
16
17
@property
18
def address(self) -> Optional[str]:
19
"""Get or set the OSC address pattern."""
20
21
@address.setter
22
def address(self, value: str):
23
"""Set the OSC address pattern."""
24
25
@property
26
def args(self) -> List[Tuple[str, Any]]:
27
"""Returns list of (type, value) argument tuples."""
28
29
def add_arg(self, arg_value: ArgValue, arg_type: Optional[str] = None):
30
"""Add typed argument to message.
31
32
Parameters:
33
- arg_value: The argument value (auto-typed if arg_type is None)
34
- arg_type: Explicit OSC type character ('i', 'f', 's', 'b', etc.)
35
"""
36
37
def build(self) -> OscMessage:
38
"""Build OscMessage from current state.
39
40
Returns:
41
OscMessage instance ready for transmission
42
43
Raises:
44
BuildError: If message cannot be built (missing address, etc.)
45
"""
46
47
def build_msg(address: str, value: ArgValue = "") -> OscMessage:
48
"""Convenience function to quickly build OSC message.
49
50
Parameters:
51
- address: OSC address pattern string
52
- value: Single argument value or list of values
53
54
Returns:
55
OscMessage ready for transmission
56
"""
57
```
58
59
### Message Parsing
60
61
Parse OSC messages from incoming datagram bytes with automatic type detection.
62
63
```python { .api }
64
class OscMessage:
65
"""Representation of a parsed OSC message."""
66
67
def __init__(self, dgram: bytes):
68
"""Initialize from datagram bytes.
69
70
Parameters:
71
- dgram: Raw OSC message datagram
72
73
Raises:
74
ParseError: If datagram cannot be parsed as OSC message
75
"""
76
77
@property
78
def address(self) -> str:
79
"""Returns OSC address pattern string."""
80
81
@property
82
def params(self) -> List[Any]:
83
"""Returns list of message parameters."""
84
85
@property
86
def size(self) -> int:
87
"""Returns datagram length in bytes."""
88
89
@property
90
def dgram(self) -> bytes:
91
"""Returns original datagram bytes."""
92
93
@staticmethod
94
def dgram_is_message(dgram: bytes) -> bool:
95
"""Check if datagram is an OSC message.
96
97
Parameters:
98
- dgram: Datagram bytes to check
99
100
Returns:
101
True if dgram contains OSC message
102
"""
103
104
def __iter__(self):
105
"""Iterator over message parameters."""
106
107
def __str__(self) -> str:
108
"""String representation of message."""
109
```
110
111
### Bundle Creation
112
113
Create OSC bundles that group messages and sub-bundles with shared timestamps for synchronized execution.
114
115
```python { .api }
116
class OscBundleBuilder:
117
"""Builds OSC bundles with timed message groups."""
118
119
def __init__(self, timestamp: Union[int, float]):
120
"""Initialize bundle with timestamp.
121
122
Parameters:
123
- timestamp: Execution time (seconds since epoch) or IMMEDIATELY constant
124
"""
125
126
def add_content(self, content: Union[OscMessage, OscBundle]):
127
"""Add message or sub-bundle to bundle.
128
129
Parameters:
130
- content: OscMessage or OscBundle to include
131
"""
132
133
def build(self) -> OscBundle:
134
"""Build OscBundle from current state.
135
136
Returns:
137
OscBundle ready for transmission
138
139
Raises:
140
BuildError: If bundle cannot be built
141
"""
142
143
# Bundle timing constant
144
IMMEDIATELY: int # Special timestamp value for immediate execution
145
```
146
147
### Bundle Parsing
148
149
Parse OSC bundles from datagram bytes and access contained messages and sub-bundles.
150
151
```python { .api }
152
class OscBundle:
153
"""Representation of a parsed OSC bundle."""
154
155
def __init__(self, dgram: bytes):
156
"""Initialize from datagram bytes.
157
158
Parameters:
159
- dgram: Raw OSC bundle datagram
160
161
Raises:
162
ParseError: If datagram cannot be parsed as OSC bundle
163
"""
164
165
@property
166
def timestamp(self) -> float:
167
"""Returns bundle timestamp as seconds since epoch."""
168
169
@property
170
def num_contents(self) -> int:
171
"""Returns number of contained elements."""
172
173
@property
174
def size(self) -> int:
175
"""Returns datagram length in bytes."""
176
177
@property
178
def dgram(self) -> bytes:
179
"""Returns original datagram bytes."""
180
181
def content(self, index: int) -> Union[OscMessage, OscBundle]:
182
"""Returns bundle content at given index.
183
184
Parameters:
185
- index: Zero-based index of content element
186
187
Returns:
188
OscMessage or OscBundle at the specified index
189
"""
190
191
@staticmethod
192
def dgram_is_bundle(dgram: bytes) -> bool:
193
"""Check if datagram is an OSC bundle.
194
195
Parameters:
196
- dgram: Datagram bytes to check
197
198
Returns:
199
True if dgram contains OSC bundle
200
"""
201
202
def __iter__(self):
203
"""Iterator over bundle contents."""
204
```
205
206
### Packet Processing
207
208
Handle complete OSC transmissions that may contain messages or bundles with timing information.
209
210
```python { .api }
211
class OscPacket:
212
"""Represents complete OSC transmission unit."""
213
214
def __init__(self, dgram: bytes):
215
"""Initialize from UDP datagram bytes.
216
217
Parameters:
218
- dgram: Complete OSC packet datagram
219
220
Raises:
221
ParseError: If packet cannot be parsed
222
"""
223
224
@property
225
def messages(self) -> List[TimedMessage]:
226
"""Returns time-sorted list of messages for execution.
227
228
Returns:
229
List of TimedMessage objects with execution timestamps
230
"""
231
232
class TimedMessage:
233
"""Message with execution timestamp."""
234
235
time: float # Execution timestamp (seconds since epoch)
236
message: OscMessage # The actual OSC message
237
```
238
239
### Message Builder Constants
240
241
Type constants for explicit argument typing in message builders.
242
243
```python { .api }
244
# Numeric types
245
ARG_TYPE_INT: str = "i" # 32-bit integer
246
ARG_TYPE_INT64: str = "h" # 64-bit integer
247
ARG_TYPE_FLOAT: str = "f" # 32-bit float
248
ARG_TYPE_DOUBLE: str = "d" # 64-bit double
249
250
# Data types
251
ARG_TYPE_STRING: str = "s" # UTF-8 string
252
ARG_TYPE_BLOB: str = "b" # Binary data
253
254
# Special types
255
ARG_TYPE_RGBA: str = "r" # RGBA color (32-bit)
256
ARG_TYPE_MIDI: str = "m" # MIDI packet (4 bytes)
257
258
# Boolean/null types
259
ARG_TYPE_TRUE: str = "T" # Boolean true
260
ARG_TYPE_FALSE: str = "F" # Boolean false
261
ARG_TYPE_NIL: str = "N" # Null/nil value
262
263
# Array delimiters
264
ARG_TYPE_ARRAY_START: str = "[" # Array start marker
265
ARG_TYPE_ARRAY_STOP: str = "]" # Array end marker
266
```
267
268
## Usage Examples
269
270
### Building Complex Messages
271
272
```python
273
from pythonosc.osc_message_builder import OscMessageBuilder, ARG_TYPE_FLOAT, ARG_TYPE_STRING
274
275
# Build message with explicit types
276
builder = OscMessageBuilder("/synth/params")
277
builder.add_arg(440.0, ARG_TYPE_FLOAT)
278
builder.add_arg("sine", ARG_TYPE_STRING)
279
builder.add_arg([1, 2, 3]) # Auto-typed as array
280
message = builder.build()
281
282
# Quick message building
283
from pythonosc.osc_message_builder import build_msg
284
msg = build_msg("/filter", 0.75)
285
```
286
287
### Creating Synchronized Bundles
288
289
```python
290
from pythonosc.osc_bundle_builder import OscBundleBuilder, IMMEDIATELY
291
import time
292
293
# Create bundle for immediate execution
294
bundle_builder = OscBundleBuilder(IMMEDIATELY)
295
bundle_builder.add_content(build_msg("/note/on", [60, 127]))
296
bundle_builder.add_content(build_msg("/note/on", [64, 127]))
297
bundle_builder.add_content(build_msg("/note/on", [67, 127]))
298
chord_bundle = bundle_builder.build()
299
300
# Create bundle for future execution
301
future_time = time.time() + 2.0 # 2 seconds from now
302
delayed_builder = OscBundleBuilder(future_time)
303
delayed_builder.add_content(build_msg("/note/off", [60, 64, 67]))
304
delayed_bundle = delayed_builder.build()
305
```
306
307
### Parsing Incoming Data
308
309
```python
310
from pythonosc.osc_message import OscMessage
311
from pythonosc.osc_bundle import OscBundle
312
from pythonosc.osc_packet import OscPacket
313
314
# Parse raw datagram
315
def handle_datagram(dgram_bytes):
316
if OscMessage.dgram_is_message(dgram_bytes):
317
message = OscMessage(dgram_bytes)
318
print(f"Message: {message.address} {message.params}")
319
elif OscBundle.dgram_is_bundle(dgram_bytes):
320
bundle = OscBundle(dgram_bytes)
321
print(f"Bundle with {bundle.num_contents} items at {bundle.timestamp}")
322
for i in range(bundle.num_contents):
323
content = bundle.content(i)
324
if isinstance(content, OscMessage):
325
print(f" Message: {content.address} {content.params}")
326
327
# Or use packet for unified handling
328
packet = OscPacket(dgram_bytes)
329
for timed_msg in packet.messages:
330
print(f"Execute at {timed_msg.time}: {timed_msg.message}")
331
```
332
333
## Types and Exceptions
334
335
```python { .api }
336
from typing import Union, List, Tuple, Any, Optional
337
338
ArgValue = Union[str, bytes, bool, int, float, MidiPacket, list]
339
MidiPacket = Tuple[int, int, int, int] # (port_id, status_byte, data1, data2)
340
341
class ParseError(Exception):
342
"""Raised when datagram parsing fails."""
343
344
class BuildError(Exception):
345
"""Raised when message/bundle building fails."""
346
```