LoadSound() causing unhandled exception; access violation

Started by
9 comments, last by StoneMask 12 years ago
I created a program from my book again that's pretty much syntactically identical, but I'm getting an error in regards to one of the wrappers I'm using.

I'll organize this post so this thread isn't cluttered and unattractive. I know some topics get dropped just because people don't format their code in a way that's easy to look through.

Also, I am using a 32-bit Windows 7 machine. These are my specs. I am using Microsoft Visual Studio 2010 as my IDE.

The problem:
[spoiler]
I get a runtime error when I try to call the LoadSound() function:
q2ceO.png
[/spoiler]

Steps I took to solve it:
[spoiler]I already knew I had to include the following libraries:
d3d9.lib; d3dx9.lib; dsound.lib; dsound.lib; DXerr.lib; winmm.lib
and have done so as such:
nF1CC.png

And I also have the Lib and Include folders included in my Include Directories, as well as the x86 folder in my Library Directories.
b59U5.png

I used breakpoints to determine that the error really only occurs when LoadSound() is called. If I create the CSound objects and leave them be until deleted, I won't get any errors. I have also tested if my sound files are broken by creating an ifstream object and opening them successfully with the open() function. The files are regular .wav files, but if you want to test them for yourself, here are download links:
snd_Bounce.wav
snd_Electric.wav
[/spoiler]

My code:
[spoiler]
The file that the errors keep referencing is my dsutil.cpp, so I'll put that first. I left out unrelated source files because otherwise, this post would be massive. The error happens in the Create() function of the dsutil.cpp file.

dsutil.h
[spoiler]//-----------------------------------------------------------------------------
// File: dsutil.h
//
// Desc:
//
// Copyright (c) Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#ifndef DSUTIL_H
#define DSUTIL_H

#include
#include
#include
#include




//-----------------------------------------------------------------------------
// Classes used by this header
//-----------------------------------------------------------------------------
class CSoundManager;
class CSound;
class CStreamingSound;
class CWaveFile;




//-----------------------------------------------------------------------------
// Typing macros
//-----------------------------------------------------------------------------
#define WAVEFILE_READ 1
#define WAVEFILE_WRITE 2

#define DSUtil_StopSound(s) { if(s) s->Stop(); }
#define DSUtil_PlaySound(s) { if(s) s->Play( 0, 0 ); }
#define DSUtil_PlaySoundLooping(s) { if(s) s->Play( 0, DSBPLAY_LOOPING ); }




//-----------------------------------------------------------------------------
// Name: class CSoundManager
// Desc:
//-----------------------------------------------------------------------------
class CSoundManager
{
protected:
LPDIRECTSOUND8 m_pDS;

public:
CSoundManager();
~CSoundManager();

HRESULT Initialize( HWND hWnd, DWORD dwCoopLevel );
inline LPDIRECTSOUND8 GetDirectSound() { return m_pDS; }
HRESULT SetPrimaryBufferFormat( DWORD dwPrimaryChannels, DWORD dwPrimaryFreq, DWORD dwPrimaryBitRate );
HRESULT Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener );

HRESULT Create( CSound** ppSound, LPTSTR strWaveFileName, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
HRESULT CreateFromMemory( CSound** ppSound, BYTE* pbData, ULONG ulDataSize, LPWAVEFORMATEX pwfx, DWORD dwCreationFlags = 0, GUID guid3DAlgorithm = GUID_NULL, DWORD dwNumBuffers = 1 );
HRESULT CreateStreaming( CStreamingSound** ppStreamingSound, LPTSTR strWaveFileName, DWORD dwCreationFlags, GUID guid3DAlgorithm, DWORD dwNotifyCount, DWORD dwNotifySize, HANDLE hNotifyEvent );
};




//-----------------------------------------------------------------------------
// Name: class CSound
// Desc: Encapsulates functionality of a DirectSound buffer.
//-----------------------------------------------------------------------------
class CSound
{
protected:
LPDIRECTSOUNDBUFFER* m_apDSBuffer;
DWORD m_dwDSBufferSize;
CWaveFile* m_pWaveFile;
DWORD m_dwNumBuffers;
DWORD m_dwCreationFlags;

HRESULT RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored );

public:
CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize, DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags );
virtual ~CSound();

HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer );
HRESULT FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger );
LPDIRECTSOUNDBUFFER GetFreeBuffer();
LPDIRECTSOUNDBUFFER GetBuffer( DWORD dwIndex );

HRESULT Play( DWORD dwPriority = 0, DWORD dwFlags = 0, LONG lVolume = 0, LONG lFrequency = -1, LONG lPan = 0 );
HRESULT Play3D( LPDS3DBUFFER p3DBuffer, DWORD dwPriority = 0, DWORD dwFlags = 0, LONG lFrequency = 0 );
HRESULT Stop();
HRESULT Reset();
BOOL IsSoundPlaying();
};




//-----------------------------------------------------------------------------
// Name: class CStreamingSound
// Desc: Encapsulates functionality to play a wave file with DirectSound.
// The Create() method loads a chunk of wave file into the buffer,
// and as sound plays more is written to the buffer by calling
// HandleWaveStreamNotification() whenever hNotifyEvent is signaled.
//-----------------------------------------------------------------------------
class CStreamingSound : public CSound
{
protected:
DWORD m_dwLastPlayPos;
DWORD m_dwPlayProgress;
DWORD m_dwNotifySize;
DWORD m_dwNextWriteOffset;
BOOL m_bFillNextNotificationWithSilence;

public:
CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize, CWaveFile* pWaveFile, DWORD dwNotifySize );
~CStreamingSound();

HRESULT HandleWaveStreamNotification( BOOL bLoopedPlay );
HRESULT Reset();
};




//-----------------------------------------------------------------------------
// Name: class CWaveFile
// Desc: Encapsulates reading or writing sound data to or from a wave file
//-----------------------------------------------------------------------------
class CWaveFile
{
public:
WAVEFORMATEX* m_pwfx; // Pointer to WAVEFORMATEX structure
HMMIO m_hmmio; // MM I/O handle for the WAVE
MMCKINFO m_ck; // Multimedia RIFF chunk
MMCKINFO m_ckRiff; // Use in opening a WAVE file
DWORD m_dwSize; // The size of the wave file
MMIOINFO m_mmioinfoOut;
DWORD m_dwFlags;
BOOL m_bIsReadingFromMemory;
BYTE* m_pbData;
BYTE* m_pbDataCur;
ULONG m_ulDataSize;
CHAR* m_pResourceBuffer;

protected:
HRESULT ReadMMIO();
HRESULT WriteMMIO( WAVEFORMATEX *pwfxDest );

public:
CWaveFile();
~CWaveFile();

HRESULT Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags );
HRESULT OpenFromMemory( BYTE* pbData, ULONG ulDataSize, WAVEFORMATEX* pwfx, DWORD dwFlags );
HRESULT Close();

HRESULT Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );
HRESULT Write( UINT nSizeToWrite, BYTE* pbData, UINT* pnSizeWrote );

DWORD GetSize();
HRESULT ResetFile();
WAVEFORMATEX* GetFormat() { return m_pwfx; };
};

#endif // DSUTIL_H
[/spoiler]

dsutil.cpp
[spoiler]//-----------------------------------------------------------------------------
// File: DSUtil.cpp
//
// Desc: DirectSound framework classes for reading and writing wav files and
// playing them in DirectSound buffers. Feel free to use this class
// as a starting point for adding extra functionality.
//
// Copyright (c) Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#define STRICT
#include
#include
#include
#include
#include "dsutil.h"
#include "dxutil.h"




//-----------------------------------------------------------------------------
// Name: CSoundManager::CSoundManager()
// Desc: Constructs the class
//-----------------------------------------------------------------------------
CSoundManager::CSoundManager()
{
m_pDS = NULL;
}




//-----------------------------------------------------------------------------
// Name: CSoundManager::~CSoundManager()
// Desc: Destroys the class
//-----------------------------------------------------------------------------
CSoundManager::~CSoundManager()
{
SAFE_RELEASE( m_pDS );
}




