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

#### Playing a MIDI Segment

Assuming that you’ve loaded a segment using the `DMusic_Load_MIDI()`, or done so manually, let `dm_segment` be the interface pointer to the segment. Then, to play it with the performance object, use `IDirectMusicPerformance::PlaySegment()`, prototyped here:

    HRESULT PlaySegment(

     IDirectMusicSegment* pSegment,  // segment to play

     DWORD dwFlags,                  // control flags

    _int64 i64StartTime,             // when to play

     IDirectMusicSegmentState** ppSegmentState); // state holder

In general, set the control flags and start time to 0. The only parameters to worry about are the segment and segment state. Here’s an example of playing `dm_segment` and storing the state in `dm_segstate:`

    dm_perf->PlaySegment(dm_segment, 0, 0, &dm_segstate);

Here, `dm_segstate` is of the type `IDirectMusicSegmentState` and is used to track the segment playing. There is a copy of this in each array element of the `dm_midi[]`, but if you do all this yourself, remember to send one yourself.

#### Stopping a MIDI Segment

To stop a segment during play, use the `IDirectMusicPerformance::Stop()` function shown here:

    HRESULT Stop(

      IDirectMusicSegment* pSegment, // segment to stop

      IDirectMusicSegmentState* pSegmentState,   // state

      MUSIC_TIME mtTime,   // when to stop

      DWORD dwFlags);      // control flags

Similar to `Play()`, you don’t need to worry about most of the parameters, but just the segment itself. Here’s an example of stopping `dm_segment`:

    dm_perf->Stop(dm_segment, NULL, 0, 0);

If you want to stop all segments that are playing, make `dm_segment NULL`.

#### Checking the Status of a MIDI Segment

Many times you want to know if a song is done playing. To test this, use the `IDirectMusicPerformance::IsPlaying()` function. It simply takes the segment to test and returns `S_OK` if the segment is still playing. Here’s an example:

    if (dm_perf->IsPlaying(dm_segment,NULL) == S_OK)

       { /* still playing */ }

    else

       { /* not playing */ }

#### Releasing a MIDI Segment

When you’re done with a segment, you have to release the resources. The first step is to unload the DLS instrument data with a call to `IDirectMusicSegment::SetParam()` and then release the interface pointer itself with `Release()`. Here’s how:

    // unload the instrument data

    dm_segment->SetParam(GUID_Unload, -1, 0, 0,(void*)dm_perf);

    // Release the segment and set to null

    dm_segment->Release();

    dm_segment  = NULL; // for good measure

#### Shutting Down DirectMusic

When you’re all done with DirectMusic, you have to close down and release the performance object, release the loader, and release all the segments (see the preceding code). Finally, you must close down COM unless it’s done elsewhere. Here’s an example of the process:

    // If there is any music playing, stop it. This is

    // not really necessary, because the music will stop when

    // the instruments are unloaded or the performance is

    // closed down.

    if (dm_perf)

       dm_perf->Stop(NULL, NULL, 0, 0);

    // *** delete all the midis if they already haven’t been

    // CloseDown and Release the performance object.

    if (dm_perf)

       {

       dm_perf->CloseDown();

       dm_perf->Release();

       } // end if

    // Release the loader object.

    if (dm_loader)

       dm_loader->Release();

    // Release COM

    CoUninitialize();

#### A Little DirectMusic Example

As an example of using DirectMusic without DirectSound or any other DirectX component, I have created a program called `DEMO10_4.CPP|EXE` on the CD. It basically loads a single MIDI file and then plays it. Take a look at it and experiment. When you’re done, come back and see how easy all this is with the latest installment of the library, `T3DLIB3.CPP|H`.

### The T3DLIB3 Sound and Music Library

I have taken all the sound and music technology that we’ve been building and used it to create the next component to your game engine, `T3DLIB3`. It is composed of two main source files:

  • `T3DLIB3.CPP`—The main C/C++ source
  • `T3DLIB3.H`—The header file

You’ll also need to include the DirectSound import library, `DSOUND.LIB`, to make anything link. However, DirectMusic doesn’t have an import library because it’s pure COM, so there isn’t a `DMUSIC.LIB`. On the other hand, you still need to point your compiler to the DirectSound and DirectMusic `.H` header files so it can find them during compilation. Just to remind you, they are

    DSOUND.H

    DMKSCTRL.H

    DMUSICI.H

    DMUSICC.H

    DMUSICF.H

With all that in mind, let’s take a look at the main elements of the `T3DLIB3.H` header file.

#### The Header

The header file `T3DLIB3.H` contains the types, macros, and externals for `T3DLIB3.CPP`. Here are the `#defines` you’ll find in the header:

    // number of midi segments that can be cached in memory

    #define DM_NUM_SEGMENTS 64

    // midi object state defines

    #define MIDI_NULL     0   // this midi object is not loaded

    #define MIDI_LOADED   1   // this midi object is loaded

    #define MIDI_PLAYING  2   // this midi object is loaded and playing

    #define MIDI_STOPPED  3   // this midi object is loaded, but stopped

    #define MAX_SOUNDS     256 // max number of sounds in system at once

    // digital sound object state defines

    #define SOUND_NULL     0 // “ ”

    #define SOUND_LOADED   1

    #define SOUND_PLAYING  2

    #define SOUND_STOPPED  3

Not much for macros; just a macro to help convert from 0-100 to the Microsoft decibels scale and one to convert multibyte characters to wide:

    #define DSVOLUME_TO_DB(volume) ((DWORD)(-30*(100 - volume)))

    // Convert from multibyte format to Unicode using the following macro

    #define MULTI_TO_WIDE( x,y)  MultiByteToWideChar( CP_ACP,MB_PRECOMPOSED,

    y,-1,x,_MAX_PATH)

> Warning: The column width of this book is too small to fit the whole macro, so the definition is on two lines. This is a no-no in real life. Macros must be on a single line!

Next are the types for the sound engine.

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.