API Reference

This manual describes version 1.3 of Mi_D.

Contents

  1. API Result Codes and Constants
  2. MIDI Message Formats
  3. Mi_D Version Information
  4. Opening and Closing MIDI
  5. Environment
  6. I/O Routines
  7. Flushing
  8. Timing
  9. Utility Functions
  10. Platform-Specific Functions

1. API Result Codes and Constants

API Result Codes

static const int mi_dNoErr              =    0;
static const int mi_dErr                =   -1;
static const int mi_dOutOfMemory        =   -3;
static const int mi_dOutOfBounds        = -100;
static const int mi_dUndefinedFlag      = -102;
static const int mi_dNullHandle         = -103;
static const int mi_dIllegalValue       = -104;
static const int mi_dEnvChanged         = -110;
static const int mi_dNoInterfaces       = -111;
static const int mi_dNoSuchInterface    = -112;
static const int mi_dUnknownSelector    = -113;

Limits

#define MI_D_MAX_CHANNELS 16              /* Max. Standard MIDI Channels    */
#define MI_D_MAX_INTERFACE_NAME_LENGTH 64 /* Max. Interface C String Length */
#define MI_D_MAX_CLIENT_NAME_LENGTH 32    /* Max. Client C String Length    */
#define MI_D_MESSAGE_BUFFER_LENGTH 80     /* Length of Message Printout     */
#define MI_D_SYSEX_BUFFER_LINE_LENGTH 68  /* Line Length of Sysex Printout  */

2. MIDI Message Formats

Mi_D's API supports two MIDI message formats. Routines ending in "_3c" pass messages as three unsigned char's, i.e. a status byte and two data bytes, whereas routines ending in "_el" pass the message as one single unsigned long in encoded format (see below). MIDI sysex data are stored and sent as strings. Running status is not used.

Standard Message Format

Standard MIDI messages are passed as three separate bytes, a status byte and two data bytes, along with an (unsigned) I/O specification representing the messages route (system messages) or logical channel (channel messages). The channel field (the lower 4 bits of the status byte in channel messages) is ignored on output and cleared on input.

/*
 * (31)    24        16         8         0  bits
 *  :... ...: .... ...: .... ...: .... ...:
 *
 *                                           system messages:
 *                      ---- ---- ---- ----  Route (unsigned short)
 *                                1--- ----  Status
 *                                0--- ----  Data Byte 1 (default: 0x00)
 *                                0--- ----  Data Byte 2 (default: 0x00)
 *
 *                                           channel messages:
 *                      ---- ---- ---- ----  Logical Channel (unsigned short)
 *                                1--- 0000  Status
 *                                0--- ----  Data Byte 1 (default: 0x00)
 *                                0--- ----  Data Byte 2 (default: 0x00)
 */

Encoded Message Format

Encoded MIDI messages pack the status byte and (up to two) data bytes of a standard MIDI message into the lower 21 bits of an unsigned long. The remaining bits (22-31) are used to hold logical channel/routing information. The nibbles of the status byte are swapped in order to allow the 4 bits channel information present in the lower nibble of the status byte of channel messages to form a contiguous field with bits 22-31. As a result, channel messages have 14 bits (bits 18-31) to represent a logical channel from 0 to 16384 whereas system messages use up to 10 bits (bits 22-31) to represent (logical) routes ranging from 0 to 1024.

/*
 *  (31)    24        16         8         0  bits
 *   :... ...: .... ...: .... ...: .... ...:
 *   
 *                                            system message fields:
 *   ---- ---- --                             mi_dEncRouteByte
 *               -- --                        mi_dEncLStatusByte
 *                    1- --                   mi_dEncUStatusByte
 *               -- --1- --                   mi_dEncSwappedStatusByte
 *                         -- ---- -          mi_dEncData1Byte
 *                                  --- ----  mi_dEncData2Byte
 * 
 *                                            channel message subfields:
 *   ---- ---- ---- --                        mi_dEncLChannelByte
 *                    1- --                   mi_dEncOpcodeByte
 */