//-----------------------------------------------------------------------------
// Name: CSoundManager::Initialize()
// Desc: Initializes the IDirectSound object and also sets the primary buffer
// format. This function must be called before any others.
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Initialize( HWND hWnd,
DWORD dwCoopLevel )
{
HRESULT hr;

SAFE_RELEASE( m_pDS );

// Create IDirectSound using the primary sound device
if( FAILED( hr = DirectSoundCreate8( NULL, &m_pDS, NULL ) ) )
return DXTRACE_ERR( TEXT("DirectSoundCreate8"), hr );

// Set DirectSound coop level
if( FAILED( hr = m_pDS->SetCooperativeLevel( hWnd, dwCoopLevel ) ) )
return DXTRACE_ERR( TEXT("SetCooperativeLevel"), hr );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CSoundManager::SetPrimaryBufferFormat()
// Desc: Set primary buffer to a specified format
// !WARNING! - Setting the primary buffer format and then using this
// same dsound object for DirectMusic messes up DirectMusic!
// For example, to set the primary buffer format to 22kHz stereo, 16-bit
// then: dwPrimaryChannels = 2
// dwPrimaryFreq = 22050,
// dwPrimaryBitRate = 16
//-----------------------------------------------------------------------------
HRESULT CSoundManager::SetPrimaryBufferFormat( DWORD dwPrimaryChannels,
DWORD dwPrimaryFreq,
DWORD dwPrimaryBitRate )
{
HRESULT hr;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;

if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;

// Get the primary buffer
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER;
dsbd.dwBufferBytes = 0;
dsbd.lpwfxFormat = NULL;

if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBPrimary, NULL ) ) )
return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );

WAVEFORMATEX wfx;
ZeroMemory( &wfx, sizeof(WAVEFORMATEX) );
wfx.wFormatTag = (WORD) WAVE_FORMAT_PCM;
wfx.nChannels = (WORD) dwPrimaryChannels;
wfx.nSamplesPerSec = (DWORD) dwPrimaryFreq;
wfx.wBitsPerSample = (WORD) dwPrimaryBitRate;
wfx.nBlockAlign = (WORD) (wfx.wBitsPerSample / 8 * wfx.nChannels);
wfx.nAvgBytesPerSec = (DWORD) (wfx.nSamplesPerSec * wfx.nBlockAlign);

if( FAILED( hr = pDSBPrimary->SetFormat(&wfx) ) )
return DXTRACE_ERR( TEXT("SetFormat"), hr );

SAFE_RELEASE( pDSBPrimary );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CSoundManager::Get3DListenerInterface()
// Desc: Returns the 3D listener interface associated with primary buffer.
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Get3DListenerInterface( LPDIRECTSOUND3DLISTENER* ppDSListener )
{
HRESULT hr;
DSBUFFERDESC dsbdesc;
LPDIRECTSOUNDBUFFER pDSBPrimary = NULL;

if( ppDSListener == NULL )
return E_INVALIDARG;
if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;

*ppDSListener = NULL;

// Obtain primary buffer, asking it for 3D control
ZeroMemory( &dsbdesc, sizeof(DSBUFFERDESC) );
dsbdesc.dwSize = sizeof(DSBUFFERDESC);
dsbdesc.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbdesc, &pDSBPrimary, NULL ) ) )
return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );

if( FAILED( hr = pDSBPrimary->QueryInterface( IID_IDirectSound3DListener,
(VOID**)ppDSListener ) ) )
{
SAFE_RELEASE( pDSBPrimary );
return DXTRACE_ERR( TEXT("QueryInterface"), hr );
}

// Release the primary buffer, since it is not need anymore
SAFE_RELEASE( pDSBPrimary );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CSoundManager::Create()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::Create( CSound** ppSound,
LPTSTR strWaveFileName,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNumBuffers )
{
HRESULT hr;
HRESULT hrRet = S_OK;

DWORD i;
LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
DWORD dwDSBufferSize = NULL;
CWaveFile* pWaveFile = NULL;

if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
if( strWaveFileName == NULL || ppSound == NULL || dwNumBuffers < 1 )
return E_INVALIDARG;

apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
if( apDSBuffer == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}

pWaveFile = new CWaveFile();
if( pWaveFile == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}

pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );

if( pWaveFile->GetSize() == 0 )
{
// Wave is blank, so don't create it.
hr = E_FAIL;
goto LFail;
}

// Make the DirectSound buffer the same size as the wav file
dwDSBufferSize = pWaveFile->GetSize();

// Create the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
// be hardware accelerated
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = dwCreationFlags;
dsbd.dwBufferBytes = dwDSBufferSize;
dsbd.guid3DAlgorithm = guid3DAlgorithm;
dsbd.lpwfxFormat = pWaveFile->m_pwfx;

// DirectSound is only guarenteed to play PCM data. Other
// formats may or may not work depending the sound card driver.
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL );

// Be sure to return this error code if it occurs so the
// callers knows this happened.
if( hr == DS_NO_VIRTUALIZATION )
hrRet = DS_NO_VIRTUALIZATION;

if( FAILED(hr) )
{
// DSERR_BUFFERTOOSMALL will be returned if the buffer is
// less than DSBSIZE_FX_MIN and the buffer is created
// with DSBCAPS_CTRLFX.

// It might also fail if hardware buffer mixing was requested
// on a device that doesn't support it.
DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );

goto LFail;
}

// Default to use DuplicateSoundBuffer() when created extra buffers since always
// create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
// DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
{
for( i=1; i {
if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer ) ) )
{
DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
goto LFail;
}
}
}
else
{
for( i=1; i {
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL );
if( FAILED(hr) )
{
DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
goto LFail;
}
}
}

// Create the sound
*ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );

SAFE_DELETE_ARRAY( apDSBuffer );
return hrRet;

LFail:
// Cleanup
SAFE_DELETE( pWaveFile );
SAFE_DELETE_ARRAY( apDSBuffer );
return hr;
}





//-----------------------------------------------------------------------------
// Name: CSoundManager::CreateFromMemory()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::CreateFromMemory( CSound** ppSound,
BYTE* pbData,
ULONG ulDataSize,
LPWAVEFORMATEX pwfx,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNumBuffers )
{
HRESULT hr;
DWORD i;
LPDIRECTSOUNDBUFFER* apDSBuffer = NULL;
DWORD dwDSBufferSize = NULL;
CWaveFile* pWaveFile = NULL;

if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
if( pbData == NULL || ppSound == NULL || dwNumBuffers < 1 )
return E_INVALIDARG;

apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
if( apDSBuffer == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}

pWaveFile = new CWaveFile();
if( pWaveFile == NULL )
{
hr = E_OUTOFMEMORY;
goto LFail;
}

pWaveFile->OpenFromMemory( pbData,ulDataSize, pwfx, WAVEFILE_READ );


// Make the DirectSound buffer the same size as the wav file
dwDSBufferSize = ulDataSize;

// Create the direct sound buffer, and only request the flags needed
// since each requires some overhead and limits if the buffer can
// be hardware accelerated
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = dwCreationFlags;
dsbd.dwBufferBytes = dwDSBufferSize;
dsbd.guid3DAlgorithm = guid3DAlgorithm;
dsbd.lpwfxFormat = pwfx;

if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer[0], NULL ) ) )
{
DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
goto LFail;
}

