View Source OSCx.Encoder (OSCx v0.1.1)

Helpers to encode Elixir types into OSC data types.

This module contains helper functions used to encode supported Elixir types (see below) into OSC binary data.

To encode the full OSC data, these functions are chained together and are used by OSCx.Message.encode/1 and OSCx.Bundle.encode/1.

Tip

Note that in practice you'll will likely not need to use this module directly and instead use OSCx.encode/1.

At it's core, OSC has the following data types:

TypeDescription
Integera 32-bit signed integer and also a 64-bit integer type)
Floata 32-bit IEEE 754 floating-point number and also a 64-bit double type
Stringa sequence of printable ASCII characters (there are also Symbols and Char types)
Bloba sequence of arbitrary binary data, with its size prepended
Timetaga 64-bit fixed-point number that represents a time in seconds since midnight on January 1, 1900. The first 32 bits of the timetag represent the number of seconds, and the last 32 bits represent fractional parts of a second to a precision of about 200 picoseconds.

The above are considered 'required' types by the OSC spec, however, OSC can be extended to support additional or optional types.

The main function in this module is encode_arg/1, which takes one of the recognised Elixir data types, and returns it as an OSC type.

Tag-specific types

Additionally the OSC 1.1 Specification includes some types which carry no data arguments, but can be encoded directly into the tag type string. These are True, False, Null and Impluse.

See the Tag specific functions below.

4-byte boundaries

OSC data is aligned on 4-byte boundaries. 32-bit types like Integers and Floats are 4-bytes, but Strings and Blobs can be of an arbintary length. For this reason they may be padded with extra null characters (<<0>>> is used in Elixir) to make the total length a multiple of 4 bytes.

Values returned

Most functions in this module return a tuple in the form {type, value}. These are defined as follows:

  • type: first element is an OSC type tag, which is a unicode charater representing the type
  • value: second element is the encoded OSC value.

For example, {105, <<0, 0, 0, 128>>} is returned for encoding a the integer 128. See the example below.

Type tags

OSC type tags are unicode characters which represent each type. This library currently implements the following types:

Type tagUnicode numberTypeOSC spec version
i10532 bit integer1.0+ required
f10232 bit float1.0+ required
s115String1.0+ required
b98Blob1.0+ required
h10464-bit big-endian two’s complement integer1.0 non-standard
d10064 bit (“double”) IEEE 754 floating point number1.0 non-standard
c99An ascii character, sent as 32 bits1.0 non-standard
m1094 byte MIDI message1.0 non-standard
t116OSC time tag1.1+ required
r14432 bit RGBA color1.0 non-standard
[ and ]91 and 93List1.0 non-standard
T84True (tag only, no arguments)1.1+ required
F80False (tag only, no arguments)1.1+ required
N78Null (tag only, no arguments)1.1+ required
I73Impulse (tag only, no arguments)1.1+ required

These type tags are used to build a type tag string, which is part of the OSC message.

Example

iex> alias OSCx.Encoder

iex> my_integer = 128
iex> Encoder.integer(my_integer)
# Returns the type 105 (integer), and the encoded value:
{105, <<0, 0, 0, 128>>}

iex> very_big_integer = 9_223_372_036_854_775_700
iex> Encoder.integer(very_big_integer)
# Returns the type 104 (64-bit big-endian two’s complement integer), with the encoded value
{104, <<127, 255, 255, 255, 255, 255, 255, 148>>}

iex> my_string = "hello world"
iex> Encoder.string(my_string)
# Returns the type 115 (string), and a list containing the string with any required padding:
{115, <<104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0>>}

More information

To learn more about how this library encodes and decodes data, see: Arguments and types.

Summary

Primary function

Encodes an argument into its OSC type and value.

Type functions

OSC-blob: a 32-bit size count followed by that many bytes of arbitrary binary data (total must be a multiple of 4) – flexibility to send any encoding

Char: Encode a character as 32 bit.

Float: 32-bit big-endian IEEE 754 floating point number, or 64 bit (“double”) IEEE 754 floating point number.

Integer: 32-bit two’s complement big-endian or 64 bit big-endian two’s complement integer

Encodes a 4-byte MIDI message.

RGBA: Encides a 32-bit RGBA color.

OSC-string: a sequence of non-null ASCII characters followed by 1-4 null characters – total string bytes must be a multiple of 4

OSC-symbol: an alternative to strings in OSC systems, used for 'symbols' which are conceptually equivalent to Atoms in Elixir.

