Lyric Notifications


Lyrics are a little simpler to talk about for several reasons:

  • There's only one way you can receive lyrics, and that is via a Tool.

  • There's no enabling or disabling of lyrics. Regular notifications need this feature because there are all kinds of messages that you may not care about. With lyrics, the messages are always exactly what you want because they've been intentionally authored into the segments.

  • The lyric pmsg, DMUS_LYRIC_PMSG, is simpler too. It has exactly one field, the lyric string:

     typedef struct _DMUS_LYRIC_PMSG {     /* begin DMUS_PMSG_PART */     DMUS_PMSG_PART     /* end DMUS_PMSG_PART */     WCHAR    wszString[1];      /* NULL-terminated Unicode lyric */ } DMUS_LYRIC_PMSG; 

Receiving a Lyric

There is exactly one way to receive a lyric — intercept it with a Tool. Going this route does mean a little more work, but in truth we're talking an extra hour of programming that can pay off easily in the long term.

Create a Tool with an IDirectMusicTool interface, set it up to handle the DMUS_PMSGT_LYRIC message type, and place it in the Performance. (We will provide example code later in this chapter when we add notifications to Jones.) When a lyric comes down the pike, DirectMusic calls the Tool's ProcessPMsg() method, which can then notify the application in whatever way it wants to.

 HRESULT CLyricTool::ProcessPMsg(IDirectMusicPerformance* pPerf,                                 DMUS_PMSG* pPMSG) {    if (pPMSG->dwType == DMUS_PMSGT_LYRIC)    {        // Read the lyric and do something based on what it says.    }    // No need to send this on down the line.    return DMUS_S_FREE; } 

Interpreting the Lyric

Once we have the lyric in hand, read it.

First, if working with both lyrics and notifications, check the dwType field of the pmsg.

    // Is this a lyric? (Only applied to reading from a Tool.)    if (pMsg->dwType == DMUS_PMSGT_LYRIC)    {      DMUS_LYRIC_PMSG *pLyric = (DMUS_LYRIC_PMSG *) pMsg;      // It's a lyric!    } 

If it is a lyric, use a series of string comparisons to see what it is. Remember that these are Unicode strings, so use the "L" to force the comparison string to Unicode.

        if (!wcscmp(pLyric->wszString,L"Boink!"))        {            // It's a Boink! Flatten Gruber's head momentarily!        } 

That's it. Since this code is probably called from within the Tool's ProcessPMsg() method, you do not even need to free the pmsg. Just return DMUS_S_FREE and the Performance does it for you.

Case Study: Begonia's Amazing Dance Moves

Although Jones has its own notification implementation, it doesn't actively do anything in response to the notifications. So, let's write something simpler that shows how to use them.

You are working on the sound design for the genre-shattering new title, "Begonia's Amazing Dance Moves." This exciting new adventure places Begonia's writhing torso center stage. Your job is to make it work. You decide to use notifications to communicate state information back to the game engine.

First, define state variables for 1) Begonia's mood, 2) whether music is playing, and 3) her current dance move.

 // Begonia's emotional state, placed in g_dwBegoniaMood. #define BM_PLACID       1 #define BM_ANGUISHED    2 #define BM_WHO_ME       3 #define BM_UPBEAT       4 #define BM_DEAD         5 static DWORD g_dwBegoniaMood = BM_PLACID; // Music status, tracked in g_dwMusicState. #define MS_RUNNING      1 #define MS_STOPPED      2 #define MS_EXPIRING     3 static DWORD g_dwMusicState = MS_STOPPED; // Begonia's dance moves, stored in g_dwBegoniaMove. #define BD_OFF          1   // Not dancing yet. #define BD_START        2   // Dance command to start. #define BD_JUMP         3   // Dance command to jump. #define BD_WIGGLE       4   // Dance command to wiggle. #define BD_NEXT         5   // Waiting for next dance command. static DWORD g_dwBegoniaMove =  BD_OFF; // Also, track the music Segment. static IDirectMusicSegmentState *g_pDanceMusic = NULL; 

Now, write a routine that takes a pmsg, be it either lyric or notification, and set the state variables appropriately. We assume there is additional code (most likely a Tool, since this supports lyrics) to capture the pmsg and deliver it to the routine ProcessNotification():

 void ProcessNotification(DMUS_PMSG *pMsg) {     // Is this a lyric? (Only applied to reading from a Tool.)     if (pMsg->dwType == DMUS_PMSGT_LYRIC)     {         DMUS_LYRIC_PMSG *pLyric = (DMUS_LYRIC_PMSG *) pMsg;         // Read the lyric and use to change game state, which will be         // picked up asynchronously by the main engine.         if (!wcscmp(pLyric->wszString,L"Agony Over"))         {             // Soul rendering theme is finished. Begonia can             // stop her tears now and be a little more upbeat.             g_dwBegoniaMood = BM_UPBEAT;         }         else if (!wcscmp(pLyric->wszString,L"Shout"))         {             // Someone shouts her name, Begonia reacts.             g_dwBegoniaMood = BM_WHO_ME;         }     }     else if (pMsg->dwType == DMUS_PMSGT_NOTIFICATION)     {         DMUS_NOTIFICATION_PMSG *pNotify = (DMUS_NOTIFICATION_PMSG *) pMsg;         DWORD dwNotificationOption = pNotify->dwNotificationOption;         if (pNotify->guidNotificationType == GUID_NOTIFICATION_PERFORMANCE)         {             if (dwNotificationOption == DMUS_NOTIFICATION_MUSICALMOSTEND)             {                 // Uh oh, primary music Segment is about to end.                 // Let main loop know to go ahead and schedule a new Segment.                 g_dwMusicState = MS_EXPIRING;             }         }         else if (pNotify->guidNotificationType == GUID_NOTIFICATION_SEGMENT)         {             if (dwNotificationOption == DMUS_NOTIFICATION_SEGSTART)             {                 // Is this the start of the dance music?                 // It was scheduled to start on a measure, so we                 // needed to wait and start once it was ready.                 if (pMsg->punkUser == g_pDanceMusic)                 {                      // Yes! Begonia can jump up and start dancing.                      g_dwBegoniaMove = BD_START;                 }             }         }         else if (pNotify->guidNotificationType ==             GUID_NOTIFICATION_MEASUREANDBEAT)         {             // Begonia has rhythm. She moves in time with the music.             // Read the beat field to decide what to do.             // Each time g_dwBegoniaMove changes, the game engine             // sets her on a new path and returns g_dwBegoniaMove to BD_NEXT.             if (pNotify->dwField1 == 2)             {                 // Begonia jumps on beat 3.                 g_dwBegoniaMove = BD_JUMP;             }             else             {                 // On any other beat, Begonia wiggles.                 g_dwBegoniaMove = BD_WIGGLE;             }         }     }     // Return the pmsg to the Performance. } 

Depending on how you acquired the pmsg, you may need to free it now:

     // Return the pmsg to the Performance.     pPerf->FreePMsg(pMsg); 

Note

If this exercise has inspired you to name your first daughter Begonia, please reconsider.




DirectX 9 Audio Exposed(c) Interactive Audio Development
DirectX 9 Audio Exposed: Interactive Audio Development
ISBN: 1556222882
EAN: 2147483647
Year: 2006
Pages: 170

flylib.com © 2008-2017.
If you may any questions please contact us: flylib@qtcs.net