Beginning Game Development Part X –Direct Sound Part III
- Posted: Jan 07, 2008 at 9:55 AM
- 5,546 Views
- 4 Comments
Loading User Information from Channel 9
Something went wrong getting user information from Channel 9
Loading User Information from MSDN
Something went wrong getting user information from MSDN
Loading Visual Studio Achievements
Something went wrong getting the Visual Studio Achievements
This content is no longer current.
| Welcome to the tenth article on beginning game development. In the last article we manipulated sounds by adding sound effects. Together with the use of 3D Buffers to make the sounds positionaly accurate we now have a fully featured sound system in the game. But, while we're are able to play and manipulate short sounds and sound effects we cannot play longer WMA or MP3 files with the DirectSound namespace. To accomplish that we need to turn to the AudioVideoPlayback namespace. | |
|
Difficulty: Intermediate
Time Required:
1-3 hours
Cost: Free
Software: Visual Studio Express 2005, Microsoft DirectX SDK
Hardware: Any PC capable of running DirectX 9.0
Download: Download
Previous Articles: Why more soundYou may be wondering why we even need to add longer sound files to the game. As I mentioned in article 8, most games include fully featured soundtracks in addition to the regular game sounds. These sound tracks are often produced specifically for the game much like a movie soundtrack is produced for a movie. A well made sound track can add additional drama to the game and provide a memorable experience. Sometimes these game tracks are also available as separate music CDs or downloads to bring more players to the game. There is really no way that anyone is going to be able to produce a nice sounding soundtrack as a WAV file. Most music uses the MP3 codec or can be converted to this codec. Audio PlaybackUsing the DirectSound namespace we were only able to play WAV files. Longer music is normally encoded in more efficient formats such as MP3 or WMA. To play these files we have to access the API in the AudioVideoPlayback namespace. This namespace is the smallest of the namespaces and contains a single class called Audio for playing audio files. (It also contains a Video class which I will not cover) Using the Audio class to play an audio file is very easy. 1. Create a new Audio class and pass the path to the Audio file to the constructor. Audio audio = new Audio("AudioFileName"); |
|
Audio audio = new Audio();
audio.Open("AudioFileName");
audio.Play();
audio.Pause();
audio.Stop();
audio.Dispose();
private void _audio_Ending(object sender, EventArgs e)
{
audio.Play();
}
audio.Open("//www.audiofile.com/music.mp3");
While playing the audio file you can control the volume and balance of the file.
Volume: Volume is expressed as an integer. Somewhat counterintuitive is that a setting of 0 is full volume. Smaller values decrease the volume up to a setting of -10,000 which is silent.
audio.Volume = 0; // Maximum
audio.Volume = -10000; // Silent
audio.Balance = -10000; // Only Left channel
audio.Balance = 10000; // only Right channel
audio.Balance = 0; // balanced
| State | Method | Event | Property (Boolean) |
|---|---|---|---|
| Started | Play | Starting | Playing* |
| Paused | Pause | Pausing | Paused |
| Stopped | Stop and StopWhenReady | Stopping | Stopped** |
| Ended | N/A | Ending |
* While playing the audio class indicates the current position of the stream with the CurrentPosition property.
** The audio class also provides a property, StopPosition, which indicates the position in the audio stream where the file is stopped
You can also use the State property of the Audio class to determine its state. This property returns a
StateFlags enumeration with the possible values of: Running, Paused and
Stopped.
Also of interest is the SeekingCaps property of the Audio class. This read only property indicates the seeking capabilities of the playback stream. It is represented in the form of the
SeekingCaps structure. This structure indicates whether the stream supports the following seek actions:
| Action | SeekingCaps property (Boolean) |
|---|---|
| Current position | CanGetCurrentPostion |
| Duration | CanGetDuration |
| Stop position | CanGetStopPostition |
| Absolute | CanSeekAbsolute |
| Seek Forwards | CanSeekForward |
| Seek Backward | CanSeekBackward |
You should check the capabilities of the stream before calling SeekCurrentPosition, SeekStopPosition or checking the Duration property.
Ok, let's package this simple class into a Jukebox. I want the Jukebox class to pull files from a predetermined location so I can just point it at a media folder within the games directory structure. I also want the Jukebox to either play all the files it finds in order or play a single file in a looping fashion.
Finally I want this class to play a specific file on demand, for example, when I am on the splash screen I want to play the intro tune, while on the main game screen I want some other background music.
NOTE: I am not providing any audio files with the source code. By default the SoundTrack class reads from C:\Documents and Settings\All Users\Documents\My Music\Sample Music where you should have two WMA files on a standard XP machine. If you do not have those files you need to change the directory and point it at a location that has sound files.
The first step is to add a reference to the Microsoft.DirectX.AudioVideoPlayback assembly.
Next we add a new class and call it Soundtrack. At the top of the class we need add the using statement for the
AudioVideoPlayback namespace.
using Microsoft.DirectX.AudioVideoPlayback;
public void Dispose()
{
Dispose(true);
GC.SuppressFinalize(this);
}
protected virtual void Dispose(bool disposing)
{
if (!this._disposed)
{
if (disposing)
{
if (_audio != null)
_audio.Dispose();
}
}
_disposed = true;
}
// Use C# destructor syntax for finalization code.
~SoundTrack()
{
// Simply call Dispose(false).
Dispose(false);
}
private bool _disposed;
public SoundTrack ( string[] songCollection, bool repeat )
{
_songList = songCollection;
_isRepeat = repeat;
if ( _songList.Length == 0 )
_enabled = false;
else
_audio = new Audio ( _songList[ _songCounter ].ToString ( ) );
}
private Audio _audio;
private string[] _songList;
private int _songCounter = 0;
private bool _isRepeat;
private bool _enabled = true;
public void Play()
{
if ( !_enabled )
return;
_audio.Play();
_audio.Ending += new EventHandler(_audio_Ending);
}
private void _audio_Ending(object sender, EventArgs e)
{
if ( _isRepeat )
{
Stop ( );
Play ( );
}
else
NextSong ( );
}
public void NextSong ( )
{
if ( !_enabled )
return;
_songCounter++;
if ( _songCounter == _songList.Length )
_songCounter = 0;
if ( _audio.Playing == true )
_audio.Stop ( );
_audio.Open ( _songList[ _songCounter ].ToString ( ) );
_audio.Play ( );
}
The only remaining method we now need is to stop the player
public void Stop ( )
{
if ( !_enabled )
return;
if ( _audio != null )
_audio.Stop ( );
}
To allow us to control the balance and volume we simply add two properties to the SoundTrack class that expose the identical properties of the Audio class. Since we know the upper and lower bounds of the values, we add a simple check to the property setter to ensure we only pass valid values. This is more efficient than passing an invalid value and having to check for exceptions. In general you should enforce boundaries whenever possible.
1: public int Volume
2: {
3: get { return _audio.Volume; }
4: set
5: {
6: if ( value > 0 | value < -10000 )
7: return;
8:
9: _audio.Volume = value;
10: }
11: }
12:
13: public int Balance
14: {
15: get { return _audio.Balance; }
16: set
17: {
18: if ( value > 10000 | value < -10000 )
19: return;
20:
21: _audio.Balance = value;
22: }
23: }
Now we can integrate the new class into the game. First we add a reference to the new class to the GameEngine class.
private SoundTrack _mainSoundTrack;
_mainSoundTrack = new SoundTrack ( Directory.GetFiles ( @"C:\Documents" +
"and Settings\All Users\Documents\My Music\Sample Music" ), true );
// Control the Sound
if ( _keyboard.State[ Key.P ] )
_mainSoundTrack.Play ( );
if ( _keyboard.State[ Key.M ] )
_mainSoundTrack.Stop ( );
if ( _keyboard.State[ Key.N ] )
_mainSoundTrack.NextSong ( );
if ( _keyboard.State[ Key.UpArrow ] )
_mainSoundTrack.Volume += 10;
if ( _keyboard.State[ Key.DownArrow ] )
_mainSoundTrack.Volume -= 10;
if ( _keyboard.State[ Key.RightArrow ] )
_mainSoundTrack.Balance += 10;
if ( _keyboard.State[ Key.LeftArrow ] )
_mainSoundTrack.Balance -= 10;
Now we have pretty much completed the pass through the basic functionality of the all the DirectX namespaces. There are many more advanced topics that could cover additional graphics classes such as HLSL (High Level Shader Language), but in the next articles we are going to focus on two non DirectX parts of game development - Artificial Intelligence (AI) and Physics.
Without good AI and Physics, even the best designed games are no fun to play. Nothing shatters the illusion of reality more than predictable enemies or rocks floating in mid air.
Together with game Physics, AI represents a major portion of the game that has no support in DirectX and limited support in other (free) libraries. We are not going to be able to fill that gap and write a fully featured AI engine, but we can cover most of the principles and techniques behind some of the more basic AI problems, such as chasing and evading and path finding.
Until then: Happy coding.
Derek Pierson is a software developer with 12 years experience designing and developing enterprise applications using a variety of programming languages. He is an enthusiastic teacher of the art of programming and believes that elegance and simplicity are defining features of good software.
Comments have been closed since this content was published more than 30 days ago, but if you'd like to continue the conversation,
please create a new thread in our Forums,
or
Contact Us and let us know.
Follow the Discussion
Oops, something didn't work.
What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in. You need to be signed in to Channel 9 to use this feature.What does this mean?
Following an item on Channel 9 allows you to watch for new content and comments that you are interested in and view them all on your notifications page.sign up for email notifications?
Thanks man!
This was very useful.
This is a very nice tutorial! Nice job! It would be better thought if you recorded a video showing us how to do all those things. Very nice though. Thanks!
This has been a huge help to getting me started on 3d 1st person game programming. I have two questions:
1: where you don't specify VB or C#, does that mean the code is neutral as it can be put in VB and C#? because im programming in VB express not C#
2: Are there more parts to this tutorial? or was this the last one? are there more tutorials like this here?
@Quagmire990 Managed DirectX is no longer supported. XNA has replaced it for .NET game development.
The download ZIP file does have a VB example with it but looks like the article only is C#.
There are more parts and are at the top of the article. But once again, I suggest you try XNA as it is supported for .NET development.
Remove this comment
Remove this thread
close