Features

Contents

  1. Summary
  2. MIDI Environment and Routing
  3. Time Stamping and Time-Sorted Scheduling
  4. API Polymorphism
  5. MIDI Input Architecture

Summary

Mi_D is a multi-platform, multi-driver, and multi-language shared library that allows clients to add sophisticated MIDI support to their applications at minimal cost (cf. Examples).

Mi_D's key features are:

MIDI Environment and Routing

At the core of Mi_D is a powerful message routing mechanism that implements a fully generalized MIDI "patch bay". The mechanism translates logical I/O specifications at the client side many-to-many into driver-side real I/O specifications and vice versa. For system messages, (logical) routes are translated into (real) connections numbers and, for channel messages, logical channels first into routes and (real) channels, then each route again into connections (see Fig. 1). Thus, system and channel messages share a common level of indirection and I/O information pertaining to multiple ports need not be duplicated in the channel matrix.

[message routing diagram]
Figure 1: Translation between logical and real I/O specifications in Mi_D involves a three-dimensional channel matrix and a two-dimensional route matrix. Note that connections do not have to be associated with actual interfaces.

A connection may be thought of as a pair of software MIDI cables, that is, as a bidirectional stream capable of transmitting up to 16 channels of MIDI data in each direction. As with MIDI cables, connections may or may not be associated with a real interface available to the system. However, MIDI may only be received on a connection that is actually associated with an (input) interface and data delivered to a connection won't be transmitted unless it has been associated with an (output) interface.

MIDI streams may be easily multicasted or multiplexed by mapping routes or logical channels onto more than one connection or route/channel or vice versa.

In order to keep memory consumption as low as possible, the environment's data structures are dimensioned according to some init-time limits determining the maximum number of logical channels, routes, and connections. A fourth init-time constant limits the number of mappings that can be established across all maps. Mappings are allocated en bloc at initialization time and then maintained in a LISP-like fashion by a simple run-time memory manager. Thus, mappings may be established or cleared at any time, without intervening system memory allocations.

Time Stamping and Time-Sorted Scheduling

Mi_D's notion of time is unsophisticated and straightforward. All timing information is expressed in milliseconds and no provisions are made to convert to or from various frame-based time formats. Also, there is no such concept as a global "MIDI System Time". Each client has its own timer provided through Mi_D with a private origin in time. Since the time base is a private variable, the client may reset reset this timer to any value at any time.

All messages in Mi_D are time-stamped. In addition, outgoing messages are written to a time-sorting queue, which allows the client to schedule note-on and note-off messages together as one single "note" message with independent duration, or, in general, to schedule messages out of order. The downside is that a very small, yet existent, delay is being added to any already existing driver latency. However, the delay is constant under normal circumstances constant and thus does not introduce jitter in the MIDI output stream.

API Polymorphism

Mi_D's I/O routines come in two different flavors to support two MIDI message formats. That way, message data may be passed and retrieved either as individual bytes or in a special encoded format that stores I/O information, status and data bytes in one single unsigned long.

MIDI Input Architecture

Mi_D provides MIDI input on a on-demand basis. That is, the client does not need to deal with intricacies related to interrupts and callbacks from Mi_D at interrupt time. Rather, incoming messages are fetched, translated, routed, and placed in an input queue from which the client may then read at non-interrupt time and upon the client's request only. Note that this approach does not introduce additional latency, unless the client application is specifically designed to execute at interrupt time (which virtually none of Mi_D's candidate clients will want to do).

Serving the input queue on demand and at non-interrupt time expects that the client is able to process incoming data at a fine enough granularity in order to avoid loss of incoming data as well as the introduction of unwanted jitter in real-time applications.