Sign in to follow this  
SnT2k

Need some help with streaming audio in DirectSound

Recommended Posts

I wrote a DirectSound framework, but I couldn't seem to get the streaming part right. It seems that data artifacts are left behind when streaming the buffer (that's why the "noise" which are sounds from the previous data are heard from time-to-time). I've reviewed the code a couple of time sub I couldn't fine anything wrong with it. At first I thought, the problem lies in the way I read Vorbis files, however when I experimented further, it's also evident in Wav files (however, Vorbis files appear to "mess-up" more often) so the problem's prolly not in the way the files are read. Anyway, here're the source to scrutinize: a part in createBuffer that creates the notification positions: notes: notification is at BufferSize/NumberOfDivisions _dwSize = size of the buffer (the standard is 3 seconds long x WaveFormat.nAvgBytesPerSec ) STREAMING_BUFFER_DIVISON = number of divisions/segments in the buffer
		DSBPOSITIONNOTIFY t_dsPosNotify[STREAMING_BUFFER_DIVISION];
		for ( unsigned int i = 0; i < STREAMING_BUFFER_DIVISION; i++ ) {
			t_dsPosNotify[i].dwOffset = _dwSize/STREAMING_BUFFER_DIVISION * i;
			t_dsPosNotify[i].hEventNotify = _eventHandle;
		}
		_dsNotify->SetNotificationPositions( STREAMING_BUFFER_DIVISION, t_dsPosNotify );
		_threadHandle = CreateThread( NULL, NULL, StreamingThread, this, 0, &_dwThreadID );


as for the thread that handles the streaming...
DWORD WINAPI cWSF::cSoundBuffer::StreamingThread( LPVOID lpParam ) {
	cSoundBuffer *SB = (cSoundBuffer*)lpParam;
	MSG msg;
	DWORD dwResult, t_dwSize = (SB->_dwSize/STREAMING_BUFFER_DIVISION);

	while ( SB->_status != ESS_Unloaded ) {
		dwResult = MsgWaitForMultipleObjects( 1, &(SB->_eventHandle), FALSE, INFINITE, QS_ALLEVENTS );
		switch ( dwResult ) {
			case WAIT_OBJECT_0:
				//The looping mechanism is handled by the file readers
				//as opposed to the Static mech where the looping mechanism
				//is handled by the thread
				SB->Read( t_dwSize, SB->_dwCurrentOffset );
				SB->_dwCurrentOffset += t_dwSize;
				SB->_dwCurrentOffset %= SB->_dwSize;
				break;
			case WAIT_OBJECT_0 + 1:
				while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
					if ( msg.message == WM_QUIT )
						return 0;
				break;
		}
	}

	return 0;
}


SB::Read() calls the vorbis or wav reader depending on which was loaded, in this case... we'll use vorbis:
bool cWSF::cSoundBuffer::ReadVorbis( unsigned long size, unsigned long offset ) {
	HRESULT hr;
	ty_BYTE *ptrBuffer;
	DWORD dwLength, dwTotalRead = 0;
	long lSizeRead;
	if ( !size ) {
		//A null size is passed when we have to read everything..
		//We lock the buffer and we don't need the second area since we're sure
		//that we're not gonna overflow (i.e. Exact size )
		if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
					return true;
			} else
				return false;
		do {
			//since there's a big chance that vorbis will randomly return without fully filling the
			//buffer, we'll have to increment the pointer in according to the size and decrement
			//the size left to read for every loop
			lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
			//increment the counter if the read is successful
			if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
		} while ( lSizeRead > 0 );
		//if the total size read is less than desirable... silence the rest of the buffer
		if ( dwTotalRead < dwLength )
			ZeroMemory( ptrBuffer + dwTotalRead, dwLength - dwTotalRead );
		_SoundBuffer->Unlock( (void*)ptrBuffer, dwLength, NULL, NULL );
		//And.. reset the file
		ov_raw_seek( &_VorbisFile, 0 );
	} else {
		if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
					return true;
			} else
				return false;
		do { //the same read routine as above
			lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
			//increment the counter if the read is successful
			if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
		} while ( lSizeRead > 0 );

		if ( dwTotalRead < dwLength ) {
			if ( _uiLoop > 1 ) { //loop counter present, loop and decrement
				_uiLoop--;
				ov_raw_seek( &_VorbisFile, 0 );
				do { //the same read routine
					lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
					if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
				} while ( lSizeRead > 0 );
			} else if ( _uiLoop == 1 ) //the last loop, don't repeat, instead, fill with silence
				ZeroMemory( ptrBuffer, dwLength );
			else { //infinite loop
				ov_raw_seek( &_VorbisFile, 0 );
				do { //the same read routine
					lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
					if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
				} while ( lSizeRead > 0 );
			}
		}
		_SoundBuffer->Unlock( ptrBuffer, dwLength, 0, 0 );
	}
	return true;
}

So basically, when a buffer is created in streaming mode, the notifications are set for a regular period of time then a thread which handles them are created. When the event gets signales, the thread calls on the Read function, passing the variables on the offset and size (if size is 0, it means fill the entire buffer) of where in the buffer to fill. The Read function then handles the file reading. Anyway, my main point is... RELP! :P the full class: NOTE: Dependent on ogg Vorbis SDK error_handler.h is basically a set of error handling routines, remove them if you want but here are the protos just to give an idea (there are 3 levels of error): void report( const char *string, long hr = 0 ); bool warn( const char *string, long errCode = 0 ); bool error( const char *string = "Unknown error", long errCode = 0 ); bool error( const char *fileName, unsigned int lineNumber, char *addInfo = "None", long errCode = 0 ); Sound.h
#define INITGUID
#define DIRECTSOUND_VERSION 0x0900
#include <dsound.h>
#pragma comment(lib, "dsound.lib")

