Adding a volume control to an application seems like it should be an easy thing to do, enter the Windows Multimedia Audio API that enables a programmer to add audio services to an application. The audio mixer functions of this API are used to set an audio device's volume but there is a steep learning curve penalty waiting for the first time user. Although Vista provides a new and somewhat easier to use set of user-mode audio components, Microsoft has stated that it does not plan to make the Vista core audio APIs available for use with earlier versions of Windows such as XP. Since there is a large population of users still using XP and older Windows operating systems, a solution is needed that applies to all of these older systems as well.
To address this problem, I created an API in the form of a small wrapper library that provides a straightforward way to programmatically interact with standard audio controls such as volume, balance, and mute. Using this API still requires some understanding of the terminology and basic concepts used in the mixer documentation.
Mixer: A Mixer combines (mixes), routes, and changes the levels and other characteristics of audio signal data. A system can have zero to several mixers.
Destination: Each mixer has one or more destinations, and each destination has zero to several controls and one or more connections.
Connection: A connection supplies audio data to a destination and has zero to several controls. There are also one or more channels per connection, if a connection has two channels, the volume of each channel may be controlled independently (balance).
Control: A control effects a change in the characteristics of audio signal data such as volume. Each control associated with a mixer has a system assigned unique ID, 0...N. A mixer with one destination that has two connections will have nine control IDs assigned to it numbered zero to eight assuming each connection and destination has three controls each. If there are three mixers, there will be three sets of control ID numbers, each set starting at zero.
The concept of a destination is somewhat confusing, but I find it useful to think of a destination as a receiver or consumer of data coming from the connections associated with it. The confusing part of this is that a destination may be an output device, such as a speaker, or an input device, such as a wave input device. A speaker is clearly an output device but a wave input device is clearly not an output device. The introductory part of the SDK documentation uses the term "audio line" to refer to both destinations and connections but the usage of this term is not consistent throughout the remainder of the documentation so I have avoided using it here.
The wrapper library mixer class,
CMixer, enumerates all destinations, connections, and controls associated with a mixer. It provides access to control labels and bounds data and read and write access to state data for each control. The following chart provides a clearer view of the relationships between mixer class components:
|Mixer ||A Mixer has a collection of Destinations|
| Destination ||A Destination has a collection of Connections and Controls|
| Connection ||A Connection has a collection of Controls|
| Control ||A Control has a collection of channels, typically two|
CMixer class draws on the support of two other classes,
CMixerDestination class manages data associated with a destination while the
CMixerControl class provides access to the state and metrics data of a control.
Using the Code
To fully use the
CMixer class, you will need to familiarize yourself with three SDK defined structures used by the class to provide information about mixer components:
MIXERCAPS structure describes the capabilities of a mixer device.
MIXERLINE structure describes the state and metrics of a connection or destination.
MIXERCONTROL structure describes the state and metrics of a single control for a connection or destination.
If you are interested in associating a Windows control with a mixer control, you will only need to refer to the
MIXERCONTROL structure definition in the SDK documentation as this structure contains the ID number, type, name, and bounds data for a control. The included
VolumeControl sample application is a simple MFC dialog application with a single volume control that is synchronized with the first volume control of the first mixer found in the system. In the case where a specific audio device, such as a wave in/out, MIDI in/out, or auxiliary device has already been opened, the
CMixer instance may be initialized using the device’s ID index value or opened handle.
AudioDialog sample MFC dialog application has been included to address the situation where more extensive mixer information is required. It enumerates all mixers in the system and allows the user to display data associated with any of the mixers, destinations, connections, and controls found. It also presents a collection of volume, balance, and mute check box control groups based on the user selected mixer and destination similar to the system provided Volume Control utility.
Both of the sample applications were built with Visual Studio 2005 as I felt that most people would at least have this version and that updating a project to a newer version of VS is much simpler than converting one to a previous version. Both applications were tested with Vista, XP, and 2K. The
AudioDialog application should be built first as it creates the mixer API library file used by the