/* Bit masks and offsets (Encoded MIDI Messages) */
static const unsigned long mi_dEncRouteByte          = 0xffc00000UL;
static const unsigned long mi_dEncLStatusByte        = 0x003c0000UL;
static const unsigned long mi_dEncUStatusByte        = 0x0003c000UL;
static const unsigned long mi_dEncSwappedStatusByte  = 0x003fc000UL;
static const unsigned long mi_dEncLChannelByte       = 0xfffc0000UL;
static const unsigned long mi_dEncOpcodeByte         = 0x0003c000UL;
static const unsigned long mi_dEncData1Byte          = 0x00003f80UL;
static const unsigned long mi_dEncData2Byte          = 0x0000007fUL;

static const unsigned int mi_dEncRouteOffs           = 22;
static const unsigned int mi_dEncUStatusOffs         = 10; /* byte-aligned */
static const unsigned int mi_dEncLStatusOffs         = 18;
static const unsigned int mi_dEncSwappedStatusOffs   = 14;  
static const unsigned int mi_dEncLChannelOffs        = 18;
static const unsigned int mi_dEncOpcodeOffs          = 10; /* byte-aligned */
static const unsigned int mi_dEncData1Offs           =  7;
static const unsigned int mi_dEncData2Offs           =  0;

/* AND with this mask to turn an encoded note on message into a note off   */
/* message with zero velocity.                                             */
static const unsigned long mi_dEncNoteOffMask        = 0xfffe3f80U;

3. Mi_D Version Information

unsigned long mi_dVersion(void);

Return the Mi_D version number. This number is a 4-byte quantity with the major version (M), minor version (m) and release number (r) in the most significant three bytes and the release status (s) and number (n) in the least significant byte:

0xMMmmrrsn

s may be one of

s Meaning
0 final release
1 beta release
2 alpha release
3 development release

n denotes the serial number of the given release and is used only if s is not zero. MM, mm and rr are binary-decimal-coded. Hence, for example,

0x01170413

translates to the third beta release of version 1.17.4, or short "1.17.4b3".

LISP Note: The LISP call corresponding to mi_dVersion returns this last "short" version string along with major version, minor version, release number, release status and serial number as multiple values.

4. Opening and Closing MIDI

extern char mi_dClientName[];		/* Default client name ("Mi_D") */

#ifdef __cplusplus
int mi_dOpen(const char* clientName = mi_dClientName,
	     const unsigned short maxLChannels = 100,
	     const unsigned short maxRoutes = 10,
	     const unsigned short maxConnections = 10,
	     const unsigned int maxMappings = 400,
	     const unsigned int queueSize = 2000);
#else
int mi_dOpen(const char* clientName,
	     const unsigned short maxLChannels,
	     const unsigned short maxRoutes,
	     const unsigned short maxConnections,
	     const unsigned int maxMappings,
	     const unsigned int queueSize);
#endif

Initialize MIDI environment and scheduler, open the driver and start the timer. Calling mi_dOpen when MIDI is already open closes MIDI first, then re-opens it again.

LISP Note: The LISP call corresponding to mi_dOpen has been, due to name conflicts with the COMMON-LISP system package, renamed to mi_d:open-midi.

OMS Note: No provisions are made at this point to specify custom client and port signatures. Rather, Mi_D generates signatures on the basis of the system clock. More precisely, the client, input port, and output port signatures will be ‘edXX’ (that is, "Mi_D" spelled out in modern pitches), ‘->XX’, and ‘<-XX’, respectively, where ‘XX’ represents the mentioned 2-byte quantity derived from the system clock.

Arguments:
clientName
client namestring (truncated to MI_D_MAX_CLIENT_NAME_LENGTH characters)
maxLChannels
maximum number of logical channels
maxRoutes
maximum number of routes
maxConnections
maximum number of connections
maxMappings
maximum number of mappings (for both, routes and logical channels)
queueSize
size of the MIDI output queue (in Events)
Result:
mi_dNoErr
success
mi_dErr
driver-related failure
mi_dOutOfMemory
not enough memory to initialize environment, driver or scheduler
void mi_dClose(void);

Close the driver, free environment and scheduler data. It is safe to call mi_dClose at any time.

LISP Note: The LISP call corresponding mi_dClose has been, due to name conflicts with the COMMON-LISP system package, renamed to mi_d:close-midi.

Arguments:
<none>
Result:
<none>

5. Environment

int mi_dUpdateSystemInfo(void);