#include "DXUTsound.h"
#include <vorbis/vorbisfile.h>

const unsigned int STREAMING_BUFFER_LENGTH = 3;
const unsigned int STREAMING_BUFFER_DIVISION = 6;

enum eSoundStatus { ESS_Unloaded, ESS_Stop, ESS_Play, ESS_FadeOut, ESS_FadeIn };

class cWSF { //handles the primary sound buffer and the directsound interface
protected:
	IDirectSound8 *_dsMain;
	IDirectSoundBuffer *_dsbPrimary;
	IDirectSound3DListener8 *_ds3DL;

public:
	class cSoundBuffer; //class for the sound buffer

	bool initialize( HWND hwnd, DWORD PrimaryBufferCaps = 0, WAVEFORMATEX *WaveFormat = NULL );
	inline IDirectSound8* getInterface() {
		return _dsMain;
	}
	inline IDirectSound3DListener8* getListener() {
		return _ds3DL;
	}
	~cWSF() {
		if ( _dsbPrimary ) {
			_dsbPrimary->Release();
			_dsbPrimary = NULL;
		}
		if ( _dsMain ) {
			_dsMain->Release();
			_dsMain = NULL;
		}
	}
};

class cWSF::cSoundBuffer {
protected:
	IDirectSoundBuffer8 *_SoundBuffer;
	IDirectSound3DBuffer8 *_3DSoundBuffer;
	IDirectSound8 *_dsMain;
	IDirectSoundNotify8 *_dsNotify;

	WAVEFORMATEX _WaveFormat;

	DWORD _dwSize, _dwCurrentOffset, _dwThreadID, _dwBufferCaps;
	HANDLE _threadHandle, _eventHandle;

	eSoundStatus _status;
	enum { SB_Vorbis, SB_Wav, SB_None } _fileLoaded;

	CWaveFile _WavFile;
	OggVorbis_File _VorbisFile;

	int _iCurrentSection;
	unsigned int _uiLoop, _HTRFLevel;
	bool _bStreaming, _b3D;

	static DWORD WINAPI StreamingThread( LPVOID lpParam );
	static DWORD WINAPI StaticThread( LPVOID lpParam );

	bool (cWSF::cSoundBuffer::*_Read)( unsigned long size, unsigned long offset );

	inline bool Read( unsigned long size = 0, unsigned long offset = 0 ) {
		return ((this->*_Read)( size, offset ));
	}
	inline void restore() {
		_SoundBuffer->Restore();
		if ( _bStreaming ) {
			DWORD t_size = _WaveFormat.nAvgBytesPerSec/(STREAMING_BUFFER_DIVISION/STREAMING_BUFFER_LENGTH);
			Read( t_size , ( _dwCurrentOffset + t_size ) % _dwSize );
		}
		else
			Read();
		return;
	}
	inline void unloadSound() {
		if ( _fileLoaded == SB_Wav )
				_WavFile.Close();
		else if ( _fileLoaded == SB_Vorbis ) {
			ov_clear( &_VorbisFile );
			ZeroMemory( &_VorbisFile, sizeof( _VorbisFile ) );
		}
		_fileLoaded = SB_None;
		_iCurrentSection = 0;
		_dwSize = _dwCurrentOffset = 0;
		return;
	}

	bool ReadWav( unsigned long size, unsigned long offset );
	bool ReadVorbis( unsigned long size, unsigned long offset );

	bool LoadVorbis( wchar_t *fileName );
	bool LoadWav( wchar_t *fileName );
	
public:
	cSoundBuffer();
	void initialize( IDirectSound8 *dsMain, unsigned int HTRFLevel = 0, 
		DWORD dwCaps = DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME, 
		WAVEFORMATEX *WaveFormat = NULL ); //Sets stuff up for creation: Doesn't create anything
	void release( bool bReleaseSound = 1 );

	bool createBuffer( WAVEFORMATEX *WaveFormat, DWORD dwCaps, DWORD dwSize, unsigned int usHTRFLevel );
	
	bool Load( wchar_t *fileName, bool bStreaming );

	void Play( unsigned int uiNumberOfTimes = 0 ); //send a 0 for an infinite loop

	inline void Stop() {
		if ( !_SoundBuffer )
			return;
		_status = ESS_Stop;
		_SoundBuffer->Stop();
	}

	void Rewind() {
		if ( !_SoundBuffer )
			return;
		if ( _bStreaming ) {
			if ( _fileLoaded == SB_Wav )
				_WavFile.ResetFile();
			else if ( _fileLoaded == SB_Vorbis )
				ov_raw_seek( &_VorbisFile, 0 );
		} else
			_SoundBuffer->SetCurrentPosition( 0 );
		return;
	}

	bool IsPlaying() {
		if ( _status == ESS_Stop || _status == ESS_Unloaded )
			return false;
		else
			return true;
	}

	inline void Pan( long Panning ) {
		if ( _SoundBuffer )
			_SoundBuffer->SetPan( Panning );
		return;
	}
	inline void SetVolume( int Percentage ) {
		if ( _SoundBuffer )
			_SoundBuffer->SetVolume( -30*(100 - Percentage) );
		return;
	}
	
