目录

一般信息

SoundBank 的类型

每个项目存在两种类型的 bank:初始化包(Initialization Bank) 和 SoundBank 。

初始化 bank

每个项目只有一个初始化包。它是在 Wwise 生成 SoundBank 时自动创建的,名为“Init.bnk”。此特殊 bank 包含一般的项目信息,包括:

  • 总线层级结构
  • States(状态)
  • Switches(切换开关)
  • RTPC
  • 总线效果

初始化包和语言无关,因此只为所有语言生成一个包。

启动游戏时加载的第一个 SoundBank 必须是初始化 Bank。如果第一个加载的不是它,则无法加载 SoundBank 。若已经加载了其它 SoundBank,则无法卸载初始化包。初始化包的加载方式与 SoundBank 相同。

Note.gif
备注: 对于使用源、效果器或编解码器插件的工程,如果这些插件事没有先注册到声音引擎中,则初始化包的加载将会失败。请参阅 集成详情——插件集成编解码器插件 了解有关插件注册的信息。

SoundBank

每个 SoundBank 可包含:

  • 事件定义
  • 声音结构信息(声音、容器、音乐对象、角色混音器等)
  • 媒体:
    • 声音数据(内存内声音)
    • 预读声音数据(零延迟流播放声音)
    • 对流播放音频文件(文件 ID)的引用

在加载初始化包后,游戏期间可随时加载和卸载 SoundBank 。您须自行负责确保在触发事件前加载包含该事件的 SoundBank。如果发送事件时其对应 SoundBank 尚未加载,则事件不会执行。

Caution.gif
注意: SoundBank 需要初始化包中存储的信息。因此,您的游戏必须使用初始化包和同一 Wwise 工程生成的 SoundBank 。

使用 ID 或字符串(Unicode 或 Ansi)

SDK 提供两种访问 SoundBank 内项目的方式:一是使用字符串,二是使用 ID。在决定游戏中使用哪种方式之前,应考虑下列事项:

  • 使用对读者友好的代码
  • 开发环境中其它领域使用字符串的情况
  • CPU 占用
  • 内存占用

使用字符串

  • 提高代码的可读性,适用于开发阶段。
  • 适用于通常使用字符串的开发环境。
  • 把字符串转换成声音引擎使用的 ID 需要少量的 CPU。然而,除非每个游戏帧内有数千条字符串在做转换,否则大多数游戏不会注意到 CPU 占用的差异。
  • 声音引擎中不存储字符串,如果游戏引擎中已经用了这些字符串,则不会占用更多的内存。然而,如果游戏不使用字符串,则游戏将使用一些内存来存储字符串,以待转换这些字符串。

使用 ID

  • 代码可读性不好,会使开发期间查错比较困难。
  • 声音引擎在内部使用 ID,因此无需占用任何额外的 CPU。
  • 无需占用额外内存。

在大多数情况下,使用字符串就够了,但如果游戏在内存和 CPU 方面非常拮据,则可考虑使用 ID。

字符串转换

游戏可用的所有 Wwise 对象(SoundBank、事件、游戏同步器等)的 ID 计算方式是,把它们的小写名称散列(hash)成 32 位整数。

Tip.gif
技巧: 在 Wwise 中,选择 Project Settings 对话框 SoundBanks 选项卡上的“Generate SoundBank content files”选项可为各个 SoundBank 创建相应的文本文件,列举出 SoundBank 中包含的所有对象的名称和 ID。请参阅 Wwise Help 中 SoundBank 工程设置 的描述。

方法 AK::SoundEngine::GetIDFromString() 在运行时将字符串转换成 ID。它不区分大小写:将输入字符串转换成小写字母,然后再应用散列函数。

示例:使用 Unicode 字符串

假设您想发送一个以名称标识的事件。您可以使用 AK::SoundEngine::PostEvent() 的重载,它的第一个参数是一个字符串。

