目录

Wwise SDK 2018.1.11
集成详情——音乐回调

简介

在为游戏创建互动音乐时,您需要音乐的节拍信息。您可以使用音乐通知从声音引擎索取这些信息。节拍由当前正在播放的主要音乐段落(music segment)决定。由于音乐段落可能具有不同的拍号,因此节拍将随着当前正在播放的音乐而变化。当没有音乐在播放时,就不会有通知。

有两种音乐回调类型:

  • 音乐通知(Music Notifications):告诉被调用方当前音乐的播放属性。
  • 音乐播放列表选择(Muisc Playlist Selection):被调用方可以强制选择音乐播放列表中的下一项。

如何使用音乐通知

如果您想收到有关音乐的标记(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,因为这些标志按位做异或运算。

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 的回调信息结构
{
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; ///< 网格偏置,单位:秒。
};
注解
当请求多个音乐通知时,将发送这些额外通知。这意味着,如果您在拍号 4/4 下注册 AK_MusicSyncBeatAK_MusicSyncBar,则每小节中您将收到 4 次节拍通知和小节本身的一次通知。拍号“0”对节拍和小节也很重要,而且在大多数情况下对 AK_MusicSyncEntry 也同样重要。这意味着,如果您注册小节、节拍和入口,则当音乐启动时,您将连续收到三个回调。
速度可通过以下公式计算:速度(以 BPM 为单位)= 60.0 / fBeatDuration
拍号的上限值可通过以下公式计算:上限值 = fBarDuration / fBeatDuration。 这告诉您每个小节有多少拍。
只有到达当前音乐段落的末尾时,才会发送通知 AK_MusicSyncExit 。如果在完成当前音乐前,音乐切换到另一段落,则不会发送 AK_MusicSyncExit 通知。
参见
快速入门示例集成——事件

如何使用音乐播放列表回调

上述回调函数还可用于手动管理音乐播放列表中的下一项选择。这可以通过添加以下标志来实现。

AK_MusicPlaylistSelect = 0x0040 // 当音乐播放列表容器必须选择要播放的下一项时,将触发回调。

一旦收到此类事件,回调函数必须把参数 in_pCallbackInfo 强制转换成类型 AkMusicPlaylistCallbackInfo。

/// 对应于 Ak_MusicPlaylistSelect 的回调信息结构
{
AkPlayingID playlistID; ///< 音乐播放列表容器中的活跃节点的 ID
AkUInt32 uNumPlaylistItems; ///< 播放列表节点中的项目数(可以是段落或其它播放列表)
AkUInt32 uPlaylistSelection; ///< 选择:由声音引擎设置,由回调函数更改(如果不在值域 0 <= uPlaylistSelection < uNumPlaylistItems 范围内,则忽略)
AkUInt32 uPlaylistItemDone; ///< 播放列表节点已完成:由声音引擎设置,回调函数更改(如果设置为除 0 以外的任何值,则执行当前播放列表条目,并忽略 uPlaylistSelection)
};

活跃的播放列表节点通过成员 playlistID 标示。在调用回调函数前,声音引擎选择播放列表节点中的下一项。此选择包含在成员 uPlaylistSelectionuPlaylistItemDone 中。如果 uPlaylistItemDone 设为 0,则 uPlaylistSelection 决定播放列表节点中要播放的下一项。如果 uPlaylistItemDone 未设为 0,则当前播放列表节点跳到末尾(然后父节点将变成活动节点)。成员 uPlaylistSelectionuPlaylistItemDone 可通过回调函数来更改。

通知延迟

目前当缓冲区向下传递到硬件时发送通知。这意味着在发送通知与实际播放它之间存在一个恒定的延时。这样在真正播放与标记关联的声音之前,应用程序有足够的时间来收集并处理标记中的信息。

注意这个延时取决于平台。

回调线程

回调从声音引擎的主线程执行。这意味着您的应用程序应从通知中收集它所需的全部信息,并立即返回。如果需要执行任何处理,则应从通知中复制相关信息后,在单独的线程中执行。

如果应用程序占用线程太久,声音引擎可能掉入 underrun(欠载运行)状态,导致输出停止播放。

参见
集成详情——事件