在为游戏创建互动音乐时,您需要音乐的节拍信息。您可以使用音乐通知从声音引擎索取这些信息。节拍由当前正在播放的主要音乐段落(music segment)决定。由于音乐段落可能具有不同的拍号,因此节拍将随着当前正在播放的音乐而变化。当没有音乐在播放时,就不会有通知。
有两种音乐回调类型:
如果您想收到有关音乐的标记(marker)通知,在设计应用程序时需要特别注意以下几点:
AK_MusicSyncBeat = 0x0100, // 在音乐节拍点上启用通知。 AK_MusicSyncBar = 0x0200, // 音乐小节时间点上启用通知。 AK_MusicSyncEntry = 0x0400, // 在音乐入口处启用通知。 AK_MusicSyncExit = 0x0800, // 在音乐出口处启用通知。 AK_MusicSyncGrid = 0x1000, // 在音乐网格上启用通知。 AK_MusicSyncUserCue = 0x2000, // 在音乐用户提示点上启用通知。 AK_MusicSyncPoint = 0x4000, // 在音乐同步点上启用通知。 AK_MusicSyncAll = 0xff00, // 如果您想收到有关 AK_MusicSync 注册的所有通知,则使用此标志。
如果您还想在事件结束时收到通知,则应使用 AK_EndOfEvent
| AK_MusicSyncBeat,因为这些标志按位做异或运算。
AkPlayingID AK::SoundEngine::PostEvent( AkUniqueID in_eventID, // 唯一的事件 ID AkGameObjectID in_gameObjectID, // 相关游戏对象 ID AkUInt32 in_uFlags = 0, // 位掩码:见 AkCallbackType AkCallbackFunc in_pfnCallback = NULL, // 回调函数 void * in_pCookie = NULL // 回调的 cookie 将与其他信息一起 // 发送到回调函数 );
static void MusicCallback( AkCallbackType in_eType, // 回调原因的类型,在本例中,类型可以是 AK_MusicSyncBeat AkCallbackInfo* in_pCallbackInfo // 指向回调信息结构的指针,在本例中 // AkMusicSyncCallbackInfo*。 )
AK_MusicSyncBar
通知,则当收到任何其它事件类型时,您应该直接返回。in_pCallbackInfo
类型转换(typecast)为相应的信息结构类型。对于音乐通知,它是 AkMusicSyncCallbackInfo。/// 对应于 Ak_MusicSync 的回调信息结构 struct AkMusicSyncCallbackInfo : public AkCallbackInfo { AkPlayingID playingID; ///< 正在播放的事件 ID,由 PostEvent() 返回 AkCallbackType musicSyncType; ///< 可以是 AK_MusicSyncEntry、AK_MusicSyncBeat、AK_MusicSyncBar、AK_MusicSyncExit、AK_MusicSyncGrid、AK_MusicSyncPoint 或 AK_MusicSyncUserCue。 AkReal32 fBeatDuration; ///< 节拍时长,单位:秒。 AkReal32 fBarDuration; ///< 小节时长,单位:秒。 AkReal32 fGridDuration; ///< 网格时长,单位:秒。 AkReal32 fGridOffset; ///< 网格偏置,单位:秒。 };
AK_MusicSyncBeat
和 AK_MusicSyncBar,则每小节中您将收到
4 次节拍通知和小节本身的一次通知。拍号“0”对节拍和小节也很重要,而且在大多数情况下对 AK_MusicSyncEntry
也同样重要。这意味着,如果您注册小节、节拍和入口,则当音乐启动时,您将连续收到三个回调。AK_MusicSyncExit
。如果在完成当前音乐前,音乐切换到另一段落,则不会发送 AK_MusicSyncExit
通知。上述回调函数还可用于手动管理音乐播放列表中的下一项选择。这可以通过添加以下标志来实现。
AK_MusicPlaylistSelect = 0x0040 // 当音乐播放列表容器必须选择要播放的下一项时,将触发回调。
一旦收到此类事件,回调函数必须把参数 in_pCallbackInfo
强制转换成类型 AkMusicPlaylistCallbackInfo。
/// 对应于 Ak_MusicPlaylistSelect 的回调信息结构 struct AkMusicPlaylistCallbackInfo : public AkEventCallbackInfo { AkPlayingID playlistID; ///< 音乐播放列表容器中的活跃节点的 ID AkUInt32 uNumPlaylistItems; ///< 播放列表节点中的项目数(可以是段落或其它播放列表) AkUInt32 uPlaylistSelection; ///< 选择:由声音引擎设置,由回调函数更改(如果不在值域 0 <= uPlaylistSelection < uNumPlaylistItems 范围内,则忽略) AkUInt32 uPlaylistItemDone; ///< 播放列表节点已完成:由声音引擎设置,回调函数更改(如果设置为除 0 以外的任何值,则执行当前播放列表条目,并忽略 uPlaylistSelection) };
活跃的播放列表节点通过成员 playlistID
标示。在调用回调函数前,声音引擎选择播放列表节点中的下一项。此选择包含在成员 uPlaylistSelection
和 uPlaylistItemDone
中。如果 uPlaylistItemDone
设为 0,则 uPlaylistSelection
决定播放列表节点中要播放的下一项。如果 uPlaylistItemDone
未设为 0,则当前播放列表节点跳到末尾(然后父节点将变成活动节点)。成员 uPlaylistSelection
和 uPlaylistItemDone
可通过回调函数来更改。
目前当缓冲区向下传递到硬件时发送通知。这意味着在发送通知与实际播放它之间存在一个恒定的延时。这样在真正播放与标记关联的声音之前,应用程序有足够的时间来收集并处理标记中的信息。
注意这个延时取决于平台。
回调从声音引擎的主线程执行。这意味着您的应用程序应从通知中收集它所需的全部信息,并立即返回。如果需要执行任何处理,则应从通知中复制相关信息后,在单独的线程中执行。
如果应用程序占用线程太久,声音引擎可能掉入 underrun(欠载运行)状态,导致输出停止播放。