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:

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 tuple

Variables:
  • 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.

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 tuple

Variables:
  • 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.

Type codes
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:

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):

  1. red
  2. green
  3. blue
  4. 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):

  1. portid
  2. status
  3. data1
  4. 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:

Automatic typing
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:

  1. cheksumprot a string indicating checksum to use
  2. rawcksum a blob with checksum
  3. authprot a string indicating authentication to use
  4. rawckauth a blob with authentication token
  5. cryptprot a string indicating encryption to use
  6. rawoscdata 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:
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