Microsoft DirectX 9.0

Notification and Event Handling

From time to time, your application may need to respond to a performance event. For example, you might need to know when the end of a segment has been reached, or you might want to synchronize graphics with the beat of the music. You get the desired information by asking DirectMusic to notify you when a certain type of event occurs.

Note   Performance notifications should not be confused with DirectSound buffer notifications, which are not used by DirectMusic applications.

To specify what types of events you want to be notified of, call the IDirectMusicPerformance8::AddNotificationType method once for each desired type of event.

The following example function causes DirectMusic to set segment-related events. The specific type of event, such as a segment start or a segment end, is derived later from the notification message.

HRESULT SetSegmentNotification(IDirectMusicPerformance8* pPerformance)
{
  GUID guid = GUID_NOTIFICATION_SEGMENT;

  return pPerformance->AddNotificationType(guid);
}

You can also add notification types for a particular segment by using the IDirectMusicSegment8::AddNotificationType method. You could do this, for example, to receive notification of when a particular segment stops playing. You cannot use this method to request GUID_NOTIFICATION_PERFORMANCE types, because these must come from the performance object.

Note   Most applications do not call the IDirectMusicTrack8::AddNotificationType method directly.

Information about notifications is sent in DMUS_NOTIFICATION_PMSG message structures. You can poll for any pending notification messages within the Windows message loop by calling the IDirectMusicPerformance8::GetNotificationPMsg method, or you can have DirectMusic signal an event object in a separate thread when a message is pending.

If you want to be alerted of pending DirectMusic notification messages by a Windows event object, you must first obtain an event handle by calling the CreateEvent function. Typically, you would create an autoreset event with a call such as the following:

HANDLE g_hNotify = CreateEvent(NULL, FALSE, FALSE, NULL);

After creating the event, assign the handle to the performance by passing it to the IDirectMusicPerformance8::SetNotificationHandle method. You can use the second parameter of this method to specify how long DirectMusic should hold onto the event if it is not retrieved. A value of 0 in this parameter indicates that the default time of 2 seconds is to be used.

In the following example, g_pPerf is a valid pointer to the IDirectMusicPerformance8 interface:

HRESULT hr = g_pPerf->SetNotificationHandle(g_hNotify, 0);

The following example function executes repeatedly in its own thread, checking for signaled events and retrieving notification messages:

void WaitForEvent(LPVOID lpv, HANDLE hNotify, IDirectMusicPerformance8* pPerformance)
{
  DWORD dwResult;
  DMUS_NOTIFICATION_PMSG* pPmsg;
 
  while (TRUE)
  {
    dwResult = WaitForSingleObject(hNotify, 100);
    while (S_OK == pPerformance->GetNotificationPMsg(&pPmsg))
    {
      // Check notification type and do something in response.
      // Then free the message.
      pPerformance->FreePMsg((DMUS_PMSG*)pPmsg); 
    }
  }
}

More than one message might be waiting when an event is signaled or when you call GetNotificationPMsg in the message loop. To be sure of catching all notifications, call GetNotificationPMsg repeatedly until it returns S_FALSE.

Multiple messages with the same time stamp are not queued in any particular order.

It is the application's responsibility to free any messages it retrieves, by calling the IDirectMusicPerformance8::FreePMsg method.