All audio device drivers are installable drivers and must provide a DriverProc entry point. Installable drivers and the DriverProc entry point are described in the Microsoft Windows Software Development Kit.
Installable drivers can supply a configuration dialog box for users to access through an application (such as a Control Panel application).
Interrupt-level and port assignments, and any other hardware-related settings, should be stored in the registry, in the appropriate subkey of the following registry key:
HKEY_LOCAL_MACHINE\System\CurrentControlSet\control\MediaResources
Regardless of how many types of audio devices a driver supports, the driver will always have a single DriverProc function.
Generally, when a driver is enabled, you initialize the hardware, hook interrupts, allocate any memory that you need, and set a flag to indicate the driver is enabled. If your driver has not been enabled by MMSYSTEM, or if it failed the enable process, the driver should return MMSYSERR_NOTENABLED from any messages it receives from client applications. When a driver is disabled, you free any memory that you allocated, unhook interrupts, reset the hardware, and set a flag to indicate the driver is not enabled.
It is possible for a driver to receive a DRV_DISABLE message while it is in the process of sending or receiving audio data. Audio device drivers should follow the behavior specified in the following table when they receive a DRV_DISABLE/DRV_ENABLE message pair:
Driver Type | Disable/Enable Behavior |
waveform output | As if the driver were paused with a WODM_PAUSE message and then restarted with a WODM_RESTART message. |
waveform input | As if the driver were stopped with a WIDM_STOP message and then restarted with a WIDM_START message. |
MIDI output | If the driver is asynchronous, stop output when disabled and continue when reenabled. |
MIDI input | As if the driver were stopped with a MIDM_STOP message and then restarted with a MIDM_START message. |
Most audio device drivers will be interrupt-driven. For example, a waveform output device interrupts when the device needs another data block. A MIDI input device interrupts when the device receives a MIDI event at its input port.
Any code segments or data segments a driver accesses at interrupt-time must be fixed segments. For best overall system performance, you should minimize the amount of code and data in fixed segments. To minimize the amount of fixed code, isolate all interrupt-time code in a few source modules and put this code into a single fixed code segment. Unless your driver has a large amount of data not accessed at interrupt time, use a single fixed data segment.
For example, the Sound Blaster sample driver is a medium-model DLL, using a single data segment and multiple code segments. This example fixes the data segment and the code segments named _TEXT and WEP_TEXT. All other code segments are moveable. The code segment _TEXT is used as a safety measure. The compiler places code for which you do not specify a segment in the _TEXT segment. This way, any code that is missed will be placed into a fixed segment, preventing possible problems at interrupt time. However, you should check your segmentation to ensure that only code that is required to be FIXED goes into the FIXED code segment.
You can allocate either local memory or global memory for use at interrupt time.
To allocate local memory for use at interrupt time, follow these steps:
1 Use LocalAlloc with the LMEM_FIXED flag to get a handle to the memory block.
2 Pass this handle to LocalLock to get a near pointer to the memory block.
Any global memory a driver uses at interrupt-time must be page-locked. To allocate and page-lock global memory, follow these steps:
1 Use GlobalAlloc with the GMEM_MOVEABLE and GMEM_SHARE flags to get a handle to the memory block.
2 Pass this handle to GlobalLock to get a far pointer to the memory block.
3 Pass the high-order word of the far pointer to GlobalPageLock to page-lock the memory block.
The only Windows functions a driver can call at interrupt time are PostMessage, PostAppMessage, DriverCallback, timeGetSystemTime, timeGetTime, timeSetEvent, timeKillEvent, midiOutShortMsg, midiOutLongMsg, and OutputDebugStr.