How to load a sound?
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
What version of DirectX are you using? If you''re using 8 you can use this (from the tutorial on this site):
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)
*/
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...
CSoundManager::CreateFromMemory(), and FillBufferWithSound()
functions...
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.
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
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]
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
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
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
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!
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?
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?
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]
#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
Popular Topics
Advertisement