oscparser 1.1.0__py3-none-any.whl
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- oscparser/__init__.py +70 -0
- oscparser/ctx.py +17 -0
- oscparser/decode.py +82 -0
- oscparser/encode.py +78 -0
- oscparser/framing/__init__.py +6 -0
- oscparser/framing/framer.py +18 -0
- oscparser/framing/fullframer.py +42 -0
- oscparser/framing/osc10.py +70 -0
- oscparser/framing/osc11.py +208 -0
- oscparser/processing/args/args.py +550 -0
- oscparser/processing/args/proccessing.py +29 -0
- oscparser/processing/osc/handlers.py +165 -0
- oscparser/processing/osc/processing.py +46 -0
- oscparser/types.py +263 -0
- oscparser-1.1.0.dist-info/METADATA +60 -0
- oscparser-1.1.0.dist-info/RECORD +19 -0
- oscparser-1.1.0.dist-info/WHEEL +5 -0
- oscparser-1.1.0.dist-info/licenses/LICENSE +21 -0
- oscparser-1.1.0.dist-info/top_level.txt +1 -0
|
@@ -0,0 +1,165 @@
|
|
|
1
|
+
import struct
|
|
2
|
+
from typing import Any, cast
|
|
3
|
+
|
|
4
|
+
from oscparser.ctx import DataBuffer
|
|
5
|
+
from oscparser.processing.args.args import (
|
|
6
|
+
ArgDispatcher,
|
|
7
|
+
_decode_string,
|
|
8
|
+
_encode_string,
|
|
9
|
+
create_arg_dispatcher,
|
|
10
|
+
)
|
|
11
|
+
from oscparser.processing.osc.processing import OSCDispatcher, OSCPacketHandler
|
|
12
|
+
from oscparser.types import OSCArg, OSCBundle, OSCMessage
|
|
13
|
+
|
|
14
|
+
_BUNDLE_PREFIX = b"#bundle\x00"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
class OSCBundleHandler(OSCPacketHandler[OSCBundle]):
|
|
18
|
+
"""Handler for OSC bundles - timetag + nested elements."""
|
|
19
|
+
|
|
20
|
+
def __init__(self, dispatcher: OSCDispatcher):
|
|
21
|
+
self.dispatcher = dispatcher
|
|
22
|
+
|
|
23
|
+
@classmethod
|
|
24
|
+
def from_dispatcher(cls, dispatcher: OSCDispatcher, arg_dispatcher: ArgDispatcher) -> "OSCBundleHandler":
|
|
25
|
+
return cls(dispatcher)
|
|
26
|
+
|
|
27
|
+
def decode(self, ctx: DataBuffer) -> OSCBundle:
|
|
28
|
+
"""Decode an OSC bundle from data buffer.
|
|
29
|
+
|
|
30
|
+
Format:
|
|
31
|
+
- Bundle prefix "#bundle\\x00"
|
|
32
|
+
- Timetag (64-bit NTP timestamp)
|
|
33
|
+
- Elements (size + content pairs)
|
|
34
|
+
"""
|
|
35
|
+
# Read and verify bundle prefix
|
|
36
|
+
prefix = ctx.read(len(_BUNDLE_PREFIX))
|
|
37
|
+
if prefix != _BUNDLE_PREFIX:
|
|
38
|
+
raise ValueError(f"Invalid bundle prefix: {prefix!r}")
|
|
39
|
+
|
|
40
|
+
# Read timetag (64-bit big-endian integer)
|
|
41
|
+
timetag = struct.unpack(">Q", ctx.read(8))[0]
|
|
42
|
+
|
|
43
|
+
# Parse bundle elements
|
|
44
|
+
elements: list[Any] = []
|
|
45
|
+
|
|
46
|
+
while ctx.remaining() > 0:
|
|
47
|
+
# Read element size (32-bit big-endian integer)
|
|
48
|
+
element_size = struct.unpack(">I", ctx.read(4))[0]
|
|
49
|
+
|
|
50
|
+
# Read element data
|
|
51
|
+
element_data = DataBuffer(ctx.read(element_size))
|
|
52
|
+
|
|
53
|
+
# Recursively decode the element using dispatcher
|
|
54
|
+
handler = self.dispatcher.get_handler(element_data)
|
|
55
|
+
element = handler.decode(element_data)
|
|
56
|
+
|
|
57
|
+
elements.append(element)
|
|
58
|
+
|
|
59
|
+
return OSCBundle(timetag=timetag, elements=tuple(elements))
|
|
60
|
+
|
|
61
|
+
def encode(self, packet: OSCBundle, buf: DataBuffer):
|
|
62
|
+
"""Encode an OSC bundle to bytes."""
|
|
63
|
+
if not isinstance(packet, OSCBundle):
|
|
64
|
+
raise TypeError(f"Expected OSCBundle, got {type(packet)}")
|
|
65
|
+
|
|
66
|
+
# Write bundle prefix
|
|
67
|
+
buf.write(_BUNDLE_PREFIX)
|
|
68
|
+
|
|
69
|
+
# Write timetag
|
|
70
|
+
buf.write(struct.pack(">Q", packet.timetag))
|
|
71
|
+
|
|
72
|
+
# Encode each element
|
|
73
|
+
for element in packet.elements:
|
|
74
|
+
# Recursively encode element
|
|
75
|
+
result = DataBuffer(b"")
|
|
76
|
+
element_handler = self.dispatcher.get_object_handler(type(element))
|
|
77
|
+
element_handler.encode(element, result)
|
|
78
|
+
# Write element size
|
|
79
|
+
buf.write(struct.pack(">I", len(result.data)))
|
|
80
|
+
|
|
81
|
+
# Write element data
|
|
82
|
+
buf.write(result.data)
|
|
83
|
+
|
|
84
|
+
|
|
85
|
+
class OSCMessageHandler(OSCPacketHandler[OSCMessage]):
|
|
86
|
+
"""Handler for OSC messages - address pattern + typed arguments."""
|
|
87
|
+
|
|
88
|
+
def __init__(self, dispatcher: OSCDispatcher, arg_dispatcher: ArgDispatcher):
|
|
89
|
+
self.dispatcher = dispatcher
|
|
90
|
+
# Use the arg dispatcher for handling individual arguments
|
|
91
|
+
self.arg_dispatcher = arg_dispatcher if arg_dispatcher is not None else create_arg_dispatcher()
|
|
92
|
+
|
|
93
|
+
@classmethod
|
|
94
|
+
def from_dispatcher(cls, dispatcher: OSCDispatcher, arg_dispatcher: ArgDispatcher) -> "OSCMessageHandler":
|
|
95
|
+
return cls(dispatcher, arg_dispatcher)
|
|
96
|
+
|
|
97
|
+
def decode(self, ctx: DataBuffer) -> OSCMessage:
|
|
98
|
+
"""Decode an OSC message from data buffer.
|
|
99
|
+
|
|
100
|
+
Format:
|
|
101
|
+
- Address pattern (string)
|
|
102
|
+
- Type tag string (string starting with ',')
|
|
103
|
+
- Arguments (based on type tags)
|
|
104
|
+
"""
|
|
105
|
+
# Parse address pattern
|
|
106
|
+
address = _decode_string(ctx)
|
|
107
|
+
|
|
108
|
+
# Check if there are any bytes remaining
|
|
109
|
+
if ctx.remaining() == 0:
|
|
110
|
+
# No arguments
|
|
111
|
+
return OSCMessage(address=address, args=())
|
|
112
|
+
|
|
113
|
+
# Parse type tag string
|
|
114
|
+
type_tag_string = _decode_string(ctx)
|
|
115
|
+
|
|
116
|
+
if not type_tag_string.startswith(","):
|
|
117
|
+
raise ValueError(f"Type tag string must start with ',': {type_tag_string!r}")
|
|
118
|
+
|
|
119
|
+
# Remove the leading comma
|
|
120
|
+
type_tags = type_tag_string[1:]
|
|
121
|
+
|
|
122
|
+
# Parse arguments based on type tags
|
|
123
|
+
args: list[OSCArg] = []
|
|
124
|
+
|
|
125
|
+
typetag_ctx = DataBuffer(type_tags.encode("utf-8"))
|
|
126
|
+
|
|
127
|
+
while typetag_ctx.remaining() > 0:
|
|
128
|
+
tag = typetag_ctx.read(1)
|
|
129
|
+
|
|
130
|
+
handler = self.arg_dispatcher.get_handler_by_tag(tag)
|
|
131
|
+
arg = cast(OSCArg, handler.decode(ctx, typetag_ctx))
|
|
132
|
+
args.append(arg)
|
|
133
|
+
|
|
134
|
+
return OSCMessage(address=address, args=tuple(args))
|
|
135
|
+
|
|
136
|
+
def encode(self, packet: OSCMessage, buf: DataBuffer):
|
|
137
|
+
"""Encode an OSC message to bytes."""
|
|
138
|
+
if not isinstance(packet, OSCMessage):
|
|
139
|
+
raise TypeError(f"Expected OSCMessage, got {type(packet)}")
|
|
140
|
+
|
|
141
|
+
# Encode address pattern
|
|
142
|
+
buf.write(_encode_string(packet.address))
|
|
143
|
+
|
|
144
|
+
# Build type tag string and argument data
|
|
145
|
+
typetag_ctx = DataBuffer(b"")
|
|
146
|
+
args_ctx = DataBuffer(b"")
|
|
147
|
+
|
|
148
|
+
# Start type tag string with comma
|
|
149
|
+
typetag_ctx.write(b",")
|
|
150
|
+
|
|
151
|
+
for arg in packet.args:
|
|
152
|
+
handler = self.arg_dispatcher.get_handler_by_object(type(arg))
|
|
153
|
+
handler.encode(arg, args_ctx, typetag_ctx)
|
|
154
|
+
|
|
155
|
+
# Write type tag string
|
|
156
|
+
buf.write(_encode_string(typetag_ctx.data.decode("utf-8")))
|
|
157
|
+
|
|
158
|
+
# Write argument data
|
|
159
|
+
buf.write(args_ctx.data)
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
def register_osc_handlers(dispatcher: OSCDispatcher) -> None:
|
|
163
|
+
"""Register OSC message and bundle handlers."""
|
|
164
|
+
dispatcher.register_handler(OSCMessage, b"/", OSCMessageHandler)
|
|
165
|
+
dispatcher.register_handler(OSCBundle, b"#bundle\x00", OSCBundleHandler)
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
from typing import Any, Protocol
|
|
2
|
+
|
|
3
|
+
from oscparser.ctx import DataBuffer
|
|
4
|
+
from oscparser.processing.args.args import create_arg_dispatcher
|
|
5
|
+
from oscparser.processing.args.proccessing import ArgDispatcher
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
class OSCPacketHandler[T: object = object](Protocol):
|
|
9
|
+
"""Protocol for OSC packet handlers (messages and bundles)."""
|
|
10
|
+
|
|
11
|
+
@classmethod
|
|
12
|
+
def from_dispatcher(cls, dispatcher: "OSCDispatcher", arg_dispatcher: ArgDispatcher) -> "OSCPacketHandler[T]": ...
|
|
13
|
+
|
|
14
|
+
def decode(self, ctx: DataBuffer) -> T:
|
|
15
|
+
"""Decode OSC packet from data buffer."""
|
|
16
|
+
...
|
|
17
|
+
|
|
18
|
+
def encode(self, packet: T, buf: DataBuffer):
|
|
19
|
+
"""Encode OSC packet to bytes."""
|
|
20
|
+
...
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
class OSCDispatcher:
|
|
24
|
+
"""Dispatcher for OSC packet types (messages and bundles)."""
|
|
25
|
+
|
|
26
|
+
def __init__(self, arg_dispatcher: ArgDispatcher | None = None):
|
|
27
|
+
self._handlers: dict[bytes, OSCPacketHandler[Any]] = {}
|
|
28
|
+
self._object_handlers: dict[type, OSCPacketHandler[Any]] = {}
|
|
29
|
+
self._arg_dispatcher = arg_dispatcher if arg_dispatcher is not None else create_arg_dispatcher()
|
|
30
|
+
|
|
31
|
+
def register_handler[T: object](self, obj: type[T], handler_tag: bytes, handler: type[OSCPacketHandler[T]]) -> None:
|
|
32
|
+
"""Register a packet handler."""
|
|
33
|
+
handler_inst = handler.from_dispatcher(self, self._arg_dispatcher)
|
|
34
|
+
self._handlers[handler_tag] = handler_inst
|
|
35
|
+
self._object_handlers[obj] = handler_inst
|
|
36
|
+
|
|
37
|
+
def get_handler(self, data: DataBuffer) -> OSCPacketHandler:
|
|
38
|
+
"""Get appropriate handler for the given data."""
|
|
39
|
+
for handler_tag, handler in self._handlers.items():
|
|
40
|
+
if data.startswith(handler_tag):
|
|
41
|
+
return handler
|
|
42
|
+
raise ValueError("No handler found")
|
|
43
|
+
|
|
44
|
+
def get_object_handler[T](self, obj: type[T]) -> OSCPacketHandler[T]:
|
|
45
|
+
"""Get handler for the given object type."""
|
|
46
|
+
return self._object_handlers[obj]
|
oscparser/types.py
ADDED
|
@@ -0,0 +1,263 @@
|
|
|
1
|
+
"""OSC 1.0 / 1.1 data types.
|
|
2
|
+
|
|
3
|
+
This module defines Python classes and type aliases that model the
|
|
4
|
+
Open Sound Control 1.0 atomic types, composite types (messages and
|
|
5
|
+
bundles), and the additional recommended argument tags listed in the
|
|
6
|
+
specification (often referred to as "OSC 1.1").
|
|
7
|
+
|
|
8
|
+
It does **not** implement parsing or encoding; it is purely types.
|
|
9
|
+
"""
|
|
10
|
+
|
|
11
|
+
from __future__ import annotations
|
|
12
|
+
|
|
13
|
+
from datetime import datetime
|
|
14
|
+
from typing import ClassVar, Tuple, Union
|
|
15
|
+
|
|
16
|
+
from pydantic import BaseModel
|
|
17
|
+
|
|
18
|
+
|
|
19
|
+
class _FrozenModel(BaseModel):
|
|
20
|
+
"""Base class for immutable OSC value types."""
|
|
21
|
+
|
|
22
|
+
class Config:
|
|
23
|
+
frozen = True
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
class OSCInt(_FrozenModel):
|
|
27
|
+
"""32-bit signed integer argument (tag 'i')."""
|
|
28
|
+
|
|
29
|
+
TAG: ClassVar[str] = "i"
|
|
30
|
+
value: int
|
|
31
|
+
|
|
32
|
+
def __init__(self, value: int) -> None:
|
|
33
|
+
super().__init__(value=value) # type: ignore
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
class OSCFloat(_FrozenModel):
|
|
37
|
+
"""32-bit IEEE 754 floating point argument (tag 'f')."""
|
|
38
|
+
|
|
39
|
+
TAG: ClassVar[str] = "f"
|
|
40
|
+
value: float
|
|
41
|
+
|
|
42
|
+
def __init__(self, value: float) -> None:
|
|
43
|
+
super().__init__(value=value) # type: ignore
|
|
44
|
+
|
|
45
|
+
|
|
46
|
+
class OSCString(_FrozenModel):
|
|
47
|
+
"""OSC string argument (tag 's')."""
|
|
48
|
+
|
|
49
|
+
TAG: ClassVar[str] = "s"
|
|
50
|
+
value: str
|
|
51
|
+
|
|
52
|
+
def __init__(self, value: str) -> None:
|
|
53
|
+
super().__init__(value=value) # type: ignore
|
|
54
|
+
|
|
55
|
+
|
|
56
|
+
class OSCBlob(_FrozenModel):
|
|
57
|
+
"""OSC blob argument (tag 'b')."""
|
|
58
|
+
|
|
59
|
+
TAG: ClassVar[str] = "b"
|
|
60
|
+
value: bytes
|
|
61
|
+
|
|
62
|
+
def __init__(self, value: bytes) -> None:
|
|
63
|
+
super().__init__(value=value) # type: ignore
|
|
64
|
+
|
|
65
|
+
|
|
66
|
+
class OSCTrue(_FrozenModel):
|
|
67
|
+
"""Boolean true argument (tag 'T')."""
|
|
68
|
+
|
|
69
|
+
TAG: ClassVar[str] = "T"
|
|
70
|
+
|
|
71
|
+
|
|
72
|
+
class OSCFalse(_FrozenModel):
|
|
73
|
+
"""Boolean false argument (tag 'F')."""
|
|
74
|
+
|
|
75
|
+
TAG: ClassVar[str] = "F"
|
|
76
|
+
|
|
77
|
+
|
|
78
|
+
class OSCNil(_FrozenModel):
|
|
79
|
+
"""Nil / null argument (tag 'N')."""
|
|
80
|
+
|
|
81
|
+
TAG: ClassVar[str] = "N"
|
|
82
|
+
|
|
83
|
+
|
|
84
|
+
class OSCInt64(_FrozenModel):
|
|
85
|
+
"""64-bit signed integer argument (tag 'h')."""
|
|
86
|
+
|
|
87
|
+
TAG: ClassVar[str] = "h"
|
|
88
|
+
value: int
|
|
89
|
+
|
|
90
|
+
def __init__(self, value: int) -> None:
|
|
91
|
+
super().__init__(value=value) # type: ignore
|
|
92
|
+
|
|
93
|
+
|
|
94
|
+
class OSCDouble(_FrozenModel):
|
|
95
|
+
"""64-bit IEEE 754 floating point argument (tag 'd')."""
|
|
96
|
+
|
|
97
|
+
TAG: ClassVar[str] = "d"
|
|
98
|
+
value: float
|
|
99
|
+
|
|
100
|
+
def __init__(self, value: float) -> None:
|
|
101
|
+
super().__init__(value=value) # type: ignore
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
class OSCTimeTag(_FrozenModel):
|
|
105
|
+
"""OSC timetag argument (tag 't'), represented as a datetime."""
|
|
106
|
+
|
|
107
|
+
TAG: ClassVar[str] = "t"
|
|
108
|
+
value: datetime
|
|
109
|
+
|
|
110
|
+
def __init__(self, value: datetime) -> None:
|
|
111
|
+
super().__init__(value=value) # type: ignore
|
|
112
|
+
|
|
113
|
+
|
|
114
|
+
class OSCChar(_FrozenModel):
|
|
115
|
+
"""Single ASCII / UTF-8 character argument (tag 'c')."""
|
|
116
|
+
|
|
117
|
+
TAG: ClassVar[str] = "c"
|
|
118
|
+
value: str # usually length 1
|
|
119
|
+
|
|
120
|
+
def __init__(self, value: str) -> None:
|
|
121
|
+
super().__init__(value=value) # type: ignore
|
|
122
|
+
|
|
123
|
+
|
|
124
|
+
class OSCSymbol(_FrozenModel):
|
|
125
|
+
"""Symbol argument (tag 'S'), semantically distinct from a string."""
|
|
126
|
+
|
|
127
|
+
TAG: ClassVar[str] = "S"
|
|
128
|
+
value: str
|
|
129
|
+
|
|
130
|
+
def __init__(self, value: str) -> None:
|
|
131
|
+
super().__init__(value=value) # type: ignore
|
|
132
|
+
|
|
133
|
+
|
|
134
|
+
class OSCRGBA(_FrozenModel):
|
|
135
|
+
"""RGBA color argument (tag 'r')."""
|
|
136
|
+
|
|
137
|
+
TAG: ClassVar[str] = "r"
|
|
138
|
+
r: int
|
|
139
|
+
g: int
|
|
140
|
+
b: int
|
|
141
|
+
a: int
|
|
142
|
+
|
|
143
|
+
|
|
144
|
+
class OSCMidi(_FrozenModel):
|
|
145
|
+
"""MIDI message argument (tag 'm').
|
|
146
|
+
|
|
147
|
+
Bytes from MSB to LSB are:
|
|
148
|
+
- port_id
|
|
149
|
+
- status
|
|
150
|
+
- data1
|
|
151
|
+
- data2
|
|
152
|
+
"""
|
|
153
|
+
|
|
154
|
+
TAG: ClassVar[str] = "m"
|
|
155
|
+
|
|
156
|
+
port_id: int
|
|
157
|
+
status: int
|
|
158
|
+
data1: int
|
|
159
|
+
data2: int
|
|
160
|
+
|
|
161
|
+
|
|
162
|
+
class OSCImpulse(_FrozenModel):
|
|
163
|
+
"""Impulse / infinitum / bang argument (tag 'I').
|
|
164
|
+
|
|
165
|
+
There is no payload; the presence of this value is the data.
|
|
166
|
+
"""
|
|
167
|
+
|
|
168
|
+
TAG: ClassVar[str] = "I"
|
|
169
|
+
|
|
170
|
+
# No fields
|
|
171
|
+
pass
|
|
172
|
+
|
|
173
|
+
|
|
174
|
+
# Singleton instance that can be reused for all impulse arguments.
|
|
175
|
+
OSC_IMPULSE = OSCImpulse()
|
|
176
|
+
|
|
177
|
+
|
|
178
|
+
class OSCArray(_FrozenModel):
|
|
179
|
+
"""Array argument (tags '[' ... ']').
|
|
180
|
+
|
|
181
|
+
Contains a sequence of other OSC arguments, which may themselves be
|
|
182
|
+
arrays (nested arrays are allowed by the 1.0 spec).
|
|
183
|
+
"""
|
|
184
|
+
|
|
185
|
+
OPEN_TAG: ClassVar[str] = "["
|
|
186
|
+
CLOSE_TAG: ClassVar[str] = "]"
|
|
187
|
+
items: tuple["OSCArg", ...]
|
|
188
|
+
|
|
189
|
+
def __init__(self, items: tuple["OSCArg", ...]) -> None:
|
|
190
|
+
super().__init__(items=items) # type: ignore
|
|
191
|
+
|
|
192
|
+
|
|
193
|
+
# === Composite packet types (messages and bundles) ===
|
|
194
|
+
|
|
195
|
+
|
|
196
|
+
OSCAtomic = Union[
|
|
197
|
+
OSCInt,
|
|
198
|
+
OSCFloat,
|
|
199
|
+
OSCString,
|
|
200
|
+
OSCBlob,
|
|
201
|
+
OSCTrue,
|
|
202
|
+
OSCFalse,
|
|
203
|
+
OSCNil,
|
|
204
|
+
OSCInt64,
|
|
205
|
+
OSCDouble,
|
|
206
|
+
OSCTimeTag,
|
|
207
|
+
OSCChar,
|
|
208
|
+
OSCSymbol,
|
|
209
|
+
OSCRGBA,
|
|
210
|
+
OSCMidi,
|
|
211
|
+
OSCImpulse,
|
|
212
|
+
]
|
|
213
|
+
|
|
214
|
+
OSCArg = Union[OSCAtomic, OSCArray]
|
|
215
|
+
|
|
216
|
+
|
|
217
|
+
class OSCMessage(_FrozenModel):
|
|
218
|
+
"""OSC message: address pattern + typed argument list.
|
|
219
|
+
|
|
220
|
+
- ``address`` is an OSC Address Pattern beginning with '/'.
|
|
221
|
+
- ``args`` is a sequence of OSCArg values.
|
|
222
|
+
"""
|
|
223
|
+
|
|
224
|
+
address: str
|
|
225
|
+
args: Tuple[OSCArg, ...]
|
|
226
|
+
|
|
227
|
+
|
|
228
|
+
class OSCBundle(_FrozenModel):
|
|
229
|
+
"""OSC bundle containing messages and/or sub-bundles.
|
|
230
|
+
|
|
231
|
+
- ``timetag`` is a 64-bit OSC timetag (NTP). 0 means "immediately".
|
|
232
|
+
- ``elements`` is a sequence of OSCMessage or nested OSCBundle.
|
|
233
|
+
"""
|
|
234
|
+
|
|
235
|
+
timetag: int
|
|
236
|
+
elements: Tuple[OSCPacket, ...]
|
|
237
|
+
|
|
238
|
+
|
|
239
|
+
OSCPacket = Union["OSCMessage", "OSCBundle"]
|
|
240
|
+
|
|
241
|
+
__all__ = [
|
|
242
|
+
"OSCRGBA",
|
|
243
|
+
"OSC_IMPULSE",
|
|
244
|
+
"OSCArg",
|
|
245
|
+
"OSCArray",
|
|
246
|
+
"OSCAtomic",
|
|
247
|
+
"OSCBlob",
|
|
248
|
+
"OSCBundle",
|
|
249
|
+
"OSCChar",
|
|
250
|
+
"OSCDouble",
|
|
251
|
+
"OSCFalse",
|
|
252
|
+
"OSCImpulse",
|
|
253
|
+
"OSCInt",
|
|
254
|
+
"OSCInt64",
|
|
255
|
+
"OSCMessage",
|
|
256
|
+
"OSCMidi",
|
|
257
|
+
"OSCNil",
|
|
258
|
+
"OSCPacket",
|
|
259
|
+
"OSCString",
|
|
260
|
+
"OSCSymbol",
|
|
261
|
+
"OSCTimeTag",
|
|
262
|
+
"OSCTrue",
|
|
263
|
+
]
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
Metadata-Version: 2.4
|
|
2
|
+
Name: oscparser
|
|
3
|
+
Version: 1.1.0
|
|
4
|
+
Summary: Library for parsing and building Open Sound Control (OSC) messages and bundles.
|
|
5
|
+
Author-email: Morph Tollon <code@morphtollon.co.uk>, Ripple <github@ripple.contact>
|
|
6
|
+
Maintainer-email: Morph Tollon <code@morphtollon.co.uk>, Ripple <github@ripple.contact>
|
|
7
|
+
License: MIT License
|
|
8
|
+
|
|
9
|
+
Copyright (c) 2025 Morph Tollon
|
|
10
|
+
|
|
11
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
12
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
13
|
+
in the Software without restriction, including without limitation the rights
|
|
14
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
15
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
16
|
+
furnished to do so, subject to the following conditions:
|
|
17
|
+
|
|
18
|
+
The above copyright notice and this permission notice shall be included in all
|
|
19
|
+
copies or substantial portions of the Software.
|
|
20
|
+
|
|
21
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
22
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
23
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
24
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
25
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
26
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
27
|
+
SOFTWARE.
|
|
28
|
+
|
|
29
|
+
Project-URL: Repository, https://gitlab.com/Theatre-Tools/python-osc-parser
|
|
30
|
+
Project-URL: Homepage, https://gitlab.com/Theatre-Tools/python-osc-parser
|
|
31
|
+
Project-URL: Issues, https://gitlab.com/Theatre-Tools/python-osc-parser/-/issues
|
|
32
|
+
Keywords: osc,sound,midi,music
|
|
33
|
+
Classifier: Development Status :: 5 - Production/Stable
|
|
34
|
+
Classifier: Intended Audience :: Developers
|
|
35
|
+
Classifier: License :: Freely Distributable
|
|
36
|
+
Classifier: Programming Language :: Python :: 3
|
|
37
|
+
Classifier: Topic :: Multimedia :: Sound/Audio
|
|
38
|
+
Classifier: Topic :: System :: Networking
|
|
39
|
+
Requires-Python: <3.14,>=3.13
|
|
40
|
+
Description-Content-Type: text/markdown
|
|
41
|
+
License-File: LICENSE
|
|
42
|
+
Dynamic: license-file
|
|
43
|
+
|
|
44
|
+
# Python OSC Parser
|
|
45
|
+
|
|
46
|
+
Open Sound Control (OSC) protocol implementation in Python.
|
|
47
|
+
## Current status
|
|
48
|
+
|
|
49
|
+
This library was developed following the
|
|
50
|
+
[OpenSoundControl Specification 1.0](https://opensoundcontrol.stanford.edu/spec-1_0.html)
|
|
51
|
+
and is currently in a stable state.
|
|
52
|
+
|
|
53
|
+
## Features
|
|
54
|
+
|
|
55
|
+
- Parsing and constructing OSC messages and bundles.
|
|
56
|
+
- Support for various OSC data types including integers, floats, strings, blobs, and more.
|
|
57
|
+
|
|
58
|
+
## License
|
|
59
|
+
|
|
60
|
+
This software is licensed under the MIT License. See the LICENSE file for details.
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
oscparser/__init__.py,sha256=f9TDvJEJTxoZCtOGzTA8B1dccER7nAfiiEr3ra_wAGM,1501
|
|
2
|
+
oscparser/ctx.py,sha256=uAt3DkXVM39xXlJFo7HVfolj9-MM9zdbEDQH6Ar5I-8,429
|
|
3
|
+
oscparser/decode.py,sha256=W9B9jcwz9-dKvjjA-gU-1Jt4wLp6QfVzX5_S0X6AIao,2765
|
|
4
|
+
oscparser/encode.py,sha256=jUsXyYP5L4mfGJiaihzhdtC4UWK39QpA0RU2D0epKhw,2316
|
|
5
|
+
oscparser/types.py,sha256=t04imRO6AjtKWzdzR8UrXKtkpSFOC6CyZq396LYdQiQ,5495
|
|
6
|
+
oscparser/framing/__init__.py,sha256=yjrteSCY0j9mBTbpp6sEoD5ns-sMvvsXgQz9lGs9MT8,207
|
|
7
|
+
oscparser/framing/framer.py,sha256=nG9yldYQenKijmqjjQRolRlYr1ZeQ3bD5AczISrkcKc,450
|
|
8
|
+
oscparser/framing/fullframer.py,sha256=QsNUeItdxDHEJU4fyBfGN0ghn4U75u2T0ctX71q7XF0,1069
|
|
9
|
+
oscparser/framing/osc10.py,sha256=gY5wOGL40v0IPuy9HjQY7j0uf3xp7ZYCOAcFmpAp0wU,2039
|
|
10
|
+
oscparser/framing/osc11.py,sha256=6MiM5Z1H2vcc6fsSRshbNYylTTKFx2GDlGa-Wyt__AI,6527
|
|
11
|
+
oscparser/processing/args/args.py,sha256=zOKMgjLixFK7n_jS3kpK-37ip9Gkzyp9ZpLGx38A_Ho,17955
|
|
12
|
+
oscparser/processing/args/proccessing.py,sha256=ZxjghxPHgAfBMS5QoJ16vrnMTAyCTweTP5ykrctxglY,1045
|
|
13
|
+
oscparser/processing/osc/handlers.py,sha256=_ExoQEM5XdLP6r2L0W7z-qfE1SzvAKDgWUCZdQO5xJ8,5645
|
|
14
|
+
oscparser/processing/osc/processing.py,sha256=3-LOXVteJLf8TYlHX-FyG2McZLVSQdyiWBbJoAEEDwY,1884
|
|
15
|
+
oscparser-1.1.0.dist-info/licenses/LICENSE,sha256=bhC-qZPLBnE1KaT__cf0Zw7qXl1xyU9qdhvVHkIeEhg,1069
|
|
16
|
+
oscparser-1.1.0.dist-info/METADATA,sha256=zMFTQ-AiQa67z63Mpsvi7RP7dZgv_HX5Inw1FE5JbGo,2740
|
|
17
|
+
oscparser-1.1.0.dist-info/WHEEL,sha256=_zCd3N1l69ArxyTb8rzEoP9TpbYXkqRFSNOD5OuxnTs,91
|
|
18
|
+
oscparser-1.1.0.dist-info/top_level.txt,sha256=3bs-r_OX2twJ4h00vGo3elKFzAhJeQ8UIN1TT73AR0E,10
|
|
19
|
+
oscparser-1.1.0.dist-info/RECORD,,
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2025 Morph Tollon
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
oscparser
|