	inline IDirectSoundBuffer8* getBufferInterface() {
		return _SoundBuffer;
	}
	inline IDirectSound3DBuffer8* get3DBufferInterface() {
		return _3DSoundBuffer;
	}	
};

Sound.cpp
#include "Sound.h"

#include "error_handler.h"
#include "misc.h"
#include "ks.h"

using namespace errorHandler;


bool cWSF::initialize( HWND hwnd, DWORD PrimaryBufferCaps, WAVEFORMATEX *WaveFormat ) {
	//This init function initializes DirectSound, the Primary sound buffer, and sets the format
	//if no WaveFormat, the default will be used (16-bits, 32,000kHz Stereo)

	HRESULT hr;
	//set-up the main interface
	if( FAILED( hr = DirectSoundCreate8( NULL, &_dsMain, NULL )) )
		return error( __FILE__, __LINE__, "[SOUND] Creating DirectSound Interface", hr );
	if( FAILED( hr = _dsMain->SetCooperativeLevel( hwnd, DSSCL_PRIORITY ) ) )
		return error( __FILE__, __LINE__, "[SOUND] Setting Cooperative Level" );

	//and create the primary sound buffer...
	DSBUFFERDESC t_dsbd;
	initStruct( t_dsbd );
	t_dsbd.dwBufferBytes = 0;
	t_dsbd.dwFlags = DSBCAPS_PRIMARYBUFFER | PrimaryBufferCaps;
	t_dsbd.lpwfxFormat = NULL;

	if ( FAILED( hr = _dsMain->CreateSoundBuffer( &t_dsbd, &_dsbPrimary, NULL ) ) )
		if ( ! error( __FILE__, __LINE__, "[SOUND] Creating Primary Sound Buffer", hr ) )
			return false;

	if ( !WaveFormat ) {
		WAVEFORMATEX t_wfx;
		t_wfx.wFormatTag = WAVE_FORMAT_PCM;
		t_wfx.nChannels = 2;
		t_wfx.nSamplesPerSec = 32000;
		t_wfx.wBitsPerSample = 16;
		t_wfx.nBlockAlign = t_wfx.wBitsPerSample/8 * t_wfx.nChannels;
		t_wfx.nAvgBytesPerSec = t_wfx.nSamplesPerSec * t_wfx.nBlockAlign;
		if ( FAILED( hr = _dsbPrimary->SetFormat( &t_wfx ) ) )
			if ( !error( __FILE__, __LINE__, "[SOUND] Setting Primary Sound buffer format", hr ) )
				return false;
	} else
		if ( FAILED( hr = _dsbPrimary->SetFormat( WaveFormat ) ) )
			if ( !error( __FILE__, __LINE__, "[SOUND] Setting Primary Sound buffer format", hr ) )
				return false;
	//if 3d control is enabled in the primary sound buffer, create
	//a listener interface for it...
	if ( PrimaryBufferCaps & DSBCAPS_CTRL3D )
		if ( FAILED( hr = _dsbPrimary->QueryInterface( IID_IDirectSound3DListener8, (void**)&_ds3DL ) ) )
			warn( "[SOUND] Creating 3D Listener Interface" );
		
	_dsbPrimary->Restore();
	
	//make sure that the primary buffer is silenced or else trash data may be played
	//and we don't want that...
	DWORD t_dwSize;
	ty_BYTE *t_ptrBuffer;
	_dsbPrimary->Lock( 0, 0, (void**)&t_ptrBuffer, &t_dwSize, 0, 0, DSBLOCK_ENTIREBUFFER );
	ZeroMemory( t_ptrBuffer, t_dwSize );
	_dsbPrimary->Unlock( t_ptrBuffer, t_dwSize, 0, 0 );

	//start-up the primary sound buffer
	if ( FAILED( hr = _dsbPrimary->Play( 0, 0, DSBPLAY_LOOPING ) ) )
		if ( !error( __FILE__, __LINE__, "[SOUND] Playing Primary Sound Buffer", hr ) )
			return false;
	return true;
}

DWORD WINAPI cWSF::cSoundBuffer::StreamingThread( LPVOID lpParam ) {
	cSoundBuffer *SB = (cSoundBuffer*)lpParam;
	MSG msg;
	DWORD dwResult, t_dwSize = (SB->_dwSize/STREAMING_BUFFER_DIVISION);

	while ( SB->_status != ESS_Unloaded ) {
		dwResult = MsgWaitForMultipleObjects( 1, &(SB->_eventHandle), FALSE, INFINITE, QS_ALLEVENTS );
		switch ( dwResult ) {
			case WAIT_OBJECT_0:
				//The looping mechanism is handled by the file readers
				//as opposed to the Static mech where the looping mechanism
				//is handled by the thread
				SB->Read( t_dwSize, SB->_dwCurrentOffset );
				SB->_dwCurrentOffset += t_dwSize;
				SB->_dwCurrentOffset %= SB->_dwSize;
				break;
			case WAIT_OBJECT_0 + 1:
				while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
					if ( msg.message == WM_QUIT )
						return 0;
				break;
		}
	}

	return 0;
}
DWORD WINAPI cWSF::cSoundBuffer::StaticThread( LPVOID lpParam ) {
	cSoundBuffer *SB = (cSoundBuffer*)lpParam;
	MSG msg;
	DWORD dwResult;

	while ( SB->_status != ESS_Unloaded ) {
		dwResult = MsgWaitForMultipleObjects( 1, &(SB->_eventHandle), FALSE, INFINITE, QS_ALLEVENTS );
		switch ( dwResult ) {
			case WAIT_OBJECT_0:
				//If a the looping is set to 0 (infinite), it will just pass through the
				//blocks below. Else, if a looping counter is set, it will keep on decrementing
				//everytime the end is encountered (which this event signals) until it reaches the
				//count of 1, then it will stop
				if ( SB->_uiLoop  == 1 )
					SB->_SoundBuffer->Stop();
				else if ( SB->_uiLoop > 1 )
					SB->_uiLoop--;
				break;
			case WAIT_OBJECT_0 + 1:
				while ( PeekMessage( &msg, NULL, 0, 0, PM_REMOVE ) )
					if ( msg.message == WM_QUIT )
						return 0;
				break;
		}
	}
	return 0;
}