Update environment information pertaining to the system interfaces. This function is called automatically by mi_dOpen, mi_dGetEnvironmentInfo and mi_dPrintEnvironment. Clients may want to call mi_dUpdateSystemInfo when their driver-side MIDI setup changed and if they experience MIDI transmission problems that may be related to missing interfaces.

Arguments:
<none>
Result:
mi_dNoErr
success
mi_dErr
an unexpected error occured
mi_dOutOfMemory
not enough memory to store interface namestrings
mi_dNoInterfaces
the system has no interfaces defined
mi_dEnvChanged
the system environment has changed (this is not an error)
#ifdef __cplusplus
void mi_dPrintEnvironment(FILE* stream = stderr, const int verbosity = 0);
#else
void mi_dPrintEnvironment(FILE* stream, const int verbosity);
#endif

Print current environment information. A verbosity level of 0 prints a summary only, level 1 prints the contents of the channel and route maps, and level 2 prints also their inverse maps.

LISP Note: The LISP version corresponding to mi_dPrintEnvironment, mi_d:print-environment accepts only the keywords :stdout and :stderr in its stream argument.

Arguments:
stream
stream to print to; if 1 or 2 are passed instead of a FILE*, print to stdout or stderr, respectively
verbosity
verbosity level: 0, 1, or 2
Result:
mi_dNoErr
success
mi_dErr
failure
int mi_dGetEnvironmentInfo(mi_dInfo morsels[], unsigned int n);

Return specific bits of information about the MIDI environment. This function is provided for clients who want access to environment data other than a simple print-out. Any arbitrary collection of data may be specified, and will be returned, using a client-side array of mi_dInfo structures:

typedef struct {
  int param;                    /* Environment info selector                */
  union {                       /* Result (type depends on selector)        */
    unsigned int ui;
    const void* ptr;
  } val;
  int err;                      /* Status: mi_dNoErr or mi_dUnknownSelector */
} mi_dInfo;

whose selector field contains upon entry one of:

enum mi_dInfoSelector {         /* Result Type:                             */
  mi_dMaxLogicalChannels  =  0, /*    unsigned int                          */
  mi_dMaxRoutes           =  1, /*    unsigned int                          */
  mi_dMaxConnections      =  2, /*    unsigned int                          */
  mi_dMaxMapCells         =  3, /*    unsigned int                          */
  mi_dMapCellsInUse       =  4, /*    unsigned int                          */
  mi_dQueueSize           =  5, /*    unsigned int                          */
  mi_dNrOfInterfaces      =  6, /*    unsigned int                          */

  mi_dInterfaceInfo       =  7, /*    mi_dInterface* (*)[]                  */
  mi_dInputInterfaces     =  8, /*    mi_dInterface* (*)[]                  */
  mi_dOutputInterfaces    =  9, /*    mi_dInterface* (*)[]                  */

  mi_dChannelMap          = 10, /*    mi_dMapCell* (*)[]                    */
  mi_dInvChannelMap       = 11, /*    mi_dMapCell* (*)[][MI_D_MAX_CHANNELS] */
  mi_dRouteMap            = 12, /*    mi_dMapCell* (*)[]                    */
  mi_dInvRouteMap         = 13  /*    mi_dMapCell* (*)[]                    */
};

#define MI_D_NR_OF_INFO_SELECTORS 14                    /* Utility Constant */

Upon return, the result will be stored in either the val.ui or val.ptr fields, depending on the selector's result type, as indicated above. The err field will be set to mi_dUnknownSelector in the event of an error, or to mi_dNoErr otherwise.

Data Structures

The mi_dInterfaceInfo, mi_dInputInterfaces, and mi_dOutputInterfaces selectors return each arrays of pointers to mi_dInterface structures holding the interface's name and direction. Interface name strings are system-dependent and will always be truncated to MI_D_MAX_INTERFACE_NAME_LENGTH characters. The direction field indicates whether the interface is an input, output, or bidirectional interface.

The array retrieved through the mi_dInterfaceInfo selector lists the all interfaces present in the system, in some system-dependend order. Its length is thus identical to the value retrieved using the mi_dNrOfInterfaces selector. The arrays returned in response to the mi_dInputInterfaces and mi_dOutputInterfaces selectors represent associations between connections and interfaces and thus have a length equal to the value retrieved through the mi_dMaxConnections selector. A NULL pointer indicates that the connection is not associated with an interface.