// Default to use DuplicateSoundBuffer() when created extra buffers since always
// create a buffer that uses the same memory however DuplicateSoundBuffer() will fail if
// DSBCAPS_CTRLFX is used, so use CreateSoundBuffer() instead in this case.
if( (dwCreationFlags & DSBCAPS_CTRLFX) == 0 )
{
for( i=1; i {
if( FAILED( hr = m_pDS->DuplicateSoundBuffer( apDSBuffer[0], &apDSBuffer ) ) )
{
DXTRACE_ERR( TEXT("DuplicateSoundBuffer"), hr );
goto LFail;
}
}
}
else
{
for( i=1; i {
hr = m_pDS->CreateSoundBuffer( &dsbd, &apDSBuffer, NULL );
if( FAILED(hr) )
{
DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
goto LFail;
}
}
}

// Create the sound
*ppSound = new CSound( apDSBuffer, dwDSBufferSize, dwNumBuffers, pWaveFile, dwCreationFlags );

SAFE_DELETE_ARRAY( apDSBuffer );
return S_OK;

LFail:
// Cleanup

SAFE_DELETE_ARRAY( apDSBuffer );
return hr;
}





//-----------------------------------------------------------------------------
// Name: CSoundManager::CreateStreaming()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSoundManager::CreateStreaming( CStreamingSound** ppStreamingSound,
LPTSTR strWaveFileName,
DWORD dwCreationFlags,
GUID guid3DAlgorithm,
DWORD dwNotifyCount,
DWORD dwNotifySize,
HANDLE hNotifyEvent )
{
HRESULT hr;

if( m_pDS == NULL )
return CO_E_NOTINITIALIZED;
if( strWaveFileName == NULL || ppStreamingSound == NULL || hNotifyEvent == NULL )
return E_INVALIDARG;

LPDIRECTSOUNDBUFFER pDSBuffer = NULL;
DWORD dwDSBufferSize = NULL;
CWaveFile* pWaveFile = NULL;
DSBPOSITIONNOTIFY* aPosNotify = NULL;
LPDIRECTSOUNDNOTIFY pDSNotify = NULL;

pWaveFile = new CWaveFile();
if( pWaveFile == NULL )
return E_OUTOFMEMORY;
pWaveFile->Open( strWaveFileName, NULL, WAVEFILE_READ );

// Figure out how big the DSound buffer should be
dwDSBufferSize = dwNotifySize * dwNotifyCount;

// Set up the direct sound buffer. Request the NOTIFY flag, so
// that we are notified as the sound buffer plays. Note, that using this flag
// may limit the amount of hardware acceleration that can occur.
DSBUFFERDESC dsbd;
ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );
dsbd.dwSize = sizeof(DSBUFFERDESC);
dsbd.dwFlags = dwCreationFlags |
DSBCAPS_CTRLPOSITIONNOTIFY |
DSBCAPS_GETCURRENTPOSITION2;
dsbd.dwBufferBytes = dwDSBufferSize;
dsbd.guid3DAlgorithm = guid3DAlgorithm;
dsbd.lpwfxFormat = pWaveFile->m_pwfx;

if( FAILED( hr = m_pDS->CreateSoundBuffer( &dsbd, &pDSBuffer, NULL ) ) )
{
// If wave format isn't then it will return
// either DSERR_BADFORMAT or E_INVALIDARG
if( hr == DSERR_BADFORMAT || hr == E_INVALIDARG )
return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );

return DXTRACE_ERR( TEXT("CreateSoundBuffer"), hr );
}

// Create the notification events, so that we know when to fill
// the buffer as the sound plays.
if( FAILED( hr = pDSBuffer->QueryInterface( IID_IDirectSoundNotify,
(VOID**)&pDSNotify ) ) )
{
SAFE_DELETE_ARRAY( aPosNotify );
return DXTRACE_ERR( TEXT("QueryInterface"), hr );
}

aPosNotify = new DSBPOSITIONNOTIFY[ dwNotifyCount ];
if( aPosNotify == NULL )
return E_OUTOFMEMORY;

for( DWORD i = 0; i < dwNotifyCount; i++ )
{
aPosNotify.dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
aPosNotify.hEventNotify = hNotifyEvent;
}

// Tell DirectSound when to notify us. The notification will come in the from
// of signaled events that are handled in WinMain()
if( FAILED( hr = pDSNotify->SetNotificationPositions( dwNotifyCount,
aPosNotify ) ) )
{
SAFE_RELEASE( pDSNotify );
SAFE_DELETE_ARRAY( aPosNotify );
return DXTRACE_ERR( TEXT("SetNotificationPositions"), hr );
}

SAFE_RELEASE( pDSNotify );
SAFE_DELETE_ARRAY( aPosNotify );

// Create the sound
*ppStreamingSound = new CStreamingSound( pDSBuffer, dwDSBufferSize, pWaveFile, dwNotifySize );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CSound::CSound()
// Desc: Constructs the class
//-----------------------------------------------------------------------------
CSound::CSound( LPDIRECTSOUNDBUFFER* apDSBuffer, DWORD dwDSBufferSize,
DWORD dwNumBuffers, CWaveFile* pWaveFile, DWORD dwCreationFlags )
{
DWORD i;

m_apDSBuffer = new LPDIRECTSOUNDBUFFER[dwNumBuffers];
if( NULL != m_apDSBuffer )
{
for( i=0; i m_apDSBuffer = apDSBuffer;

m_dwDSBufferSize = dwDSBufferSize;
m_dwNumBuffers = dwNumBuffers;
m_pWaveFile = pWaveFile;
m_dwCreationFlags = dwCreationFlags;

FillBufferWithSound( m_apDSBuffer[0], FALSE );
}
}




//-----------------------------------------------------------------------------
// Name: CSound::~CSound()
// Desc: Destroys the class
//-----------------------------------------------------------------------------
CSound::~CSound()
{
for( DWORD i=0; i {
SAFE_RELEASE( m_apDSBuffer );
}

SAFE_DELETE_ARRAY( m_apDSBuffer );
SAFE_DELETE( m_pWaveFile );
}




//-----------------------------------------------------------------------------
// Name: CSound::FillBufferWithSound()
// Desc: Fills a DirectSound buffer with a sound file
//-----------------------------------------------------------------------------
HRESULT CSound::FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )
{
HRESULT hr;
VOID* pDSLockedBuffer = NULL; // Pointer to locked buffer memory
DWORD dwDSLockedBufferSize = 0; // Size of the locked DirectSound buffer
DWORD dwWavDataRead = 0; // Amount of data read from the wav file

if( pDSB == NULL )
return CO_E_NOTINITIALIZED;

// Make sure we have focus, and we didn't just switch in from
// an app which had a DirectSound device
if( FAILED( hr = RestoreBuffer( pDSB, NULL ) ) )
return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );

// Lock the buffer down
if( FAILED( hr = pDSB->Lock( 0, m_dwDSBufferSize,
&pDSLockedBuffer, &dwDSLockedBufferSize,
NULL, NULL, 0L ) ) )
return DXTRACE_ERR( TEXT("Lock"), hr );

// Reset the wave file to the beginning
m_pWaveFile->ResetFile();

if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
dwDSLockedBufferSize,
&dwWavDataRead ) ) )
return DXTRACE_ERR( TEXT("Read"), hr );