bool cWSF::cSoundBuffer::ReadWav( unsigned long size, unsigned long offset ) {
	HRESULT hr;
	ty_BYTE *ptrBuffer;
	DWORD dwLength, dwSizeRead;
	if ( !size ) {
		//A null size is passed when we have to read everything..
		//We lock the buffer and we don't need the second area since we're sure
		//that we're not gonna overflow (i.e. Exact size )
		if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
					return true;
			} else
				return false;
		_WavFile.Read( ptrBuffer, dwLength, &dwSizeRead );
		//if the total size read is less than desirable... silence the rest of the buffer
		if ( dwSizeRead < dwLength )
			ZeroMemory( ptrBuffer + dwSizeRead, dwLength - dwSizeRead );
		_SoundBuffer->Unlock( (void*)ptrBuffer, dwLength, NULL, NULL );
		//And let's not forget to reset the file...
		_WavFile.ResetFile();
	} else {
		if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
					return true;
			} else
				return false;
		_WavFile.Read( ptrBuffer, dwLength, &dwSizeRead );

		if ( dwSizeRead < dwLength ) { 
			//If the WavRead fell short, it means that it already reached the end
			//so we'll have to handle the looping here
			if ( _uiLoop > 1 ) { //if we still have to loop, reset the file
					_uiLoop--;
					_WavFile.ResetFile();
					_WavFile.Read( ptrBuffer + dwSizeRead, dwLength - dwSizeRead, &dwSizeRead );
			} else if ( _uiLoop == 1 ) //we don't need to loop any further
				ZeroMemory( ptrBuffer + dwSizeRead, dwLength - dwSizeRead );
			else { //handle the infinite loop
				_WavFile.ResetFile();
				_WavFile.Read( ptrBuffer + dwSizeRead, dwLength - dwSizeRead, &dwSizeRead );
			}
		}
	}
	_SoundBuffer->Unlock( ptrBuffer, dwLength, 0, 0 );
	return true;
}
bool cWSF::cSoundBuffer::ReadVorbis( unsigned long size, unsigned long offset ) {
	HRESULT hr;
	ty_BYTE *ptrBuffer;
	DWORD dwLength, dwTotalRead = 0;
	long lSizeRead;
	if ( !size ) {
		//A null size is passed when we have to read everything..
		//We lock the buffer and we don't need the second area since we're sure
		//that we're not gonna overflow (i.e. Exact size )
		if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( 0, 0, (void**)&ptrBuffer, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER )) )
					return true;
			} else
				return false;
		do {
			//since there's a big chance that vorbis will randomly return without fully filling the
			//buffer, we'll have to increment the pointer in according to the size and decrement
			//the size left to read for every loop
			lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
			//increment the counter if the read is successful
			if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
		} while ( lSizeRead > 0 );
		//if the total size read is less than desirable... silence the rest of the buffer
		if ( dwTotalRead < dwLength )
			ZeroMemory( ptrBuffer + dwTotalRead, dwLength - dwTotalRead );
		_SoundBuffer->Unlock( (void*)ptrBuffer, dwLength, NULL, NULL );
		//And.. reset the file
		ov_raw_seek( &_VorbisFile, 0 );
	} else {
		if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
			if ( hr == DSERR_BUFFERLOST ) {
				restore();
				if ( FAILED(hr = _SoundBuffer->Lock( offset, size, (void**)&ptrBuffer, &dwLength, NULL, NULL, 0 )) )
					return true;
			} else
				return false;
		do { //the same read routine as above
			lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
			//increment the counter if the read is successful
			if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
		} while ( lSizeRead > 0 );

		if ( dwTotalRead < dwLength ) {
			if ( _uiLoop > 1 ) { //loop counter present, loop and decrement
				_uiLoop--;
				ov_raw_seek( &_VorbisFile, 0 );
				do { //the same read routine
					lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
					if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
				} while ( lSizeRead > 0 );
			} else if ( _uiLoop == 1 ) //the last loop, don't repeat, instead, fill with silence
				ZeroMemory( ptrBuffer, dwLength );
			else { //infinite loop
				ov_raw_seek( &_VorbisFile, 0 );
				do { //the same read routine
					lSizeRead = ov_read( &_VorbisFile, (char*)ptrBuffer + dwTotalRead, dwLength - dwTotalRead, 0, 2, 1, &_iCurrentSection );
					if ( lSizeRead > 0 ) dwTotalRead += lSizeRead;
				} while ( lSizeRead > 0 );
			}
		}
		_SoundBuffer->Unlock( ptrBuffer, dwLength, 0, 0 );
	}
	return true;
}

