Advanced 3D Game Programming with DirectX - phần 3 pot - Pdf 21


143
HRESULT WINAPI DirectSoundCreate8(
LPCGUID lpcGuid,
LPDIRECTSOUND8 * ppDS,
LPUNKNOWN pUnkOuter
);
lpcGuid
A pointer to a GUID that describes the device you wish to create. While you can
enumerate all of the sound devices with DirectSoundEnumerate, generally there is
only one sound card on a machine. To get the default device (which is what you want,
usually), set this to NULL.

ppDS
A pointer to an LPDIRECTSOUND8 interface pointer that will be filled with a valid
interface pointer if the function succeeds.

pUnkOuter
Used for COM aggregation; leave this as NULL.
Sample code to create the sound interface appears in the following:
LPDIRECTSOUND8 m_pDSound = 0;

// Create IDirectSound using the primary sound device
hr = DirectSoundCreate8( NULL, &m_pDSound, NULL );
if( FAILED( hr ) )
{
// Handle critical error
}
Setting the Cooperative Level
After you acquire the interface pointer, the next step is to declare how cooperative you intend on being.
Just like DirectInput, this is done using the SetCooperativeLevel command.

}
Grabbing the Primary Buffer
Since the sound layer sets the cooperative level's priority, it can do some crazy things like change the
format of the primary buffer. Generally it's best to set the primary buffer to the same format that all of
your secondary buffers will be in; this makes the mixer's job easier, as it doesn't have to resample any
sound effects to be able to mix them into the primary buffer. You can imagine what would happen if you
tried to play a 22 KHz sound effect in a 44 KHz buffer without resampling: You would run out of samples
twice as soon as you would expect, and the sound effect would have sort of a chipmunkish quality to it.
To change the format of the primary buffer, you just need to grab it using CreateSoundBuffer, fill out a
new format description, and set it using the SetFormat() method on the primary buffer. Listing 4.2
has
code that sets the primary format to 22 KHz, 16-bit stereo.
Listing 4.2: Sample code to change the format of the primary buffer

145

// pDSound is a valid LPDIRECTSOUND object.
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;

sAutoZero<DSBUFFERDESC> dsbd;
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;

HRESULT hr = pDSound->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL );
if( FAILED( hr ) )
{
/* handle error */
}


* copyright (c) 2002 by Peter A Walsh and Adrian Perez
* See license.txt for modification and distribution information
******************************************************************/

#ifndef _SOUNDLAYER_H
#define _SOUNDLAYER_H

#include <dsound.h>
#include "GameErrors.h" // Added by ClassView

class cSound;