if( dwWavDataRead == 0 )
{
// Wav is blank, so just fill with silence
FillMemory( (BYTE*) pDSLockedBuffer,
dwDSLockedBufferSize,
(BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
}
else if( dwWavDataRead < dwDSLockedBufferSize )
{
// If the wav file was smaller than the DirectSound buffer,
// we need to fill the remainder of the buffer with data
if( bRepeatWavIfBufferLarger )
{
// Reset the file and fill the buffer with wav data
DWORD dwReadSoFar = dwWavDataRead; // From previous call above.
while( dwReadSoFar < dwDSLockedBufferSize )
{
// This will keep reading in until the buffer is full
// for very short files
if( FAILED( hr = m_pWaveFile->ResetFile() ) )
return DXTRACE_ERR( TEXT("ResetFile"), hr );

hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
dwDSLockedBufferSize - dwReadSoFar,
&dwWavDataRead );
if( FAILED(hr) )
return DXTRACE_ERR( TEXT("Read"), hr );

dwReadSoFar += dwWavDataRead;
}
}
else
{
// Don't repeat the wav file, just fill in silence
FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead,
dwDSLockedBufferSize - dwWavDataRead,
(BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
}
}

// Unlock the buffer, we don't need it anymore.
pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CSound::RestoreBuffer()
// Desc: Restores the lost buffer. *pbWasRestored returns TRUE if the buffer was
// restored. It can also NULL if the information is not needed.
//-----------------------------------------------------------------------------
HRESULT CSound::RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )
{
HRESULT hr;

if( pDSB == NULL )
return CO_E_NOTINITIALIZED;
if( pbWasRestored )
*pbWasRestored = FALSE;

DWORD dwStatus;
if( FAILED( hr = pDSB->GetStatus( &dwStatus ) ) )
return DXTRACE_ERR( TEXT("GetStatus"), hr );

if( dwStatus & DSBSTATUS_BUFFERLOST )
{
// Since the app could have just been activated, then
// DirectSound may not be giving us control yet, so
// the restoring the buffer may fail.
// If it does, sleep until DirectSound gives us control.
do
{
hr = pDSB->Restore();
if( hr == DSERR_BUFFERLOST )
Sleep( 10 );
}
while( ( hr = pDSB->Restore() ) == DSERR_BUFFERLOST );

if( pbWasRestored != NULL )
*pbWasRestored = TRUE;

return S_OK;
}
else
{
return S_FALSE;
}
}




//-----------------------------------------------------------------------------
// Name: CSound::GetFreeBuffer()
// Desc: Finding the first buffer that is not playing and return a pointer to
// it, or if all are playing return a pointer to a randomly selected buffer.
//-----------------------------------------------------------------------------
LPDIRECTSOUNDBUFFER CSound::GetFreeBuffer()
{
if( m_apDSBuffer == NULL )
return FALSE;

DWORD i;
for( i=0; i {
if( m_apDSBuffer )
{
DWORD dwStatus = 0;
m_apDSBuffer->GetStatus( &dwStatus );
if ( ( dwStatus & DSBSTATUS_PLAYING ) == 0 )
break;
}
}

if( i != m_dwNumBuffers )
return m_apDSBuffer[ i ];
else
return m_apDSBuffer[ rand() % m_dwNumBuffers ];
}




//-----------------------------------------------------------------------------
// Name: CSound::GetBuffer()
// Desc:
//-----------------------------------------------------------------------------
LPDIRECTSOUNDBUFFER CSound::GetBuffer( DWORD dwIndex )
{
if( m_apDSBuffer == NULL )
return NULL;
if( dwIndex >= m_dwNumBuffers )
return NULL;

return m_apDSBuffer[dwIndex];
}




//-----------------------------------------------------------------------------
// Name: CSound::Get3DBufferInterface()
// Desc:
//-----------------------------------------------------------------------------
HRESULT CSound::Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )
{
if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;
if( dwIndex >= m_dwNumBuffers )
return E_INVALIDARG;

*ppDS3DBuffer = NULL;

return m_apDSBuffer[dwIndex]->QueryInterface( IID_IDirectSound3DBuffer,
(VOID**)ppDS3DBuffer );
}


//-----------------------------------------------------------------------------
// Name: CSound::Play()
// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
// in the dwFlags to loop the sound
//-----------------------------------------------------------------------------
HRESULT CSound::Play( DWORD dwPriority, DWORD dwFlags, LONG lVolume, LONG lFrequency, LONG lPan )
{
HRESULT hr;
BOOL bRestored;

if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;

LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();

if( pDSB == NULL )
return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );

// Restore the buffer if it was lost
if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );

if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
}

if( m_dwCreationFlags & DSBCAPS_CTRLVOLUME )
{
pDSB->SetVolume( lVolume );
}

if( lFrequency != -1 &&
(m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY) )
{
pDSB->SetFrequency( lFrequency );
}

if( m_dwCreationFlags & DSBCAPS_CTRLPAN )
{
pDSB->SetPan( lPan );
}

return pDSB->Play( 0, dwPriority, dwFlags );
}




//-----------------------------------------------------------------------------
// Name: CSound::Play3D()
// Desc: Plays the sound using voice management flags. Pass in DSBPLAY_LOOPING
// in the dwFlags to loop the sound
//-----------------------------------------------------------------------------
HRESULT CSound::Play3D( LPDS3DBUFFER p3DBuffer, DWORD dwPriority, DWORD dwFlags, LONG lFrequency )
{
HRESULT hr;
BOOL bRestored;
DWORD dwBaseFrequency;

if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;

LPDIRECTSOUNDBUFFER pDSB = GetFreeBuffer();
if( pDSB == NULL )
return DXTRACE_ERR( TEXT("GetFreeBuffer"), E_FAIL );

// Restore the buffer if it was lost
if( FAILED( hr = RestoreBuffer( pDSB, &bRestored ) ) )
return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );

if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( pDSB, FALSE ) ) )
return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
}

if( m_dwCreationFlags & DSBCAPS_CTRLFREQUENCY )
{
pDSB->GetFrequency( &dwBaseFrequency );
pDSB->SetFrequency( dwBaseFrequency + lFrequency );
}

// QI for the 3D buffer
LPDIRECTSOUND3DBUFFER pDS3DBuffer;
hr = pDSB->QueryInterface( IID_IDirectSound3DBuffer, (VOID**) &pDS3DBuffer );
if( SUCCEEDED( hr ) )
{
hr = pDS3DBuffer->SetAllParameters( p3DBuffer, DS3D_IMMEDIATE );
if( SUCCEEDED( hr ) )
{
hr = pDSB->Play( 0, dwPriority, dwFlags );
}

pDS3DBuffer->Release();
}

return hr;
}



