Managing MIDI Recording

Once you open a waveform input device, you can begin recording MIDI data. The Multimedia extensions provide the following functions for managing MIDI recording:

midiInAddBuffer

Sends a buffer to the device driver so it can be filled with recorded MIDI data.

midiInReset

Stops MIDI recording and marks all pending buffers as done.

midiInStart

Starts MIDI recording and resets the time stamp to zero.

midiInStop

Stops MIDI recording.

Use the midiInAddBuffer function to send data buffers to the device driver for recording system-exclusive messages. As the buffers are filled with recorded data, the application is notified by one of the techniques discussed in “Managing Audio Data Blocks,” earlier in this chapter.

Use the midiInStart function to begin recording. To record system-exclusive messages, send at least one buffer to the driver before starting recording. To stop recording, use midiInStop. Before closing the device using midiInClose, call midiInReset to mark any pending data blocks as being done.

You must use either a window-procedure function or a low-level callback function to receive MIDI data. If you want time-stamped data, you must use a low-level callback function.

To record system-exclusive messages, you must supply the device driver with data buffers. These buffers are specified by a MIDIHDR data structure. This is the same data structure used for MIDI system-exclusive playback described in “Sending System-Exclusive Messages,” earlier in this chapter. Memory for the MIDIHDR structure and its accompanying data buffer must be allocated and prepared as shown in “Allocating and Preparing Audio Data Blocks,” earlier in this chapter.

Using Window Messages to Manage MIDI Recording

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

Message Description

MM_MIM_CLOSE Sent when the device is closed using midiInClose.
MM_MIM_DATA Sent when a complete MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MM_MIM_ERROR Sent when an invalid MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MM_MIM_LONGDATA Sent when either a complete MIDI system-exclusive message is received, or when a data buffer sent using midiInAddBuffer is filled with system-exclusive data.
MM_MIM_LONGERROR Sent when an invalid MIDI system-exclusive message is received.
MM_MIM_OPEN Sent when the device is opened using midiInOpen.

A wParam and lParam parameter is associated with each of these messages. The wParam parameter always specifies a handle to the open MIDI device. The lParam parameter is unused for the MM_MIM_CLOSE and MM_MIM_OPEN messages.

Summary: Receiving Regular MIDI Data

For the MM_MIM_DATA message, lParam specifies the received MIDI data. This data is packed into a DWORD, as shown in the following illustration:

Summary: Receiving System-Exclusive MIDI Data

For the MM_MIM_LONGDATA message, lParam specifies a far pointer to a MIDIHDR structure that identifies the data buffer for system-exclusive messages. The data buffer might not be completely filled—you usually don't know the size of the system-exclusive messages before recording them and must allocate a buffer large enough for the largest expected message. Use the dwBytesRecorded field of the MIDIHDR structure to determine the amount of valid data present in the buffer.

Using a Low-Level Callback to Manage MIDI Recording

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

void FAR PASCAL midiInCallback(hMidiIn, wMsg, dwInstance, dwParam1, dwParam2)

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

Message Description

MIM_CLOSE Sent when the device is closed using midiInClose.
MIM_DATA Sent when a complete MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_ERROR Sent when an invalid MIDI message is received (this message is used for all MIDI messages except system-exclusive messages).
MIM_LONGERROR Sent when an invalid MIDI system-exclusive message is received.
MIM_LONGDATA Sent when either a complete MIDI system- exclusive message is received, or when a data buffer is filled with system-exclusive data.
MIM_OPEN Sent when the device is opened using midiInOpen.

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 that was passed using midiInOpen.

The callback has two message-dependent parameters: dwParam1 and dwParam2. For the MIM_OPEN and MIM_CLOSE messages, these parameters are unused.

For the MIM_DATA message, dwParam1 specifies the received MIDI data and dwParam2 specifies a time stamp for the data. The data is packed into a DWORD, as shown in the previous section on using window messages.

For the MIM_LONGDATA message, dwParam1 specifies a far pointer to a MIDIHDR structure that identifies the data buffer for system-exclusive messages. As with the MIM_DATA message, dwParam2 specifies a time stamp for the data. The data buffer might not be completely filled. Use the dwBytesRecorded field of the MIDIHDR structure to determine the amount of valid data present in the buffer.

After the device 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. You must set some semaphores and do this outside of the callback.