typedef struct {
  char name[MI_D_MAX_INTERFACE_NAME_LENGTH]; 
  int direction;	     /* mi_dInput, mi_dOutput, or mi_dBidirectional */
} mi_dInterface;

The mi_dChannelMap, mi_dInvChannelMap, mi_dRouteMap, and mi_dInvRouteMap selectors return environment maps as pointers to arrays of mi_dMapCell structures. The size of these arrays depends on the map returned and should be retrieved using the mi_dMaxLogicalChannels, mi_dMaxRoutes, or mi_dMaxConnections selectors:

Each mi_dMapCell holds exactly one mapping (a structure of type mi_dMapping) specifying either the logical channel, a pair consisting of a route and a channel (a structure of type mi_dRoutedChannel), the route, or the connection the current value should be translated into.

Finally, since Mi_D supports many-to-many mappings in each translation table, several mi_dMapCell structures may be chained together via their next field to form a linked list.

typedef struct {                /* "routed" channel specification */
  unsigned short route;
  unsigned short chan;
} mi_dRoutedChannel;

typedef union {
  unsigned short lchan;         /* logical channel  */
  mi_dRoutedChannel rchan;      /* "routed" channel */
  unsigned short conn;          /* connection       */
  unsigned short route;         /* route            */
} mi_dMapping;

typedef struct mi_dMapCell {
  mi_dMapping val;
  struct mi_dMapCell* next;
} mi_dMapCell;

LISP Note: Parsing of the various return values is not necessary for LISP clients, since the LISP call corresponging to mi_dGetEnvironmentInfo, mi_d:get-environment-info, returns the data in standard list form.

Arguments:
morsels
array of mi_dInfo structures
n
number of mi_dInfo structures to fill
Result:
mi_dNoErr
success
mi_dErr
the environment is uninitialized
int mi_dCheckEnvironment(void);

Check the consistency of the various maps in the MIDI environment. This function does not check whether connections are actually associated with interfaces, since it is explicitly allowed to have connections "dangling".

If mi_dErr is returned, mi_dPrintEnvironment or mi_dGetEnvironmentInfo may be used to get a more detailed description of the inconsistencies encountered.

Arguments:
<none>
Result:
mi_dNoErr
environment is consistent
mi_dErr
environment is inconsistent
int mi_dAddChanmapMapping(const unsigned short lchan,
                          const unsigned short route,
                          const unsigned short chan);
int mi_dClearChanmapMapping(const unsigned short lchan,
                            const unsigned short route,
                            const unsigned short chan);

Add (or clear) a mapping from a logical channel to a route and (real) channel and vice versa to (or from) the environment's channel map.

Arguments:
lchan
logical channel number
route
(logical) route number
chan
(real) channel number
Result:
mi_dNoErr
success
mi_dIllegalValue
an argument was out of range (see mi_dOpen)
mi_dOutOfMemory
no more mi_dMapCell's available
mi_dNullHandle
the specified mapping did not exist
void mi_dClearChanmap(void);

Clear all channel map entries.

Arguments:
<none>
Result:
<none>
int mi_dAddRoutemapMapping(const unsigned short route,
                           const unsigned short conn);
int mi_dClearRoutemapMapping(const unsigned short route,
                             const unsigned short conn);

Add (or clear) a mapping from a route to a connection and vice versa to (or from) the environment's route map.

Arguments:
route
(logical) route number
conn
(real) connection number
Result:
mi_dNoErr
success
mi_dIllegalValue
an argument was out of range (see mi_dOpen)
mi_dOutOfMemory
no more mi_dMapCell's available
mi_dNullHandle
the specified mapping did not exist
void mi_dClearRoutemap(void);

Clear all route map entries.

Arguments:
<none>
Result:
<none>
int mi_dStandardMaps(void);

Map 16 logical channels onto route 0, channels 0-15, and 1 route onto connection 0. This provides a simple, one-connection, 16-channel Standard MIDI environment. It does not, however, associate an actual interface with the connection, since there is no standard way of doing so. Call mi_dConnect to associate an interface and thus make the actual input and output connections.