bool cWSF::cSoundBuffer::LoadVorbis( wchar_t *fileName ) {
	FILE *fp;
	vorbis_info *viInfo;
	fp = _wfopen( fileName, L"rb" );
	if ( ov_open( fp, &_VorbisFile, NULL, 0 ) < 0 ) {
		if ( fp )
			fclose( fp );
		warn( "[SOUND] Unable to open/locate vorbis file" );
		return false;
	}
	viInfo = ov_info( &_VorbisFile, -1 );
	_WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
	_WaveFormat.wBitsPerSample = 16;
	_WaveFormat.nSamplesPerSec = viInfo->rate;
	_WaveFormat.nChannels = viInfo->channels;
	_WaveFormat.nBlockAlign = _WaveFormat.wBitsPerSample/8 * _WaveFormat.nChannels;
	_WaveFormat.nAvgBytesPerSec = _WaveFormat.nBlockAlign * _WaveFormat.nSamplesPerSec;
	_WaveFormat.cbSize = 0;

	_dwSize = ov_raw_total( &_VorbisFile, -1 );
	_Read = ReadVorbis;
	_fileLoaded = SB_Vorbis;
	return true;
}
bool cWSF::cSoundBuffer::LoadWav( wchar_t *fileName ) {
	WAVEFORMATEX t_WavFormat, *t_ptrWavFormat;
	if (!_WavFile.Open( fileName, &t_WavFormat ))
		return false;
	t_ptrWavFormat = _WavFile.GetFormat();

	_WaveFormat.nAvgBytesPerSec = t_ptrWavFormat->nAvgBytesPerSec;
	_WaveFormat.nBlockAlign = t_ptrWavFormat->nBlockAlign;
	_WaveFormat.nChannels = t_ptrWavFormat->nChannels;
	_WaveFormat.nSamplesPerSec = t_ptrWavFormat->nSamplesPerSec;
	_WaveFormat.wBitsPerSample = t_ptrWavFormat->wBitsPerSample;
	_WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
	_dwSize = _WavFile.m_dwSize;

	//assign the "Read" function pointer to use the wav file reader
	_Read = ReadWav;
	_fileLoaded = SB_Wav;
	return true;
}

cWSF::cSoundBuffer::cSoundBuffer() {
	_SoundBuffer = NULL;
	_3DSoundBuffer = NULL;
	_dsMain = NULL;
	_dsNotify = NULL;
	_dwSize = _dwCurrentOffset = _dwThreadID = _dwBufferCaps = 0;
	_threadHandle = _eventHandle = 0;
	_status = ESS_Unloaded;
	_fileLoaded = SB_None;
	_iCurrentSection = 0;
	_uiLoop = _HTRFLevel = 0;
	_bStreaming = _b3D = 0;
	return;
}

void cWSF::cSoundBuffer::initialize( IDirectSound8 *dsMain, unsigned int HTRFLevel, DWORD dwCaps, WAVEFORMATEX *WaveFormat ) {
	_dsMain = dsMain;
	_dwBufferCaps = dwCaps;
	if ( dwCaps & DSBCAPS_CTRL3D ) {
		_HTRFLevel = HTRFLevel;
		_b3D = true;
	} else 
		_b3D = false;
	if ( WaveFormat )
		_WaveFormat = *WaveFormat;
	else {
		_WaveFormat.wFormatTag = WAVE_FORMAT_PCM;
		_WaveFormat.wBitsPerSample = 16;
		_WaveFormat.nSamplesPerSec = 32000;
		_WaveFormat.nBlockAlign = _WaveFormat.wBitsPerSample/8 * _WaveFormat.nChannels;
		_WaveFormat.nAvgBytesPerSec = _WaveFormat.nBlockAlign * _WaveFormat.nSamplesPerSec;
		_WaveFormat.cbSize = 0;
	}
	_WaveFormat.nChannels =  ( _b3D ? 1 : 2 );
	return;
}
void cWSF::cSoundBuffer::release( bool bReleaseSound ) {
	//this releases al DS resources but not all things
	//things that are not reset:
	// _dsMain, _WaveFormat, _dwBufferCaps, _HTRFLevel
	//which are basically the parameters called upon cSoundBuffer::initialize.
	//We did this so that we don't need to call cSoundBuffer::initialize again
	//when we want to reuse this object.
	if ( bReleaseSound ) 
		//in some cases, we want to release DirectSound without releasing the soundFile
		unloadSound();
	if ( _dsNotify ) {
		PostThreadMessage( _dwThreadID, WM_QUIT, 0, 0 );
		WaitForSingleObject( _threadHandle, 5 );
		CloseHandle( _threadHandle );
		CloseHandle( _eventHandle );
		_dsNotify->Release();
		_dsNotify = NULL;
		_threadHandle = _eventHandle = 0;
		_dwThreadID = 0;
	}
	if ( _3DSoundBuffer ) {
		_3DSoundBuffer->Release();
		_3DSoundBuffer = NULL;
	}
	if ( _SoundBuffer ) {
		_SoundBuffer->Stop();
		_SoundBuffer->Release();
		_SoundBuffer = NULL;
	}	
	_uiLoop = 0;
	_status = ESS_Unloaded;
}