Note.gif
备注: 声音引擎在内部把 Unicode 字符串转换成 ID,然后调用以 ID 作为第一个参数的 PostEvent() 重载版本。除涉及到设备 I/O 的 AK::SoundEngine::LoadBank() 重载外,SDK 中所有提供字符串和 ID 重载的方法都按照这种方式来工作。section 标识 SoundBank 中将对此进行说明。
AkGameObjectID gameObj = 3;
AK::SoundEngine::RegisterGameObj( gameObj );

AkPlayingID playingID = AK::SoundEngine::PostEvent(
    L"Play_Sound_01",                   // 事件的名称(不区分大小写)。
    gameObj                             // 相关游戏对象 ID
    );

启用 ID

要直接使用 ID,而不在运行时把字符串转换成 ID,则应在生成 SoundBank 时选中“Generate header file”选项。此选项位于 Wwise 中 Project Settings 对话框的 SoundBanks 选项卡上。名为 Wwise_IDs.h 的头文件包含所有必需的 ID,此文件需要包含在游戏中。这个文件在每次生成 SoundBank 时都会更新。

有关在 Wwise 中生成 SoundBank 的详情,请参阅 Wwise 帮助。

以下是 Wwise 生成的一个非常简单的头文件示例:

///////////////////////////////////////////////////////////////////////
//
// Audiokinetic Wwise 生成 include 文件。请勿编辑。
//
///////////////////////////////////////////////////////////////////////

#ifndef __WWISE_IDS_H__
#define __WWISE_IDS_H__

namespace AK
{
    namespace EVENTS
    {
        static const AkUniqueID PLAY_SOUND_01 = 2580655723U;
        static const AkUniqueID PLAY_SOUND_02 = 2580655720U;
        static const AkUniqueID PLAY_SOUND_03 = 2580655721U;
    } // 名字空间 EVENTS
    
    namespace BANKS
    {
        static const AkUniqueID INIT = 1355168291U;
        static const AkUniqueID BANK_01 = 1576947084U;
        static const AkUniqueID BANK_02 = 1819748216U;
    } // 名字空间 BANKS
} // 名字空间 AK

#endif // __WWISE_IDS_H__

除上述信息外,Wwise 生成的头文件通常还包含其它信息,因为其中为各个 SoundBank 、Event、State、Switch 等都添加有条目。

Caution.gif
注意: 如果使用了 ID,则要在生成新 SoundBank 时持续更新 .h 文件,这点很重要。否则,可能发生 ID 不匹配或编译错误。

示例:使用 ID

假设您想使用 ID 发送某个事件。则必须包含生成的头文件“Wwise_IDs.h”。您只需使用以 ID 作为第一个参数的 PostEvent() 重载函数。

#include "Wwise_IDs.h"

// ...

AkGameObjectID gameObj = 3;
AK::SoundEngine::RegisterGameObj( gameObj );

AkPlayingID playingID = AK::SoundEngine::PostEvent(
    AK::EVENTS::PLAY_SOUND_01,          // 事件的唯一 ID
    gameObj                             // 相关游戏对象 ID
    );

标识 SoundBank

与游戏中的其它 Wwise 对象一样,SoundBank 通过 ID 进行标识。其 ID 是通过散列它们的名称而生成的。加载和卸载 SoundBank 总是涉及在任意时刻访问 I/O 设备。

从内存中加载 SoundBank

AK::SoundEngine::LoadBank() 的重载之一使用指针和大小。如果您想自己执行 I/O,则应使用它,只需告诉声音引擎您需要它准备内容即可。指针必须在 SoundBank 卸载之前一直保持有效。

SoundBank ID 存储在 SoundBank 中。AK::SoundEngine::LoadBank() 直接读取内存的重载版本会解析 SoundBank ID,并把它返回给您。您必须保管好 ID,以便用来卸载 SoundBank (使用 AK::SoundEngine::UnloadBank() 的 ID 重载)。

