Click here to Skip to main content
15,867,568 members
Articles / Multimedia / DirectX
Article

The ultimate Managed DirectSound 9 Tutorial. Part 1: a full introduction to Playback

Rate me:
Please Sign up or sign in to vote.
4.72/5 (46 votes)
28 Sep 2005CPOL7 min read 355.7K   7.1K   134   59
How to playback sounds, apply effects and more with the Managed DirectSound 9.

Introduction

Managed DirectSound 9 is a part of Managed DirectX 9 library. In this tutorial I’m going to explain how to play sounds with Microsoft Managed DirectSound 9, how to apply effects, select the output audio device and a few more tricks. I hope you’ll discover that DirectSound is not as difficult as it seems.

Requirements

In order to develop and run applications using Managed DirectSound 9 (and all Managed DirectX 9), you have to install in your system the DirectX 9 standard redistributable package specifying in the command line the argument /InstallManagedDX (for example D:\Download\dxsetup /InstallManagedDX). You can also download from Microsoft’s website the package called the ‘DirectX 9.0c Redistributable for Software Developers - with updated DirectX for Managed Code and D3DX’, which includes and installs automatically the Managed DirectX libraries. Obviously, you have to add to your projects the references to Microsoft.DirectX and Microsoft.DirectX.DirectSound.

Here is an important note: in order to run the apps, the user is not forced to install the Managed DX9, but it is sufficient to copy in your apps’ root folder the referenced assemblies. To do this, set the LocalCopy property of the assemblies to true or copy them manually. I suggest the first way because if you create the Installer for the app with Visual Studio, it will detect the references and copy the assemblies to the installation destination. In the second way you have to remember to add them manually. To simplify your life, add these using clauses to your source files:

C#
using Microsoft.DirectX;
using Microsoft.DirectX.DirectSound;

First lines of code: play a Wave file

The first operation you have to do, is to create a DirectSound Device:

C#
private Device dSound;

After this, set it up:

C#
dSound = new Device();
dSound.SetCooperartiveLevel(handle, 
               CooperativeLevel.Priority);

Notes: handle is the handle to your main window (IntPtr), so write this.Handle. CooperativeLevel sets the hardware managing of the playback. There are three possibilities, but you should use Priority because it uses the hardware acceleration whenever possible. The Device constructor is overloaded: we’ll see other options later on.

The next step is to create a sound, using a Buffer, and its descriptor:

C#
private SecondaryBuffer sound;
private BufferDescription d = new BufferDescription();
// Set descriptor’s flags
d.ControlPan = true;
d.ControlVolume = true;
d.ControlFrequency = true;
d.ControlEffects = true;

The flags are:

  • ControlPan: allows you to control the balance (left/right) of the sound.
  • ControlVolume: allows you to control the volume of the sound.
  • ControlFrequency: allows you to control the sampling frequency of the sound (rarely used).
  • ControlEffects: allows you to apply effects to the sound.

There are a few other flags, but we are not interested in them.

C#
// Create the sound
sound = new SecondaryBuffer(filePath, d, dSound);

filePath is the full path of the .wav file, d is the descriptor created above, and dSound is the Device that will play the sound. After this, the sound is ready to be played. As a first parameter you can also specify System.IO.Stream, for example if you are receiving the sound from the Internet (in this case you must manage the difference between data consuming and receiving rates: think about your media player when it stops the playback to retrieve more data from the server).

The operations you can perform with a SecondaryBuffer are:

  • sound.Play(priority, flags): priority is the priority of the playback (0 is the default value, it means lowest priority), flags is a value of the enum BufferPlayFlags. The most important values are BufferPlayFlags.Default (stops when the sound finishes) and BufferPlayFlags.Looping (loops the sound).
  • sound.Stop(): pauses the sound. After this, if you call Play, the sound starts from the position where it was paused. To really stop the sound, you could use the following method.
  • sound.SetCurrentPosition(pos): sets the position in the sound at byte level. You can retrieve the total length (in bytes!) of the sound using the sound.Caps.BufferBytes property. If pos is zero, then that rewinds the sound.
  • sound.PlayPosition: returns the current playback position in the sound (in bytes!).
  • sound.Volume: the volume of the sound. Allowed values are from zero to -10000 decibel (logarithmic attenuation). 0 is the max volume, -10000 is the zero volume. At a value of -2500 or so, the sound is muted. It needs the flag sound.ControlVolume set to true.
  • sound.Pan: the balance of the sound. Values are from -10000 (all to left) to 10000 (all to right). Zero is the balanced value. Needs the flag sound.ControlPan set to true.
  • sound.Frequency: the sampling frequency of the sound (samples per second). Zero is the default value, but the allowed values are in the range 100 to 10000. This property is rarely used. Needs the flag sound.ControlFrequency set to true.
  • sound.Status.*: supplies information about the status of the sound. Playing (bool) indicates if the sound is currently playing, Looping (bool) indicates if the sound is set to loop.
  • sound.Format.*: more interesting info about the sound. Important members are AverageBytesPerSecond, BitsPerSample, Channels, SamplesPerSecond. They are self-explanatory, and thanks to them, we can compute the duration of the sound (that is not shown by any other property!). You can compute this in the following way:
    C#
    int totalSeconds = sound.Caps.BufferBytes / 
                       sound.Format.AverageBytesPerSecond;

