How to load a sound?

Started by
13 comments, last by bartiss 20 years, 1 month ago
I know it sounds trivial but I started learning DirectSound an hour ago Initialization is complete, primary and secondary buffers are ready and here I hit the wall. How to load a small wave file and put it into the buffer? Is there a method to do this? (just like loading bitmaps onto surfaces) Or do I have to create my own function from scratch? Anyone got a "LoadSound()" function? Or anybody knows where to get it? Thanks
Advertisement
What version of DirectX are you using? If you''re using 8 you can use this (from the tutorial on this site):
char SearchPath[MAX_PATH];IDirectMusicSegment8* pSegment = NULL;CoCreateInstance(CLSID_IDirectMusicSegment, NULL, CLSTX_INPROC, IID_IDirectMusicSegment8, (void**)&pSegment);GetCurrentDirectory(MAX_PATH, SearchPath);// g_pMusicLoader: Predefined IDirectMusicLoader8*g_pMusicLoader->SetSearchDirectory(GUID_DirectMusicAllTypes, SearchPath, FALSE);g_pMusicLoader->LoadObjectFromFile(CLSID_DirectMusicSegment, IID_IDirectMusicSebment8, Filename, (void**)&pSegment);// g_pPerformance: Predefined IDirectMusicPerformance8*pSegment->Download(g_pPerformance);g_pPerformance->PlaySegmentEx(pSegment, NULL, NULL, 0, 0, NULL, NULL, NULL);// To stopg_pPerformance->StopEx(pSegment, 0, 0);


This is just a modified version of the DirectAudio8 tutorial here on GameDev.

/*
I use DirectX 8.1 and C++ (Microsoft Visual C++ 6.0 Professional edition)
*/
You should check out CSoundManager class, and use:
CSoundManager::CreateFromMemory(), and FillBufferWithSound()
functions...
Bulma
Yes, have a look at the dsutil.h and dsutil.cpp files in DXSDK\Samples\C++\Common\Include
Use a CSoundManager class to create CSound objects. You specify a filename on creation so everything is already done Unless you are doing this as a learning excercise in which case you will learn next to nothing using this method.
i ripped the stuff out of the 3d directsound example and made a class out of it, its quite messy looking but works nicely