bool cWSF::cSoundBuffer::createBuffer( WAVEFORMATEX *WaveFormat, DWORD dwCaps, DWORD dwSize, unsigned int usHTRFLevel ) {
	IDirectSoundBuffer *t_dsBuffer;
	DSBUFFERDESC t_dsBufferDesc;
	initStruct( t_dsBufferDesc );
	t_dsBufferDesc.dwBufferBytes = dwSize;
	t_dsBufferDesc.dwFlags = dwCaps;
	t_dsBufferDesc.dwReserved = 0;
	t_dsBufferDesc.lpwfxFormat = WaveFormat;

	if ( dwCaps & DSBCAPS_CTRL3D ) { //set the 3d algorithm if 3d is enabled
		_b3D = true;
		if ( usHTRFLevel == 1 ) 
			t_dsBufferDesc.guid3DAlgorithm = DS3DALG_HRTF_LIGHT;
		else if (usHTRFLevel == 2 )
			t_dsBufferDesc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
		else
			t_dsBufferDesc.guid3DAlgorithm = DS3DALG_DEFAULT;
	} else
		t_dsBufferDesc.guid3DAlgorithm = GUID_NULL;
	HRESULT hr;
	//We get the sound buffer interface...
	if ( FAILED(hr = _dsMain->CreateSoundBuffer( &t_dsBufferDesc, &t_dsBuffer, 0 )) ) {
		report( "[SOUND] Error in creating a sound buffer", hr );
		return false;
	}
	//then we get the DirectSound8 interface
	if ( FAILED(hr = t_dsBuffer->QueryInterface( IID_IDirectSoundBuffer8, (void**)&_SoundBuffer )) ) {
		report( "[SOUND] Error in Querying for SoundBuffer8 interface" );
		return false;
	}
	//And get the 3d interface is the 3d switch is on...
	if ( _b3D )
		if ( FAILED(hr = _SoundBuffer->QueryInterface( IID_IDirectSound3DBuffer8, (void **) _3DSoundBuffer )) ) {
			report("[SOUND] Error in Querying for 3D Buffer inteface" );
			return false;
		}
	return true;
}
bool cWSF::cSoundBuffer::Load( wchar_t *fileName, bool bStreaming ) {
	if ( !_dsMain )
		return warn( "[SOUND] cSoundBuffer::Load called without initializing" );

	//first we see if the sound buffer is already loaded
	//then we try to load the file as a wavefile, if we can't,
	//we'll try loading it as vorbis.. if we still can't....
	//bail out.
	if ( _status != ESS_Unloaded ) {
		//if it is, and we wish to replace it with a static buffer, release the previous buffer
		//in order to create a new one.
		if ( !(bStreaming & _bStreaming) ) {
			release();
			if ( !LoadWav( fileName ) )
				if ( !LoadVorbis( fileName ) )
					return warn( "[SOUND FILE] Unable to load/locate specified sound" );
		} else {
			//else, the previous buffer is streaming and we wish to replace it
			//with another streaming buffer, so we'll only clear the sound buffer
			//by filling it with silence and release the sound file
			
			//begin be releasing the loaded sound file
			unloadSound();

			//next we clear the sound buffer (make sure it's stopped first)
			_SoundBuffer->Restore();
			_SoundBuffer->Stop();
			ty_BYTE *ptrStart;
			DWORD dwLength;
			_SoundBuffer->Lock( 0, 0, (void**)&ptrStart, &dwLength, 0, 0, DSBLOCK_ENTIREBUFFER );
			ZeroMemory( ptrStart, dwLength );
			_SoundBuffer->Unlock( ptrStart, dwLength, 0, 0 );
			DWORD t_dwBPS = _WaveFormat.nAvgBytesPerSec; //temporary variable to hold the current sound BPS
			if ( !LoadWav( fileName ) )
				if ( !LoadVorbis( fileName ) )
				return warn( "[SOUND FILE] Unable to load/locate specified sound" );

			//check if we have the same bps as the previous soundfile
			//if yes, read it and return (finished!); else, we release the DirectSound resources
			//and continue on like the rest
			if ( _WaveFormat.nAvgBytesPerSec != t_dwBPS )
				release( 0 );
			else
				return Read();
		}
	} else
		if ( !LoadWav( fileName ) )
			if ( !LoadVorbis( fileName ) )
				return warn( "[SOUND FILE] Unable to load/locate specified sound" );
	
	//if we're handling streaming data, make sure that the buffer length is
	//only STREAMING_BUFFER_LENGTH seconds
	if ( bStreaming )
		_dwSize = _WaveFormat.nAvgBytesPerSec * STREAMING_BUFFER_LENGTH;
	//Then create the buffer
	if ( !createBuffer( &_WaveFormat, _dwBufferCaps | DSBCAPS_CTRLPOSITIONNOTIFY, _dwSize, _HTRFLevel ) )
		return false;

	//then we set the notifications
	HRESULT hr;
	//get the dsnotify interface
	if ( FAILED(hr = _SoundBuffer->QueryInterface( IID_IDirectSoundNotify8, (void**)&_dsNotify )) ) {
		release();
		return false;
	}
	//create the event for the notification
	_eventHandle = CreateEvent( NULL, FALSE, FALSE, NULL );
	if ( bStreaming ) {
		//for streaming, we'll do it every
		// _dwSize/STREAMING_BUFFER_DIVISION seconds
		DSBPOSITIONNOTIFY t_dsPosNotify[STREAMING_BUFFER_DIVISION];
		for ( unsigned int i = 0; i < STREAMING_BUFFER_DIVISION; i++ ) {
			t_dsPosNotify[i].dwOffset = _dwSize/STREAMING_BUFFER_DIVISION * i;
			t_dsPosNotify[i].hEventNotify = _eventHandle;
		}
		_dsNotify->SetNotificationPositions( STREAMING_BUFFER_DIVISION, t_dsPosNotify );
		_threadHandle = CreateThread( NULL, NULL, StreamingThread, this, 0, &_dwThreadID );
	} else {
		//for static, we'll do it every end of the buffer
		DSBPOSITIONNOTIFY t_dsPosNotify;
		t_dsPosNotify.dwOffset = _dwSize;
		t_dsPosNotify.hEventNotify = _eventHandle;
		_dsNotify->SetNotificationPositions( 1, &t_dsPosNotify );
		_threadHandle = CreateThread( NULL, NULL, StaticThread, this, 0, &_dwThreadID );
	}
	_bStreaming = bStreaming;
	_status = ESS_Stop;
	return Read();
}

