Table of Contents

Integration Details - Music Callbacks

Introduction

When creating the interactive music for your game, you may need information about the music's beat. You can request this information from the sound engine using music notifications. The beat is determined by the main music segment currently playing. Since segments can have different time signatures, the beat will change based on the music currently playing. When no music is playing, there will be no notifications.

There are two types of music callbacks:

  • Music Notifications: inform the callee of current music playback properties.
  • Music Playlist Selection: allows the callee to force the selection of a music playlist's next item.

How to Use Music Notifications

If you want to receive marker notifications about your music, there are specific things you need to be aware of when designing your application:

  • When posting a play event that contains music with the beat you want to follow, you can add one or more of the following flags:
AK_MusicSyncBeat                = 0x0100,   // Enable notifications on Music Beat.
AK_MusicSyncBar                 = 0x0200,   // Enable notifications on Music Bar.
AK_MusicSyncEntry               = 0x0400,   // Enable notifications on Music Entry Point.
AK_MusicSyncExit                = 0x0800,   // Enable notifications on Music Exit Point.
AK_MusicSyncGrid                = 0x1000,   // Enable notifications on Music Grid.
AK_MusicSyncUserCue             = 0x2000,   // Enable notifications on Music User Cue.
AK_MusicSyncPoint               = 0x4000,   // Enable notifications on Music synchronisation point.
AK_MusicSyncAll                 = 0xff00,   // Use this flag if you want to receive all notifications concerning AK_MusicSync registration. 

If you also want to receive a notification at the end of an event, you should use AK_EndOfEvent | AK_MusicSyncBeat since the flags are bitwise exclusive.

AkPlayingID AK::SoundEngine::PostEvent(
    AkUniqueID in_eventID,                  // Unique ID of the event
    AkGameObjectID in_gameObjectID,         // Associated game object ID
    AkUInt32 in_uFlags = 0,                 // Bitmask: see AkCallbackType
    AkCallbackFunc in_pfnCallback = NULL,   // Callback function
    void * in_pCookie = NULL                // Callback cookie that will be sent to the callback function 
                                            // along with additional information
);
  • Your callback function must have the following form:
static void MusicCallback(
    AkCallbackType in_eType,            // Type of callback reason, in this case it could be AK_MusicSyncBeat
    AkCallbackInfo* in_pCallbackInfo    // Pointer to callback information structure, in this case
                                        // AkMusicSyncCallbackInfo*.
    )
  • When your callback function is called, you first need to check what type of notification is passed. For example, if you only want to process AK_MusicSyncBar notifications, you should return when any other event type is received.
  • Based on the type of notification, you can typecast in_pCallbackInfo into the appropriate information structure type. For music notifications, it is AkMusicSyncCallbackInfo.
/// Callback information structure corresponding to Ak_MusicSync
struct AkMusicSyncCallbackInfo : public AkCallbackInfo
{
    AkPlayingID playingID;          ///< Playing ID of Event, returned by PostEvent()
    AkCallbackType musicSyncType;   ///< Would be either AK_MusicSyncEntry, AK_MusicSyncBeat, AK_MusicSyncBar, AK_MusicSyncExit, AK_MusicSyncGrid, AK_MusicSyncPoint or AK_MusicSyncUserCue.
    AkReal32 fBeatDuration;         ///< Beat Duration in seconds.
    AkReal32 fBarDuration;          ///< Bar Duration in seconds.
    AkReal32 fGridDuration;         ///< Grid duration in seconds.
    AkReal32 fGridOffset;           ///< Grid offset in seconds.
};
Note:
When requesting multiple music notifications, they will be sent additionally. That means that if you register for both AK_MusicSyncBeat and AK_MusicSyncBar in a 4/4 time signature, you will receive 4 beat notifications per bar + one notification for the bar itself. Time "0" also counts for a beat and a bar and in most cases so does the AK_MusicSyncEntry. This means that if you register for bars, beats and entry points, you will receive three callbacks back to back when the music starts.
The tempo can be calculated by using the following formula: Tempo (in BPM) = 60.0 / fBeatDuration
The upper value of the time signature can be calculated by using the following formula: Upper value = fBarDuration / fBeatDuration. This tells you how many beats per bar there are.
The notification AK_MusicSyncExit will only be sent if the end of the body of the current segment is reached. If the music switches to another segment before finishing the current one, the AK_MusicSyncExit nofification will not be sent.
See also:
Quick Start Sample Integration - Events

How to Use Music Playlist Callbacks

The callback function described above may also be used to manually manage a music playlist's next item selection. This is done by adding the following flag.

AK_MusicPlaylistSelect          = 0x0040    // Callback triggered when music playlist container must select the next item to play.

Upon reception of this type of event, the callback function must typecast the parameter in_pCallbackInfo to type AkMusicPlaylistCallbackInfo.

/// Callback information structure corresponding to Ak_MusicPlaylistSelect
struct AkMusicPlaylistCallbackInfo : public AkEventCallbackInfo
{
    AkPlayingID playlistID;         ///< ID of active node in music playlist container
    AkUInt32 uNumPlaylistItems;     ///< Number of items in playlist node (may be segments or other playlists)
    AkUInt32 uPlaylistSelection;    ///< Selection: set by sound engine, modified by callback function (if not in range 0 <= uPlaylistSelection < uNumPlaylistItems then ignored)
    AkUInt32 uPlaylistItemDone;     ///< Playlist node done: set by sound engine, modified by callback function (if set to anything but 0 then the current playlist item is done, and uPlaylistSelection is ignored)
};

The active playlist node is indicated by the member playlistID. The sound engine selects the next item in the playlist node to play prior to the callback function call. The selection is contained in the members uPlaylistSelection and uPlaylistItemDone. If uPlaylistItemDone is set to 0 then uPlaylistSelection determines the next item to play in the playlist node. If uPlaylistItemDone is not set to 0 then the current playlist node is to end (the parent node will then become the active node). Both members uPlaylistSelection and uPlaylistItemDone may be changed by the callback function.

Notification Latency

Currently, notification is sent when the buffer is passed down to the hardware. This means that there is a certain constant delay between when the notification is sent and the moment it actually gets played. This gives your application enough time to gather the information on the marker and process it before the sound associated with that marker is really played.

Note that this delay is platform-dependent.

Callback Thread

The callbacks are done from the sound engine's main thread. This means that your application should gather all the information it needs from the notification and return immediately. If any processing needs to be done, it should be performed in a separate thread after the relevant information has been copied from the notification.

If the application holds the thread for too long, the sound engine might fall into an underrun state and the output might stop playing.

See also:
Integration Details - Events