you need to include string header
class DWave{private:	LPDIRECTSOUND8 m_pDS;    WAVEFORMATEX* m_pwfx;            HMMIO         m_hmmio;           MMCKINFO      m_ck;              MMCKINFO      m_ckRiff;          MMIOINFO      m_mmioinfoOut;    DWORD         m_dwFlags;    BYTE*         m_pbData;    BYTE*         m_pbDataCur;    ULONG         m_ulDataSize;    CHAR*         m_pResourceBuffer;	void Open( char strFileName[], WAVEFORMATEX* pwfx, DWORD dwFlags )	{		m_dwFlags = dwFlags;				if( m_dwFlags == 1 )		{			if(m_pwfx)			{ 				delete[] m_pwfx;				m_pwfx=NULL;			}			m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF | MMIO_READ );						if( NULL == m_hmmio )			{				DWORD   dwSize=0;				VOID*   pvRes=NULL; 				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 );			}			ReadMMIO();			ResetFile();			m_ck.cksize = m_ck.cksize;		}		else		{			m_hmmio = mmioOpen( strFileName, NULL, MMIO_ALLOCBUF  | MMIO_READWRITE | MMIO_CREATE );			WriteMMIO( pwfx );			ResetFile();     		}	}	void ReadMMIO()	{		MMCKINFO        ckIn;          		PCMWAVEFORMAT   pcmWaveFormat;    		m_pwfx = NULL;		mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 );		ckIn.ckid = mmioFOURCC('f', 'm', 't', ' ');		mmioDescend( m_hmmio, &ckIn, &m_ckRiff, MMIO_FINDCHUNK ) ;		mmioRead( m_hmmio, (HPSTR) &pcmWaveFormat, sizeof(pcmWaveFormat));       		if( pcmWaveFormat.wf.wFormatTag == WAVE_FORMAT_PCM )		{			m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) ];			memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );			m_pwfx->cbSize = 0;		}		else		{			WORD cbExtraBytes = 0L;			mmioRead( m_hmmio, (CHAR*)&cbExtraBytes, sizeof(WORD)) ;			m_pwfx = (WAVEFORMATEX*)new CHAR[ sizeof(WAVEFORMATEX) + cbExtraBytes ];			memcpy( m_pwfx, &pcmWaveFormat, sizeof(pcmWaveFormat) );			m_pwfx->cbSize = cbExtraBytes; 			if( mmioRead( m_hmmio, (CHAR*)(((BYTE*)&(m_pwfx->cbSize))+sizeof(WORD)), cbExtraBytes ) != cbExtraBytes )			{				if(m_pwfx) 				{ 					delete m_pwfx;					m_pwfx=NULL; 				} 			} 		}		if( 0 != mmioAscend( m_hmmio, &ckIn, 0 ) )		{			if(m_pwfx)			{ 				delete m_pwfx; 				m_pwfx=NULL; 			}		}	}	void ResetFile()	{		if( m_dwFlags == 1 )		{			mmioSeek( m_hmmio, m_ckRiff.dwDataOffset + sizeof(FOURCC),SEEK_SET );			m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');			mmioDescend( m_hmmio, &m_ck, &m_ckRiff, MMIO_FINDCHUNK ) ;		}		else		{			m_ck.ckid = mmioFOURCC('d', 'a', 't', 'a');			m_ck.cksize = 0;			mmioCreateChunk( m_hmmio, &m_ck, 0 ) ;			mmioGetInfo( m_hmmio, &m_mmioinfoOut, 0 );		}	}	void Read( BYTE* pBuffer, DWORD dwSizeToRead, DWORD* pdwSizeRead )	{		MMIOINFO mmioinfoIn; 		if( pdwSizeRead != NULL )			*pdwSizeRead = 0;		mmioGetInfo( m_hmmio, &mmioinfoIn, 0 );                  		UINT cbDataIn = dwSizeToRead;        		if( cbDataIn > m_ck.cksize ) 			cbDataIn = m_ck.cksize;       		m_ck.cksize -= cbDataIn;    		for( DWORD cT = 0; cT < cbDataIn; cT++ )		{			if( mmioinfoIn.pchNext == mmioinfoIn.pchEndRead )				mmioAdvance( m_hmmio, &mmioinfoIn, MMIO_READ );			*((BYTE*)pBuffer+cT) = *((BYTE*)mmioinfoIn.pchNext);			mmioinfoIn.pchNext++;		}		mmioSetInfo( m_hmmio, &mmioinfoIn, 0 );           		if( pdwSizeRead != NULL )			*pdwSizeRead = cbDataIn;	}	void Close()	{		if( m_dwFlags == 1 )		{			mmioClose( m_hmmio, 0 );			m_hmmio = NULL;   			if(m_pResourceBuffer) 			{ 				delete[] m_pResourceBuffer; 				m_pResourceBuffer=NULL; 			}  		}		else		{			m_mmioinfoOut.dwFlags |= MMIO_DIRTY;			mmioSetInfo( m_hmmio, &m_mmioinfoOut, 0 );			mmioAscend( m_hmmio, &m_ck, 0 );			mmioAscend( m_hmmio, &m_ckRiff, 0 ) ;			mmioSeek( m_hmmio, 0, SEEK_SET );			(INT)mmioDescend( m_hmmio, &m_ckRiff, NULL, 0 );			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 ); 			}    			mmioAscend( m_hmmio, &m_ckRiff, 0 );			mmioClose( m_hmmio, 0 );			m_hmmio = NULL;		} 	}	void WriteMMIO( WAVEFORMATEX *pwfxDest )	{		DWORD    dwFactChunk; 		MMCKINFO ckOut1;		dwFactChunk = (DWORD)-1;		m_ckRiff.fccType = mmioFOURCC('W', 'A', 'V', 'E');       		m_ckRiff.cksize = 0;		mmioCreateChunk( m_hmmio, &m_ckRiff, MMIO_CREATERIFF ) ;       		m_ck.ckid = mmioFOURCC('f', 'm', 't', ' ');		m_ck.cksize = sizeof(PCMWAVEFORMAT);   		mmioCreateChunk( m_hmmio, &m_ck, 0 );       		if( pwfxDest->wFormatTag == WAVE_FORMAT_PCM )			 mmioWrite( m_hmmio, (HPSTR) pwfxDest, sizeof(PCMWAVEFORMAT)); 		else         			(UINT)mmioWrite( m_hmmio, (HPSTR) pwfxDest, sizeof(*pwfxDest) + pwfxDest->cbSize );  		mmioAscend( m_hmmio, &m_ck, 0 ) ;		ckOut1.ckid = mmioFOURCC('f', 'a', 'c', 't');		ckOut1.cksize = 0;		mmioCreateChunk( m_hmmio, &ckOut1, 0 );       		mmioWrite( m_hmmio, (HPSTR)&dwFactChunk, sizeof(dwFactChunk));		mmioAscend( m_hmmio, &ckOut1, 0 );           	}    LPDIRECTSOUNDBUFFER m_apDSBuffer;    DWORD m_dwDSBufferSize;    DWORD m_dwCreationFlags;	void CSoundA(char filename[] , GUID guid3DAlgorithm ,DWORD dwFlags = 0)	{		m_pwfx    = NULL;		m_hmmio   = NULL;		m_pResourceBuffer = NULL;   		Open( filename, NULL, 1 );		DSBUFFERDESC dsbd;		ZeroMemory( &dsbd, sizeof(DSBUFFERDESC) );		dsbd.dwSize          = sizeof(DSBUFFERDESC);		dsbd.dwFlags         = dwFlags;		dsbd.dwBufferBytes   = m_ck.cksize;		dsbd.guid3DAlgorithm = guid3DAlgorithm;		dsbd.lpwfxFormat     = m_pwfx;		m_pDS->CreateSoundBuffer( &dsbd, &m_apDSBuffer, NULL );		m_dwDSBufferSize = m_ck.cksize;		m_dwCreationFlags = dwFlags;		FillBufferWithSound( m_apDSBuffer, FALSE );		Close();	}	void FillBufferWithSound( LPDIRECTSOUNDBUFFER pDSB, BOOL bRepeatWavIfBufferLarger )	{		VOID*   pDSLockedBuffer      = NULL; 		DWORD   dwDSLockedBufferSize = 0;   		DWORD   dwWavDataRead        = 0;   		RestoreBuffer( pDSB, NULL );		pDSB->Lock( 0, m_dwDSBufferSize, &pDSLockedBuffer, &dwDSLockedBufferSize,   NULL, NULL, 0L );		ResetFile();		Read( (BYTE*) pDSLockedBuffer,  dwDSLockedBufferSize,   &dwWavDataRead ) ;		if( dwWavDataRead == 0 )			FillMemory( (BYTE*) pDSLockedBuffer, dwDSLockedBufferSize, (BYTE)(m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );		else if( dwWavDataRead < dwDSLockedBufferSize )		{			if( bRepeatWavIfBufferLarger )			{       				DWORD dwReadSoFar = dwWavDataRead;   				while( dwReadSoFar < dwDSLockedBufferSize )				{  					ResetFile();					Read( (BYTE*)pDSLockedBuffer + dwReadSoFar, dwDSLockedBufferSize - dwReadSoFar, &dwWavDataRead );					dwReadSoFar += dwWavDataRead;				} 			}			else				FillMemory( (BYTE*) pDSLockedBuffer + dwWavDataRead, dwDSLockedBufferSize - dwWavDataRead, (BYTE)(m_pwfx->wBitsPerSample == 8 ? 128 : 0 ) );		}		pDSB->Unlock( pDSLockedBuffer, dwDSLockedBufferSize, NULL, 0 );	}	void RestoreBuffer( LPDIRECTSOUNDBUFFER pDSB, BOOL* pbWasRestored )	{		HRESULT hr;		if( pbWasRestored )			*pbWasRestored = FALSE;		DWORD dwStatus;		pDSB->GetStatus( &dwStatus );    		if( dwStatus & DSBSTATUS_BUFFERLOST )		{			do 			{				hr = pDSB->Restore();				if( hr == DSERR_BUFFERLOST )					Sleep( 10 );			}			while( ( pDSB->Restore() ) == DSERR_BUFFERLOST );			if( pbWasRestored != NULL )				*pbWasRestored = TRUE;		}	}	HRESULT Get3DBufferInterface( DWORD dwIndex, LPDIRECTSOUND3DBUFFER* ppDS3DBuffer )	{		*ppDS3DBuffer = NULL;		return m_apDSBuffer->QueryInterface( IID_IDirectSound3DBuffer, (VOID**)ppDS3DBuffer );	}	LPDIRECTSOUND3DBUFFER   g_pDS3DBuffer;   	DS3DBUFFER              g_dsBufferParams;               	bool threeDFlag;		long volume;	float posX, posY, posZ;	float minDist;	float maxDist;	float rolloff;public:	~DWave()	{		if(m_apDSBuffer)		{ 			m_apDSBuffer->Release();			m_apDSBuffer=NULL; 		}				if(g_pDS3DBuffer) 		{ 			g_pDS3DBuffer->Release(); 			g_pDS3DBuffer=NULL; 		}	}		void create(LPDIRECTSOUND8 dsDevice,string filename, int threeDimensionLevel=0)	{		m_pDS=dsDevice;		LPSTR cfilename =strdup(filename.c_str());		switch (threeDimensionLevel) {			case 0:				CSoundA(cfilename,GUID_NULL,DSBCAPS_CTRLVOLUME);				threeDFlag=false;				break;						case 1:				CSoundA(cfilename,GUID_NULL,DSBCAPS_CTRL3D|DSBCAPS_CTRLVOLUME);				break;						case 2:				CSoundA(cfilename,DS3DALG_NO_VIRTUALIZATION,DSBCAPS_CTRL3D|DSBCAPS_CTRLVOLUME);				break;						case 3:				CSoundA(cfilename,DS3DALG_HRTF_LIGHT,DSBCAPS_CTRL3D|DSBCAPS_CTRLVOLUME);				break;						case 4:				CSoundA(cfilename,DS3DALG_HRTF_FULL,DSBCAPS_CTRL3D|DSBCAPS_CTRLVOLUME);				break;		}					if (threeDimensionLevel!=0)		{			Get3DBufferInterface( 0, &g_pDS3DBuffer );			g_dsBufferParams.dwSize = sizeof(DS3DBUFFER);			g_pDS3DBuffer->GetAllParameters( &g_dsBufferParams );			g_dsBufferParams.dwMode = DS3DMODE_HEADRELATIVE;			g_pDS3DBuffer->SetAllParameters( &g_dsBufferParams, DS3D_IMMEDIATE );						DSBCAPS dsbcaps;			ZeroMemory( &dsbcaps, sizeof(DSBCAPS) );			dsbcaps.dwSize = sizeof(DSBCAPS);						m_apDSBuffer->GetCaps( &dsbcaps );			threeDFlag=true;		}		threeDFlag=false;		setMinDistance(1);		setMaxDistance(1);		setPosition(0,0,0);		setVolume(0);	}	void setPosition(float x, float y, float z)	{		if (threeDFlag)			g_pDS3DBuffer->SetPosition(x ,y,z,DS3D_IMMEDIATE);	}		void setMinDistance(float value)	{		if (threeDFlag)			g_pDS3DBuffer->SetMinDistance(value,DS3D_IMMEDIATE);	}	void setMaxDistance(float value)	{		if (threeDFlag)			g_pDS3DBuffer->SetMaxDistance(value,DS3D_IMMEDIATE);	}	void setVolume(int value)	{		m_apDSBuffer ->SetVolume(volume);	}	void play()	{		m_apDSBuffer ->Stop();		m_apDSBuffer ->SetCurrentPosition(0);		m_apDSBuffer->Play(0,0,0 );	}	void stop()	{		m_apDSBuffer ->Stop();		m_apDSBuffer ->SetCurrentPosition(0);	}	bool isPlaying()	{		bool answer=false;		DWORD dwStatus = 0;		m_apDSBuffer->GetStatus( &dwStatus );		answer |= ( ( dwStatus & DSBSTATUS_PLAYING ) != 0 );		return answer;	}};


basically to use it is:
//initialise
DWave sndGunshot;

//load
sndGunshot.create(dsDevice,"gunshot.wav",0);

//play
sndGunshot.play();


The 0 at the end represents the 3d sound level,
0 is none, 1 -4 , 4 being slowest but best 3d level.

ive got other functions that set the position etc

.............dammmit programmer16 thats direct music stop getting mixed up!


[edited by - johnnyBravo on March 17, 2004 6:39:04 PM]
All you need to do is to use the DirectSoundBuffer methods ->Lock() and ->Unlock() to load your buffer. If it is a sound that will be repeated over and over again all you need to do is load it once and then call ->Play() when you want to use it. If you have a huge amount of sound that will be continuously loaded (like a CD track) then you will have to do a streaming buffer.

The ->Lock() function opens the buffer for writing. You specify where and how much you want to write (maybe the whole buffer) and it returns a set of pointers (two pointers because it is a circular buffer). Then you can just ''memcpy()'' your sound into the buffer. Then you call the ->Unlock() function and the job is done. To hear it call ->Play().

Here''s some simple code from a streaming example:

===================================================
void Mtransceiver::SendData(void)
{
void *firstBuf, *secondBuf;
DWORD firstLen, secondLen;

// Lock the send buffer and load some data
if (FAILED(pdsTXSecBufOb->Lock(
txwriteposition,// Offset in bytes from start to where lock begins (this is my pointer needed to keep track of where I am for streaming purposes)
bytestoread, // Number of bytes to lock
&firstBuf, // Returns a pointer to start of first buffer
&firstLen, // Returns number of bytes in first buffer
&secondBuf, // Returns pointer to start of second buffer (may be NULL)
&secondLen, // Returns number of bytes in second buffer (not needed if second buffer is NULL)
0)))
{
StopSending(0);
return;
}

// Copy the data into the first buffer (txbuffer is my pre-loaded junk)
memcpy(firstBuf, txbuffer, firstLen);

// Is there more (wrapped) data to copy? If so, append it to the first chunk of copied data
if (secondLen)
{
memcpy(secondBuf, txbuffer + firstLen, secondLen);
}

// Unlock the buffer
if (FAILED(pdsTXSecBufOb->Unlock(firstBuf, firstLen, secondBuf, secondLen)))
{
StopSending(0);
return;
}

LoadSendBuffer(); // THis loads ''txbuffer'' for next time (only needed for streaming)
}
=========================================

Hope it helps. Its a little more low level than the other approaches, but that''s how it works.

Brian
Brian Reinhold
Someone needs to tell me how to do that neat loading of code samples. It''s a lot easier to read than my cut and paste.

Brian
Brian Reinhold
Thanks Gyannea.

I like low level But that''s not the point. You see, I need to see a code sample which would tell me how to load a specific file ("sound.wav") to the sound buffer (or to any buffer )

I''m a beginner in windows programming, but I managed to startup and use DirectDraw so I make terribly coded,mute games for the pleeasure of creation itself. I would never suspect that loading a wave file is more complicated than loading a bitmap onto a surface... But it''s probably just my lack of knowledge.

Thanks anyway!

uh, johnnyBravo, i''m having problems using your code. i get some wierd error with the GUID_NULL

c:\documents and settings\owner\desktop\game - english class\game\dwave.h(334) : error C2065: ''GUID_NULL'' : undeclared identifier

any ideas on how to fix that?
oops...
try adding these
#define INITGUID
#include <dsound.h>
#include <string>

and add these to the linkers:
dxguid.lib, dsound.lib

but see if you can run the directsound sdk samples, the 3d one would be ideal.

if that runs,mine will work

(you probably dont need INITGUID, i think i had that in mine because i was attempting dplay)

[edited by - johnnyBravo on March 18, 2004 7:10:04 PM]

This topic is closed to new replies.

Advertisement