IDirectSound8* ds = NULL;
IDirectSoundBuffer* dsb = NULL;
byte* sndbuf = NULL;
DWORD sndbuf_size = 0;

HANDLE play_event = NULL;
HANDLE stop_event = NULL;
HANDLE sound_thread = NULL;
UINT sound_thread_id;

unsigned __stdcall sound_thread_func( void* p )
{
	/* ensure that these events are not set */
	ResetEvent( play_event );
	ResetEvent( stop_event );

	while( true )
	{
		DWORD status;
		DWORD res;

		/* Check for play event signal */
		res = WaitForSingleObject( play_event, 0 );
		if( res == WAIT_OBJECT_0 )
		{
			/* Start playing the sound effect, if it isn't already */
			dsb->GetStatus( &status );
			if( status != DSBSTATUS_PLAYING )
				dsb->Play( 0, 0, 0 );

			/* Reset the play event */
			ResetEvent( play_event );

			/* idle time */
			D3DDevice_BlockUntilVerticalBlank();
		}

		/* Check for stop event signal */
		res = WaitForSingleObject( stop_event, 0 );
		if( res == WAIT_OBJECT_0 )
		{
			/* Stop playing the sound effect */
			dsb->StopEx( 0, DSBSTOPEX_IMMEDIATE );
			do
			{
				dsb->GetStatus( &status );
			} while( status == DSBSTATUS_PLAYING );

			/* Reset the stop event */
			ResetEvent( stop_event );

			/* idle time */
			D3DDevice_BlockUntilVerticalBlank();
		}

		/* more idle time */
		D3DDevice_BlockUntilVerticalBlank();
	}
}



HRESULT xboxDownloadDSPImage( IDirectSound8* pDS, char* szDSPFile )
{
	HANDLE hFile;
	DWORD dwSize;
	LPVOID pBuffer = NULL;
	HRESULT hr;
	LPDSEFFECTIMAGEDESC pDesc;
	DSEFFECTIMAGELOC EffectLoc;
	DWORD dwBytesRead;
	BOOL bResult;

	// Open dsp image (i.e. dsstdfx.bin)
	hFile = CreateFile( szDSPFile, 
						GENERIC_READ,
						0,
						NULL,
						OPEN_EXISTING,
						0, 
						NULL );

	if( hFile == INVALID_HANDLE_VALUE )
	{
		//CleanupAndExit( "Error loading dsp image\n" );
		return E_FAIL;
	}

	// Find the size of the image
	dwSize = SetFilePointer( hFile, 0, NULL, FILE_END );
	SetFilePointer( hFile, 0, NULL, FILE_BEGIN );

	// Allocate memory to read the dsp image
	pBuffer = malloc( sizeof( BYTE ) * dwSize );

	// Read in the dsp data
	bResult = ReadFile( hFile,
							 pBuffer,
							 dwSize,
							 &dwBytesRead, 0 );

	if( !bResult )
	{
		//CleanupAndExit( "Error opening dsp image!\n" );
		return E_FAIL;
	}

	// Call the Xbox DirectSound API to download the dsp image
	EffectLoc.dwI3DL2ReverbIndex = DSFX_IMAGELOC_UNUSED;
	EffectLoc.dwCrosstalkIndex = DSFX_IMAGELOC_UNUSED;

	hr = IDirectSound_DownloadEffectsImage( pDS,
									  pBuffer,
									  dwSize,
									  &EffectLoc,
									  &pDesc );

	// Release the file pointers
	free( pBuffer );
	CloseHandle( hFile );

	return hr;
}

