2. Messages and Bundles¶
Note
OSC structures are defined in module oscbuildparse
.
This module provides all low level tools to manipulate these structures, build them, encode them
to raw OSC packets, and decode them back.
You may specially be interested by message construction in the examples (encoding and decoding is
normally done automatically for you by osc4py3
).
This module is only here to translate OSC packets from/to Python values. It can be reused anywhere as is (only depend on Python3 standard modules).
Examples:
>>> from osc4py3.oscbuildparse import *
>>> dir()
['OSCBundle', 'OSCCorruptedRawError', 'OSCError', 'OSCInternalBugError',
'OSCInvalidDataError', 'OSCInvalidRawError', 'OSCInvalidSignatureError',
'OSCMessage', 'OSCUnknownTypetagError', 'OSC_BANG', 'OSC_IMMEDIATELY',
'OSC_IMPULSE', 'OSC_INFINITUM', 'OSCbang', 'OSCmidi', 'OSCrgba', 'OSCtimetag',
'__builtins__', '__doc__', '__name__', '__package__', 'decode_packet',
'dumphex_buffer', 'encode_packet', 'float2timetag', 'timetag2float',
'timetag2unixtime', 'unixtime2timetag']
>>> msg = OSCMessage('/my/pattern',',iisf',[1,3,"a string",11.3])
>>> raw = encode_packet(msg)
>>> dumphex_buffer(raw)
000:2f6d792f 70617474 65726e00 2c696973 /my/ patt ern. ,iis
016:66000000 00000001 00000003 61207374 f... .... .... a st
032:72696e67 00000000 4134cccd ring .... A4..
>>> decode_packet(raw)
OSCMessage(addrpattern='/my/pattern', typetags=',iisf', arguments=(1, 3,
'a string', 11.300000190734863))
>>> import time
>>> bun = OSCBundle(unixtime2timetag(time.time()+1),
[OSCMessage("/first/message",",ii",[1,2]),
OSCMessage("/second/message",",fT",[4.5,True])])
>>> raw = encode_packet(bun)
>>> dumphex_buffer(raw)
000:2362756e 646c6500 d2c3e04f 455a9000 #bun dle. ...O EZ..
016:0000001c 2f666972 73742f6d 65737361 .... /fir st/m essa
032:67650000 2c696900 00000001 00000002 ge.. ,ii. .... ....
048:00000018 2f736563 6f6e642f 6d657373 .... /sec ond/ mess
064:61676500 2c665400 40900000 age. ,fT. @...
>>> decode_packet(raw)
OSCBundle(timetag=OSCtimetag(sec=3536052435, frac=3018637312),
elements=(OSCMessage(addrpattern='/first/message', typetags=',ii',
arguments=(1, 2)), OSCMessage(addrpattern='/second/message', typetags=',fT',
arguments=(4.5, True))))
>>> msg = OSCMessage("/shortcut/with/typedetection", None,
[True, OSC_BANG, 12, 11.3])
>>> raw = encode_packet(msg)
>>> dumphex_buffer(raw)
000:2f73686f 72746375 742f7769 74682f74 /sho rtcu t/wi th/t
016:79706564 65746563 74696f6e 00000000 yped etec tion ....
032:2c544969 66000000 0000000c 4134cccd ,TIi f... .... A4..
>>> decode_packet(raw)
OSCMessage(addrpattern='/shortcut/with/typedetection', typetags=',TIif',
arguments=(True, OSCbang(), 12, 11.300000190734863))
Note : you can find other examples in osc4py3/tests/buildparse.py
module.
2.1. Programming interface¶
There are two main functions for advanced users:
encode_packet()
build the binary representation for OSC datadecode_packet()
retrieve OSC data from binary representation
An OSC packet can either be an OSC message, or an OSC bundle (which contains a collection of messages and bundles - recursively if needed).
2.1.1. OSC Messages¶
For developer point of view, there is an OSCMessage
named tuple class which is used as
container to encode and decode messages. It contains fields accordingly to OSC1.1 protocol:
-
class
osc4py3.oscbuildparse.
OSCMessage
¶ OSCMessage(addrpattern, typetags, arguments)
→ named tupleVariables: - addrpattern (string) – a string beginning by
/
and used by OSC dispatching protocol. - typetags (string) – a string beginning by
,
and describing how to encode values - arguments (list|tuple) – a list or tuple of values to encode.
- addrpattern (string) – a string beginning by
The typetag
must start by a comma (','
) and use a set of chars to describe OSC defined
data types, as listed in the Supported atomic data types table.
It may optionally be set to None
for an automatic detection of type tags from values
(see Automatic type tagging for detection rules).
2.1.2. OSC Bundles¶
And to add a time tag or group several messages in a packet, there is an OSCBundle
named
tuple which is used to encode and decode bundles.
It contains fields accordingly to OSC1.1 protocol:
-
class
osc4py3.oscbuildparse.
OSCBundle
¶ OSCBundle(timetag, elements)
→ named tupleVariables: - timetag – a time representation using two int values, sec:frac
- elements (list|tuple) – a list or tuple of mixed OSCMessage / OSCBundle values
Its first timetag
field must be set to osc4py3.oscbuildparse.OSC_IMMEDIATELY
to request an immediate processing of the bundle messages by the server’s matching handlers.
Else, it is considered as an OSC time (see Time Tag) and must be computed
for planned processing time.
2.1.3. Supported atomic data types¶
In addition to the required OSC1.1 ifsbtTFNI
type tag chars, we support optional types of OSC1.0
protocol hdScrm[]
(support for new types is easy to add if necessary).
Attention
Check that programs receiving your data also support optional data types.
You may use the Out of band options restrict_typetags to limit the data
types manipulated by osc4py3
.
Tag | Data | Python | Notes |
---|---|---|---|
i | int32 | int |
signed integer |
f | float32 | float |
a C float (4 bytes) |
s | string | str |
ASCII string |
b | blob | memoryview |
mapping to part in received blob data |
h | int64 | int |
to transmit larger integers |
t | timetag | OSCtimetag |
two bytes named tuple time |
d | float64 | float |
a C double (8 bytes) |
S | alt-string | str |
ASCII strings to distinguish with ‘s’ strings |
c | ascii-char | str |
one ASCII char |
r | rgba-color | OSCrgba |
four bytes fields named tuple RGBA data |
m | midi-msg | OSCmidi |
four bytes fields named tuple MIDI data |
T | (none) | True |
direct True value only with type tag |
F | (none) | False |
direct False value only with type tag |
N | (none) | None |
‘nil’ in OSC only with type tag |
I | (none) | OSCbang |
named tuple with no field (see bang) |
[ | (none) | tuple |
beginning of an array |
] | (none) | end of the array (to terminate tuple) |
2.1.3.1. Integer¶
Care that Python int has a range with “no limit”. Overflows will only be detected when trying to pack such values into the 32 bits representation of an OSC packet integer.
2.1.3.2. String and char¶
They are normally transmitted as ASCII, default processing ensure this encoding
(with strict
error handling, raising an exception if a non-ASCII char
is in a string).
An oob
option (see oob options below) allows to specify an encoding.
The value for a string/char is normally a Python str
;
you can give a bytes
or bytearray
or memoryview
, but they must not contain a zero byte
(except at the end - and it will be used a string termination when decoding).
For a char, the string
/ bytes
/ … must contain only one element.
In OSC, distinction between s
strings and S
strings are application meaning
defined. And in osc4py3
you don’t have direct access to data type codes
(you may request to get the .
2.1.3.3. Blob¶
They allow transmission of any binary data of your own.
The value for a blob can be bytes
or bytearray
or memoryview
.
When getting blob values on packet reception, they are returned as memoryview
objects to avoid
extra data copying.
You may cast them to bytes
if you want to copy/extract the value from the OSC packet.
2.1.3.4. Infinitum / Impulse / Bang¶
The Infinitum data ('I'
), renamed as Impulse ‘bang’ in OSC 1.1, is returned in Python as a
OSCbang
named tuple (with no value in the tuple).
Constant OSC_INFINITUM
is defined as an OSCbang
value, and aliases constants
OSC_IMPULSE
and OSC_BANG
are also defined.
You should test on object class with isinstance(x,OSCbang)
.
2.1.3.5. Time Tag¶
As time tag is stored into an OSCtimetag
named tuple with two items.
-
class
osc4py3.oscbuildparse.
OSCtimetag
¶ OSCtimetag(sec, frac) → named tuple
Time tags are represented by a 64 bit fixed point number of seconds relative to 1/1/1900, same as Internet NTP timestamps .
Warning
We don’t check that sec and frac parts fill in 32 bits integers, this is detected by struct.pack() function.
Attribute int sec: first 32 bits specify the number of seconds since midnight on January 1, 1900, Attribute int frac: last 32 bits specify fractional parts of a second to a precision of about 200 picoseconds.
As it is not really usable with usual Python time, four conversion functions have been defined:
timetag2float()
convert anOSCtimetag
tuple into a float value in seconds from 1/1/1900,timetag2unixtime()
convert anOSCtimetag
tuple into a Unix float time in seconds from 1/1/1970 (Python time),float2timetag()
convert a float value of seconds from 1/1/1900 into anOSCtimetag
tuple,unixtime2timetag()
convert a Unix float value of seconds from 1/1/1970 (Python time) into anOSCtimetag
tuple - can be used
The special value used in OSC to indicate an “immediate” time, with a time tag having 0 in seconds
field and 1 in factional part field (represented as 0x00000001 value), is available for comparison
and usage in constant osc4py3.oscbuildparse.OSC_IMMEDIATELY
.
2.1.3.6. Array¶
An array is a way to group some data in the OSC message arguments. On the Python side an array is simply a list or a tuple of values. By example, to create a message with two int followed by four grouped int, you will have:
- Type tags string:
',ii[iiii]'
- Arguments list:
[3, 1, [4, 2, 8, 9]]
Note : When decoding a message, array arguments are returned as tuple, not list.
In this example: (3, 1, (4, 2, 8, 9))
.
2.1.3.7. RGBA data¶
RGBA values are stored into an OSCrgba
named tuple
containing four single byte values (int in 0..255 range):
red
green
blue
alpha
2.1.3.8. MIDI data¶
MIDI values are stored into an OSCmidi
named tuple
containing four single byte values (int in 0..255 range):
portid
status
data1
data2
OSCbang = namedtuple(‘OSCbang’, ‘’)
2.1.4. Automatic type tagging¶
When creating an OSCMessage
, you can give a None
value as typetags.
Then, message arguments are automatically parsed to identify their types and build the type tags
string for you.
The following mapping is used:
What | Type tag and corresponding data |
---|---|
value None |
N without data |
value True |
T without data |
value False |
F without data |
type int |
i with int32 |
type float |
f with float32 |
type str |
s with string |
type bytes |
b with raw binary |
type bytearray |
b with raw binary |
type memoryview |
b with raw binary |
type OSCrgba |
r with four byte values |
type OSCmidi |
m with four byte values |
type OSCbang |
I without data |
type OSCtimetag |
t with two int32 |
2.2. Errors¶
All errors explicitly raised by the module use specify hierarchy of exceptions:
Exception
OSCError
OSCCorruptedRawError
OSCInternalBugError
OSCInvalidDataError
OSCInvalidRawError
OSCInvalidSignatureError
OSCUnknownTypetagError
2.2.1. OSCError¶
This is the parent class for OSC errors, usable as a catchall for all errors related to this module.
2.2.2. OSCInvalidDataError¶
There is a problem in some OSC data provided for encoding to raw OSC representation.
2.2.3. OSCInvalidRawError¶
There is a problem in a raw OSC buffer when decoding it.
2.2.4. OSCInternalBugError¶
Hey, we detected a bug in OSC module. Please, signal it with description of the context, data processed, options used.
2.2.5. OSCUnknownTypetagError¶
Found an invalid (unknown) type tag when encoding or decoding. This include type tags not in a subset with restrict_typetags option.
2.2.6. OSCInvalidSignatureError¶
Check of raw data with signature failed due bad source or modified data. This can only occur with advanced packet control enabled and signature functions installed in out-of-band.
2.2.7. OSCCorruptedRawError¶
Check of raw data with checksum failed. This can only occur with advanced packet control enabled and checksum functions installed in out-of-band.
2.3. Out of band options¶
Warning
Out of band options may need further debugging.
These OOB options are transmitted as a simple Python dict among internal oscbuildparse
functions to enable and define parameters of extra processing.
You may add your own keys in this dict to transmit data to your extra processing functions.
2.3.1. Supported data types¶
2.3.1.1. restrict_typetags¶
oob['restrict_typetags']
must contain a string with the subset
typecode chars you want to allow (in ifsbtTFNIhdScrm[]
)
— see Supported atomic data types.
This make your program ensure that it don’t use data types
unsupported by other OSC implementations.
2.3.2. Strings encoding¶
The OSC standard encode strings as ASCII only chars, which include control chars (codes 1 to 31 and 127; code 0 is used as end of string marker), whitespace and following printable chars: !”#$%&’()*+,-./ 0123456789 :;<=>?@ ABCDEFGHIJKLMNOPQRSTUVWXYZ []^_` abcdefghijklmnopqrstuvwxyz {|}~
This is how osc4py3
works, converting all Unicode Python strings
into an ASCII encoding.
By default the encoding and decoding use strict
error handling scheme:
any out of ASCII char in a Python string raise an UnicodeEncodeError
when
encoding to OSC sctring,
and any non-ASCII char in an OSC string coming from somewhere
raise an UnicodeDecodeError
when decoding to Python string.
You can modify the encoding to use and the error processing scheme
(strict
, replace
, ignore
…) with following OOB options.
Caution
Changing strings encoding to non-ASCII goes out of OSC standards, you may brake communications with other OSC implementations. It may be better to transmit encoded text in blobs and to agree on encoding on both sides (ex. transmit encoding in a separate OSC string).
2.3.2.1. str_decode¶
oob['str_decode']
must contain a tuple of two values
to specify how to decode OSC strings.
First item is the encoding to use, second item the error handling scheme.
Default to ('ascii', 'strict')
.
2.3.2.2. str_encode¶
oob['str_encode']
must contain a tuple of two values
to specify how to encode OSC strings.
First item is the encoding to use, second item the error handling scheme.
Default to ('ascii', 'strict')
.
2.3.2.3. char_decode¶
oob['char_decode']
must contain a tuple of two values
to specify how to decode OSC char.
First item is the encoding to use, second item the error handling scheme.
Default to ('ascii', 'strict')
.
2.3.2.4. char_encode¶
oob['char_encode']
must contain a tuple of two values
to specify how to encode OSC char.
First item is the encoding to use, second item the error handling scheme.
Default to ('ascii', 'strict')
.
2.3.3. Compression of addresses¶
Note
The osc4py3
package implement support for OSC address compression as presented in
Improving the Efficiency of Open Sound Control (OSC) with Compressed Address Strings
(SMC 2011, by Jari Kleimola and Patrick J. McGlynn).
Two sides of an OSC communication agree on some int to string mapping.
The address is then sent as a single "/"
OSC string followed by a
32 bits int code.
This implementation only do compression / decompression of addresses, it’s up to the user to exchange int / address mapping — by example via an initial exchange of OSC messages (eventually grouped in a bundle).
2.3.3.1. addrpattern_decompression¶
oob['addrpattern_decompression']
must contain the int to string mapping
to retrieve message address from int code for incoming packets.
2.3.3.2. addrpattern_compression¶
oob['addrpattern_decompression']
must contain the string to int mapping
to get int code from message address for outgoing packets.
2.3.4. Basic messages controls¶
2.3.4.1. check_addrpattern¶
This option allows to check that address string correctly follow OSC pattern.
oob['check_addrpattern']
must be a boolean set to True
to check
that address string correctly follow OSC pattern.
2.3.4.2. force_typetags¶
This option force presence of type tags in received OSC packets, you can’t
send an only address message with this option enabled (it must contain at least
a ","
string indicating no data).
oob['force_typetags']
must be a boolean set to True
to force
presence of a type tags specification, even with no data
(in such case type tags simply contains ","
string).
2.3.5. Dump of packets¶
2.3.5.1. decode_packet_dumpraw¶
oob['decode_packet_dumpraw']
must be a boolean set to True
to enable
file writing of raw OSC packets in hexadecimal representation.
2.3.5.2. encode_packet_dumpraw¶
oob['encode_packet_dumpraw']
must be a boolean set to True
to enable
file writing of raw OSC packets in hexadecimal representation.
2.3.5.3. decode_packet_dumpacket¶
oob['decode_packet_dumpacket']
must be a boolean set to True
to enable file writing
of decoded OSC packets representation (OSCMessage or OSCBundle).
2.3.5.4. encode_packet_dumpacket¶
oob['encode_packet_dumpacket']
must be a boolean set to True
to enable file writing
of encoded OSC packets representation (OSCMessage or OSCBundle).
2.3.5.5. dump_decoded_values¶
oob['dump_decoded_values']
must be a boolean set to True
to enable file writing
of individual fields of decoded message data .
2.3.5.6. dumpfile¶
oob['dumpfile']
must be a writable stream (file…), used to dump OSC packets
(raw or decoded) when decode_packet_dumpraw or decode_packet_dumpacket
encode_packet_dumpraw or encode_packet_dumpacket is enabled.
If it is not defined, packets are dump to sys.stdout
stream.
2.3.6. Advanced control¶
Note
Following OOB options have been installed to setup controlled OSC communications, with possible encryption of data, authentication, checksum…
In such situation OSC messages have an address string set to "/packet"
,
and data is a set of 6 data corresponding to:
cheksumprot
a string indicating checksum to userawcksum
a blob with checksumauthprot
a string indicating authentication to userawckauth
a blob with authentication tokencryptprot
a string indicating encryption to userawoscdata
a blob containing (encrypted) data
Once the message have passed all steps, a normal OSC message is retrieved (which
can go normally in osc4py3
pipeline).
When receiving a packet, data is decoded then authentified then sumchecked.
When sending a packet, data is sumchecked then authentified then encoded.
If a support function is not present in the oob, its feature is simply ignored.
When advanced control functions receive raw data, it’s a memoryview (on the rawoscdata blob).
2.3.6.1. advanced_packet_control¶
oob['advanced_packet_control']
must be a boolean set to True
to enable
packets control.
2.3.6.2. packet_crypt_prot¶
oob['packet_crypt_prot']
may contain string indicating encryption protocol to use.
It default to empty string.
2.3.6.3. packet_encrypt_fct¶
oob['packet_encrypt_fct']
is a function to encode raw osc data.
It is called with the data to encode, indication of the encryption protocol,
and the oob.
It must return binary representation of encoded data.
Call example:
tobuffer = fencrypt(tobuffer, cryptprot, oob)
2.3.6.4. packet_decrypt_fct¶
oob['packet_decrypt_fct']
is a function to decode raw osc data.
It is called with the data to decode, indication of the encryption protocol,
and the oob.
It must return binary representation of decoded data.
Call example:
rawoscdata = fdecrypt(rawoscdata, cryptprot, oob)
2.3.6.5. packet_authsign_prot¶
oob['packet_authsign_prot']
may contain string indicating authentication
protocol to use.
It default to empty string.
2.3.6.6. packet_mkauthsign_fct¶
oob['packet_mkauthsign_fct']
is a function to build authentication
data.
It is called with osc data buffer and the authentication protocol.
It must return the authentication value to transmit as a blob compatible data.
Call example:
authsign = fauthsign(tobuffer, authprot, oob)
2.3.6.7. packet_ckauthsign_fct¶
oob['packet_ckauthsign_fct']
is a function to check authentication.
It is called with (decoded) osc data, the two authentication fields
and the oob.
It must simply raise an exception if authentication is not proven.
Call example:
fckauthsign(rawoscdata, rawckauth, authprot, oob)
2.3.6.8. packet_checksum_prot¶
oob['packet_checksum_prot']
may contain string indicating checksum
protocol to use.
It default to empty string.
2.3.6.9. packet_mkchecksum_fct¶
oob['packet_mkchecksum_fct']
is a function to build data integrity
checksum value.
It is called with osc data buffer, the checksum protocol and the oob.
It must return the checksum value to transmit as a blob compatible data.
Call example:
cksum = fchecksum(tobuffer, cksumprot, oob)
2.3.6.10. packet_ckcheksum_fct¶
oob['packet_ckauthsign_fct']
is a function to check data integrity.
It is called with (decoded) osc data, the two checksum fields and the oob.
It must simply raise an exception if checksum is not verified.
Call example:
fchecksumcheck(rawoscdata, rawcksum, cheksumprot, oob)
2.4. Code documentation¶
-
osc4py3.oscbuildparse.
decode_packet
(rawoscdata, oob=None)¶ From a raw OSC packet, extract the list of OSCMessage.
Generally the packet come from an OSC channel reader (UDP, multicast, USB port, serial port, etc). It can contain bundle or message. The function guess the packet content and call ah-hoc decoding.
This function map a memoryview on top of the raw data. This allow sub-called functions to not duplicate data when processing. You can provide directly a memoryview if you have a packet from which just a part is the osc data.
Parameters: - rawoscdata (bytes or bytearray or memoryview (indexable bytes)) – content of packet data to decode.
- oob (dict) – out of band extra parameters (see Out of band options).
Returns: decoded OSC messages from the packet, in decoding order.
Return type: [ OSCMessage ]
-
osc4py3.oscbuildparse.
encode_packet
(content, oob=None)¶ From an OSCBundle or an OSCMessage, build OSC raw packet.
Parameters: - content (OSCMessage or OSCBundle) – data of packet to encode
- oob (dict) – out of band extra parameters (see Out of band options).
Returns: raw representation of the packet
Return type: bytearray
-
osc4py3.oscbuildparse.
dumphex_buffer
(rawdata, tofile=None)¶ Dump hexa codes of OSC stream, group by 4 bytes to identify parts.
Parameters: - data (bytes) – some raw data to format.
- tofile (file (or file-like)) – output stream to receive dump
-
osc4py3.oscbuildparse.
timetag2float
(timetag)¶ Convert a timetag tuple into a float value in seconds from 1/1/1900.
Parameters: timetag (OSCtimetag) – the tuple time to convert Returns: same time in seconds, with decimal part Return type: float
-
osc4py3.oscbuildparse.
timetag2unixtime
(timetag)¶ Convert a timetag tuple into a float value of seconds from 1/1/1970.
Parameters: timetag (OSCtimetag) – the tuple time to convert Returns: time in unix seconds, with decimal part Return type: float
-
osc4py3.oscbuildparse.
float2timetag
(ftime)¶ Convert a float value of seconds from 1/1/1900 into a timetag tuple.
Parameters: ftime (float) – number of seconds to convert, with decimal part Returns: same time in sec,frac tuple Return type: OSCtimetag
-
osc4py3.oscbuildparse.
unixtime2timetag
(ftime=None)¶ Convert a float value of seconds from 1/1/1970 into a timetag tuple.
Parameters: ftime (float) – number of seconds to convert, with decimal part. If not specified, the function use current Python time.time(). Returns: same time in sec,frac tuple Return type: OSCtimetag