在 Wwise 中,二路输出(Secondary Output)指定常规 TV 音频输出之外的任何物理音频终端。最常见的二路输出是游戏控制器扬声器和耳机。二路输出功能可用于为各个输出定义独立的混音,而主扬声器/TV 混音不受影响。适用于常规混音的Wwise 功能集对二路输出也同样适用,除输出对象是控制器而非扬声器/TV 外,无其它特殊限制。
在制作方面,连通到 Secondary Bus(二路总线)层级结构的声音将使用以下两种方法之一发送到二路输出:
使用同一声源可在多个控制器和 TV 上同时播放同一声音。 在设计方面,无需知道有多少玩家可能在玩此游戏。正因如此,所以只有一条 Master Secondary Bus(主二路总线),即使可以有多个输出也是如此。此总线层级结构将用作模版在为游戏中注册的各个输出布线时使用。因此各个输出上可能会施加不同的混音和效果,具体取决于播放的声源、游戏对象上活跃的 RTPC 和 Swtich(切换开关)值。请参见下面示例部分中有关这方面的示例。
在许多设备(例如 TV 和游戏控制器)上输出同一音频时,您也许会发现设备之间存在延迟。这是声音信号路径的硬件差异造成的,因此无法避免。在控制器方面,此信号可能必须通过无线信道传输,无线信道造成的延迟可能不同于有线控制器。对于 TV,信号离开主机后,将进入接收器或 TV,它们的处理器会造成一定程度的延时。由于各个系统的 AV 设置造成的延时各有不同,因此对分别传输到扬声器/TV 和游戏控制器的声音而言,无法保证两者之间的同步。您的声音设计可能需要考虑到这条限制。
为了表示游戏中的设备,采用了常规的听者(Listener)/游戏对象(GameObject)概念。请参阅 概念: Listener 了解更多信息。游戏程序员要负责使用 AK::SoundEngine::AddSecondaryOutput
将输出设备与听者关联起来。程序员还必须选择将哪些“听者”游戏对象与各“发声体”游戏对象关联起来:使用 AK::SoundEngine::SetListeners
或 Ak::SoundEngine::SetDefaultListeners
。若此声音同时输出至 TV,请不要忘记将 TV 的听者添加至各“发声体”游戏对象。
|
Note: 每当游戏控制器(或任何其它类型的音频终端)连接到系统或从系统断开,游戏代码负责调用 AddSecondaryOutput 和 RemoveSecondaryOutput。Wwise 无法自动知道如何将具体设备关联到哪一个听者,从概念上讲,即关联到哪个玩家。 |
以下示例为 PS4 而编写。j
获取 UserID 的代码(仅限于 PS4):
SceUserServiceLoginUserIdList list; sceUserServiceGetLoginUserIdList(&list);
一个游戏控制器输出上的声音:
// 为玩家 0 添加连接到耳机终端的二路输出,与听者 #1 关联 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); // 设置听者 RegisterGameObj(MY_LISTENER1); RegisterGameObj(MY_LISTENER2); AkGameObjectID [] listenerArray1[] = {MY_LISTENER1} AkGameObjectID [] listenerArray2[] = {MY_LISTENER2} AkGameObjectID [] listenerArrayBoth = {MY_LISTENER1, MY_LISTENER2} // 设置将声音发送到听者 1 的游戏对象。 RegisterGameObj(MY_GAME_OBJECT, MY_LISTENER1, 1); // 播放一个事件。此声音必须连通到 Master Secondary Bus(或任何子总线) PostEvent("Play_Pow", MY_GAME_OBJECT);
在两个不同控制器上播放同一声音:
// 为玩家 0 添加连接到耳机终端的二路输出,与听者 #1 关联 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD, listenerArray2, 1); // 设置将声音发送给听者 1(玩家 0)和 2(玩家 1)的游戏对象 SetActiveListeners(EXISTING_GAME_OBJECT, listenerArrayBoth, 2); // 播放一个事件。此声音必须连通到 Master Secondary Bus(或任何子总线) PostEvent("Play_Pow", EXISTING_GAME_OBJECT);
在两个不同控制器上播放不同声音:
// 为玩家 0 添加连接到耳机终端的二路输出,与听者 #1 关联 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); AddSecondaryOutput(list.userId[1] /*Player ID (second player)*/, AkSink_PAD, listenerArray2, 1); // 设置将声音发送到相应听者的游戏对象 RegisterGameObj(MY_GAME_OBJECT1, listenerArray1, 1); RegisterGameObj(MY_GAME_OBJECT2, listenerArray2, 1); // 播放一个事件。此声音必须连通到 Master Secondary Bus(或任何子总线) PostEvent("Play_Pow", MY_GAME_OBJECT1); PostEvent("Play_Pif", MY_GAME_OBJECT2);
在游戏控制器输出和 TV 上播放同一声音:
// 为玩家 0 添加连接到耳机终端的二路输出,与听者 #1 关联 AddSecondaryOutput(list.userId[0] /*Player ID (first player)*/, AkSink_PAD, listenerArray1, 1); // 设置将声音发送到听者 0(TV)和 1(对于玩家 0,发送到控制器)的游戏对象 AkGameObjectID [] listenerArrayWithDefault = {MY_MAIN_LISTENER, MY_LISTENER1}; // 通常,会将 MY_MAIN_LISTENER 用作听者(具体由 AK::SoundEngine::SetDefaultListeners 定义)。 RegisterGameObj(MY_GAME_OBJECT, listenerArrayWithDefault, 2); // 播放一个事件。此声音必须连通到 Master Secondary Bus(或任何子总线),并且将一个发送连接到主层级结构中的辅助总线。 PostEvent("Play_Pow", MY_GAME_OBJECT);
以下示例阐述了如何在 Windows 上添加 SecondaryOutput 并通过耳机播放:
// 将搜索名称中包含 Headphones 的设备。 uDeviceID = AK::GetDeviceIDFromName("Headphones"); // 添加与之前发现的设备相连的二路输出,与 listener1 关联 AddSecondaryOutput(uDeviceID, AkSink_Secondary, listenerArray1, 1); // 注册仅与 listener1 关联的游戏对象。 RegisterGameObj(MY_GAME_OBJECT, listenerArray1, 1); // 播放一个事件。此声音必须连通到 Master Secondary Bus(或任何子总线),并且将一个发送连接到主层级结构中的辅助总线。 PostEvent("Play_Pow", MY_GAME_OBJECT);