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

From EDM2
Jump to: navigation, search
MMPM/2 Device Driver Reference
  1. Adding Support for Audio and Video Adapters
  2. Audio Physical Device Driver Template
  3. Audio Virtual Device Driver Template
  4. MAD16 PDD and VDD Sample Device Drivers
  5. PDD Sample for Video Capture Adapters
  6. PDD Sample for MPEG Video Playback Devices
  7. Audio Sample for Vendor-Specific Drivers
  8. Using the High-Resolution Timer
  9. Real-Time MIDI Subsystem
  10. Audio Device Driver Exerciser (PMADDE) Tool
  11. AP2/P2STRING Tool
  12. Ultimotion Data Stream Specification
  13. DDCMD Messages
  14. SHD Messages
  15. Vendor-Specific Driver Commands
  16. IOCtl Functions
  17. Data Types
  18. Types of MIDI Messages
  19. Notices
  20. Glossary

Reprint Courtesy of International Business Machines Corporation, © International Business Machines Corporation

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

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;