Windows Mixer Control in C#

Introduction

In this article, I'll show you how to use a Windows Mixer from C#.

For some time, I tried to get information about how to program the mixer from C#. I didn't have too much luck, and the few examples found were in C++. So, I took the hard and fun way... doing it myself.

This library is part of my Audio library to control Wave Audio (Playback/Recording), Mixer, Playback/Recording compressed files using ACM, basic speech recognition, and some other stuff that I'll release in future articles.

AudioMixer Namespace

Hierarchical objects view

The hierarchical view shows how the classes are organized.

A main object Mixers contains two objects: Mixer Playback and Recording. Those will work with default devices, but can be changed by setting the Mixers.Playback.DeviceId or Mixers.Recording.DeviceId properties.

I made it as simple as possible, hiding all the flat Win32 API implementation from the developer and creating a hierarchical set of objects.

Every mixer is autonomous to each other. This means that you can have a Playback mixer set to one sound card and a Recording mixer to another one. Also, each one contains two array or MixerLines (Lines, UserLines).

The Lines object contains all lines inside the mixer; for example, all the lines that don't have controls associated with them or lines that are not source lines.

UserLines will contain all lines that the developer can interact with, having controls like volume, Mute, Fadder, Bass, and so on (basically, is the same as a Lines object but a filter was applied to it).

Every Line will contain a collection of controls, such as Mute, Volume, Bass, Fader, and the like.

If you are interested in knowing more about how Windows Mixer works, here is an excellent link with all the information about it: http://www.borg.com/~jglatt/tech/mixer.htm.

Here Is Some Code

To get the audio devices in the computer:

foreach(MixerDetail mixerDetail in mMixers.Devices)
{
   ...
   ...
}

To get the input devices:

foreach(MixerDetail mixerDetail in mMixers.Recording.Devices)
{
   ...
   ...
}

To change the output mixer device:

Mixers mixers = new Mixers();
foreach(MixerDetail mixerDetail in mixers.Playback.Devices)
{
   if (mixerDetail.MixerName == "Sound Blaster Live")
       mixers.Playback.DeviceId = mixerDetail.DeviceId;
}

To change the output mixer device to the default device:

Mixers mixers = new Mixers();
mixers.Playback.DeviceId = -1;

or

mixers.Playback.DeviceId = mixers.Playback.DeviceIdDefault;

Getting the Playback Speaker Master volume:

mixers.Playback.Lines.GetMixerFirstLineByComponentType(
   MIXERLINE_COMPONENTTYPE.DST_SPEAKERS).Volume;

Setting the Playback Speaker Master volume for the left channel only:

MixerLine line = mixers.Playback.Lines.
   GetMixerFirstLineByComponentType(
   MIXERLINE_COMPONENTTYPE.DST_SPEAKERS);
line.Channel = Channel.Left;
line.Volume  = 32000;

Selecting the Microphone as the default input:

mixers.Recording.Lines.GetMixerFirstLineByComponentType(
   MIXERLINE_COMPONENTTYPE.SRC_MICROPHONE).Selected = true;

Getting callback notifications when a line has changed:

/* Initialization */
mMixers = new Mixers();
mMixers.Playback.MixerLineChanged +=
   new WaveLib.AudioMixer.Mixer.
   MixerLineChangeHandler(mMixer_MixerLineChanged);
mMixers.Recording.MixerLineChanged +=
   new WaveLib.AudioMixer.Mixer.
   MixerLineChangeHandler(mMixer_MixerLineChanged);
/* Events */
private void mMixer_MixerLineChanged(Mixer mixer, MixerLine line)
{
   Console.WriteLine("Mixer: " + mixer.DeviceDetail.MixerName);
   Console.WriteLine("Mixer Type: " + mixer.MixerType);
   Console.WriteLine("Mixer Line: " + line.Name);
}

Getting and Setting Rare Controls

Specific controls like Fadder, Microphone Boost, bass, treble, and so forth can be accessed via the MixerControl object using ValueAsSigned, ValueAsUnsigned, and ValueAsBoolean properties, but they are not implemented as standard properties because they don't belong to all controls.

Notes

All the current functionality is tested and working. I tried to not include bugs, but they are there and I find them every once in a while. If you find bugs, I'll be grateful to get the feedback to update the article.

For now, I don't need anything else from the library, but if you think of something not included in it that could could make it better, just let me know and I'll try to include it.

If you have a problem with it, just feel free to write me an e-mail.



About the Author

Gustavo Franco

started with programming about 19 years ago as a teenager, from my old Commodore moving to PC/Server environment Windows/UNIX SQLServer/Oracle doing gwBasic, QBasic, Turbo Pascal, Assembler, Turbo C, BC, Clipper, Fox, SQL, C/C++, Pro*C, VB3/5/6, Java, and today loving C#. Currently working on VOIP/SIP technology. Passion for most programming languages and my son Aidan.

Downloads