OSC-timetag: 64 bit, big-endian, fixed-point floating point number

Converts a list of encoded arguments to an OSC type tag string. Can also take a single encoded argument.

Tag specific

Encodes a list.

Used to encode false into the tag type string.

Used to encode impulse into the tag type string.

Used to encode null into the tag type string.

Used to encode true into the tag type string.

Helper functions

Returns the encoded values from the encoded argument list.

Guard to test if a map for chars has been provided.

Guard to test if a MIDI map has been provided. A MIDI map is in the following format: %{midi: value}. The value is a 4-byte binary.

Guard to test if a map for chars has been provided.

Guard to test if a time map has been provided. A time map is in the following format: %{seconds: seconds, fraction: fraction}.

Adds padding to a value based on it's size.

Used for prepending the size of a value.

A helper function to encode a tag based on an Elixir type or special atom.

Primary function

Encodes an argument into its OSC type and value.

Elixir to OSC types

You can call this function with the following Elixir types:

Elixir typeOSC type tagUnicode numberOSC type
Integeri10532 bit integer
Floatf10232 bit float
Strings115String
Atoms115String
Bitstringb98Blob
Integer (64 bit)h10464-bit big-endian two’s complement integer
Float (64 bit)d10464-bit big-endian two’s complement integer
Time mapt116OSC time tag
MIDI mapm1094-byte MIDI message
Char mapc994-byte ASCII character

Note the:

  • time map is in the format %{seconds: seconds, fraction: fraction} where seconds and fraction are 32-bit numbers.
  • MIDI map is in the format %{midi: value} where the value is a 4 byte MIDI message
  • Char map is in the format %{char: value} where value is a single character string (e.g. "A"), a single char (e.g. 'A' or ~c"A") or an integer of an ASCII char (e.g. 65).

Return format

The function will return a tuple with the first element containing the OSC type tag, and the second element the OSC encoded value such as {105, <<0, 0, 0, 1>>}.

If an elixir List is given, each argument in the list will be encoded and a list is returned, for example:

iex> Encoder.encode_arg([1,2,3])
[{105, <<0, 0, 0, 1>>}, {105, <<0, 0, 0, 2>>}, {105, <<0, 0, 0, 3>>}]

An unrecognised Elixir type will return an error tuple in the following format:

{:error, "Unknown type"}

Examples

alias OSCx.Encoder

# Encode an integer of value 1
iex> Encoder.encode_arg(1)
{105, <<0, 0, 0, 1>>}

# Encode a float of 2.1
iex> Encoder.encode_arg(2.1)
{102, <<64, 6, 102, 102>>}

# Encode a string of "hello world" (this will also add padding do the end)
# Bit
iex> Encoder.encode_arg("hello world")
{115, <<104, 101, 108, 108, 111, 32, 119, 111, 114, 108, 100, 0>>}

# Encode a 64-bit integer
iex> Encoder.encode_arg(9_223_372_036_854_775_700)
{104, <<127, 255, 255, 255, 255, 255, 255, 148>>}

Type functions

OSC-blob: a 32-bit size count followed by that many bytes of arbitrary binary data (total must be a multiple of 4) – flexibility to send any encoding

Char: Encode a character as 32 bit.

In OSC 1.0, the Char type is optional and is used to encode an ascii character in 32 bits.

This function accepts a map %{char: value} as the first parameter, where value can be a

  • single character string, e.g. "A"
  • single charlist, e.g. ~c"A" or 'A'
  • an integer representing an ASCII char, e.g. 65.

Example

All of the following are equivalent for the ASCII 'A' character:

iex> %{char: "A"} |> OSCx.Encoder.char()
{99, <<0, 0, 0, 65>>}

iex-> %{char: ~c"A"} |> OSCx.Encoder.char()
{99, <<0, 0, 0, 65>>}

iex-> %{char: 'A'} |> OSCx.Encoder.char()
{99, <<0, 0, 0, 65>>}

iex-> %{char: 65} |> OSCx.Encoder.char()
{99, <<0, 0, 0, 65>>}

Float: 32-bit big-endian IEEE 754 floating point number, or 64 bit (“double”) IEEE 754 floating point number.

This function encodes Elixir's float types as follows:

TypeLower valueUpper value
32 bit float1.175494351e-383.402823466e+38
64 bit float2.2250738585072014e-3081.7976931348623158e+308

Note the ranges in this table are approximate.

Integer: 32-bit two’s complement big-endian or 64 bit big-endian two’s complement integer

