MCI requires audio devices be opened before they can be accessed. Use the MCI_OPEN command along with the MCI_OPEN_PARMS parameter block to open an audio device and obtain an MCI device ID. Subsequent commands use this device ID to identify the device to receive the command. MMSYSTEM.H defines the MCI_OPEN_PARMS parameter block as follows:
typedef struct {
DWORD dwCallback; /* callback for MCI_NOTIFY flag */
UINT wDeviceID; /* device ID returned to user */
UINT wReserved0; /* reserved */
LPCSTR lpstrDeviceType; /* device name */
LPCSTR lpstrElementName; /* device element */
LPCSTR lpstrAlias; /* optional device alias (reserved) */
} MCI_OPEN_PARMS;
The MCI device ID is returned in the wDeviceID field. You should always check the return value of mciSendCommand after sending an MCI_OPEN command before using this device ID. A non-zero return value indicates that there was an error in opening the device and the returned device ID will not be valid.
For waveform audio devices, you can use an extended parameter block, MCI_WAVE_OPEN_PARMS. This structure has a dwBufferSeconds field to specify the number of seconds of buffering used by the MCI waveform device driver. If you use this field, you must specify the MCI_WAVE_OPEN_BUFFER flag for the dwParam1 parameter of mciSendCommand to validate the field. MMSYSTEM.H defines the MCI_WAVE_OPEN_PARMS parameter block as follows:
typedef struct {
DWORD dwCallback; /* callback for MCI_NOTIFY flag */
UINT wDeviceID; /* device ID returned to user */
UINT wReserved0; /* reserved */
LPCSTR lpstrDeviceType; /* device name */
LPCSTR lpstrElementName; /* device element */
LPCSTR lpstrAlias; /* optional device alias (reserved) */
DWORD dwBufferSeconds; /* buffer size in seconds */
} MCI_WAVE_OPEN_PARMS;
Unless you want to specify the number of seconds of buffering for the driver to use, you can use the MCI_WAVE_OPEN_PARMS parameter block when you open waveform audio devices.
When you open a simple device, such as a compact disc audio device, you must specify the device name in the lpstrDeviceType field. When you open a compound device, such as a waveform or MIDI sequencer device, the device name is optional.
Use the lpstrDeviceType field of the MCI_OPEN_PARMS structure to specify the device name. MCI lets you use a string or a constant for this field. The following table shows the strings and constants for MCI audio devices:
Device | String | Constant |
Compact disc | cdaudio | MCI_DEVTYPE_CD_AUDIO |
Waveform | waveaudio | MCI_DEVTYPE_WAVEFORM_AUDIO |
MIDI sequencer | sequencer | MCI_DEVTYPE_SEQUENCER |
Using a string is the default convention for specifying device names. If you use a constant to specify the device name, you must specify the MCI_OPEN_TYPE_ID flag in addition to the MCI_OPEN_TYPE flag.
Waveform and MIDI sequencer devices are compound devices. Compound devices require an associated device element—a WAVE or MIDI file. There are three ways to open compound devices:
Specify only the device name.
Specify only the device element and let MCI select the device from the file extension of the device element.
Specify both the device name and the device element.
Use the first approach, specifying only the device name, when opening a device to query its capabilities with the MCI_GETDEVCAPS command and when you plan to use the device to play more than one device element.
If you don't specify a device name when you open a compound device, MCI will choose an appropriate device type by looking at the file extension of the device element and at entries in the [mci extensions] section of WIN.INI. The following code fragment uses this technique to open a MIDI sequencer device to play a MIDI file named CHOPIN.RMI:
UINT wDeviceID;
MCI_OPEN_PARMS mciOpenParms;
.
.
.
/* Open the device by specifying only the device element */
mciOpenParms.lpstrElementName = "CHOPIN.RMI";
if (mciSendCommand(0, // device ID
MCI_OPEN, // command
MCI_OPEN_ELEMENT, // flags
(DWORD) (LPVOID) &mciOpenParms)) // parameter block
/* Error, unable to open device
*/
...
else
/* Device opened successfully, get the device ID
*/
wDeviceID = mciOpenParms.wDeviceID;
Instead of letting MCI choose the device, you can specify the device name when you open the device. The following code fragment uses this technique to open a waveform audio device to play the C:\SOUNDS\BELLS.WAV file. This example uses a string to specify the device name. For an example using a constant to specify the device name, see “Opening Compact Disc Devices,” later in this chapter.
UINT wDeviceID;
MCI_OPEN_PARMS mciOpenParms;
.
.
.
/* Open the device by specifying both the device
* element and the device name
*/
mciOpenParms.lpstrDeviceType = "waveaudio";
mciOpenParms.lpstrElementName = "C:\\SOUNDS\\BELLS.WAV";
if (mciSendCommand(0, // device ID
MCI_OPEN, // command
MCI_OPEN_ELEMENT | MCI_OPEN_TYPE, // flags
(DWORD)(LPVOID) &mciOpenParms)) // parameter block
/* Error, unable to open device
*/
...
else
/* Device opened successfully, get the device ID
*/
wDeviceID = mciOpenParms.wDeviceID;
The MIDI Mapper is the default output device for the MCI MIDI sequencer. It provides standard patch services for device-independent playback of MIDI files. Applications that use the MCI sequencer to play MIDI files should use the MIDI Mapper. For details on the MIDI Mapper, see “The MIDI Mapper,” later in this chapter. For information on authoring device-independent MIDI files, see “Authoring MIDI Files,” also later in this chapter.
When you open the MCI MIDI sequencer, MCI attempts to select the MIDI Mapper as the output device. If the Mapper is unavailable because it's already in use, MCI selects another MIDI output device.
Note:
The MIDI Mapper currently supports only one client at a time. This might change in future versions of Windows.
After opening the sequencer, you should check to see if the MIDI Mapper was available and selected as the output device. The following code fragment uses the MCI_STATUS command to verify that the MIDI Mapper is the output device for the MCI sequencer:
UINT wDeviceID;
DWORD dwReturn;
MCI_STATUS_PARMS mciStatusParms;
.
.
.
/* Make sure the opened device is the MIDI Mapper
*/
mciStatusParms.dwItem = MCI_SEQ_STATUS_PORT;
if (dwReturn = mciSendCommand(wDeviceID, MCI_STATUS, MCI_STATUS_ITEM,
(DWORD)(LPVOID) &mciStatusParms))
{
/* Error sending MCI_STATUS command */
...
return;
}
if (LOWORD(mciStatusParms.dwReturn) == MIDI_MAPPER)
/* The MIDI Mapper is the output device */
...
else
/* The MIDI Mapper is not the output device */
...
MCI also provides a command to explicitly select the MIDI Mapper as the output device for the sequencer. The following code fragment uses the MCI_SET command to select the MIDI Mapper as the output device for the MCI sequencer:
UINT wDeviceID;
DWORD dwReturn;
MCI_SEQ_SET_PARMS mciSeqSetParms;
.
.
.
/* Set the MIDI Mapper as the output port for the open device
*/
mciSeqSetParms.dwPort = MIDI_MAPPER;
if (dwReturn = mciSendCommand(wDeviceID, MCI_SET, MCI_SEQ_SET_PORT,
(DWORD)(LPVOID) &mciSeqSetParms))
{
/* Error, unable to set Mapper as output port */
...
}
Before querying the sequencer or setting an output port, you must successfully open the sequencer. Both of the previous examples assume that the wDeviceID parameter contains a valid device ID for the sequencer.
Because a compact disc audio device is a simple device, you need only specify the device name when opening it by using either a string or a constant ID. The following code fragment opens a compact disc device using a constant ID to specify the device name:
UINT wDeviceID;
MCI_OPEN_PARMS mciOpenParms;
.
.
.
/* Open the device by specifying a device ID constant
*/
mciOpenParms.lpstrDeviceType = (LPCSTR) MCI_DEVTYPE_CD_AUDIO;
if (mciSendCommand(0, // device ID
MCI_OPEN, // command
MCI_OPEN_TYPE | MCI_OPEN_TYPE_ID, // flags
(DWORD)(LPVOID) &mciOpenParms)) // parameter block
/* Error, unable to open device
*/
...
else
/* Device opened successfully, get the device ID
*/
wDeviceID = mciOpenParms.wDeviceID;