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

#### Loading the MIDI File

To load the MIDI file, you have to tell the loader where to look and what to look for (type of file), and then tell it to create a segment and load the file into it. I have created a function to do this along with some data structure, so I might as well show it to you now. First, the data structure that’s going to hold each musical MIDI segment (DirectMusic likes to call data chunks segments) is called `DMUSIC_MIDI` and is shown here:

    typedef struct DMUSIC_MIDI_TYP

    {

    IDirectMusicSegment        *dm_segment;  // the directmusic segment

    IDirectMusicSegmentState   *dm_segstate; // the state of the segment

    int                        id;           // the id of this segment

    int                        state;        // state of midi song

    } DMUSIC_MIDI, *DMUSIC_MIDI_PTR;

This is used to hold each MIDI segment. But you may have more than a few songs for a whole game, so let’s make an array of them:

    DMUSIC_MIDI                dm_midi[DM_NUM_SEGMENTS];

Here, `DM_NUM_SEGMENTS` is defined as

    #define DM_NUM_SEGMENTS 64 // number of midi segments that can be cached

    in memory

Okay, with that all in mind, take a look at the `DMusic_Load_MIDI()` function that follows. It’s heavily commented, so take your time, and also pay attention to the funky wide character strings that the DirectMusic functions use:

    int DMusic_Load_MIDI(char *filename)

    {

    // this function loads a midi segment

    DMUS_OBJECTDESC ObjDesc;

    HRESULT hr;

    IDirectMusicSegment* pSegment = NULL;

    int index; // loop var

    // look for open slot for midi segment

    int id = -1;

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

        {

        // is this one open

        if (dm_midi[index].state == MIDI_NULL)

           {

           // validate id, but don’t validate object until loaded

           id = index;

           break;

           } // end if

        } // end for index

    // found good id?

    if (id==-1)

       return(-1);

    // get current working directory

    char szDir[_MAX_PATH];

    WCHAR wszDir[_MAX_PATH];

    if(_getcwd( szDir, _MAX_PATH) == NULL)

      {

      return(-1);;

      } // end if

    MULTI_TO_WIDE(wszDir, szDir);

    // tell the loader were to look for files

    hr = dm_loader->SetSearchDirectory(GUID_DirectMusicAllTypes,

                                       wszDir, FALSE);

    if (FAILED(hr))

       {

       return (-1);

       } // end if

    // convert filename to wide string

    WCHAR wfilename[_MAX_PATH];

    MULTI_TO_WIDE(wfilename, filename);

    // setup object description

    DD_INIT_STRUCT(ObjDesc);

    ObjDesc.guidClass = CLSID_DirectMusicSegment;

    wcscpy(ObjDesc.wszFileName, wfilename);

    ObjDesc.dwValidData = DMUS_OBJ_CLASS | DMUS_OBJ_FILENAME;

    // load the object and query it for the IDirectMusicSegment interface

    // This is done in a single call to IDirectMusicLoader::GetObject

    // note that loading the object also initializes the tracks and does

    // everything else necessary to get the MIDI data ready for playback.

    hr = dm_loader->GetObject(&ObjDesc,IID_IDirectMusicSegment,

                              (void**) &pSegment);

    if (FAILED(hr))

       return(-1);

    // ensure that the segment plays as a standard MIDI file

    // you now need to set a parameter on the band track

    // Use the IDirectMusicSegment::SetParam method and let

    // DirectMusic find the trackby passing -1

    // (or 0xFFFFFFFF) in the dwGroupBits method parameter.

    hr = pSegment->SetParam(GUID_StandardMIDIFile,-1, 0, 0, (void*)dm_perf);

    if (FAILED(hr))

       return(-1);

    // This step is necessary because DirectMusic handles program changes and

    // bank selects differently for standard MIDI files than it does for MIDI

    // content authored specifically for DirectMusic.

    // The GUID_StandardMIDIFile parameter must

    // be set before the instruments are downloaded.

    // The next step is to download the instruments.

    // This is necessary even for playing a simple MIDI file

    // because the default software synthesizer needs the DLS data

    // for the General MIDI instrument set

    // If you skip this step, the MIDI file will play silently.

    // Again, you call SetParam on the segment,

    // this time specifying the GUID_Download parameter:

    hr = pSegment->SetParam(GUID_Download, -1, 0, 0, (void*)dm_perf);

    if (FAILED(hr))

       return(-1);

    // at this point we have MIDI loaded and a valid object

    dm_midi[id].dm_segment  = pSegment;

    dm_midi[id].dm_segstate = NULL;

    dm_midi[id].state       = MIDI_LOADED;

    // return id

    return(id);

    } // end DMusic_Load_MIDI

The function isn’t too bad. It basically looks for an open slot in your `dm_midi[]` array to load the new MIDI segment, sets the search path, creates the segment, loads the segment, and bails. The function takes the filename of the MIDI file and then returns an ID to the array index containing the segment in your data structure.

### Manipulating MIDI Segments

A number of interface functions (methods) are available to the IDirectMusicSegment interface that represents a loaded MIDI segment. You can look them up in the SDK if you’re interested, but the two functions that should seem most important to you are the ones that play and stop a segment, right? Ironically, these are part of the IDirectMusicPerformance interface rather than the IDirectMusicSegment interface. This makes sense if you think about it: The performance object is like the ringmaster, and everything has to go through him. Like my girlfriend says, “Whatever.”

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.