void cWSF::cSoundBuffer::Play( unsigned int uiNumberOfTimes )  { //0 for infinite loop
	if ( !_SoundBuffer )
		return;
	_uiLoop = uiNumberOfTimes;
	HRESULT hr;
	if ( FAILED( hr = _SoundBuffer->Play( 0, 0, DSBPLAY_LOOPING )) ) {
		if ( hr = DSERR_BUFFERLOST ) {
			restore();
			_SoundBuffer->Play( 0, 0, DSBPLAY_LOOPING );
		} else
			warn( "[SOUND] Unable to play sound", hr );
	} else
		_status = ESS_Play;
	return;
}

DXUTSound in the meanwhile is the same as the stuff supplied in the SDK except that I stripped everything except the WAV reader (which I'm too lazy to implement myself... but that's another story..) and replaced the error handlers with my own. Anyway, here are the contents just in case you want to know (though unecessary): DXUTsound.h:
//-----------------------------------------------------------------------------
// File: DXUTsound.h
//
// Copyright (c) Microsoft Corp. All rights reserved.
//-----------------------------------------------------------------------------
#ifndef DXUTSOUND_H
#define DXUTSOUND_H


class CWaveFile;



//-----------------------------------------------------------------------------
// 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;
    BOOL          m_bIsReadingFromMemory;
    BYTE*         m_pbData;
    BYTE*         m_pbDataCur;
    ULONG         m_ulDataSize;
    CHAR*         m_pResourceBuffer;

protected:
    HRESULT ReadMMIO();

public:
    CWaveFile();
    ~CWaveFile();

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

    bool Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead );

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


#endif // DXUTSOUND_H


DXUTsound.cpp
#include <windows.h>
#include <mmsystem.h>
#include <mmreg.h>

#pragma comment( lib, "winmm.lib" )

#include "DXUTsound.h"
#include "error_handler.h"

using namespace errorHandler;


#ifndef SAFE_DELETE
    #define SAFE_DELETE(p)       { if(p) { delete (p);     (p)=NULL; } }
#endif    
#ifndef SAFE_DELETE_ARRAY
    #define SAFE_DELETE_ARRAY(p) { if(p) { delete[] (p);   (p)=NULL; } }
#endif    
#ifndef SAFE_RELEASE
    #define SAFE_RELEASE(p)      { if(p) { (p)->Release(); (p)=NULL; } }
#endif

//-----------------------------------------------------------------------------
// 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
//-----------------------------------------------------------------------------
bool CWaveFile::Open( LPWSTR strFileName, WAVEFORMATEX* pwfx )
{
    HRESULT hr;

    m_bIsReadingFromMemory = FALSE;

	if( strFileName == NULL ) {
		warn( "[WavFile] Invalid filename supplied" );
        return false;
	}
    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, L"WAVE" ) ) )
        {
			if( NULL == ( hResInfo = FindResource( NULL, strFileName, L"WAV" ) ) ) {
				report( "[WavFile] Cannot Load as Resource" );
                return false;
			};
        }

        if( NULL == ( hResData = LoadResource( NULL, hResInfo ) ) ) {
				report( "[WavFile] Cannot Load as Resource" );
                return false;
			};

        if( 0 == ( dwSize = SizeofResource( NULL, hResInfo ) ) )  {
				report( "[WavFile] Cannot Load the Size of the Resource" );
                return false;
			};

        if( NULL == ( pvRes = LockResource( hResData ) ) ) {
				report( "[WavFile] Cannot lock Resource" );
                return false;
			};

        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 );
		report( "[WavFile] Non-Wav file suppplied" );
        return false;
    }

	if( FAILED( hr = ResetFile() ) )
        return warn( "[WavFile] Failed to Reset File", hr );

    // After the reset, the size of the wav file is m_ck.cksize so store it now
    m_dwSize = m_ck.cksize;

    return true;
}


//-----------------------------------------------------------------------------
// Name: CWaveFile::OpenFromMemory()
// Desc: copy data to CWaveFile member variable from memory
//-----------------------------------------------------------------------------
bool 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;    
    
    return true;
}
//-----------------------------------------------------------------------------
// 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 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 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 E_FAIL;

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

    // Read the 'fmt ' chunk into <pcmWaveFormat>.
    if( mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat, 
                  sizeof(pcmWaveFormat)) != sizeof(pcmWaveFormat) )
        return 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 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 E_FAIL;

        m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];
        if( NULL == m_pwfx )
            return 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 E_FAIL;
        }
    }

    // Ascend the input file out of the 'fmt ' chunk.
    if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )
    {
        SAFE_DELETE( m_pwfx );
        return 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 
//-----------------------------------------------------------------------------
bool CWaveFile::ResetFile()
{
    if( m_bIsReadingFromMemory )
    {
        m_pbDataCur = m_pbData;
    }
    else 
    {
        if( m_hmmio == NULL )
            return false;

            // Seek to the data
            if( -1 == mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),
                            SEEK_SET ) )
                return warn( "[WavFile] Unable to seek" );

            // 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 warn( "[WavFile] Unable to find data chunk" );
    }
    
    return true;
}


