//-----------------------------------------------------------------------------
// 
// Sample Name: PlayAudio Sample
// 
// Copyright (c) Microsoft Corporation. All rights reserved.
//
// GM/GS® Sound Set Copyright ©1996, Roland Corporation U.S.
// 
//-----------------------------------------------------------------------------



Description
===========
  The PlayAudio sample shows how to load a segment and play it on an 
  audiopath, how to use DirectMusic notifications, and how to change 
  global performance parameters.
  
Path
====
  Source:     DXSDK\Samples\C++\DirectMusic\PlayAudio
  Executable: DXSDK\Samples\C++\DirectMusic\Bin

User's Guide
============
  Play the default segment, or load another wave, MIDI, or DirectMusic 
  Producer segment file by clicking Open File. Adjust the volume by
  using the Master Volume slider.  When using segments you can adjust 
  the tempo by using the Tempo slider.
  
Programming Notes
=================
  This and other DirectMusic samples uses the DirectMusic sample 
  framework, CMusicManager and CMusicSegment to help encapsulate some of 
  the common functionality of DirectMusic.  The framework is contained 
  in dmutil.cpp.
  
  This is how the sample works:
  
  * Upon WM_INITDIALOG.  See OnInitDialog()
        1. Create a Win32 event, g_hDMusicMessageEvent.  This will be 
           used by DirectMusic to signal the app whenever a DirectMusic 
           notification comes in.
        2. Create a help class CMusicManager called g_pMusicManager.  
        3. Initialize the CMusicManager class.  This does the following. 
           See CMusicManager::Initialize() in dmutil.cpp
                - Creates a IDirectMusicLoader8 using CoCreateInstance
                - Creates a IDirectMusicPerformance8 using CoCreateInstance
                - Calls IDirectMusicPerformance8::InitAudio to init DirectMusic 
                  using a standard audio path.
        4. Call IDirectMusicPerformance8::AddNotificationType() passing in 
           GUID_NOTIFICATION_SEGMENT. This will make DirectMusic tell us about any 
           segment notifications that come in.  This is needed to by this
           sample to know when the segment has ended.  However DirectMusic
           games may not care when the segment has ended.           
        5. Call IDirectMusicPerformance8::SetNotificationHandle() passing
           in the Win32 event, g_hDMusicMessageEvent.  This tells DirectMusic
           to signal this event when a notification is available.

  * Setting up the app message loop.  See WinMain()
        1. Create the dialog using CreateDialog().  
        2. In a loop call MsgWaitForMultipleObjects() passing in 
           g_hDMusicMessageEvent.  This will tell us when g_hDMusicMessageEvent
           is signaled.  Above we have told DirectMusic to signal this event 
           whenever a DirectMusic notification has come in.
        3. If WAIT_OBJECT_0 is returned, then call ProcessDirectMusicMessages(),
           See below for details.
        4. If WAIT_OBJECT_0 + 1 is returned, then Windows msgs are available, so
           do standard msg processing using PeekMessage().
           
  * When "Open File" is clicked.  See OnOpenSoundFile()
        1. Get the file name from using GetOpenFileName().
        2. Release the any old g_pMusicSegment.
        3. Call CMusicManager::CollectGarbage().  See dmutil.cpp.
           This calls IDirectMusicLoader8::CollectGarbage which 
           collects any garbage from any old segment that was present.  
           This is done because some sophisticated segments, in particular 
           ones that include segment trigger tracks or script tracks, may 
           have a cyclic reference. For example, a segment trigger that 
           references another segment that references the first segment, also 
           via a segment trigger track.
        4. Call CMusicManager::SetSearchDirectory(). See dmutil.cpp
           This calls IDirectMusicLoader8::SetSearchDirectory() 
           passing in the GUID_DirectMusicAllTypes and a directory.
           This will tell DirectMusic where to look for files that 
           are referenced inside of segments.
        5. Call CMusicManager::CreateSegmentFromFile() to create a
           CMusicSegment called g_pMusicSegment from the file.  
           See dmutil.cpp.  This does the following:
                - Calls IDirectMusicLoader8::LoadObjectFromFile() to 
                  load the IDirectMusicSegment8 into pSegment.
                - Creates CMusicSegment passing in pSegment.
                - If the file is a pure MIDI file then it calls 
                  IDirectMusicSegment8::SetParam passing in 
                  GUID_StandardMIDIFile to DirectMusic this.  This makes 
                  sure that patch changes are handled correctly.                  
                - If requested, it calls IDirectMusicSegment8::Download()
                  this will download the segment's bands to the synthesizer.  
                  Some apps may want to wait before calling this to because 
                  the download allocates memory for the instruments. The 
                  more instruments currently downloaded, the more memory 
                  is in use by the synthesizer.
                  
   * When "Play" is clicked.  See OnPlayAudio()
        1. If the UI says the sound should be looped, then call 
           CMusicSegment::SetRepeats passing in DMUS_SEG_REPEAT_INFINITE,
           otherwise call CMusicSegment::SetRepeats passing in 0.
        2. Call CMusicSegment::Play() which calls 
           IDirectMusicPerformance8::PlaySegmentEx().  See dmutil.cpp.
        
   * Upon a DirectMusic notification. See ProcessDirectMusicMessages().
        This sample wants to know if the primary segment has stopped playing
        so it can updated the UI so tell the user that they can play 
        the sound again. This is rather complex, but typically apps 
        will not need this functionality.  Here is what has to be done:
        
        1. Call IDirectMusicPerformance8::GetNotificationPMsg() in a loop
           to process each PMsg that has occurred.
        2. Switch off the pPMsg->dwNotificationOption.  This sample 
           only handles it if its a DMUS_NOTIFICATION_SEGEND.  This tells 
           us that segment has ended.
        3. Call QueryInterface on the pPMsg->punkUser, quering for a 
           IDirectMusicSegmentState8.
        4. Using the IDirectMusicSegmentState8, call GetSegment to 
           get a IDirectMusicSegment* of the segment it refers to.  
           This call may fail is the segment may have gone away before this
           notification was handled.
        5. Call QueryInterface IDirectMusicSegment to get a IDirectMusicSegment8
        6. Compare this pointer to the IDirectMusicSegment8 pointer 
           in g_pMusicSegment, to see if this was the primary segment.
           This may not always be the case since segments can have segments enbedded
           inside of them, we only want handle when the primary segment has
           stopped playing.  If it has, then update the UI
        7. Cleanup all the interfaces.
        
