For MIDI input operations, clients call the user-mode driver's midMessage function. The user-mode driver should expect the client to first send a MIDM_OPEN message to open a driver instance. Next, the client allocates memory for one or more data buffers and sends MIDM_PREPARE messages to prepare the buffers for use. The client then sends a MIDM_ADDBUFFER message for each buffer, which passes the address of the empty buffer to the user-mode driver. The user-mode driver keeps a queue of available empty buffers.
To start the read operation, the client sends MIDM_START. The user-mode driver then uses a separate thread to begin requesting data from the kernel-mode driver, typically by calling ReadFileEx. The user-mode driver receives a buffer of MIDI data that can consist of a combination of short MIDI messages, or single events, and long MIDI messages, or system-exclusive events. (For descriptions of MIDI events, see the Standard MIDI Files 1.0 specification.) The user-mode driver must parse the bytes received and do the following:
·Create a time stamp (see Adding Time Stamps, below).
·If the received event is system-exclusive, place the event's bytes in the next available buffer from the queue of client buffers. If the buffer becomes full, notify the client with a MIM_LONGDATA callback message. The client can read the buffer and re-use it by sending another MIDM_ADDBUFFER message.
·If the received event is not system-exclusive, check the message to see if running status (see Running Status, below) is in effect and if so, add the previous status byte to the event. (All events passed to clients must include a status byte.) Then pass the event's bytes to the client with a MIM_DATA callback message.
When the client has finished the input operation, it sends MIDM_STOP. It can also send MIDM_RESET, which indicates to the user-mode driver that it should not fill any remaining data buffers. The client can then send a MIDM_UNPREPARE message for each buffer and deallocate the buffers. Finally, the driver should expect the client to close the instance by sending MIDM_CLOSE.
All MIDI events that are returned to a client must include a time stamp. The time stamp represents the number of milliseconds that have passed since input began. When a client sends the MIDM_START message, the kernel-mode driver saves the current system time to use as a reference time. Then each time the kernel-mode driver reads an event, it saves a time stamp value equal to the difference between the current time and the reference time.
MIDI events might or might not include a status byte. If the status byte is not included, then the client is employing running status. This means that the last status byte sent is still in effect and need not be re-sent. When a user-mode driver receives a MODM_DATA message it checks the status byte and if no value is present, it does not pass the byte to the kernel-mode driver.
Code within winmm.dll supports MIDI thru-ing to the extent that it will connect one MIDI input driver to one MIDI output driver. You can write a thru-ing driver by responding to DRVM_ADD_THRU and DRVM_REMOVE_THRU messages within midMessage and modMessage. For more information, see the discussion of managing MIDI thru-ing and the description of midiConnect in the Win32 SDK.