This function encodes Elixir's integer types as follows:

TypeLower valueUpper valueComment
32 bit integer-2_147_483_6472_147_483_647This is 2^31 rounded
64 bit integer-9_223_372_036_854_775_8089_223_372_036_854_775_808This is 2^63 rounded

Encodes a 4-byte MIDI message.

Takes as it's first parmeter a map with the key-value pair of: %{midi: value}.

Format of the value

The OSC defines the 4 byte MIDI messages as bytes from MSB to LSB are: port id, status byte, data1, data2.

If only a 3 byte message is provided (e.g. a status byte followed by two data bytes), a port id of <<0>> is prepended to make 4 bytes.

The MIDI value can be in any of these forms:

  • Binary, e.g. <<153, 77, 63>>
  • List, e.g. [153, 77, 63]
  • An Elixir type which can be directly encoded to 4-byte binary value

Key:

  • MSB = Most significant byte
  • LSB = Least singificant byte

RGBA: Encides a 32-bit RGBA color.

Takes as it's first parameter an %{rgba: [r, g, b, a]} map.

The map contains 4 integer values, repesenging R, G, B and A in that order.

Example

iex> OSCx.Encoder.rgba(%{rgba: [255, 255, 60, 20]})
{114, <<255, 255, 60, 20>>}

OSC-string: a sequence of non-null ASCII characters followed by 1-4 null characters – total string bytes must be a multiple of 4

OSC-symbol: an alternative to strings in OSC systems, used for 'symbols' which are conceptually equivalent to Atoms in Elixir.

OSC-timetag: 64 bit, big-endian, fixed-point floating point number

Takes a map in the format of either:

  • %{seconds: seconds, fraction: fraction} where seconds and fraction are 32-bit integers
  • %{time: value} where value is a 64-bit integer.

Immediate time

OSC can encode a time tag which means "process immediately". This is a time tag with a value of 63 zero bits followed by a one in the least signifigant bit.

You can set an immediate time by using the :immediate atom as follows:

%{time: :immediate}

OSC time tag specification

The OSC Specification defines a time tag as a 64-bit fixed-point number that represents a time in seconds since midnight on January 1, 1900.

The first 32 bits of the timetag represent the number of seconds, and the last 32 bits represent fractional parts of a second to a precision of about 200 picoseconds.

This is the representation used by Internet NTP timestamps.

Link to this function

type_tag_string(encoded_arg_tuple)

View Source

Converts a list of encoded arguments to an OSC type tag string. Can also take a single encoded argument.

Tag specific

Encodes a list.

Returns a tuple with the first element containing the OSC array type tags, and the second element containing the binary encoded array data.

Used to encode false into the tag type string.

True equates to the charater 'F'.

Used to encode impulse into the tag type string.

Impulse is also known as Infinitum in OSC 1.0 Spec, or 'Bang'.

True equates to the charater 'I'.

Used to encode null into the tag type string.

True equates to the charater 'N'.

Used to encode true into the tag type string.

True equates to the charater 'T'.

Helper functions

Link to this function

encoded_value(encoded_arg)

View Source

Returns the encoded values from the encoded argument list.

e.g. returns the value from the {type, value} tuple as a list.

Link to this macro

is_char_map(value)

View Source (macro)

Guard to test if a map for chars has been provided.

Link to this macro

is_midi_map(value)

View Source (macro)

Guard to test if a MIDI map has been provided. A MIDI map is in the following format: %{midi: value}. The value is a 4-byte binary.

Link to this macro

is_rgba_map(value)

View Source (macro)

Guard to test if a map for chars has been provided.

Link to this macro

is_time_map(value)

View Source (macro)

Guard to test if a time map has been provided. A time map is in the following format: %{seconds: seconds, fraction: fraction}.

Adds padding to a value based on it's size.

This is used for types of variable length so that they're equal to 4-bytes in length, or a mutuple of 4-bytes.

Link to this function

prefix_size(value, size \\ 32)

View Source

Used for prepending the size of a value.

This is mainly used for prepending the size of a binary.

The size is encoded in 32 bits, but this can be overridden when needed.

A helper function to encode a tag based on an Elixir type or special atom.

This function accepts the following Elixir types and returns the equivalent OSC string tag type character as below:

Elixir valueOSC typeCharacter returned for OSC string tag type
trueTrueT
falseFalseF
nilNullN
:nullNullN
:impulseImpulse (also known as Infinitum in OSC 1.0 Spec, or 'Bang')I