2016-07-15 10:14:56 UTC
Draft Proposal: Fast Method Lookup for Embedded OSC Implementations
Sound Consulting, Seattle
15th July 2016
OSC Address Patterns are variable-length ASCII strings which pose problems for fast matching on embedded systems, particularly 8-bit micro-controllers with lower clock speeds and simple instruction sets. Without breaking from the spirit of OSC, the goal of the following proposal is to improve embedded response time in a way that is maximally compatible.
The first task of an embedded processor upon receipt of an OSC Message is to look up the corresponding Method(s). Variable-length strings and pattern matching can consume hundreds of processor cycles, which can add up on low-power embedded systems. Typical OSC Address Patterns are quite long, often with redundant sections, and this is not conducive to prompt event responses.
OSC combines a human-readable Address Pattern (and optional Type Tag String) with machine-readable Arguments. The promise of human-readable Address Patterns is to allow easy configuration by users. The machine-readable Arguments are presumably encoded in binary format for efficient packing on 32-bit boundaries at the sacrifice of human readability. Unfortunately, the human-readable Address Pattern sacrifices machine readability at a potentially time-critical point in an embedded processor's communications parser and method executor. Poignantly, entry and viewing of Address Patterns typically only happen at setup time, whereas performers might desire to view actual Arguments during a live performance. Since viewing of live Arguments requires machine translation, it seems acceptable for the Address Patterns to be similarly encoded separate from the entry and viewing phase and thus use machine translation.
An analogy from the internet is that servers have human-readable names that are translated by distributed databases known as Domain Name Servers into fixed-length 32-bit (IPv4), 128-bit (IPv6), and 48-bit (MAC) values for the low-level routers and other network transport, so that the fastest possible responses can be attained. The human-readable host name is silently translated to a fixed-width bit pattern behind the scenes, offering the best of both worlds. These fixed-width bit patterns can be quickly matched or ignored by simple processors and even field-programmable gate array circuits.
We do not have the equivalent of DNS servers for OSC, but even the modern trends of IoT have required DNS services to be supplanted by options like Link-local Addressing and Zeroconf (a.k.a. Bonjour or mDNS and DNS-SD). Todays electronics users do not want to configure DNS or even DHCP servers. Thankfully, OSC has already embraced Zeroconf for discovery of OSC Servers.
It seems prudent that an option like Zeroconf for OSC Address Patterns could help improve embedded performance without changing the way developers or performers use OSC. Admittedly, mapping of Address Patterns to fixed-width bit values is more akin to web servers mapping a URL to a file system iNode, but the DNS analogy seems more understandable.
In contrast, MIDI was designed for embedded processors and requires only a few bits within the first byte to determine the equivalent of a method. MIDI was designed for quick and simple decoding to enable timely responses to synchronization messages. Within the realm of note-based performances with timing synchronization and dedicated and general real-time controllers, MIDI offers an incredibly efficient communications encoding. OSC does not need to change the gist of its design in order to gain a great deal of efficiency of coding.
Inspired by the 2004 Schmeder/Wright CNMAT paper, "A Query System for Open Sound Control," it seems that it would actually be quite simple for any OSC Server to act as something like DNS by providing a hash value (iNode) for any Address Pattern.
A #hash query command with an int32 response would provide a substitute for the provided Address Pattern, and this might even work for wild cards if the OSC Server supports them. Subsequent OSC Messages of Bundles sent to the same OSC Server could use the int32 hash instead of the OSC Address Pattern, with the simple caveat that any int32 with an MSB of '/' or '#' would be considered illegal. Thus 0x23000000 through 0x23FFFFFF and 0x2F000000 through 0x2FFFFFFF would certainly be off-limits for hash values, but theoretically all other int32 values would be fair game. It might be prudent to reserve 0xFFFFFFFF as a NULL indicator to signify invalid hash requests.
OSC Clients using these int32 hash values would also omit the OSC Type Tag String, since it is another variable-length string. This seems perfectly workable since any such Address Pattern would have already been queried.
A simple OSC synthesizer with 128 notes and some continuous controllers might response to the following queries:
/spastic/machine/note/#hash (ii) 60 64
#reply (ss) '/spastic/machine/note/#type-signature' 'ii'
#reply (si) '/spastic/machine/note/#hash' 0
Future note events, subsequent to these queries, would no longer have to be of the form:
/spastic/machine/note (ii) 60 64
but would instead be simply a sequence of binary values:
0 60 64
(Note that OSC Bundles should continue to follow the established format, with int32 size followed by a multiple of 4 bytes. Only the OSC Message format would be extended to allow an Address Pattern to start with something other than '/' or '#')
It may be more difficult to conjure an example of hash values for wild cards, but it seems at least theoretically possible that a given OSC Server could anticipate specific useful wild card patterns and provide hash values for those. An one example, an All Notes Off hash might be anticipated and provided in response to a wild card Address Pattern that is equivalent to making all notes silent. It would probably be more difficult to provide hash values on the fly for random note ranges, but it's an interesting exercise to consider. It would also be helpful to consider real-world uses of wild cards in OSC to see if there are any clues as to how to implement hashes for them.