从文件系统加载 SoundBank

Wwise 声音引擎永远不会直接访问 I/O。所有 I/O 请求均通过接口为 AK::IAkStreamMgr 的 Stream Manager 执行(请参阅 流播放/流管理器 )。可以不沿用此模块,但 Audiokinetic 的默认实现为 I/O 传输和文件系统的底层访问以及 Low-Level IO 模块进一步定义了抽象层。 Low-Level IO(底层 IO)模块的接口是 AK::IAkLowLevelIO,并专用于 Audiokinetic 的 AK::IAkStreamMgr 实现。虽然应用中提供了 Low-Level IO(Low-Level IO)的默认实现,但其目的是让您把它替换成您自己的 Low-Level IO,特别是用于解析文件位置时(请参阅 Low-Level I/O )。

Stream Manager 和 Low-Level IO 定义了 2 种打开文件的重载:一种是使用字符串,另一种是使用 ID。同样,声音引擎 API 提供使用字符串或 ID 的 LoadBank() 重载。声音引擎最终调用的 AK::IAkLowLevelIO::Open() 的版本取决于游戏所使用的 LoadBank() 重载。另外,还取决于是否在选择“Use SoundBank names”选项的情况下生成 SoundBank。该选项位于 Project Settings 对话框的 SoundBanks 选项卡上。请参阅 Wwise Help 中 SoundBank 工程设置 的描述。

使用 SoundBank 名称

“Use SoundBank names”选项是 Wwise 中可用于生成 SoundBank 的设置之一。它会影响到声音引擎在 I/O 和文件系统方面加载 SoundBank 的方式。

Warning.gif

警告: 在使用 SDK 中提供的 Low-Level IO 的默认实现(关于 CAkDefaultLowLevelIO,请参阅 默认底层 I/O 实现 )时,存在以下限制:

  • 如果选择了Use SoundBank names,则只有基于名称的 LoadBank() 版本(带字符串参数的版本)能用。
  • 如果未选择Use SoundBank names,则只有基于名称的 LoadBank() 版本(带字符串参数的版本)能用。

然而,在使用基于文件包(File Package)的 Low-Level IO 时(关于 CAkFilePackageLowLevelIO,请参阅 示例 File Package Low-Level I/O 实现纵览 ),LoadBank() 的两个版本均可使用,且无需顾虑Use SoundBank names设置。

未选择“Use SoundBank Names”选项

在未选择此选项时,Wwise 将以以下格式的名称生成 SoundBank 文件:

  • ID.bnk。

其中“ID”是通过对 SoundBank 名称执行散列操作(hashing)而生成的 32 位数字 ID(请参阅 AK::SoundEngine::GetIDFromString())。

在此模式下,SoundBank 在内部通过 ID 来引用其它 SoundBank (其它 SoundBank 的名称未存储在引用它们的 SoundBank 中)。因此,从 PrepareEvent() 命令发出的 AK::IAkLowLevelIO::Open() 的所有调用均使用 ID 版本。将此 ID 解析为有效的文件描述符是 Low-Level IO 的责任。

AK::IAkLowLevelIO::Open() 的 ID 版本中,SDK 中提供的 Low-Level IO 的默认实现(关于 CAkDefaultLowLevelIO,请参阅 默认底层 I/O 实现 )使用 ID 创建字符串,在末尾加上“.bnk”扩展名,并调用特定于平台的本机 File Open 方法(请参阅 基本文件定位 )。

Tip.gif
技巧: 头文件 Wwise_IDs.h 中可查看 SoundBank ID——请参阅 启用 ID 一节。

选择“Use SoundBank Names”选项

当选择此选项时,Wwise 使用它们的原始名称生成为 SoundBank 文件,并在末尾加上 BNK 扩展名。