Arguments:
<none>
Result:
mi_dNoErr
success
mi_dErr
environment does not allow for either 16 channels, 1 route or doesn't have enough mi_dMapCell's (see mi_dOpen)
static const int mi_dInput                =    1;
static const int mi_dOutput               =    2;
static const int mi_dBidirectional        =    3;   /* mi_dInput | mi_dOutput */

int mi_dConnect(const unsigned short conn,
                const char* name,
                const int direction);

Associate or dissociate a named interface with a connection. The operation may apply to either the input, output, or both associations.

LISP Note: The LISP version corresponding to mi_dConnect, mi_d:connect accepts only strings for its name argument. Hence, an empty string has to be passed to mi_d:connect in order to clear an existing association.

Arguments:
conn
connection to associate with interface name
name
interface name to associate with connection conn;if NULL, clear (dissociate) an existing association
direction
mi_dInput, mi_dOutput, or mi_dBidirectional
Result:
mi_dNoErr
success
mi_dErr
failure
mi_dUndefinedFlag
direction was not mi_dInput, mi_dOutput, or mi_dBidirectional
mi_dNoSuchInterface
name is not a known interface namestring

6. I/O Routines

Warning: For performance reasons, the output routines do not test whether the environment is valid and hence will cause a segmentation violation if called with midi closed. DO NOT CALL ANY OF THESE ROUTINES WITHOUT HAVING OPENED MIDI FIRST.

int mi_dWriteMessage_3c(const unsigned short output,
                        const char status,
                        const char data1,
                        const char data2, 
                        const unsigned long time);
int mi_dWriteMessage_el(const unsigned long message,
                        const unsigned long time);

Send a message. Messages may either be sent as (logical) output plus three individual bytes (mi_dWriteMessage_3c) or as an encoded long containing (logical) output specification according to the format detailed above (mi_dWriteMessage_el). System messages output on (logical) routes, channel messages on logical channels.

Arguments:
output
logical channel or route (depending on message type)
status
status byte (bits 0-3 are ignored in channel messages)
data1
data byte 1
data2
data byte 2
message
message in encoded format
time
time stamp (in ms)
Result:
mi_dNoErr
success
mi_dErr
a logical channel or route could not be resolved
#ifdef __cplusplus
int mi_dWriteSysex(const unsigned short route,
                   const unsigned int length,
                   const char* data,
                   const unsigned long time,
                   unsigned long* refcounter = NULL);
#else
int mi_dWriteSysex(const unsigned short route,
                   const unsigned int length,
                   const char* data,
                   const unsigned long time,
                   unsigned long* refcounter);
#endif

Send a sysex message. The sysex message is stored in a block of memory pointed to by data whose length (in bytes) is stored in length. It is generally the client's responsibility not to deallocate data before the last message pointing to it has been written out. (Note, too, that the last message written out is not necessarily the last scheduled message!) That is, unless the client stores sysex both, as constant data and in static memory, it needs to know when it is safe to dispose of old data. This issue arises not only if (dynamic) sysex data is scheduled for future output, but also (due to latencies inherent in the scheduler, driver and OS) if it is to be output immediately. Hence, unless the client stores sysex data statically, it is recommended that it stores along with the sysex message an unsigned long value and passes its address as refcounter. The long should be cleared initially. mi_dWriteSysex then increments this value when the sysex message is queued and decrements it after it has been written out. The client should examine its value before every attempt to release the data and only do so if it is again equal to zero. Note that this mechanism requires that the client consistently passes the same address in refCount in case it writes a sysex message multiple times in a row.

Note: Watch out for languages with automatic garbage collection! E.g., a LISP call like

(let ((sysex (make-c-array ...)))
  (mi_d:write-sysex sysex (+ (mi_d:get-time) 100)))
could be subject to garbage collection as soon as the let form returns.

Arguments:
route
(logical) route to output the message on
length
length of data in bytes
sysex
string holding a complete sysex message (including the F7/F0 markers)
time
time stamp (in ms)
refCount
pointer to storage used as data reference counter
Result:
mi_dNoErr
success
mi_dErr
a logical channel or route could not be resolved
int mi_dWriteNote_3c(const unsigned short lchan,
                     const char key,
                     const char onVelocity,
                     const char offVelocity,
                     const unsigned long duration,
                     const unsigned long time);
int mi_dWriteNote_el(const unsigned long onMessage,
                     const char offVelocity,
                     const unsigned long duration,
                     const unsigned long time);

Convenience routine to schedule note-on and note-off messages in pairs. A message is either a logical channel followed by three individual bytes specifying the key and both velocities (mi_dWriteNote_3c), or an encoded note-on message according to the format detailed above (mi_dWriteNote_el). Both functions take a duration and time parameter.

Arguments:
lchan
logical channel
key
MIDI key number
onVelocity
key velocity for the note-on message
offVelocity
key velocity for the note-off message
onMessage
note-on message in encoded format
duration
duration of the note (in ms)
time
time stamp (in ms)
Result:
mi_dNoErr
success
mi_dErr
a logical channel or route could not be resolved
int mi_dReadMessages_3c(void);
int mi_dReadMessages_el(void);

Receive all MIDI events that arrived since this function has been called last (or since MIDI has been opened or input has been flushed). The incoming events are placed in an input queue and may be retrieved using the corresponding mi_dInputMessage_3c or mi_dInputMessage_el calls below. The client may switch between both forms of these routines any time mi_dReadMessages_3c or mi_dReadMessages_el is called, that is, it is only required that the mi_dInputMessage_3c or mi_dInputMessage_el calls be consistent with the last call to mi_dReadMessages_3c or mi_dReadMessages_el.

Note that reception of MIDI messages is subject to availability, request and input buffer storage space. That is, incoming messages are lost unless requested in time before the buffer overruns and mi_dReadMessages_3c and mi_dReadMessages_el return zero without blocking if no messages are available.

Arguments:
<none>
Result:
int
the number of MIDI events read
mi_dErr
driver-side failure
int mi_dInputMessage_3c(const unsigned int i,
                        unsigned short* input,
                        char* status,
                        char* data1,
                        char* data2,
                        unsigned long* time);
int mi_dInputMessage_el(const unsigned int i,
                        unsigned long* message,
                        unsigned long* time);
int mi_dInputSysex(const unsigned int i,
                   const char** sysex,
                   unsigned int* length);

Return components of an input event. MIDI messages other than System Exclusive messages may be retrieved either as individual bytes in standard format or as one message in encoded format (see Message Formats). If the message is a sysex message, status will be set to 0xF0 (mi_dInputMessage_3c) or the encoded status byte to 0xF0 (mi_dInputMessage_el). mi_dInputSysex may then be used to retrieve a pointer to the sysex data, whose length is stored in length. Since the input queue is ring buffered, the client should copy the data as soon as possible in order to prevent data loss due to buffer overruns or other incoming sysex messages. Note that sysex data is not copied if MIDI input data is multiplexed in the environment. Instead, all (strictly sequential) input events retrieved by the same call to mi_dReadMessages_3c or mi_dReadMessages_el share the same sysex data block and the client can avoid copying the same data over and over again by comparing each pointer with the pointer the immediately previous event. A sysex data block whose first byte is not 0xF0 is invalid (i.e., has most likely been overrun).

Arguments:
i
message index; must be less than the number of messages read as returned by the last call to mi_dReadMessages_3c or mi_dReadMessages_el
input
storage for route or logical channel of the message
status
storage for status byte
data1
storage for data byte 1
data2
storage for data byte 2
message
storage for encoded message
time
storage for time stamp
sysex
storage for pointer to sysex data
length
storage for length of sysex data
Result:
mi_dNoErr
success
mi_dErr
message at index <i> is not a sysex message
mi_dOutOfBounds
i was larger than the result of the last call to mi_dReadMessages_3c or mi_dReadMessages_el

7. Flushing

void mi_dFlushInput(void);
void mi_dFlushOutput(void);

Flush pending input or output.

Arguments:
<none>
Result:
<none>
void mi_dAllNotesOff(void);

Broadcast All-Notes-Off, All-Sound-Off, and Reset-All-Controllers control messages on all active output connections. Note that this does not work with some older MIDI devices that are unaware of these messages. These devices continue to need note-off messages on every channel and key number.

Note: mi_dAllNotesOff uses control messages for efficiency. Mi_D currently does not provide a "traditional" version of this routine.

