• Advertisement
Sign in to follow this  

DirectSound Noob

This topic is 3826 days old which is more than the 365 day threshold we allow for new replies. Please post a new topic.

If you intended to correct an error in the post then please contact us.

Recommended Posts

Hello everyone, Currently in my project I have a .wav file loaded into memory using C++.NET, and has all the header information parsed properly. Now I need to load the audio into a DirectSound buffer and play but seem to be stuck in an error-less dead end. Originally I was using memcpy to copy the data stored in memory to the sound-buffer but always came up with crazy errors, until I wrote to the sound-buffer from the file. I don't receive any errors, but the sound doesn't play at all...
Quote:
// BEGINNING OF DirectSound Initialization. LPDIRECTSOUND lpDSO; WAVEFORMATEX wFX; DSBUFFERDESC dsbd; LPDIRECTSOUNDBUFFER pDSb = NULL; memset(&wFX, 0, sizeof(WAVEFORMATEX)); memset(&dsbd, 0, sizeof(DSBUFFERDESC)); bool dx_sound_is_on = true; if(FAILED(DirectSoundCreate(NULL, &lpDSO, NULL))) dx_sound_is_on = false; if(FAILED(lpDSO->SetCooperativeLevel(GetConsoleWindow(),DSSCL_EXCLUSIVE))) dx_sound_is_on = false; //WAVEFORMATEX & DirectSound Buffer Description wFX.wFormatTag = WAVE_FORMAT_PCM; wFX.nChannels = header.wChannels; wFX.nSamplesPerSec = header.sampleRate; wFX.nBlockAlign = header.wBlockAlign; wFX.nAvgBytesPerSec = header.avgBytesPerSec; wFX.wBitsPerSample = header.bitsPerSample; dsbd.dwReserved = 0; dsbd.dwSize = sizeof(DSBUFFERDESC); dsbd.dwFlags = DSBCAPS_CTRLVOLUME; dsbd.dwBufferBytes = 3 * wFX.nAvgBytesPerSec; dsbd.lpwfxFormat = &wFX; //Creating Secondary Buffer if(FAILED(lpDSO->CreateSoundBuffer(&dsbd,&pDSb,NULL))) cout<<"Failed creating sound buffer"<<endl; LPVOID playSnd; DWORD dwLength; //Lock'n'Load! if(FAILED(pDSb->Lock(0,0,&playSnd, &dwLength, NULL, NULL, DSBLOCK_ENTIREBUFFER))) { cout<<"Failed Locking"<<endl; } else { cout<<"Locking successful!"<<endl<<"Copying mem to buffer."<<endl; rewind (f); fseek (f, 46, SEEK_SET); fread (&playSnd,1,fileSize,f); //Used to be memcpy() but gave fclose (f); //errors like crazy =( cout<<"Copied... (i hope)"<<endl; if(FAILED(pDSb->Unlock(playSnd,dwLength,NULL,NULL))) cout<<"Failed Unlocking"<<endl; if(FAILED(pDSb->Play(0,0,DSBPLAY_LOOPING))) { cout<<"FAILED PLAYING"<<endl; } else { cout<<"Should be playing..."<<endl; } if(lpDSO) { IDirectSound_Release(lpDSO); //Killing DirectSoundObj } } cout<<endl<<"ERROR RESULT:"<<dx_sound_is_on<<endl;
Any tips would be greatly appreciated, just seems like everything is workin' out fine, but no sound comes at all =(

Share this post


Link to post
Share on other sites
Advertisement
Oh and also I did find the tutorial by Nathan Davidson

http://www.gamedev.net/reference/articles/article592.asp
& http://oasis.peterlink.ru/~dap/nnres/misc/data/Programming_Languages/48.html

Great information, but his two old sites are down, and none of his email-addresses match up anymore. Does anyone know if he has a newer site, or where I can find the next part of his tutorial (as it helped the most).

Thanks again!

Share this post


Link to post
Share on other sites
The only two things I noticed so far are:
1) You are not using DSBCAPS_STATIC when creating your buffer
2) When setting DSBUFFERDESC::dwBufferBytes you are calculating the wave data size, when you should be using the size you read from DATA chunk.

[EDIT]

Wait a sec... Are you releasing DirectSound right after you call Play()? In that case, it won't have time to start playing anything. Try inserting a call to Sleep() to sleep for like 3 seconds after you call Play().

Share this post


Link to post
Share on other sites
Quote:
The only two things I noticed so far are:
1) You are not using DSBCAPS_STATIC when creating your buffer
2) When setting DSBUFFERDESC::dwBufferBytes you are calculating the wave data size, when you should be using the size you read from DATA chunk.

[EDIT]

Wait a sec... Are you releasing DirectSound right after you call Play()? In that case, it won't have time to start playing anything. Try inserting a call to Sleep() to sleep for like 3 seconds after you call Play().


Thanks for the reply. I tried adding DSPCAPS_STATIC, didn't seem to alter anything, I've also tried a number of different things for DSBUFFERDESC::dwBufferBytes and currently have it back to the chunk size, but isn't doing anything for me right now aswell. Originally I didn't have it immediately releasing after playing, but just added it there just incase it was holding the soundsystem up for some obscure reason. With the sleep command I still get nothing...

For some reason I got a feeling that it's the way I copied the data over using fread, instead of using memcpy.

Share this post


Link to post
Share on other sites
Quote:
Original post by ThiefSpanner
For some reason I got a feeling that it's the way I copied the data over using fread, instead of using memcpy.
What does your debugger say? Visual Studio allows you to view a memory dump. I suggest you break just after the fread and take a look at the contents of the locked buffer.

Admiral

Share this post


Link to post
Share on other sites
ARGH!

