Search Tips Advanced Search |
| Delphi Graphics and Game Programming Exposed with DirectX 7.0 by John Ayres Wordware Publishing, Inc. ISBN: 1556226373 Pub Date: 12/01/99
Search this book:
Previous | Table of Contents | Next
For the most part, the steps required to load and play a sound are identical for both static and streaming buffers. The primary difference is in how a streaming buffer is continually loaded with new information as it is played. The most common situation, and easiest to follow, is loading and playing static buffers, which is discussed first, followed by streaming buffers. Static Buffers The first step in creating any secondary sound buffer is to initialize a TWaveFormatEx structure with information concerning the format of the sound buffer. Of course, this information comes from the desired sound itself. As described earlier in the chapter, WAV files are stored in the RIFF file format, which includes the information we are seeking conveniently configured in the TWaveFormatEx format. Parsing WAV file information out of a RIFF file is not too terribly complicated, but is involved enough that it would take several pages just to describe the process. Instead of wasting space describing such an esoteric task, we will use several functions from the DSWaveFiles.pas unit (converted from the original Wave.C unit found in the DirectX SDK) that perform this function. These functions use several of the low-level multimedia input/output functions, and perusing their code may provide useful insight for providing your own wave parsing routines. To retrieve the desired information, we call the WaveOpenFile function. This function opens the WAV file and initializes a TWaveFormatEx structure (passed in as a variable parameter) with the WAV file’s format information. Then we must call the WaveStartDataRead function, which positions a file pointer at the start of the actual sound data within the WAV file, and retrieves the total size of the sound data. At this point, we are just about ready to create the actual sound buffer object, so we must initialize a TDSBufferDesc structure with information describing what type of sound buffer to create. The TDSBufferDesc structure is defined as:
    TDSBufferDesc = packed record

    dwSize: DWORD;                 // the size of the structure, in bytes

    dwFlags: DWORD;                // buffer description flags

    dwBufferBytes: DWORD;          // the size of the sound buffer, in bytes

    dwReserved: DWORD;             // reserved, must be 0

    lpwfxFormat: PWaveFormatEx;    // a pointer to the TWaveFormatEx structure

    end;
| Note: The dwSize member of the TDSBufferDesc structure must be set to SizeOf(TDSBufferDesc) before calling the CreateSoundBuffer method.
For static buffers, the dwBufferBytes member should be set to the total size of the sound data as retrieved by the WaveStartDataRead function. The lpwfxFormat member should point to the TWaveFormatEx structure initialized by the WaveOpenFile function. The most important member of this structure, dwFlags, can be set to a combination of values that determine several things about the sound buffer, including its location in memory and its type. By default, DirectSound tries to create a streaming buffer, so this member must be set to DSBCAPS_STATIC in order to create a static buffer. Also by default, the sound buffer will be located in hardware memory if any is available. The DSBCAPS_LOCHARDWARE flag can be used to force the sound buffer into hardware memory (failing if there is not enough free hardware memory for the buffer), or the DSBCAPS_LOCSOFTWARE flag can be used to force the sound buffer into system memory. Several other flags are available which provide other controls over the buffer, such as panning and volume, which will be explained below. Now that the buffer description has been initialized, the CreateSoundBuffer method of the IDirectSound object is called. The CreateSoundBuffer method is defined as:
    function CreateSoundBuffer(

    const lpDSBufferDesc: TDSBufferDesc;           // the buffer description

    var lpIDirectSoundBuffer: IDirectSoundBuffer;  // the sound buffer object

    pUnkOuter: IUnknown                            // unused

    ): HResult;                                    // returns a DirectX error code
The first parameter is the TDSBufferDesc structure that has been initialized as discussed above. The second parameter is an IDirectSoundBuffer object that will be instantiated when the function returns. The final parameter is used for COM aggregation and should be set to nil. This creates a secondary sound buffer that is now ready to receive actual sound data. In order to start copying audio data from the sound file into the buffer, we must retrieve a pointer directly to the sound buffer memory itself. This is accomplished by calling the Lock method of the IDirectSoundBuffer object (this is similar to calling the Lock method of a DirectDraw surface). The Lock method is defined as:
    function Lock(

    dwWriteCursor,                  // offset of start of lock

    dwWriteBytes: DWORD;            // number of bytes to lock

    var lplpvAudioPtr1: Pointer;    // first memory pointer

    var lpdwAudioBytes1: DWORD;     // number of bytes locked

    var lplpvAudioPtr2: Pointer;    // second memory pointer

    var lpdwAudioBytes2: DWORD;     // number of bytes locked

    dwFlags: DWORD                  // lock control flags

    ): HResult;                     // returns a DirectX error code
The first parameter is the offset, in bytes, of the beginning of the locked memory from the start of the sound buffer. The second parameter indicates how many bytes should be locked. The next four parameters indicate where the buffer is actually locked and how many bytes were locked. These parameters are explained in detail below under streaming buffers. The final parameter can indicate that the entire buffer should be locked, or locking should begin from the position of the Write cursor. The information returned by this function is, in turn, used in a call to the WaveReadFile function, which actually copies the audio data from the WAV file into the sound buffer. Once the data is copied, the Unlock method of the IDirectSoundBuffer is called to unlock the sound buffer memory, and the WaveCloseReadFile function is called to close the actual WAV file. The Unlock method is defined as:
    function Unlock(

    lpvAudioPtr1: Pointer;           // offset of first lock

    dwAudioBytes1: DWORD;            // number of bytes to be unlocked

    lpvAudioPtr2: Pointer;           // offset of second lock

    dwAudioBytes2: DWORD             // number of bytes to be unlocked

    ): HResult;                      // returns a DirectX error code
The four parameters passed to this function correspond to the pointers and byte lock counts retrieved from the initial Lock method. The sound buffer has been created and loaded with audio data, and is now ready to be output through the audio hardware. The SetCurrentPosition method of the IDirectSoundBuffer object can be called to set the actual position within the sound data to start the audio playback. The SetCurrentPosition method is defined as:
    function SetCurrentPosition(

    dwPosition: DWORD                // the current position offset

    ): HResult;                      // returns a DirectX error code
The only parameter in this function is the offset, in bytes, from the beginning of the buffer to which the current playing position should be set.
Previous | Table of Contents | Next

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 whole or in part in any form or medium without express written permission of EarthWeb is prohibited. Read EarthWeb's privacy statement.