class cSoundLayer
{

LPDIRECTSOUND8 m_pDSound;
LPDIRECTSOUNDBUFFER8 m_pPrimary; // primary mixer

static cSoundLayer* m_pGlobalSLayer; 147
cSoundLayer( HWND hWnd );

public:
virtual ~cSoundLayer();

static cSoundLayer* GetSound()
{
return m_pGlobalSLayer;

* See license.txt for modification and distribution information
******************************************************************/

#include "stdafx.h"

#include "SoundLayer.h"
#include "Sound.h"

cSoundLayer* cSoundLayer::m_pGlobalSLayer = NULL;

cSoundLayer::cSoundLayer( HWND hWnd )
{
m_pDSound = NULL;
m_pPrimary = NULL;

if( m_pGlobalSLayer )
{
throw cGameError( "cSoundLayer already initialized!" );
}
m_pGlobalSLayer = this;

HRESULT hr;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;

// Create IDirectSound using the primary sound device
hr = DirectSoundCreate8( NULL, &m_pDSound, NULL );
if( FAILED( hr ) )
{

149

wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; 150
if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
{
throw cGameError( "CreateSoundBuffer (DS) failed!" );
}
SafeRelease( pDSBPrimary );
}

cSoundLayer::~cSoundLayer()
{
SafeRelease( m_pPrimary );
SafeRelease( m_pDSound );
m_pGlobalSLayer = NULL;
} The cSound Class
To help facilitate the creation and playback of secondary buffers, I constructed an encapsulation class
called cSound. A cSound object can be constructed either from a filename or from another cSound
object. The copy constructor uses a ref-counting map so that all cSounds based on the same WAV file
use the same CWaveSoundRead object. The overhead of the map could have been avoided if the
CWaveSoundRead code was changed to accommodate the needed functionality, but I felt it was better
to leave the code unchanged from the DirectX SDK.
Without any further ado, let's just dive into the code. The details of how this code works isn't terribly
interesting but have a look through it anyway to get accustomed to it.
Listing 4.5: Sound.h


* I would have just changed CWaveSoundRead,
* but I wanted to keep it unchanged from the
* samples.
*/
static std::map< CWaveSoundRead*, int > m_waveMap;

void Init();

public:
cSound( char* filename );
cSound( cSound& in );

152
cSound& operator=( const cSound &in );

virtual ~cSound();

void Restore();
void Fill();
void Play( bool bLoop = false );

bool IsPlaying();

};

#endif //_SOUND_H Listing 4.6: Sound.cpp


if( FAILED( m_pWaveSoundRead->Open( filename)))
{
throw cGameError("couldn't open file!");
}
Init();
Fill();
}

cSound::cSound( cSound& in )
{
m_pWaveSoundRead = in.m_pWaveSoundRead;
m_waveMap[ m_pWaveSoundRead ]++;
Init();
Fill();
}

cSound& cSound::operator=( const cSound &in )
{
/**

154
* Destroy the old object
*/
int count = m_waveMap[ m_pWaveSoundRead ];
if( !count )
{
delete m_pWaveSoundRead;
}
SafeRelease( m_pBuffer );


{
/**
* Set up the DirectSound surface. The size of the sound file
* and the format of the data can be retrieved from the wave
* sound object. Besides that, we only set the STATIC flag,
* so that the driver isn't restricted in setting up the
* buffer.
*/
sAutoZero<DSBUFFERDESC> dsbd;
dsbd.dwFlags = DSBCAPS_STATIC;
dsbd.dwBufferBytes = m_pWaveSoundRead->m_ckIn.cksize;
dsbd.lpwfxFormat = m_pWaveSoundRead->m_pwfx;

HRESULT hr;

// Temporary pointer to old DirectSound interface
LPDIRECTSOUNDBUFFER pTempBuffer = 0;

// Create the sound buffer
hr = Sound()->GetDSound()->CreateSoundBuffer( &dsbd, &pTempBuffer,
NULL );
if( FAILED( hr ) )
{
throw cGameError( "couldn't get buffer status" );
}

// Upgrade the sound buffer to version 8

156
pTempBuffer->QueryInterface( IID_IDirectSoundBuffer8,

{

157
/**
* Chances are, we got here because the app /just/
* started, and DirectSound hasn't given us any
* control yet. Just spin until we can restore
* the buffer
*/
do
{
hr = m_pBuffer->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
}
while( hr = m_pBuffer->Restore() );

/**
* The buffer was restored. Fill 'er up.
*/
Fill();
}
}

void cSound::Fill()
{
HRESULT hr;
uchar* pbWavData; // Pointer to actual wav data
uint cbWavSize; // Size of data
void* pbData = NULL;

/**
* Reset the file to the beginning
*/
m_pWaveSoundRead->Reset();

/**
* Lock the buffer so we can copy the data over
*/
hr = m_pBuffer->Lock(

159
0, m_bufferSize, &pbData, &dwLength,
&pbData2, &dwLength2, 0L );
if( FAILED( hr ) )
{
delete [] pbWavData;
throw cGameError("m_pBuffer->Lock failed");
}

/**
* Copy said data over, unlocking afterwards
*/
memcpy( pbData, pbWavData, m_bufferSize );
m_pBuffer->Unlock( pbData, m_bufferSize, NULL, 0 );

/**
* We're done with the wav data memory.
*/
delete [] pbWavData;
}


Additions to cApplication
The only addition to cApplication is the InitSound call, which initializes the sound layer. After the call
completes you can freely create cSound objects and play them. If this is not the behavior you would like
in your application, the function is overloadable. The code is in the following:
void cApplication::InitSound()
{
cSoundLayer::Create( MainWindow()->GetHWnd() );
}
Application: DirectSound Sample
Adrian, the lead author of the DirectX 7.0 version of this book, has a few interesting hobbies. As part of
an ongoing effort, he does extracurricular activities that actually have nothing to do with programming.
One of them is an a cappella group that he sings bass in. One of his jobs in the a cappella group is to
take care of some of the vocal percussion.
A cappella music can't have any sort of accompaniment, so any percussion needs to be done with the
human voice. This has spawned an entire subculture of vocal percussionists, each trying to make that

161
perfect snare sound or cymbal crash using only their mouths. The DirectSound sample for this chapter
was created using Adrian's unique vocal abilities.
When you load the file DSSAMPLE from the companion files, you're presented with a small window that
lists six different vocal percussion sounds. The keys 1 through 6 play each of the sounds, and you can
press multiple keys simultaneously to play multiple sounds.
You'll note that I didn't show you a DirectInput sample, because I figured it would be better to roll
DirectSound and DirectInput into one sample. DirectInput is used to capture the keystrokes. With some
practice you can get a pretty swank beat going. The code behind the sample appears in Listing 4.7
.
Listing 4.7: The vocal percussion DirectSound sample app

/*******************************************************************

virtual void SceneInit();

cDSSampleApp() :
cApplication()
{
m_title = string( "DirectSound Sample" );
m_width = 320;
m_height = 200;
for( int i=0; i<6; i++ ) m_states[i] = 0;
}

~cDSSampleApp()
{
for( int i=0; i<6; i++ )
{
for( int i2=0; i2< m_sounds[i].size(); i2++ )
{
delete m_sounds[i][i2];
}
}
}

virtual void KeyUp( int key );
virtual void KeyDown( int key ); 163
};

cApplication* CreateApplication()

164
* for a sound that isn't currently playing.
*/
vector<cSound*>::iterator iter;
for( iter = m_sounds[num].begin(); iter != m_sounds[num].end(); iter++
)
{
if( !(*iter)->IsPlaying() )
{
(*iter)->Play();
return;
}
}

/**
* A sound wasn't found. Create a new one.
*/
DP("spawning a new sound\n");
cSound* pNew = new cSound( *m_sounds[num][0] );
m_sounds[num].push_back( pNew );
m_sounds[num][ m_sounds[num].size() - 1 ]->Play();
}

void cDSSampleApp::DoFrame( float timeDelta )
{
// Clear the previous contents of the back buffer
Graphics()->GetDevice()->Clear( 0, 0, D3DCLEAR_TARGET |
D3DCLEAR_ZBUFFER,
D3DCOLOR_XRGB( 0,0,200), 1.0f, 0 );
// Set up the strings

case DIK_1:
if( !m_states[0] )
{
m_states[0] = 1;
PlaySound(0);
}
break;

166
case DIK_2:
if( !m_states[1] )
{
m_states[1] = 1;
PlaySound(1);
}
break;
case DIK_3:
if( !m_states[2] )
{
m_states[2] = 1;
PlaySound(2);
}
break;
case DIK_4:
if( !m_states[3] )
{
m_states[3] = 1;
PlaySound(3);
}
break;

m_states[2] = 0;
break;
case DIK_4:
m_states[3] = 0;
break;
case DIK_5:
m_states[4] = 0;
break;
case DIK_6:
m_states[5] = 0;
break;
}
}


Nhờ tải bản gốc

Tài liệu, ebook tham khảo khác

Music ♫

Copyright: Tài liệu đại học © DMCA.com Protection Status