HRESULT DSound_CreateAudioBuffer( int nChannels, WORD wSamplesPerSecond, WORD wBitsPerSample,
								  int nSeconds, DWORD dwFlags, DWORD* pdwBufferSize,
								  IDirectSoundBuffer **ppBuffer )
{
	WAVEFORMATEX wfx;
	DSBUFFERDESC dsbdesc;
	HRESULT hr;

	// Initialize the Audio buffer pointer
	if( *ppBuffer )
		(*ppBuffer)->Release();

	// Set up the WAV format structure.  The buffer should be created to suit the needs
	// of what it needs to play, and nothing more.
	::ZeroMemory( &wfx, sizeof( wfx ) );
	wfx.wFormatTag = WAVE_FORMAT_PCM;	// Use the standard PCM format (Pulse Code Modulation)
	wfx.nChannels = nChannels;
	wfx.nSamplesPerSec = wSamplesPerSecond;
	wfx.nBlockAlign = ( wfx.nChannels * wBitsPerSample ) / 8;
	wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
	wfx.wBitsPerSample = wBitsPerSample;

	// Set up the DSBUFFERDESC structure
	::ZeroMemory( &dsbdesc, sizeof( DSBUFFERDESC ) );
	dsbdesc.dwSize = sizeof( DSBUFFERDESC );
	dsbdesc.dwFlags = /*DSBCAPS_CTRLPAN |*/			// Enable 2D panning control 
					  DSBCAPS_CTRLVOLUME |		// Enable volume control
					  DSBCAPS_CTRLFREQUENCY |	// Enable frequency modification
					  /*DSBCAPS_GLOBALFOCUS |*/		// Use global focus (so that the buffer will
												// play even when it's parent window is not
												// in the foreground)
					  dwFlags;					// Additional flags
	dsbdesc.dwBufferBytes = nSeconds * wfx.nAvgBytesPerSec;
	dsbdesc.lpwfxFormat = &wfx;

#if 0
	// Enable 3D capabilities if desired
	if( dwFlags & DSBCAPS_CTRL3D )
	{
		// Remove DSBCAPS_CRTLPAN because that's only for 2D sound stuff
		// and will cause the IDirectSoundBuffer::CreateSoundBuffer function
		// fail miserably.
		dsbdesc.dwFlags &= ~DSBCAPS_CTRLPAN;
		// Set the 3D audio algorithm to the default
		dsbdesc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
	}
#endif

	// Create the secondary audio buffer with an IDirectSoundBuffer interface
	hr = ds->CreateSoundBuffer( &dsbdesc, ppBuffer, NULL );
	if( FAILED( hr ) )
	{
	//	DXErrorA( "DSound_CreateAudioBuffer(): Error creating IDirectSoundBuffer pointer!\n", hr );
		return hr;
	}

	*pdwBufferSize = dsbdesc.dwBufferBytes;

	return hr;
}


	int snd_init()
	{
		/* initialize directsound */
		HRESULT hr = DirectSoundCreate( NULL, &ds, NULL );
		if( FAILED( hr ) )
			return 0;

		IDirectSound_SetCooperativeLevel( ds, NULL, DSSCL_NORMAL );

		/* get the dsp */
		hr = xboxDownloadDSPImage( ds, "D:\\xbox\\dsstdfx.bin" );
		if( FAILED( hr ) )
			return 0;

		/* create basic sound buffer */
		hr = DSound_CreateAudioBuffer( 1, 8000, 8, 1, 0, &sndbuf_size, &dsb );
		if( FAILED( hr ) )
			return 0;

		/* allocate the data buffer */
		sndbuf = (byte*) malloc( sndbuf_size );
		if( !sndbuf )
			return 0;

		/* Point to this data buffer */
		dsb->SetBufferData( sndbuf, sndbuf_size );
#if 0
		/* create playback events */
		play_event = CreateEvent( NULL, TRUE, FALSE, "Play Event" );
		stop_event = CreateEvent( NULL, TRUE, FALSE, "Stop Event" );

		/* create sound playback thread */
		sound_thread = (HANDLE) _beginthreadex( NULL, 0, sound_thread_func, NULL, 0, &sound_thread_id );
#endif
		/* set thread priority? */

		return 1;
	}