//-----------------------------------------------------------------------------
// Name: CSound::Stop()
// Desc: Stops the sound from playing
//-----------------------------------------------------------------------------
HRESULT CSound::Stop()
{
if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;

HRESULT hr = 0;

for( DWORD i=0; i hr |= m_apDSBuffer->Stop();

return hr;
}




//-----------------------------------------------------------------------------
// Name: CSound::Reset()
// Desc: Reset all of the sound buffers
//-----------------------------------------------------------------------------
HRESULT CSound::Reset()
{
if( m_apDSBuffer == NULL )
return CO_E_NOTINITIALIZED;

HRESULT hr = 0;

for( DWORD i=0; i hr |= m_apDSBuffer->SetCurrentPosition( 0 );

return hr;
}




//-----------------------------------------------------------------------------
// Name: CSound::IsSoundPlaying()
// Desc: Checks to see if a buffer is playing and returns TRUE if it is.
//-----------------------------------------------------------------------------
BOOL CSound::IsSoundPlaying()
{
BOOL bIsPlaying = FALSE;

if( m_apDSBuffer == NULL )
return FALSE;

for( DWORD i=0; i {
if( m_apDSBuffer )
{
DWORD dwStatus = 0;
m_apDSBuffer->GetStatus( &dwStatus );
bIsPlaying |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );
}
}

return bIsPlaying;
}




//-----------------------------------------------------------------------------
// Name: CStreamingSound::CStreamingSound()
// Desc: Setups up a buffer so data can be streamed from the wave file into
// a buffer. This is very useful for large wav files that would take a
// while to load. The buffer is initially filled with data, then
// as sound is played the notification events are signaled and more data
// is written into the buffer by calling HandleWaveStreamNotification()
//-----------------------------------------------------------------------------
CStreamingSound::CStreamingSound( LPDIRECTSOUNDBUFFER pDSBuffer, DWORD dwDSBufferSize,
CWaveFile* pWaveFile, DWORD dwNotifySize )
: CSound( &pDSBuffer, dwDSBufferSize, 1, pWaveFile, 0 )
{
m_dwLastPlayPos = 0;
m_dwPlayProgress = 0;
m_dwNotifySize = dwNotifySize;
m_dwNextWriteOffset = 0;
m_bFillNextNotificationWithSilence = FALSE;
}




//-----------------------------------------------------------------------------
// Name: CStreamingSound::~CStreamingSound()
// Desc: Destroys the class
//-----------------------------------------------------------------------------
CStreamingSound::~CStreamingSound()
{
}



//-----------------------------------------------------------------------------
// Name: CStreamingSound::HandleWaveStreamNotification()
// Desc: Handle the notification that tells us to put more wav data in the
// circular buffer
//-----------------------------------------------------------------------------
HRESULT CStreamingSound::HandleWaveStreamNotification( BOOL bLoopedPlay )
{
HRESULT hr;
DWORD dwCurrentPlayPos;
DWORD dwPlayDelta;
DWORD dwBytesWrittenToBuffer;
VOID* pDSLockedBuffer = NULL;
VOID* pDSLockedBuffer2 = NULL;
DWORD dwDSLockedBufferSize;
DWORD dwDSLockedBufferSize2;

if( m_apDSBuffer == NULL || m_pWaveFile == NULL )
return CO_E_NOTINITIALIZED;

// Restore the buffer if it was lost
BOOL bRestored;
if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );

if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
return S_OK;
}

// Lock the DirectSound buffer
if( FAILED( hr = m_apDSBuffer[0]->Lock( m_dwNextWriteOffset, m_dwNotifySize,
&pDSLockedBuffer, &dwDSLockedBufferSize,
&pDSLockedBuffer2, &dwDSLockedBufferSize2, 0L ) ) )
return DXTRACE_ERR( TEXT("Lock"), hr );

// m_dwDSBufferSize and m_dwNextWriteOffset are both multiples of m_dwNotifySize,
// it should the second buffer, so it should never be valid
if( pDSLockedBuffer2 != NULL )
return E_UNEXPECTED;

if( !m_bFillNextNotificationWithSilence )
{
// Fill the DirectSound buffer with wav data
if( FAILED( hr = m_pWaveFile->Read( (BYTE*) pDSLockedBuffer,
dwDSLockedBufferSize,
&dwBytesWrittenToBuffer ) ) )
return DXTRACE_ERR( TEXT("Read"), hr );
}
else
{
// Fill the DirectSound buffer with silence
FillMemory( pDSLockedBuffer, dwDSLockedBufferSize,
(BYTE)( m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );
dwBytesWrittenToBuffer = dwDSLockedBufferSize;
}

// If the number of bytes written is less than the
// amount we requested, we have a short file.
if( dwBytesWrittenToBuffer < dwDSLockedBufferSize )
{
if( !bLoopedPlay )
{
// Fill in silence for the rest of the buffer.
FillMemory( (BYTE*) pDSLockedBuffer + dwBytesWrittenToBuffer,
dwDSLockedBufferSize - dwBytesWrittenToBuffer,
(BYTE)(m_pWaveFile->m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );

// Any future notifications should just fill the buffer with silence
m_bFillNextNotificationWithSilence = TRUE;
}
else
{
// We are looping, so reset the file and fill the buffer with wav data
DWORD dwReadSoFar = dwBytesWrittenToBuffer; // From previous call above.
while( dwReadSoFar < dwDSLockedBufferSize )
{
// This will keep reading in until the buffer is full (for very short files).
if( FAILED( hr = m_pWaveFile->ResetFile() ) )
return DXTRACE_ERR( TEXT("ResetFile"), hr );

if( FAILED( hr = m_pWaveFile->Read( (BYTE*)pDSLockedBuffer + dwReadSoFar,
dwDSLockedBufferSize - dwReadSoFar,
&dwBytesWrittenToBuffer ) ) )
return DXTRACE_ERR( TEXT("Read"), hr );

dwReadSoFar += dwBytesWrittenToBuffer;
}
}
}

// Unlock the DirectSound buffer
m_apDSBuffer[0]->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );

// Figure out how much data has been played so far. When we have played
// past the end of the file, we will either need to start filling the
// buffer with silence or starting reading from the beginning of the file,
// depending if the user wants to loop the sound
if( FAILED( hr = m_apDSBuffer[0]->GetCurrentPosition( &dwCurrentPlayPos, NULL ) ) )
return DXTRACE_ERR( TEXT("GetCurrentPosition"), hr );

// Check to see if the position counter looped
if( dwCurrentPlayPos < m_dwLastPlayPos )
dwPlayDelta = ( m_dwDSBufferSize - m_dwLastPlayPos ) + dwCurrentPlayPos;
else
dwPlayDelta = dwCurrentPlayPos - m_dwLastPlayPos;

m_dwPlayProgress += dwPlayDelta;
m_dwLastPlayPos = dwCurrentPlayPos;

// If we are now filling the buffer with silence, then we have found the end so
// check to see if the entire sound has played, if it has then stop the buffer.
if( m_bFillNextNotificationWithSilence )
{
// We don't want to cut off the sound before it's done playing.
if( m_dwPlayProgress >= m_pWaveFile->GetSize() )
{
m_apDSBuffer[0]->Stop();
}
}

// Update where the buffer will lock (for next time)
m_dwNextWriteOffset += dwDSLockedBufferSize;
m_dwNextWriteOffset %= m_dwDSBufferSize; // Circular buffer

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CStreamingSound::Reset()
// Desc: Resets the sound so it will begin playing at the beginning
//-----------------------------------------------------------------------------
HRESULT CStreamingSound::Reset()
{
HRESULT hr;

if( m_apDSBuffer[0] == NULL || m_pWaveFile == NULL )
return CO_E_NOTINITIALIZED;

m_dwLastPlayPos = 0;
m_dwPlayProgress = 0;
m_dwNextWriteOffset = 0;
m_bFillNextNotificationWithSilence = FALSE;

// Restore the buffer if it was lost
BOOL bRestored;
if( FAILED( hr = RestoreBuffer( m_apDSBuffer[0], &bRestored ) ) )
return DXTRACE_ERR( TEXT("RestoreBuffer"), hr );

if( bRestored )
{
// The buffer was restored, so we need to fill it with new data
if( FAILED( hr = FillBufferWithSound( m_apDSBuffer[0], FALSE ) ) )
return DXTRACE_ERR( TEXT("FillBufferWithSound"), hr );
}

m_pWaveFile->ResetFile();

return m_apDSBuffer[0]->SetCurrentPosition( 0L );
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::CWaveFile()
// Desc: Constructs the class. Call Open() to open a wave file for reading.
// Then call Read() as needed. Calling the destructor or Close()
// will close the file.
//-----------------------------------------------------------------------------
CWaveFile::CWaveFile()
{
m_pwfx = NULL;
m_hmmio = NULL;
m_pResourceBuffer = NULL;
m_dwSize = 0;
m_bIsReadingFromMemory = FALSE;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::~CWaveFile()
// Desc: Destructs the class
//-----------------------------------------------------------------------------
CWaveFile::~CWaveFile()
{
Close();

if( !m_bIsReadingFromMemory )
SAFE_DELETE_ARRAY( m_pwfx );
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::Open()
// Desc: Opens a wave file for reading
//-----------------------------------------------------------------------------
HRESULT CWaveFile::Open( LPTSTR strFileName, WAVEFORMATEX* pwfx, DWORD dwFlags )
{
HRESULT hr;

m_dwFlags = dwFlags;
m_bIsReadingFromMemory = FALSE;

if( m_dwFlags == WAVEFILE_READ )
{
if( strFileName == NULL )
return E_INVALIDARG;
SAFE_DELETE_ARRAY( m_pwfx );

m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );

if( NULL == m_hmmio )
{
HRSRC hResInfo;
HGLOBAL hResData;
DWORD dwSize;
VOID* pvRes;

// Loading it as a file failed, so try it as a resource
if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAVE") ) ) )
{
if( NULL == ( hResInfo = FindResource( NULL, strFileName, TEXT("WAV") ) ) )
return DXTRACE_ERR( TEXT("FindResource"), E_FAIL );
}

if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) )
return DXTRACE_ERR( TEXT("LoadResource"), E_FAIL );

if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )
return DXTRACE_ERR( TEXT("SizeofResource"), E_FAIL );

if( NULL == ( pvRes = LockResource( hResData ) ) )
return DXTRACE_ERR( TEXT("LockResource"), E_FAIL );

m_pResourceBuffer = new CHAR[ dwSize ];
memcpy( m_pResourceBuffer, pvRes, dwSize );

MMIOINFO mmioInfo;
ZeroMemory( &mmioInfo, sizeof(mmioInfo) );
mmioInfo.fccIOProc = FOURCC_MEM;
mmioInfo.cchBuffer = dwSize;
mmioInfo.pchBuffer = (CHAR*) m_pResourceBuffer;

m_hmmio = mmioOpen( NULL, &mmioInfo, MMIO_ALLOCBUF | MMIO_READ );
}

if( FAILED( hr = ReadMMIO() ) )
{
// ReadMMIO will fail if its an not a wave file
mmioClose( m_hmmio, 0 );
return DXTRACE_ERR( TEXT("ReadMMIO"), hr );
}

if( FAILED( hr = ResetFile() ) )
return DXTRACE_ERR( TEXT("ResetFile"), hr );

// After the reset, the size of the wav file is m_ck.cksize so store it now
m_dwSize = m_ck.cksize;
}
else
{
m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF |
MMIO_READWRITE |
MMIO_CREATE );
if( NULL == m_hmmio )
return DXTRACE_ERR( TEXT("mmioOpen"), E_FAIL );

if( FAILED( hr = WriteMMIO( pwfx ) ) )
{
mmioClose( m_hmmio, 0 );
return DXTRACE_ERR( TEXT("WriteMMIO"), hr );
}

if( FAILED( hr = ResetFile() ) )
return DXTRACE_ERR( TEXT("ResetFile"), hr );
}

return hr;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::OpenFromMemory()
// Desc: copy data to CWaveFile member variable from memory
//-----------------------------------------------------------------------------
HRESULT CWaveFile::OpenFromMemory( BYTE* pbData, ULONG ulDataSize,
WAVEFORMATEX* pwfx, DWORD dwFlags )
{
m_pwfx = pwfx;
m_ulDataSize = ulDataSize;
m_pbData = pbData;
m_pbDataCur = m_pbData;
m_bIsReadingFromMemory = TRUE;

if( dwFlags != WAVEFILE_READ )
return E_NOTIMPL;

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::ReadMMIO()
// Desc: Support function for reading from a multimedia I/O stream.
// m_hmmio must be valid before calling. This function uses it to
// update m_ckRiff, and m_pwfx.
//-----------------------------------------------------------------------------
HRESULT CWaveFile::ReadMMIO()
{
MMCKINFO ckIn; // chunk info. for general use.
PCMWAVEFORMAT pcmWaveFormat; // Temp PCM structure to load in.

m_pwfx = NULL;

if( ( 0 != mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) ) )
return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );

// Check to make sure this is a valid wave file
if( (m_ckRiff.ckid != FOURCC_RIFF) ||
(m_ckRiff.fccType != mmioFOURCC('W', 'A', 'V', 'E') ) )
return DXTRACE_ERR( TEXT("mmioFOURCC"), E_FAIL );

// Search the input file for for the 'fmt ' chunk.
ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');
if( 0 != mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) )
return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );

// Expect the 'fmt' chunk to be at least as large as ;
// if there are extra parameters at the end, we'll ignore them
if( ckIn.cksize < (LONG) sizeof(PCMWAVEFORMAT) )
return DXTRACE_ERR( TEXT("sizeof(PCMWAVEFORMAT)"), E_FAIL );

// Read the 'fmt ' chunk into .
if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat,
sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );

// Allocate the waveformatex, but if its not pcm format, read the next
// word, and thats how many extra bytes to allocate.
if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )
{
m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];
if( NULL == m_pwfx )
return DXTRACE_ERR( TEXT("m_pwfx"), E_FAIL );

// Copy the bytes from the pcm structure to the waveformatex structure
memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
m_pwfx->cbSize = 0;
}
else
{
// Read in length of extra bytes.
WORD cbExtraBytes = 0L;
if( mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) != sizeof(WORD) )
return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );

m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
if( NULL == m_pwfx )
return DXTRACE_ERR( TEXT("new"), E_FAIL );

// Copy the bytes from the pcm structure to the waveformatex structure
memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );
m_pwfx->cbSize = cbExtraBytes;

// Now, read those extra bytes into the structure, if cbExtraAlloc != 0.
if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)),
cbExtraBytes ) != cbExtraBytes )
{
SAFE_DELETE( m_pwfx );
return DXTRACE_ERR( TEXT("mmioRead"), E_FAIL );
}
}

// Ascend the input file out of the 'fmt ' chunk.
if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
{
SAFE_DELETE( m_pwfx );
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );
}

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::GetSize()
// Desc: Retuns the size of the read access wave file
//-----------------------------------------------------------------------------
DWORD CWaveFile::GetSize()
{
return m_dwSize;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::ResetFile()
// Desc: Resets the internal m_ck pointer so reading starts from the
// beginning of the file again
//-----------------------------------------------------------------------------
HRESULT CWaveFile::ResetFile()
{
if( m_bIsReadingFromMemory )
{
m_pbDataCur = m_pbData;
}
else
{
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;

if( m_dwFlags == WAVEFILE_READ )
{
// Seek to the data
if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
SEEK_SET ) )
return DXTRACE_ERR( TEXT("mmioSeek"), E_FAIL );

// Search the input file for the 'data' chunk.
m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
if( 0 != mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );
}
else
{
// Create the 'data' chunk that holds the waveform samples.
m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
m_ck.cksize = 0;

if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );

if( 0 != mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );
}
}

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::Read()
// Desc: Reads section of data from a wave file into pBuffer and returns
// how much read in pdwSizeRead, reading not more than dwSizeToRead.
// This uses m_ck to determine where to start reading from. So
// subsequent calls will be continue where the last left off unless
// Reset() is called.
//-----------------------------------------------------------------------------
HRESULT CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
{
if( m_bIsReadingFromMemory )
{
if( m_pbDataCur == NULL )
return CO_E_NOTINITIALIZED;
if( pdwSizeRead != NULL )
*pdwSizeRead = 0;

if( (BYTE*)(m_pbDataCur + dwSizeToRead) >
(BYTE*)(m_pbData + m_ulDataSize) )
{
dwSizeToRead = m_ulDataSize - (DWORD)(m_pbDataCur - m_pbData);
}

CopyMemory( pBuffer, m_pbDataCur, dwSizeToRead );

if( pdwSizeRead != NULL )
*pdwSizeRead = dwSizeToRead;

return S_OK;
}
else
{
MMIOINFO mmioinfoIn; // current status of m_hmmio

if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( pBuffer == NULL || pdwSizeRead == NULL )
return E_INVALIDARG;

if( pdwSizeRead != NULL )
*pdwSizeRead = 0;

if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
return DXTRACE_ERR( TEXT("mmioGetInfo"), E_FAIL );

UINT cbDataIn = dwSizeToRead;
if( cbDataIn > m_ck.cksize )
cbDataIn = m_ck.cksize;

m_ck.cksize -= cbDataIn;

for( DWORD cT = 0; cT < cbDataIn; cT++ )
{
// Copy the bytes from the io to the buffer.
if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
{
if( 0 != mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ ) )
return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );

if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
return DXTRACE_ERR( TEXT("mmioinfoIn.pchNext"), E_FAIL );
}

// Actual copy.
*((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);
mmioinfoIn.pchNext++;
}

if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );

if( pdwSizeRead != NULL )
*pdwSizeRead = cbDataIn;

return S_OK;
}
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::Close()
// Desc: Closes the wave file
//-----------------------------------------------------------------------------
HRESULT CWaveFile::Close()
{
if( m_dwFlags == WAVEFILE_READ )
{
mmioClose( m_hmmio, 0 );
m_hmmio = NULL;
SAFE_DELETE_ARRAY( m_pResourceBuffer );
}
else
{
m_mmioinfoOut.dwFlags |= MMIO_DIRTY;

if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;

if( 0 != mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 ) )
return DXTRACE_ERR( TEXT("mmioSetInfo"), E_FAIL );

// Ascend the output file out of the 'data' chunk -- this will cause
// the chunk size of the 'data' chunk to be written.
if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );

// Do this here instead...
if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );

mmioSeek( m_hmmio, 0, SEEK_SET );

if( 0 != (INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 ) )
return DXTRACE_ERR( TEXT("mmioDescend"), E_FAIL );

m_ck.ckid = mmioFOURCC('f', 'a', 'c', 't');

if( 0 == mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) )
{
DWORD dwSamples = 0;
mmioWrite( m_hmmio, (HPSTR)&dwSamples, sizeof(DWORD) );
mmioAscend( m_hmmio, &m_ck, 0 );
}

// Ascend the output file out of the 'RIFF' chunk -- this will cause
// the chunk size of the 'RIFF' chunk to be written.
if( 0 != mmioAscend( m_hmmio, &m_ckRiff, 0 ) )
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );

mmioClose( m_hmmio, 0 );
m_hmmio = NULL;
}

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::WriteMMIO()
// Desc: Support function for reading from a multimedia I/O stream
// pwfxDest is the WAVEFORMATEX for this new wave file.
// m_hmmio must be valid before calling. This function uses it to
// update m_ckRiff, and m_ck.
//-----------------------------------------------------------------------------
HRESULT CWaveFile::WriteMMIO( WAVEFORMATEX *pwfxDest )
{
DWORD dwFactChunk; // Contains the actual fact chunk. Garbage until WaveCloseWriteFile.
MMCKINFO ckOut1;

dwFactChunk = (DWORD)-1;

// Create the output file RIFF chunk of form type 'WAVE'.
m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');
m_ckRiff.cksize = 0;

if( 0 != mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) )
return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );

// We are now descended into the 'RIFF' chunk we just created.
// Now create the 'fmt ' chunk. Since we know the size of this chunk,
// specify it in the MMCKINFO structure so MMIO doesn't have to seek
// back and set the chunk size after ascending from the chunk.
m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
m_ck.cksize = sizeof(PCMWAVEFORMAT);

if( 0 != mmioCreateChunk( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );

// Write the PCMWAVEFORMAT structure to the 'fmt ' chunk if its that type.
if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )
{
if( mmioWrite( m_hmmio, (HPSTR) pwfxDest,
sizeof(PCMWAVEFORMAT)) != sizeof(PCMWAVEFORMAT))
return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
}
else
{
// Write the variable length size.
if( (UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest,
sizeof(*pwfxDest) + pwfxDest->cbSize ) !=
( sizeof(*pwfxDest) + pwfxDest->cbSize ) )
return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );
}

// Ascend out of the 'fmt ' chunk, back into the 'RIFF' chunk.
if( 0 != mmioAscend( m_hmmio, &m_ck, 0 ) )
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );

// Now create the fact chunk, not required for PCM but nice to have. This is filled
// in when the close routine is called.
ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');
ckOut1.cksize = 0;

if( 0 != mmioCreateChunk( m_hmmio, &ckOut1, 0 ) )
return DXTRACE_ERR( TEXT("mmioCreateChunk"), E_FAIL );

if( mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk)) !=
sizeof(dwFactChunk) )
return DXTRACE_ERR( TEXT("mmioWrite"), E_FAIL );

// Now ascend out of the fact chunk...
if( 0 != mmioAscend( m_hmmio, &ckOut1, 0 ) )
return DXTRACE_ERR( TEXT("mmioAscend"), E_FAIL );

return S_OK;
}




//-----------------------------------------------------------------------------
// Name: CWaveFile::Write()
// Desc: Writes data to the open wave file
//-----------------------------------------------------------------------------
HRESULT CWaveFile::Write( UINT nSizeToWrite, BYTE* pbSrcData, UINT* pnSizeWrote )
{
UINT cT;

if( m_bIsReadingFromMemory )
return E_NOTIMPL;
if( m_hmmio == NULL )
return CO_E_NOTINITIALIZED;
if( pnSizeWrote == NULL || pbSrcData == NULL )
return E_INVALIDARG;

*pnSizeWrote = 0;

for( cT = 0; cT < nSizeToWrite; cT++ )
{
if( m_mmioinfoOut.pchNext == m_mmioinfoOut.pchEndWrite )
{
m_mmioinfoOut.dwFlags |= MMIO_DIRTY;
if( 0 != mmioAdvance( m_hmmio, &m_mmioinfoOut, MMIO_WRITE ) )
return DXTRACE_ERR( TEXT("mmioAdvance"), E_FAIL );
}

*((BYTE*)m_mmioinfoOut.pchNext) = *((BYTE*)pbSrcData+cT);
(BYTE*)m_mmioinfoOut.pchNext++;

(*pnSizeWrote)++;
}

return S_OK;
}
[/spoiler]

game.h
[spoiler]#ifndef GAME_H
#define GAME_H

#include
#include
#include
#include
#include
#include
#include
#include

// framework-specific headers
#include "dxgraphics.h"
#include "dxaudio.h"

// application title
#define APPTITLE "DirectX Practice"

// screen setup
#define FULLSCREEN 0
#define SCREEN_WIDTH 640
#define SCREEN_HEIGHT 480

// macros to read the keyboard asynchronously
#define KEY_DN(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)
#define KEY_UP(vk_code) ((GetAsyncKeyState(vk_code) & 0x8000) ? 1 : 0)

// function prototypes
int Game_Init(HWND);
void Game_Run(HWND);
void Game_End(HWND);

// sprite structure
typedef struct {
int width, height;
int curFrame, lastFrame;
int frameDelay, frameCount;
int rotation, r_Speed;
int x_Pos, y_Pos;
int x_Speed, y_Speed;
int x_Scale, y_Scale;
} BERRY;

#endif
[/spoiler]

game.cpp
[spoiler]#include "game.h"
#include
// number of mufns on the screen
#define BERRIES 100

using namespace std;

// graphic variables
LPD3DXSPRITE spr_HANDLER;
LPDIRECT3DSURFACE9 env_Background;
LPDIRECT3DTEXTURE9 spr_Berry;
BERRY obj_Berry[BERRIES];

HRESULT result;
long start = GetTickCount();

// the wave sound
CSound *snd_Bounce;
CSound *snd_Electric;

// initializes the game
int Game_Init(HWND hwnd)
{
srand(time(NULL));

// create sprite handler object
result = D3DXCreateSprite(d3ddev, &spr_HANDLER);
if (result != D3D_OK)
return 0;

// load background image
env_Background = LoadSurface("Graphics/Environments/env_Background.bmp", NULL);
if (env_Background == NULL)
return 0;

// load the berry sprite
spr_Berry = LoadTexture("Graphics/Sprites/spr_Berry.bmp", NULL);
if (spr_Berry == NULL)
return 0;

// set the berry's properties
int n;
for (n = 0; n < BERRIES; n++)
{
obj_Berry[n].x_Pos = rand() % SCREEN_WIDTH;
obj_Berry[n].y_Pos = rand() % SCREEN_HEIGHT;
obj_Berry[n].width = 32;
obj_Berry[n].height = 32;
obj_Berry[n].x_Speed = 1 + rand() % 6;
obj_Berry[n].y_Speed = rand() % 12 - 6;
}

// load bounce wave file
snd_Bounce = LoadSound("Sounds/snd_Bounce.wav");
if (snd_Bounce == NULL)
return 0;

// load electric wave file
snd_Electric = LoadSound("Sounds/snd_Electric.wav");
if (snd_Electric == NULL)
return 0;

return 1;
}

// the main game loop
void Game_Run(HWND hwnd)
{
D3DXVECTOR3 position(0, 0, 0); // berry position vector
int playing = 0;

// make sure the Direct3D device is valid
if (d3ddev == NULL)
return;

// keep the framrate steady
if (GetTickCount() - start >= 30)
{
// reset timing
start = GetTickCount();

// move the berry sprite
for (int n = 0; n < BERRIES; n++)
{
obj_Berry[n].x_Pos += obj_Berry[n].x_Speed;
obj_Berry[n].y_Pos += obj_Berry[n].y_Speed;

// bounce the berry at the walls
if (obj_Berry[n].x_Pos > SCREEN_WIDTH - obj_Berry[n].width)
{
obj_Berry[n].x_Speed *= -1;
obj_Berry[n].x_Pos += obj_Berry[n].x_Speed;
PlaySound(snd_Bounce);
}
else if (obj_Berry[n].x_Pos < 0)
{
obj_Berry[n].x_Speed *= -1;
obj_Berry[n].x_Pos += obj_Berry[n].x_Speed;
PlaySound(snd_Bounce);
}
else if (obj_Berry[n].y_Pos > SCREEN_HEIGHT - obj_Berry[n].height)
{
obj_Berry[n].y_Speed *= -1;
obj_Berry[n].y_Pos += obj_Berry[n].y_Speed;
PlaySound(snd_Bounce);
}
else if (obj_Berry[n].y_Pos < 0)
{
obj_Berry[n].y_Speed *= -1;
obj_Berry[n].y_Pos += obj_Berry[n].y_Speed;
PlaySound(snd_Bounce);
}
}
}

// start rendering
if (d3ddev->BeginScene())
{
// erase the entire background
d3ddev->StretchRect(env_Background, NULL, backbuffer, NULL, D3DTEXF_NONE);

// start sprite handler
spr_HANDLER->Begin(D3DXSPRITE_ALPHABLEND);

// draw the berries
int n;
for (n = 0; n < BERRIES; n++)
{
position.x = (float)obj_Berry[n].x_Pos;
position.y = (float)obj_Berry[n].y_Pos;
spr_HANDLER->Draw(
spr_Berry,
NULL,
NULL,
&position,
D3DCOLOR_XRGB(255, 255, 255));
}

// stop drawing
spr_HANDLER->End();

// stop rendering
d3ddev->EndScene();
}

// display the back buffer on the screen
d3ddev->Present(NULL, NULL, NULL, NULL);

// check for escape key
if (KEY_DN(VK_ESCAPE))
PostMessage(hwnd, WM_DESTROY, 0, 0);

// spacebar plays the electric sound
if (KEY_DN(VK_SPACE))
LoopSound(snd_Electric);

// spacebar plays the electric sound
if (KEY_DN(VK_RETURN))
StopSound(snd_Electric);
}