Using speakers

Another amazing thing you can do, is to set the correct type of speakers attached to the output audio card. This option allows you to obtain better sound on each output system. The property you have to set is dSound.SpeakerConfig:

C#
// Create new Speakers
Speakers s = new Speakers();

// Set properties
s.Mono = false; // Sets as a mono speaker
s.Headphone = false; // Sets as headphones
s.Stereo = false; // Sets as generic stereo speakers
s.Quad = false; // Sets as quad system (two front, two rear)
s.FiveDotOne = false; // Sets as a 5.1 surround system
s.SevenDotOne = true; // Sets as a 7.1 surround system
s.Surround = false; // Sets as a generic surround system

dSound.SpeakerConfig = s;

Note: if you set the Speakers creating a new Speakers object every time, you can avoid resetting the old properties. So just replace the old Speakers object.

Choosing between sound cards

In many systems there are more than one sound card. DirectSound 9 allows you to choose the correct one, arranging a way to select the default one, or to choose the card that the user wants. To enumerate and show the user the installed cards, do as follows (supposing that the list of sound cards is put into a ComboBox, named cmbAudioCards):

C#
private DevicesCollection devList = new DevicesCollection();

cmbAudioCards.Items.Clear();
for(int i = 0; i < devList.Count; i++) {
   cmbAudioCards.Items.Add(devList[i].Description);
}

The first element is the default audio card that is always listed. The other items are the ‘physical’ audio cards. For example you can see:

  • Main Audio Driver
  • Audio SB Live! [400]
  • Bluetooth Audio

When the user selects a specific card, you can rebuild the Device as follows (in the ComboBox event handler):

C#
dSound = new Device(devList[cmbAudioCards.SelectedIndex].DriverGuid);
dSound.SetCooperativeLevel(this.Handle, CooperativeLevel.Priority);
// You have to recreate the sound (the descriptor d can be reused)
sound = new SecondaryBuffer(filePath, d, dSound);

DriverGuid is the Global Unique Identifier of the driver instance for the selected audio card. At the first start, or if the user doesn’t select a specific audio card, you can use the default constructor of Device, or select via-code the first element in devList, that is the default audio card.

Selecting different audio cards can effect the system performance: in the example above, the SoundBlaster Live! has in-hardware acceleration capabilities and supports upto 5.1 systems. Bluetooth audio is worst, and can cause a CPU load increment while applying effects or when managing 3D audio.

Applying effects to the audio playback

One of the most important features of DirectSound 9 is the possibility to apply real-time audio effects to the sounds in playback. You can also apply a virtually unlimited chain of effects (according to the system capabilities). All the effects are applied in-hardware whenever possible, otherwise emulated via-software (causing an important drop in the performance!). Remember to set the flag sound.ControlEffects to true!

In DirectSound 9 there are – needless to say :) – 9 effects: Chorus, Compressor, Distortion, Echo, Flanger, Gargle, Interactive3DLevel2Reverb, ParamEqualizer, WavesReverb. I want to say that there is not much documentation about these effects, especially because each of them has different settings. The first thing is to create an array of EffectDescription:

C#
EffectDescription[] fx = new EffectDescription[1];

In this example we use only one effect, but if you want, you can use more effects by creating an array long enough, and inserting one effect per element. Suppose you want to apply the Echo effect:

C#
fx[0].GuidEffectClass = DSoundHelper.StandardEchoGuid;
sound.SetEffects(fx);

Suppose now you want to apply the Parametric Equalizer effect:

C#
fx[0].GuidEffectClass = DSoundHelper.StandardParamEqGuid;
sound.SetEffects(fx);

Note: you can apply effects only when the sound is not played. As I reported above, each effect has different options. I will explain here how to set up the Parametric Equalizer effect:

C#
fx[0].GuidEffectClass = DSoundHelper.StandardParamEqGuid;
sound.SetEffects(fx);
ParamEqEffect eqEffect = (ParamEqEffect)sound.GetEffects(0);
EffectsParamEq eqParams = eqEffect.AllParameters;
// Specific properties!
eqParams.Bandwidth = 36; // Apply a gain on the highest frequency
eqParams.Gain = ParamEqEffect.GainMax;
eqEffect.AllParameters = eqParams;

Abstracting the procedure, you have to first create an array of effects with StandardEFFECTNAMEGuid, then set the parameters, using EFFECTNAMEEffect and EffectsEFFECTNAME objects, where EFFECTNAME is the name of the Effect. Always remember to perform the correct casts. To reset the effects on a sound, you have to overwrite it:

