MMPM/2 Device Driver Reference:Real-Time MIDI Subsystem

=Real-Time MIDI Subsystem= The real-time MIDI subsystem (RTMIDI) provides real-time processing of MIDI data within the driver itself. The following sections describe how device drivers communicate with RTMIDI: Refer to the Multimedia Subsystem Programming Guide (included with the IBM Developer's Toolkit for OS/2) for more information on the real-time MIDI subsystem.
 * IDC Interface
 * Type-A Drivers
 * Registering a Type-A Driver

IDC Interface
IDC stands for inter-device-driver communication. It is a technique for making function calls from one driver to another, thereby allowing the two drivers to communicate with one another. For more information on IDC, refer to the OS/2 Physical Device Driver Reference.

Function prototypes and other declarations are found in MIDI_IDC.H. Note that "function pointers" and "entry points" are synonymous. All pointers, function or otherwise, are 16:16 (far) pointers.

Supported IDC Interfaces
The RTMIDI IDC interface is designed to support multiple "types" of client device drivers. An RTMIDI client device driver is a 16-bit physical device driver that registers itself with RTMIDI as a particular type. Currently, only Type A drivers are supported. The Type A drivers send and receive single MIDI bytes. This type is primarily intended for supporting the UART MIDI port on standard sound cards.

An individual physical device driver can be of multiple types and it can register itself with RTMIDI as many times as necessary. For instance, a sound card with four physical MIDI ports would make four Type-A registrations. RTMIDI would not realize that these four devices actually existed on one physical sound card and are handled by one driver.

The header file MIDI_IDC.H contains the function prototype for the entry points of RTMIDI. The initial call to the RTMIDI's main IDC entry point is used to obtain additional function entry points, one of each type.

Initializing IDC Communication
To initialize communication between your driver and RTMIDI:

Use the following code segment to obtain the main IDC entry point to RTMIDI and the entry points used to register the driver with RTMIDI. DevHelp_ AttachDD is used to obtain the main entry point, and DDTable.pfn retrieves the registration entry points.

This routine is normally executed when processing the init_complete strategy call. Make sure that DDTable is located in the current data segment (DS) and not on the stack (SS). MIDI_ATTACH_DD DDTable; MIDI_REGISTER reg;

if (DevHelp_AttachDD("MIDI$ ", (NPBYTE) &DDTable)) { // Error // Return }

reg.usSize=sizeof( MIDI_REGISTER ); DDTable.pfn(&reg);

Type-A Drivers
Type-A drivers send and receive single bytes to and from RTMIDI. They are typically used for simple UART MIDI ports or simple synthesizers, such as those found on most sound cards.

Type-A Driver Capabilities
When Type-A drivers register with RTMIDI, they must provide information on their capabilities by setting the appropriate bits in the flCapabilitiesfield of the MIDIREG_TYPEA structure that is passed for registration. (See Registering a Type-A Driver for an example of registering a Type-A driver.) Flags marked with an asterisk (*) are not currently supported and should not be set. The flags are:


 * MIDICAPSA_INPUT :Set this flag to indicate that this device can receive MIDI messages from RTMIDI. If set, then the pfnRecvByte and pfnRecvString fields in the MIDIREG_TYPEA structure must be properly initialized. If not set, then the corresponding hardware node cannot be enabled for receive.


 * MIDICAPSA_OUTPUT :Set this flag to indicate that this device can send MIDI messages to RTMIDI. If not set, then the corresponding hardware node cannot be enabled for send.


 * MIDICAPSA_USES_BRIDGE :Set this flag to indicate that the device is a candidate for the MMPM/2 bridge.


 * MIDICAPSA_NOT_DEFAULT :Set this flag to indicate that this device should be selectable as the default device used by MIDISimpleOpen.


 * MIDICAPSA_RUNNING_STATUS :Set this flag to tell RTMIDI that the device or the driver, or both, support running status.

Registering a Type-A Driver
The following is an example of registering a Type-A driver: USHORT __far __loadds __cdecl Open( USHORT usPort, USHORT  usMode ) { // Open hardware // For example: grab IRQ, send I/O commands to initialize the chips }

USHORT __far __loadds __cdecl Close( USHORT usPort, USHORT  usMode ) { // Close hardware // For example: detach IRQ }

USHORT __far __loadds __cdecl RecvByte( USHORT usPort, BYTE  b ) { // Send byte bData to hardware // For example: via an outp command }

USHORT __far __loadds __cdecl RecvString( USHORT usPort, BYTE __far *pb,                                          USHORT  usLength ) { // Send byte bData to hardware // For example: via an outp command }

void __far __loadds __cdecl *Ioctl( PIOCTL_RP pioc ) { // Process MMPM/2 IOCtl commands here, like volume change // pioc is a pointer to the actual IOCtl request packet }

HW_REGISTER hwreg; ULONG ulHandle; PFNSENDBYTE pfnSendByte;

hwreg.usSize=sizeof( HW_REGISTER ); hwreg.in.flCapabilities = MIDICAPSA_INPUT | MIDICAPSA_OUTPUT; hwreg.in.pszDeviceName="My Device"; hwreg.in.pfnOpen=Open; hwreg.in.pfnClose=Close; hwreg.in.pfnRecvByte=RecvByte; hwreg.in.pfnRecvString=RecvString;

if(!reg.pfnHWRegister(&hwreg)) { // Error // Return } ulHandle=hwreg.out.ulHandle; pfnSendByte=hwreg.out.pfnSendByte;