Well I was going to try and post you the code I'd written for my DirectSoundBuffer loader, but it's too tied up in my sound library.

Anyway, having looked at your code the first thing you need to be sure of, is the wave type, and of that there are hundreds (check online help, it gives you a whole litany of different wave formats).

So problem number one is that virtually all of them have in-built compression data that needs to be decompressed in order to get the original wave data. However format;

#define WAVE_FORMAT_PCM 1

as defined in mmsystem.h, represents "lossless" uncompressed wave data and is thus the "easiest" to extract from a memory file (but don't be fooled, its not that easy as you'll see).

Since we're living in an age of hundreds of formats, there are many good wave file converters out there that will convert to this natural wave format (Thank God!)

KK... So to cut to the chase, let's assume that you've downloaded the wave into memory and have obtained a pointer to that memory called buffer. First thing we need to do is set up a "MMIOINFO" structure. This large multi-media input-output structure is to be used later to create a multi-media memory file, based on your buffer. Here's the code:


PBYTE buffer;
MMIOINFO mmioInfo = {0}; // clears structure (important!)
mmioInfo.fccIOProc = FOURCC_MEM; // flag to specify a read from memory
mmioInfo.cchBuffer = sizeOfBufferInBytes; // cchBuffer holds your buffer size in bytes
mmioInfo.pchBuffer = reinterpret_cast<HPSTR> (static_cast<PBYTE> (buffer)); // pchBuffer member points to your buffer



For more info, please check MSDN on the multi-media API, it's a huge subject!

KK, now comes the tricky bit. It will take me ages to comment on each line, but the strategy is this, most multi-media files use some variation of what is called a "Resource Interchange File Format" or RIFF. Basically, it's a flexible file format that allows one to share all sorts of information, namely multi-media ones. The following archaic code, basically locates and reads what are called "chunks" of the file (bits of related data), checks the format and then passes that info on into WAVEFORMATEX struct. That way, you get the correct WAVEFORMATEX parameters from the actual file itself.


HMMIO hmmio (mmioOpen (0, &mmioInfo, MMIO_READWRITE));
MMCKINFO mmckInfoParent = {0};
mmckInfoParent.fccType = mmioStringToFOURCCW (L"WAVE", 0);
mmioDescend (hmmio, &mmckInfoParent, 0, MMIO_FINDRIFF);
MMCKINFO mmckInfoChild = {0};
mmckInfoChild.ckid = mmioStringToFOURCCW (L"fmt", 0);
mmioDescend (hmmio, &mmckInfoChild, &mmckInfoParent, MMIO_FINDCHUNK);
WAVEFORMATEX waveFormat = {0};
mmioRead (hmmio, reinterpret_cast<HPSTR> (&waveFormat), sizeof waveFormat);
assert (waveFormat.wFormatTag = WAVE_FORMAT_PCM); // checks wave format type
mmioAscend (hmmio, &mmckInfoChild, 0);
mmckInfoChild.ckid = mmioStringToFOURCCW (L"data", 0);
mmioDescend (hmmio, &mmckInfoChild, &mmckInfoParent, MMIO_FINDCHUNK)


From here it gets more straight forward, simply set up the buffer description:


DSBUFFERDESC dsBufferDesc = {0};
DSBUFFERDESC.dwSize = sizeof (DSBUFFERDESC);
dsBufferDesc.dwFlags = flags; // use whatever flags here
dsBufferDesc.dwBufferBytes = mmckInfoChild.cksize; // set size
dsBufferDesc.lpwfxFormat = &waveFormat; // set format
PBYTE waveData = 0;
DWORD waveSize = 0;



Set up the interfaces (although the main IDirectSound8 interface should be set up previously of course with SetCoop.Level etc). Shame about the usual hassle of having to obtain a IDirectSoundBuffer8 interface indirect however :-(


IDirectSound8 DirectSound8;
IDirectSoundBuffer DirectSoundBuffer;
IDirectSoundBuffer8 DirectSoundBuffer8;

DirectSound8->CreateSoundBuffer (&dsBufferDesc, &DirectSoundBuffer, 0))
DirectSoundBuffer->QueryInterface (IID_IDirectSoundBuffer8, reinterpret_cast<PVOID *> (&DirectSoundBuffer8));



Then finally we lock, read from the still open mmio file, and then unlock.


DirectSoundBuffer8->Lock (0, dsBufferDesc.dwBufferBytes, reinterpret_cast<PVOID *> (&waveData), &waveSize, 0, 0, 0))
mmioRead (hmmio, reinterpret_cast<HPSTR> (waveData), waveSize); // IMPORTANT! Data gets read in here.
DirectSoundBuffer8->Unlock (waveData, waveSize, 0, 0);



Then we're done! Obviously check for errors as I omitted like 20 of them to make the code more readable and of course make sure all files are closed etc etc. I'm not sure if there are better ways of loading wave data into DirectSoundBuffers, but from what I've seen so far, all approaches seem to use these multi-media structures on which I decided to base my code on.

To be honest I don't understand why they just can't give us a wave loader. They gave us plenty helper functions in D3DX9 ;-(

One good thing though, is that you don't have to worry about setting up the waveformat, as that's easily obtained using the multi-media structs.

KK hope this helps. I had to hack this code out from my sound library, so apologies if there are any bugs or strange unexplained code in it. I'm pretty sure you can adapt it to work with your code.

Share this post


Link to post
Share on other sites
You can also look at my sound code if you want.
http://downloads.sourceforge.net/hitman2d/thunderstorm21.zip?modtime=1192079684&big_mirror=0

Look at ThunderSound.cpp, CThunderSound::Deserialize loads wav into a static buffer, and CThunderSound::Play does the playing.

Share this post


Link to post
Share on other sites
Sign in to follow this  

  • Advertisement