C#
sound = new SecondaryBuffer(filePath, d, dSound);

For further info about the effects, please go through the MSDN Library.

Conclusions

By now you should have developed a little familiarity with a DirectSound device, the Effects and other options. DirectSound fits to playbacks of short sounds, such as explosions, shots and so on. If you want to play a long Wave sound you should use the namespace Microsoft.DirectX.AudioVideoPlayback, that I will explain in future. In the next tutorial I will explain how to use 3D Sounds with DirectSound.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Italy Italy
Software Development Manager working on IaaS cloud computing. Cloud believer, (former) entrepreneur, F1 addict.

Follow me at dariosolera.it or on Twitter.

Comments and Discussions

 
Questionhi Pin
ehssan652-Apr-17 12:30
ehssan652-Apr-17 12:30 
QuestionAny idea how I can do this in VB? Pin
dj.3agl311-Nov-14 14:00
dj.3agl311-Nov-14 14:00 
AnswerNice Pin
mr.kage26-Jul-14 4:17
mr.kage26-Jul-14 4:17 
GeneralMy vote of 5 Pin
cobzarug18-Jun-13 13:04
cobzarug18-Jun-13 13:04 
Question[Windows 8] [VS2012 Premium] Not A Win32 valid application (HResult Exception 0x800700C1) Pin
Vincent DUVERNET (Nolmë Informatique)6-Oct-12 8:41
Vincent DUVERNET (Nolmë Informatique)6-Oct-12 8:41 
AnswerRe: [Windows 8] [VS2012 Premium] Not A Win32 valid application (HResult Exception 0x800700C1) Pin
programmerdon19-Nov-12 8:46
programmerdon19-Nov-12 8:46 
QuestionNoise Suppression Pin
Mihaescu Florin13-Sep-12 22:08
Mihaescu Florin13-Sep-12 22:08 
GeneralMy vote of 5 Pin
Mihaescu Florin13-Sep-12 22:06
Mihaescu Florin13-Sep-12 22:06 
QuestionGood example Pin
Jazzflyer14-Mar-12 10:42
Jazzflyer14-Mar-12 10:42 
Your code has helped me a lot. I have a WPF app running in my car and I want to stream the sound via bluetooth to the car head unit. Now I am able to set the correct rendering filter.

Mille grazie.
QuestionUtilizing Multiple Hardware Outputs Pin
bitbrain10-Jan-12 8:08
bitbrain10-Jan-12 8:08 
Questionhow to get digitized samples coming from sound card Pin
rrsharif24-Aug-10 0:53
rrsharif24-Aug-10 0:53 
GeneralBadImageFormatException Pin
Jan Wiaz25-Nov-09 10:06
Jan Wiaz25-Nov-09 10:06 
GeneralRe: BadImageFormatException Pin
see_seA6-Mar-10 13:32
see_seA6-Mar-10 13:32 
Questionis there any other method than this 4 listed? Pin
hase-yachi23-Sep-09 22:34
hase-yachi23-Sep-09 22:34 
GeneralNice Code ! Pin
monster_kill18-Jul-09 18:39
monster_kill18-Jul-09 18:39 
GeneralRe: Nice Code ! Pin
omlove12-Nov-09 17:41
omlove12-Nov-09 17:41 
QuestionVolume Pin
TowerTurtle19-Aug-08 11:07
TowerTurtle19-Aug-08 11:07 
Generalvery good article Pin
arbel kfir11-Aug-08 2:16
arbel kfir11-Aug-08 2:16 
GeneralSplit Audio Channel Pin
ananduk767-Aug-08 16:07
ananduk767-Aug-08 16:07 
QuestionWhy am I getting Pin
Iluminar Magician11-Apr-08 11:34
Iluminar Magician11-Apr-08 11:34 
General24 Bit Pin
Jammer31-Mar-08 9:54
Jammer31-Mar-08 9:54 
Questionhow can i play mp3 file?? Pin
Ibrahim Dwaikat7-Nov-07 9:24
Ibrahim Dwaikat7-Nov-07 9:24 
AnswerRe: how can i play mp3 file?? Pin
Ibrahim Dwaikat14-Nov-07 11:44
Ibrahim Dwaikat14-Nov-07 11:44 
GeneralRe: how can i play mp3 file?? Pin
rcarty27-Jan-08 8:06
rcarty27-Jan-08 8:06 
QuestionUse a 5.1 card to play 3 sounds from 3 sockets Pin
ThePPK28-Oct-07 1:05
ThePPK28-Oct-07 1:05 

General General    News News    Suggestion Suggestion    Question Question    Bug Bug    Answer Answer    Joke Joke    Praise Praise    Rant Rant    Admin Admin   

Use Ctrl+Left/Right to switch messages, Ctrl+Up/Down to switch threads, Ctrl+Shift+Left/Right to switch pages.