SoundBank 中存储了它们所引用的其它 SoundBank 的名称。在 PrepareEvent() 命令后,当声音引擎的 Bank Manager 需要从 I/O 加载另一 SoundBank 时,它使用 AK::IAkLowLevelIO::Open() 的字符串版本。AK::IAkLowLevelIO::Open() 的字符串版本接收 SoundBank 的名称。SoundBank 名称带有“.bnk”扩展名。在访问平台文件系统前,在文件名前面加上 SoundBank 位置的路径或者执行任何必要的路径转换是 Low-Level IO 的责任。

在选中Use SoundBank Names 选项的情况下生成的 SoundBank 稍微有点大,因为其中不仅包含它们的 ID,而且还必须存储所引用的 Soundbank 的名称。

Note.gif
备注: 生成的 SoundBank 名称及其 ID 在文件 SoundBanksInfo.xml 中一一列举出来。——请参阅 SoundBanksInfo.xml 一节。
Tip.gif
技巧:UnloadBank() 的字符串重载中,字符串在内部转换成 ID,然后 ID 重载才能被调用。可使用字符串重载函数来加载 SoundBank ,保管好返回的相关 SoundBank ID,稍后使用此 ID 卸载 SoundBank 。

.

多语言专用的(“语音”和“混合”) SoundBank

当 Wwise 创建某种语言专用的 SoundBank 时,它使用相同的 ID/文件名为有特定语言数据的每种语言生成文件。这些特殊的语言文件存储在单独的语言专用目录下。然而,声音引擎 API 的 SoundBank 加载方法(LoadBank())中没有标志来指定需要从哪个语言目录打开文件。如果选择不沿用,文件位置则应由 Low-Level IO 或 Stream Manager 来解析。

Stream Manager API 公开了(为文件 I/O)创建流的方法,流中包含指定语言特征的标志。此标志向下传播到 Low-Level IO。请参阅 文件系统标志 了解详情。

由于声音引擎的 Bank Manager 不知道需要加载的 SoundBank 是否包含特定语言的数据,因此它总是会要求 Stream Manager 首先在语言专用的目录中搜索文件(bIsLanguageSpecific 值为 True)。如果搜索过程失败,Bank Manager 会再试一次,但这次它将要求 Stream Manager 在通用目录中搜索(bIsLanguageSpecific 值为 False)。

请参阅 文件位置解析 了解有关文件位置的讨论。您可能还想阅读描述默认实现的章节(基本文件定位 ),了解有关如何避免 SoundBank 文件路径定位错误的技巧。

流播放音频文件

SoundBank 总是存储它们所引用的流播放音频文件的 ID。当声音引擎准备开始播放正在流播放的源时,它从 SoundBank 中获取 ID,并调用 Stream Manager 的 ID 重载版本。此操作最终会调用 AK::IAkLowLevelIO::Open() 的 ID 重载版本。Low-Level IO 的默认实现使用 ID 创建字符串,并串接对应文件格式的扩展名。如果您想复制一份使用此命名方案创建的流播放文件,然后存储在 Generated SoundBanks 目录下,请使用 Project Settings 对话框 SoundBanks 选项卡上的“Copy Streamed Files”选项。此操作被定义为生成后步骤(post-generation step)。因此此操作在生成 SoundBank 后会立即执行。请参阅 Wwise 帮助文档来了解 SoundBank 工程设置的完整描述。

SoundBanksInfo.xml

Wwise 中每次生成 SoundBank 时,都会直接在 SoundBank 路径下为每个平台创建一个名为 SoundBanksInfo.xml 的文件。该文件是 XML 文件,其中描述了声音引擎所需要的全部工程文件。

内容一目了然。第一部分(StreamedFiles)列举了所有的流播放音频文件,指定了这些文件的 ID、原始名称、语言和完整路径。第二部分(SoundBank)对 SoundBank 文件执行相同的操作。另外,各个 SoundBank 都会列出它所引用的流播放音频文件。

加载 SoundBank

有关 SoundBank 加载 API 的完整说明,请参阅 加载 SoundBank

参见: