Sending System-Exclusive Messages

MIDI system-exclusive messages are the only MIDI messages that will not fit into a single DWORD. System exclusive messages can be any length. The Multimedia extensions provide the following function for sending system-exclusive messages to MIDI output devices:

midiOutLongMsg

Sends a MIDI system-exclusive message to a specified MIDI output device.

Use the MIDIHDR data structure to specify MIDI system-exclusive data blocks. This structure contains a pointer to a locked data block, the data-block length, and some assorted flags. The MMSYSTEM.H file defines the MIDIHDR data structure as follows:

typedef struct midihdr_tag {
  LPSTR                            lpData;                                /* pointer to data block */
  DWORD                            dwBufferLength;                /* length of data block */
  DWORD                            dwBytesRecorded;        /* number of bytes recorded */
  DWORD                            dwUser;                                /* user instance data */
  DWORD                            dwFlags;                        /* assorted flags */
  struct wavehdr_tag far *lpNext;                /* private to the driver */
  DWORD                            reserved;                        /* private to the driver */
} MIDIHDR;

Memory for the MIDIHDR data structure and the data block pointed to by lpData must be allocated and prepared, as shown in “Allocating and Preparing Audio Data Blocks,” earlier in this chapter.

After you send a system-exclusive data block using midiOutLongMsg, you must wait until the device driver is finished with the data block before freeing it. If you are sending multiple data blocks, you must monitor the completion of each data block so you know when to send additional blocks. For information on different techniques for monitoring data-block completion, see “Managing Audio Data Blocks,” earlier in this chapter.

Note:

Any MIDI status byte other than a system-real-time message will terminate a system exclusive message. If you are using multiple data blocks to send a single system-exclusive message, do not send any MIDI messages other than system-real-time messages between data blocks.

Using Window Messages to Manage System-Exclusive Playback

The following messages can be sent to a window-procedure function for managing MIDI system-exclusive playback:

Message Description

MM_MOM_CLOSE Sent when the device is closed using midiOutClose.
MM_MOM_DONE Sent when the device driver is finished with a data block sent using midiOutLongMsg.
MM_MOM_OPEN Sent when the device is opened using midiOutOpen.

A wParam and lParam parameter is associated with each of these messages. The wParam parameter always specifies a handle to the open MIDI device. For the MM_MOM_DONE message, lParam specifies a far pointer to a MIDIHDR structure identifying the completed data block. The lParam parameter is unused for the MM_MOM_CLOSE and MM_MOM_OPEN messages.

The most useful message is the MM_MOM_DONE message. Unless you need to allocate memory or initialize variables, you probably don't need to process the MM_MOM_OPEN and MM_MOM_CLOSE messages. When playback of a data block is completed, you can clean up and free the data block as de-scribed in “Allocating and Preparing Audio Data Blocks,” earlier in this chaper.

Using a Callback to Manage System-Exclusive Playback

This syntax of the low-level callback function for MIDI output devices is as follows:

void FAR PASCAL midiOutCallback(hMidiOut, wMsg, dwInstance, dwParam1, dwParam2)

The following messages can be sent to the wMsg parameter of MIDI output callback functions:

Message Description

MOM_CLOSE Sent when the device is closed using midiOutClose.
MOM_OPEN Sent when the device is opened using midiOutOpen.
MOM_DONE Sent when the device driver is finished with a data block sent using midiOutLongMsg.

These messages are similar to those sent to window-procedure functions, but the parameters are different. A handle to the open MIDI device is passed as a parameter to the callback, along with the DWORD of instance data passed using midiOutOpen.

Summary: Message-Dependent Parameters

The callback has two message-dependent parameters: dwParam1 and dwParam2. For the MOM_OPEN and MOM_CLOSE messages, these parameters are not used. For the MOM_DONE message, dwParam1 specifies a far pointer to a MIDIHDR structure identifying the completed data block and dwParam2 is not used.

After the driver is finished with a data block, you can clean up and free the data block. Because of the restrictions of low-level audio callbacks, you can't do this within the callback. See “Using a Callback Function to Process Driver Messages,” earlier in this chapter, for details on the restrictions when using callback functions.

Using midiOutLongMsg to Send Regular MIDI Messages

In addition to system-exclusive data blocks, you can also use midiOutLongMsg to send regular MIDI messages. You can even mix complete system-exclusive messages with regular MIDI messages in a single data block. Regular MIDI messages should be packed into the data block with the most significant byte (the status byte) coming first—no DWORD padding is used.

Note:

MIDI output drivers are not required to verify any data in a MIDI data block before sending the data to an output port. It is up to applications to ensure only valid data is sent using midiOutLongMsg.