Loading and Playing a Static Sound

In the simplest case, what do you want to do for a sound? You want to have some type of audio data, and you want to output this audio data to all of the speakers attached to the system. Sounds easy enough, but how do you do that in a DirectX application? For the simple case just described, it is exceedingly simple.

Much like Direct3D has a Device class that controls the actual graphics hardware, DirectSound has a Device class that controls the actual sound hardware. Since both of these classes share the same name (in different namespaces), it's important to remember that if you are referencing both Direct3D and DirectSound in the same code file, you may need to fully qualify any references to a "Device" variable.

DirectSound also has buffers that are used to hold the audio data it needs to play the sounds, much like Direct3D used buffers to hold geometry or pixel data. There are only two types of buffers in DirectSound, either the stock "Buffer" object, or the more robust "SecondaryBuffer" object (which also derives from Buffer).

So since the simple case is so simple, you can just write it now, and take a look at it. First, create a new project and get the DirectSound references and namespaces in, and then add the following variable declarations:

 private Device device = null; private SecondaryBuffer sound = null; 

You will have one device that is used to talk to the sound hardware, and you will have one buffer you can use to play the actual audio data that will be loaded. Now, you can write the "InitializeSound" method, which will load and play a sound. Since this method will reference an audio file, you will need to provide one. The file used in this method was copied from the DirectX SDK. You can copy this file from the included source on the CD. Add the following method:

 public void InitializeSound() {     device = new Device();     device.SetCooperativeLevel(this, CooperativeLevel.Normal);     sound = new SecondaryBuffer(@"..\..\drumpad-crash.wav", device);     sound.Play(0, BufferPlayFlags.Default); } 

As you can see, the code is quite simple. You create a new device (by using the parameter-less constructor; the other overloads for this object will be discussed later in this chapter), and then set the cooperative level on the device. I know what you're thinking: What exactly is a cooperative level?

The sound hardware in your machine is shared among many different applications. Windows may beep at you when an error has occurred. Messenger may beep when a friend has logged in, and all of these things can happen while you're listening to your favorite songs. The cooperative level is used to determine how your application behaves with others, hence its name. The choice selected here is the default option. It has the best multitasking and resource sharing behavior. You may look in the DirectX SDK documentation for details on the other priority levels; for the needs of this application, you can stick with normal.

After you have set the cooperative level, and are prepared to play nice with the rest of the system, you can create the buffer. You will load the buffer from a file (the code on the included CD uses a simple sound that ships with the DirectX SDK), and finally just play it. The first parameter of the play call is the priority, which is only valid if you've created your buffer deferred (which you haven't). You play the buffer using the default flags, and you're off. Now, you just need to actually call this method from somewhere, so how about replacing the main code with this:

 static void Main() {     using (Form1 frm = new Form1())     {         frm.InitializeSound();         Application.Run(frm);     } } 

The simple case really is that simple. Just a few lines of code and the sound plays when the application starts up; it doesn't get much easier than that. If you look at the constructor for the SecondaryBuffer though, you'll notice that it takes quite a few different sets of parameters. You should look at those now. The following two overloads cover the basic variations of the constructors:

 public SecondaryBuffer ( System.String fileName ,     Microsoft.DirectX.DirectSound.BufferDescription desc ,     Microsoft.DirectX.DirectSound.Device parent ) public SecondaryBuffer ( System.IO.Stream source , System.Int32 length ,     Microsoft.DirectX.DirectSound.BufferDescription desc ,     Microsoft.DirectX.DirectSound.Device parent ) 

All of the constructors for the secondary buffer take in the device that will be used to play the actual audio data. As you can see, the constructors can take either a filename for the audio data you wish to load, or a stream that contains the audio data. There is only one constructor available that does not take in a BufferDescription object as well (which happens to be the one you used). A default BufferDescription is used in that case, because all buffers need to have a description when they are created.

So what does the BufferDescription do? As the name implies, it describes the various options of the buffer you are creating. The properties of this object are found in Table 14.1.

Table 14.1. Buffer Description Properties

PROPERTY

DESCRIPTION

BufferBytes

A read-write property for the size of the new buffer in bytes. If you are creating a primary buffer, or a buffer from a stream or sound file, you can leave this member at zero.

CanGetCurrentPosition

A read-write Boolean property that allows you to specify if you want an accurate position of the playing cursor.

Control3D

A read-write Boolean property indicating whether or not your buffer can be manipulated in 3D space. This option can not be used if your buffer has a stereo (two channel) format, or if the ControlPan option is set to true.

ControlEffects

A read-write Boolean property indicating that this buffer can or cannot use effects processing. In order to use these effects, you must have an 8-or 16-bit PCM format audio data, and are not allowed more than two channels (stereo).

ControlFrequency

A read-write Boolean property indicating your buffer's frequency can be modified when true.