//-----------------------------------------------------------------------------
// 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.
//-----------------------------------------------------------------------------
bool CWaveFile::Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )
{
    if( m_bIsReadingFromMemory )
    {
        if( m_pbDataCur == NULL )
            return false;
        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 true;
    }
    else 
    {
        MMIOINFO mmioinfoIn; // current status of m_hmmio

        if( m_hmmio == NULL )
            return false;
        if( pBuffer == NULL || pdwSizeRead == NULL )
            return false;

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

        if( 0 != mmioGetInfo( m_hmmio, &mmioinfoIn, 0 ) )
            return warn( "[WavFile] Unable to get mmio info" );
                
        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 warn( "[WavFile] Unable to advance" );

                if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )
                    return warn( "[WavFile] Unable to \"EndRead\"" );
            }

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

        if( 0 != mmioSetInfo( m_hmmio, &mmioinfoIn, 0 ) )
            return warn( "[WavFile] Unable to set info" );

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

        return true;
    }
}


//-----------------------------------------------------------------------------
// Name: CWaveFile::Close()
// Desc: Closes the wave file 
//-----------------------------------------------------------------------------
bool CWaveFile::Close()
{
    mmioClose( m_hmmio, 0 );
    m_hmmio = NULL;
    SAFE_DELETE_ARRAY( m_pResourceBuffer );

    return true;
}


P.S. just for those who are wondering why I'm not using the sample framework provided in DirectX... I need to implement OGG Vorbis and Wav

Share this post


Link to post
Share on other sites
I'm too lazy to look through all that code, but I wrote a Music class that streams Ogg Vorbis files and a Sound class that plays Wav files (it doesn't stream wav files though, because I figured that a wav file so long you need to stream it takes up way too much space. If you want to stream wave files however, you can probably easily implement from the Ogg Vorbis streaming code.). If you'd like the code I can upload and link to the files.

Share this post


Link to post
Share on other sites
I had a few of those problems when I was writing a sound class, artifacts at the end and artifacts in between depending on when the files were played. It was really a pain in the butt, but if you'd like I'll send you a link to my working sound class. Maybe you can find your answers in there.

One of the things that was creating a lot of the artifacts for me was multithreading and critical zones which I don't seem to see in your code (I may be wrong). I ended up replacing the thread with an update function that processed new updates every frame. You really don't lose any preformance anyhow.

I source I got for my sound class also uses callbacks for buffered vorbis files in memory, speeds things up a bit for smaller sounds that get played a lot.

Share this post


Link to post
Share on other sites
Yeah, for smaller sounds (if the streaming flag is passed as false) it works fine (because well, we don't need to update it too) and it also works fine on the first round of the streaming... and there's only one thread that has the power to access the buffer, to the case of the critical section problem is out.

Anyway, load_bitmap_file, the code would be appreciated

Share this post


Link to post
Share on other sites
Source here

Some notes:

- "Sound.h/.cpp" is for the (nonstreaming) wav files, "Music.h/.cpp" is for the streaming ogg vorbis files. EDIT: As I think I said before, if you need to stream the wav files as well, the ogg vorbis streaming code should work with the wav files too with a little modification.

- With my streaming ogg vorbis code, only one ogg can be played at a time. When multiple oggs play at once, one usually plays super fast and the other doesn't update correctly, in other words, messed up. I have not figured out why yet. If you or anyone else can find out why, I'd be much obliged. If this limitation is a problem, you should probably ask PumpkinPieman for his source.

- I used a #pragma command in my Music.h to link the ogg vorbis libraries. I'm not sure if this is a Visual C++ specific command. If it is, delete those lines and link them however your compiler wants it.

- I have not learned how to use threads yet, so you have to call Update() every frame for the streaming oggs.

- My wav code uses the CWave wrapper class Microsoft wrote and included in their DirectX SDK. That's what the dsutil.h/.cpp and the dxutil.h/.cpp files are for.

- This code is from the engine I'm working it which I have dubbed "Nonexistent", hence the sticking-of-all-the-code in the nxt namespace.

- Do whatever you want with the code.

- It was really annoying writing the code. [grin]

Hope it helps.

Share this post


Link to post
Share on other sites
Finally solved my problem... it's something with the way I calculated the notification size... which should go like this:

//for streaming, we'll do it every
// _dwSize/STREAMING_BUFFER_DIVISION seconds
DSBPOSITIONNOTIFY t_dsPosNotify[STREAMING_BUFFER_DIVISION];
DWORD dwNotifySize = _dwSize / STREAMING_BUFFER_DIVISION;
dwNotifySize -= dwNotifySize % _WaveFormat.nBlockAlign;

for ( unsigned int i = 0; i < STREAMING_BUFFER_DIVISION; i++ ) {
t_dsPosNotify[i].dwOffset = (dwNotifySize * i) + dwNotifySize - 1;
t_dsPosNotify[i].hEventNotify = _eventHandle;
}



Anyway, thanks for the help guys..

Share this post


Link to post
Share on other sites

Create an account or sign in to comment

You need to be a member in order to leave a comment

Create an account

Sign up for a new account in our community. It's easy!

Register a new account

Sign in

Already have an account? Sign in here.

Sign In Now

Sign in to follow this