// cleanup
void Game_End(HWND hwnd)
{
if (spr_Berry != NULL)
spr_Berry->Release();

if (env_Background != NULL)
env_Background->Release();

if (spr_HANDLER != NULL)
spr_HANDLER->Release();

if (snd_Bounce != NULL)
delete snd_Bounce;

if (snd_Electric != NULL)
delete snd_Electric;
}
[/spoiler]

winmain.cpp
[spoiler]// DirectX Practice and Study
// Winmain.cpp

#include
#include
#include
#include
#include "dxgraphics.h"
#include "game.h"

// window event callback function
LRESULT WINAPI WinProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)
{
switch(msg)
{
case WM_DESTROY:
// release the Direct3D
if (d3ddev != NULL)
d3ddev->Release();

// release the Direct3D object
if (d3d != NULL)
d3d->Release();

// call the front-end shutdown function
Game_End(hWnd);

// tell Windows to kill the program
PostQuitMessage(0);
return 0;
}
return DefWindowProc(hWnd, msg, wParam, lParam);
}

// helper function to set up the window properties
ATOM MyRegisterClass(HINSTANCE hInstance)
{
// create the window class structure
WNDCLASSEX wc;
wc.cbSize = sizeof(WNDCLASSEX);

// fill the struct with info
wc.cbClsExtra = 0;
wc.cbWndExtra = 0;
wc.hbrBackground = (HBRUSH)GetStockObject(BLACK_BRUSH);
wc.hCursor = LoadCursor(NULL, IDC_ARROW);
wc.hIcon = NULL;
wc.hIconSm = NULL;
wc.hInstance = hInstance;
wc.lpfnWndProc = (WNDPROC)WinProc;
wc.lpszClassName = APPTITLE;
wc.lpszMenuName = NULL;
wc.style = CS_HREDRAW | CS_VREDRAW;

// set up the window with the class info
return RegisterClassEx(&wc);
}

// entry point for a Windows program
int WINAPI WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
MSG msg;
HWND hWnd;

// register the class
MyRegisterClass(hInstance);

// set up the screen in windowed or fullscreen mode
DWORD style;
if (FULLSCREEN)
style = WS_EX_TOPMOST | WS_VISIBLE | WS_POPUP;
else
style = WS_OVERLAPPED;

// create a new window
hWnd = CreateWindow(
APPTITLE,
APPTITLE,
style,
CW_USEDEFAULT,
CW_USEDEFAULT,
SCREEN_WIDTH,
SCREEN_HEIGHT,
NULL,
NULL,
hInstance,
NULL);

// was there an error?
if (!hWnd)
return false;

// display the window
ShowWindow(hWnd, nCmdShow);
UpdateWindow(hWnd);

if (!Init_Direct3D(hWnd, SCREEN_WIDTH, SCREEN_HEIGHT, FULLSCREEN))
return 0;

// initialize the game
if (!Game_Init(hWnd))
{
MessageBox(hWnd, "Error initializing the game", "Initialization error", MB_OK);
return 0;
}

// main message loop
short done = 0;
while(!done)
{
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
{
// look for quit message
if (msg.message == WM_QUIT)
done = 1;

// decode and pass messages on to WinProc
TranslateMessage(&msg);
DispatchMessage(&msg);
}
else
// process game loop
Game_Run(hWnd);
}
return msg.wParam;
}
[/spoiler]

[/spoiler]

I hope you guys can help me with this problem! I honestly can't really advance much without solving this first.
Thanks!
Advertisement
I hope you guys have a 48-hour rule, because I'll probably keep posting every 48 hours until I can get a suggestion as to why my program doesn't work.
The error message gives you a big hint to what's going wrong. "Access violation reading location 0x00000000" Looks like a pointer wasn't initialized. The code pointer in the first screenshot points to line 179 in dsutil.cpp where you are comparing m_pDS to NULL. My guess is that you are calling the Create function on a null pointer. i.e You havent created a soundmanager instance yet.
How would I go about doing that? I checked and double checked, but the class constructor says it's initialized to NULL.
Your LoadSound function code is missing in the code you posted.

What Madhed meant is that your SoundManager instance doesn't seem to have been created yet. You probably have a SoundManager pointer, but not set it to new SoundManager.

Inside the SoundManager::CreateFunction the member m_pDS is being access while "this" is NULL. Which crashes.

Fruny: Ftagn! Ia! Ia! std::time_put_byname! Mglui naflftagn std::codecvt eY'ha-nthlei!,char,mbstate_t>

Yes, but how do I fix that? I tried setting it to a new CSoundManager type, or a new LPDIRECTSOUND8 object, but both don't work. Further, where would I even initialize it? The m_pDS pointer was initialized to NULL in the constructor, so it does have a value to test against. If it wasn't modified on the way to the Create function, then it should return CO_E_NOTINITIALIZED. However, instead, it gives me an unhandled exception error. It is a NULL pointer, rather than an uninitialized one.

Oh wait, wow. I checked with breakpoints, and apparently, it skips completely over the constructor, which initializes my value to NULL. So there isn't a new CSoundManager. Where would I put one? I tried just brute forcing it in order to get a result, by setting m_pDS to NULL right before the if statement, but it still gave me the error.

I'm pretty new to DirectX, so please don't assume I know exactly what you're talking about lol. Please tell me what I need to do in order to fix this, and understanding will come later.
I think you need to show us the LoadSound function
Oh, wow. I apologize, lol. I didn't know that it wasn't there, and I was getting confused signals.

Alright, here it is:

LoadSound()
[spoiler]CSound *LoadSound(char *filename)
{
HRESULT result;

//create local reference to wave data
CSound *wave;

//attempt to load the wave file
result = dsound->Create(&wave, filename);
if (result != DS_OK)
return NULL;

//return the wave
return wave;
}
[/spoiler]

dxaudio.cpp
[spoiler]// Beginning Game Programming
// Chapter 9
// dxaudio.cpp - DirectSound framework header file

#include "dxaudio.h"

CSoundManager *dsound;

int Init_DirectSound(HWND hwnd)
{
HRESULT result;

//create DirectSound manager object
dsound = new CSoundManager();

//initialize DirectSound
result = dsound->Initialize(hwnd, DSSCL_PRIORITY);
if (result != DS_OK)
return 0;

//set the primary buffer format
result = dsound->SetPrimaryBufferFormat(2, 22050, 16);
if (result != DS_OK)
return 0;

//return success
return 1;
}

CSound *LoadSound(char *filename)
{
HRESULT result;

//create local reference to wave data
CSound *wave;

//attempt to load the wave file
result = dsound->Create(&wave, filename);
if (result != DS_OK)
return NULL;

//return the wave
return wave;
}

void PlaySound(CSound *sound)
{
sound->Play();
}

void LoopSound(CSound *sound)
{
sound->Play(0, DSBPLAY_LOOPING);
}

void StopSound(CSound *sound)
{
sound->Stop();
}

[/spoiler]
Well as I see it you are never calling Init_DirectSound...
Another +1 to you lol. I put it in. I skipped over where my book says to put it the first time, apparently. However, it's still giving me the same error. If it gets too convoluted then I'll probably just link both folders and ask what the significant difference is between them.

This topic is closed to new replies.

Advertisement