Arguments:
<none>
Result:
<none>
void mi_dHush(void);

mi_dHush is equivalent to a call to mi_dAllNotesOff followed by calls to mi_dFlushOutput and mi_dFlushInput.

Arguments:
<none>
Result:
<none>

8. Timing

int mi_dStartTimer(void);
int mi_dStopTimer(void);

Start or stop the timer used by the system. Starting it resets the time to zero. This is normally done automatically during mi_dOpen, but the timer may be restarted anytime, whether it has been previously stopped using mi_dStopTimer or not (mi_dStopTimer is a no-op and provided for backward compatibility only).

Arguments:
<none>
Result:
mi_dNoErr
mi_dStartTimer and mi_dStopTimer always return successfully
unsigned long mi_dGetTime(void);
int mi_dSetTime(const unsigned long time);

Get or set the current time (in ms). Calling mi_dSetTime does not interrupt the timer but rather sets an internal offset that is used to calculate time.

Arguments:
time
value to set the current time to
Result:
unsigned long
mi_dGetTime returns the current time in ms
mi_dNoErr
mi_dSetTime returns always mi_dNoErr

9. Utility Functions

void mi_dPrintMessage_3c(FILE* stream,
                         char* buf,
                         const unsigned short ioref,
                         const unsigned char status,
                         const unsigned char data1,
                         const unsigned char data2,
                         const unsigned long time);
void mi_dPrintMessage_el(FILE* stream,
                         char* buf,
                         const unsigned long message,
                         const unsigned long time);
void mi_dPrintSysexData(FILE* stream,
                        char* buf,
                        const unsigned int lines,
                        const char* data,
                        const unsigned int length);

Print an (encoded or unencoded) message, or a sysex message.

LISP Notes: The LISP versions corresponding to mi_dPrintMessage_3c, mi_dPrintMessage_el, and mi_dPrintSysexData, mi_d:print-message_3c, mi_d:print-message_el, and mi_d:print-sysex-data, repectively, accept only the keywords :stdout and :stderr in their stream arguments.

Also note that strings may not be side-effected in the Common LISP standard. As a result, mi_d:print-message_3c, mi_d:print-message_el, and mi_d:print-sysex-data accept a boolean string argument instead of an actual string object. If string is T, mi_d:print-message_3c, mi_d:print-message_el, and mi_d:print-sysex-data return a freshly allocated string containing their formatted output or NIL, otherwise.

Finally, note that the third argument to mi_d:print-sysex-data, lines, may also be set to NIL, which has the same effect as setting it to 0.

Arguments:
stream
if not NULL, stream to print to; if 1 or 2 are passed instead of a FILE*, print to stdout or stderr, respectively
buf
if not NULL, buffer to print to; has to be at least MI_D_MESSAGE_BUFFER_LENGTH in size for standard messages;
ioref
logical channel or route (depending on message type)
status
status byte (bits 0-3 are ignored in channel messages)
data1
data byte 1
data2
data byte 2
message
message in encoded format
time
time stamp (in ms)
lines
print up to <lines> lines of sysex data; if printing to <buf>, <buf> has to be at least of size <lines> * MI_D_SYSEX_BUFFER_LINE_LENGTH bytes; if <data> contains more bytes than fit in <lines> lines, the last line will print a message indicating the amount of bytes remaining in the message; setting <lines> to 0 always prints the full message
data
pointer to a block of sysex data
length
length of sysex data in bytes
Result:
mi_dNoErr
success
mi_dErr
a logical channel or route could not be resolved
const char* mi_dGetErrorString(const int code);

Return the string corresponding to a Mi_D result code. A generic string is returned in case of an unrecognized result code, along with its numerical value. The client should deal with the string before calling mi_dGetErrorString again, since another unrecognized result code will cause mi_dGetErrorString to overwrite the old string.

Arguments:
code
result code
Result:
char*
string corresponding to the result code

10. Platform-Specific Functions

#if defined(OMS)
void mi_dOMSOpenCurStudioSetup(void);
void mi_dOMSOpenMIDISetupDialog(void);
#endif

Open the current OMS Studio Setup or OMS MIDI Setup dialog, respectively. OMS only.

Arguments:
<none>
Result:
<none>