ControlPan

A read-write Boolean property indicating if your buffer can support panning. Cannot be used with the Control3D flag.

ControlPositionNotify

A read-write Boolean property indicating whether or not your buffer will support position notification.

ControlVolume

A read-write Boolean property indicating whether or not your buffer will be able to control the volume.

DeferLocation

A read-write Boolean property indicating that your buffer can be assigned to either play in hardware or software at play time. This flag must be set to true for any buffer that will use voice management.

Flags

A bitwise combination of the BufferDescriptionFlags enumeration. The values for these items in the enumeration are matched as the Boolean properties of this object for ease of use. For example, rather than saying

 desc.ControlPan = true; desc.ControlEffects = true; 

you could say

[View full width]

 desc.Flags = BufferDescriptionFlags.ControlPan | graphics/ccc.gif BufferDescriptionFlags.ControlEffects; 

Format

A read-write property specifying the wave format of the audio data you are creating. If you load your buffer from a file or a stream, this object will be filled for you when the constructor returns, informing you of the format of the buffer you just created.

GlobalFocus

A read-write Boolean property indicating whether or not your buffer is global. By default, sounds will only play if your window has the focus on the system. By setting this member to true, your sound will continue to play even while your application does not have focus.

Guid3DAlgorithm

A read-write GUID property used to specify the algorithm used for 3D virtualization. You may use any of the DSoundHelper.Guid3Dxxxx GUID constants listed in Managed DirectX for the built-in behaviors.

LocateInHardware

A read-write Boolean property indicating whether or not this buffer is required to be located in hardware. If true and the necessary hardware support isn't available, creating this buffer will fail.

LocateInSoftware

A read-write Boolean property indicating whether or not this buffer is required to be located in software. If true, this buffer will always be located in software, regardless of the availability of hardware resources.

Mute3DAtMaximumDistance

A read-write Boolean property indicating whether or not to stop playing a sound if the maximum distance has been exceeded. This only applies to software buffers.

PrimaryBuffer

A read-write Boolean property indicating whether or not this buffer is a primary buffer.

StaticBuffer

A read-write Boolean property indicating whether or not to place the buffer in hardware memory if it is available. If no hardware is available, the call will still succeed, but the buffer will be placed in software. You may not have ControlEffects true when specifying this flag.

StickyFocus

A read-write Boolean property indicating whether or not "sticky" focus is in use. As already mentioned when discussing the global focus flag, the default for DirectSound is to stop playing your buffer if your window does not have focus. If the sticky focus flag is set to true, your buffer will still play if the currently focused window is not already using DirectSound. If it is, it will revert back to default behavior.

As you can see, there are quite a few options for a buffer. This next example will use a few of them to show you what they do. It will be based off the simple one you've already done; however, this one will rotate the sound back and forth between left and right by controlling the pan of the sound.

In order to do this, you'll need to use a buffer description object like you've just described. Add the following code after your call to SetCooperativeLevel:

 BufferDescription desc = new BufferDescription(); desc.ControlPan = true; desc.GlobalFocus = true; 

You are essentially telling DirectSound that you will be creating a buffer and will want to allow the pan to be controlled. Also, you want the buffer to be global across the entire system.

You will also need to modify the creation of the buffer to use the constructor that takes the buffer description you just created. To improve the effect, you will have the buffer loop forever while it is being played. Modify the code as follows:

 sound = new SecondaryBuffer(@"..\..\drumpad-crash.wav",desc, device); sound.Play(0, BufferPlayFlags.Looping); 

Running the application now will cause the sound to play, and loop continuously, but the pan value of the buffer is never actually updated anywhere. For a nifty effect, why don't you update it every 50 milliseconds or so. In the design view for your form, add a timer control, and set the interval to 50. Add the following code for the timer event (double-clicking the timer in design view will bring up the event handler method):

 private void timer1_Tick(object sender, System.EventArgs e) {     // Adjust the pan     sound.Pan *= -1; } 

The pan value is an integer value that specifies the stereo position of the sound; the farther negative the value, the more the sound comes out of the left speaker. The more the value is positive, the more it comes out of the right speaker. A value of zero (the default) says to come out of both speakers equally. Since the default is zero, the code above will not actually do anything (since 0 * -1 is still 0). Now set the initial pan value to the left speaker and start the timer. Add this code directly after the play call in InitializeSound:

 sound.Pan = -5000; timer1.Enabled = true; 

Run the example now. You should now hear the sound file being played back and forth across your two speakers for an interesting effect. It's really quite simple to use sounds for your application.



Managed DirectX 9 Graphics and Game Programming, Kick Start
Managed DirectX 9 Kick Start: Graphics and Game Programming
ISBN: B003D7JUW6
EAN: N/A
Year: 2002
Pages: 180
Authors: Tom Miller

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net