Archived

This topic is now archived and is closed to further replies.

bartiss

How to load a sound?

Recommended Posts

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

Share this post


Link to post
Share on other sites
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 stop

g_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)
*/

Share this post


Link to post
Share on other sites
You should check out CSoundManager class, and use:
CSoundManager::CreateFromMemory(), and FillBufferWithSound()
functions...

Share this post


Link to post
Share on other sites
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.

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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

Share this post


Link to post
Share on other sites
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!

Share this post


Link to post
Share on other sites
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?

Share this post


Link to post
Share on other sites
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]

Share this post


Link to post
Share on other sites
nope, those didn''t do the trick. already had the linkers. but the INITGUID and dsound.h didn''t help. i can''t compile the sdk examples, but the exe''s work.

Share this post


Link to post
Share on other sites
quote:
Original post by johnnyBravo
.............dammmit programmer16 thats direct music stop getting mixed up!
[edited by - johnnyBravo on March 17, 2004 6:39:04 PM]


I''m sorry, I was just copying what I learned from the DirectAudio 8 tutorial here on GameDev.net. Whats the difference between DirectMusic and DirectSound (weren''t they combined into DirectAudio 8)? Thanks!


/*
I use DirectX 8.1 and C++ (Microsoft Visual C++ 6.0 Professional edition)
*/

Share this post


Link to post
Share on other sites