Tricks of the Windows Game Programming Gurus:Sounding Off with DirectSound and DirectMusic

All ITKnowledge Source Code Search Tips Advanced Search |

| Tricks of the Windows Game Programming Gurus by Andre LaMothe Sams, Macmillan Computer Publishing ISBN: 0672313618 Pub Date: 09/27/99

Search this book:

Previous | Table of Contents | Next

#### Reading .WAV Files

The `.WAV` file format is based on chunks—ID chunks, format chunks, and data chunks. In essence, you need to open up a `.WAV` file and read in the header and format information, which then tells you how many channels there are, the bits per channel, the playback rate, and so forth, along with the length of the sampled sound. Then you load the sound.

Now, to help facilitate loading and playing sounds, you’re going to create a sound library API, and hence a set of globals and wrapper functions around all this DirectSound stuff to make things easy. Let’s begin with a data structure that will hold a virtual sound, which you’ll use instead of the lower-level DirectSound stuff:

    // this holds a single sound

    typedef struct pcm_sound_typ

    {

    LPDIRECTSOUNDBUFFER dsbuffer;   // the ds buffer containing the sound

    int state;                      // state of the sound

    int rate;                       // playback rate

    int size;                       // size of sound

    int id;                         // id number of the sound

    } pcm_sound, *pcm_sound_ptr;

This nicely contains the DirectSound buffer associated with a sound, along with a copy of the important information about the sound. Now let’s create an array to hold all the sounds in the system:

    pcm_sound sound_fx[MAX_SOUNDS];  // the array of secondary sound buffers

So, when you load a sound, the idea is to find an open space and set up a `pcm_sound` structure. This is exactly what the following `DSound_Load_WAV()` function does:

    int DSound_Load_WAV(char *filename, int control_flags = DSBCAPS_

    CTRLDEFAULT)

    {

    // this function loads a .wav file, sets up the directsound

    // buffer and loads the data into memory, the function returns

    // the id number of the sound

    HMMIO         hwav;    // handle to wave file

    MMCKINFO        parent,  // parent chunk

                    child;   // child chunk

    WAVEFORMATEX    wfmtx;   // wave format structure

    int    sound_id = -1,       // id of sound to be loaded

        index;               // looping variable

    UCHAR *snd_buffer,       // temporary sound buffer to hold voc data

          *audio_ptr_1=NULL, // data ptr to first write buffer

          *audio_ptr_2=NULL; // data ptr to second write buffer

    DWORD audio_length_1=0,  // length of first write buffer

          audio_length_2=0;  // length of second write buffer

    // step one: are there any open id’s ?

    for (index=0; index < MAX_SOUNDS; index++)

        {

        // make sure this sound is unused

        if (sound_fx[index].state==SOUND_NULL)

           {

           sound_id = index;

           break;

           } // end if

        } // end for index

    // did we get a free ID?

    if (sound_id==-1)

        return(-1);

    // set up chunk info structure

    parent.ckid         = (FOURCC)0;

    parent.cksize         = 0;

    parent.fccType        = (FOURCC)0;

    parent.dwDataOffset = 0;

    parent.dwFlags        = 0;

    // copy data

    child = parent;

    // open the WAV file

    if ((hwav = mmioOpen(filename, NULL, MMIO_READ | MMIO_ALLOCBUF))==NULL)

        return(-1);

    // descend into the RIFF

    parent.fccType = mmioFOURCC(‘W’, ‘A’, ‘V’, ‘E’);

    if (mmioDescend(hwav, &parent, NULL, MMIO_FINDRIFF))

        {

        // close the file

        mmioClose(hwav, 0);

        // return error, no wave section

        return(-1);

        } // end if

    // descend to the WAVEfmt

    child.ckid = mmioFOURCC(‘f’, ‘m’, ‘t’, ‘ ’);

    if (mmioDescend(hwav, &child, &parent, 0))

        {

        // close the file

        mmioClose(hwav, 0);

        // return error, no format section

        return(-1);

        } // end if

    // now read the wave format information from file

    if (mmioRead(hwav, (char *)&wfmtx, sizeof(wfmtx)) != sizeof(wfmtx))

        {

        // close file

        mmioClose(hwav, 0);

        // return error, no wave format data

        return(-1);

        } // end if

    // make sure that the data format is PCM

    if (wfmtx.wFormatTag != WAVE_FORMAT_PCM)

        {

        // close the file

        mmioClose(hwav, 0);

        // return error, not the right data format

        return(-1);

        } // end if

    // now ascend up one level, so we can access data chunk

    if (mmioAscend(hwav, &child, 0))

       {

       // close file

       mmioClose(hwav, 0);

       // return error, couldn’t ascend

       return(-1);

       } // end if

    // descend to the data chunk

    child.ckid = mmioFOURCC(‘d’, ‘a’, ‘t’, ‘a’);

    if (mmioDescend(hwav, &child, &parent, MMIO_FINDCHUNK))

        {

        // close file

        mmioClose(hwav, 0);

        // return error, no data

        return(-1);

        } // end if

    // finally!!!! now all we have to do is read the data in and

    // set up the directsound buffer

    // allocate the memory to load sound data

    snd_buffer = (UCHAR *)malloc(child.cksize);

    // read the wave data

    mmioRead(hwav, (char *)snd_buffer, child.cksize);

    // close the file

    mmioClose(hwav, 0);

    // set rate and size in data structure

    sound_fx[sound_id].rate  = wfmtx.nSamplesPerSec;

    sound_fx[sound_id].size  = child.cksize;

    sound_fx[sound_id].state = SOUND_LOADED;

    // set up the format data structure

    memset(&pcmwf, 0, sizeof(WAVEFORMATEX));

    pcmwf.wFormatTag    = WAVE_FORMAT_PCM;  // pulse code modulation

    pcmwf.nChannels    = 1;                // mono

    pcmwf.nSamplesPerSec  = 11025;            // always this rate

    pcmwf.nBlockAlign     = 1;

    pcmwf.nAvgBytesPerSec = pcmwf.nSamplesPerSec * pcmwf.nBlockAlign;

    pcmwf.wBitsPerSample  = 8;

    pcmwf.cbSize        = 0;

    // prepare to create sounds buffer

    dsbd.dwSize        = sizeof(DSBUFFERDESC);

    dsbd.dwFlags       = control_flags | DSBCAPS_STATIC |

                       DSBCAPS_LOCSOFTWARE;

    dsbd.dwBufferBytes    = child.cksize;

    dsbd.lpwfxFormat    = &pcmwf;

    // create the sound buffer

    if (lpds->CreateSoundBuffer(&dsbd,

                    &sound_fx[sound_id].dsbuffer,NULL)!=DS_OK)

       {

       // release memory

       free(snd_buffer);

       // return error

       return(-1);

       } // end if

    // copy data into sound buffer

    if (sound_fx[sound_id].dsbuffer->Lock(0,

                      child.cksize,

                      (void **) &audio_ptr_1,

                      &audio_length_1,

                      (void **)&audio_ptr_2,

                      &audio_length_2,

                      DSBLOCK_FROMWRITECURSOR)!=DS_OK)

         return(0);

    // copy first section of circular buffer

    memcpy(audio_ptr_1, snd_buffer, audio_length_1);

    // copy last section of circular buffer

    memcpy(audio_ptr_2, (snd_buffer+audio_length_1),audio_length_2);

    // unlock the buffer

    if (sound_fx[sound_id].dsbuffer->Unlock(audio_ptr_1,

                            audio_length_1,

                            audio_ptr_2,

                            audio_length_2)!=DS_OK)

                     return(0);

    // release the temp buffer

    free(snd_buffer);

    // return id

    return(sound_id);

    } // end DSound_Load_WAV

Previous | Table of Contents | Next

Copyright © Macmillan Computer Publishing, Inc.

Products | Contact Us | About Us | Privacy | Ad Info | Home
Use of this site is subject to certain Terms & Conditions, Copyright © 1996-2000 EarthWeb Inc. All rights reserved. Reproduction in whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.