目录

Wwise SDK 2019.2.3
使用 Speaker Matrix Callback 定制高级混音

某些游戏对信号通路和声像平移有非常特殊的要求,而 Wwise 中可能无法满足这些要求。解决此限制的一种方法是注册到“Speaker Matrix Callback”(扬声器矩阵回调)。当 voice(声部)或总线将混入到另一条总线时,将调用此回调。通过此回调,您可以更改全局的和声道专用的声部或总线电平,从而修改混音或声像平移。

下面示例显示您可以如何为声部注册到此回调。注册是在发送播放此声部的事件时完成的。

‘AK::SoundEngine::PostEvent( AK::EVENTS::PLAY_HELLO, GAME_OBJECT_HUMAN, AK_SpeakerVolumeMatrix, VoiceCallback );

VoiceCallback 回调描述如何识别输出总线,更改声部混入输出总线时的基础音量,以及更改声像平移音量来模拟不同的入射角。AkSpeakerVolumeMatrixCallbackInfo::pContext 暴露出声部相关信息,而 AkSpeakerVolumeMatrixCallbackInfo::pMixerContext 暴露出声部混入的总线相关信息(干信号的输出总线或辅助发送)。

static void VoiceCallback(
AkCallbackType in_eType, // 回调类型.
AkCallbackInfo* in_pCallbackInfo // 包含所需信息的结构。根据回调类型,您可以将它转换为适当的子类型。
)
{
// 我们知道这是扬声器音量矩阵回调。转换到适当的子类型。
AKASSERT( in_eType == AK_SpeakerVolumeMatrix );
AkSpeakerVolumeMatrixCallbackInfo* pVolumeCallbackInfo = (AkSpeakerVolumeMatrixCallbackInfo*)in_pCallbackInfo;
// 事件、游戏对象和播放 ID 对应于传递给 PostEvent() 以及 PostEvent() 返回的 ID。
AkUniqueID eventID = pVolumeCallbackInfo->eventID;
AkGameObjectID objID = pVolumeCallbackInfo->gameObjID;
AkPlayingID playingID = pVolumeCallbackInfo->playingID;
AKASSERT( eventID == AK::EVENTS::PLAY_HELLO );
// 针对声部连通到的各条总线调用此回调。在本例中,我们只希望定制混音到“My_Dry_Bus”总线。
if ( pVolumeCallbackInfo->pMixerContext->GetBusID() != AK::SoundEngine::GetIDFromString( "My_Dry_Bus" ) )
return;
// 随便更改一下“基本”音量(即通用于所有声道)。
// ---------------------------------------------------------------------------------
// 将送入“My_Dry_Bus”的声部音量提高两倍(+6dB)。
*pVolumeCallbackInfo->pfBaseVolume *= 2.f;
// 撤消进入“My_Dry_Bus”的声部的距离衰减(在单一位置情况下)。
*pVolumeCallbackInfo->pfEmitterListenerVolume = 1.f;
// 更改进入“My_Dry_Bus”的声部的声像平移。假设声音使用3D定位。
// ---------------------------------------------------------------------------------
AkUInt32 uNumPosition = pVolumeCallbackInfo->pContext->GetNum3DPositions();
// 3D声音可具有多个位置(请参阅AK::SoundEngine::SetMultiplePositions())。在本例中,只考虑第一个位置。
if ( uNumPosition > 0 )
{
// 查询听者位置。通常,声部混音所用总线会与听者绑定。藉此,将游戏对象与混音器关联。
AkTransform posListener;
AK::IAkGameObjectPluginInfo * pBusObject = pVolumeCallbackInfo->pMixerContext->GetGameObjectInfo();
if (pBusObject)
{
pBusObject->GetGameObjectPosition(0, posListener);
// 颠倒听者位置,看有什么效果。
AkVector listenerTop = posListener.OrientationTop();
listenerTop.X = -listenerTop.X;
listenerTop.Y = -listenerTop.Y;
listenerTop.Z = -listenerTop.Z;
posListener.SetOrientation(posListener.OrientationFront(), listenerTop);
// 获取“发声体”游戏对象位置。
AkTransform posEmitter;
pVolumeCallbackInfo->pContext->GetVoiceInfo()->GetGameObjectPosition(0, posEmitter);
// 使用总线/混音器的混音服务计算新的声像平移音量。
pVolumeCallbackInfo->pMixerContext->Compute3DPositioning(
posEmitter, // Emitter transform.
posListener, // 听者的变换。
pVolumeCallbackInfo->pContext->GetCenterPerc(), // 中置百分比。仅将单声道输入应用于带中置的输出。
pVolumeCallbackInfo->pContext->GetSpread(0), // 散布(Spread)。
pVolumeCallbackInfo->pContext->GetFocus(0), // 聚焦(Focus)。
pVolumeCallbackInfo->inputConfig, // 输入的声道配置。
pVolumeCallbackInfo->inputConfig.uChannelMask, // 声像摆位选用的输入声道掩码(被排除的输入声道将不会作用于输出)。
pVolumeCallbackInfo->outputConfig, // 所需输出配置。
pVolumeCallbackInfo->pVolumes // 返回的音量矩阵。Must be preallocated using AK::SpeakerVolumes::Matrix::GetRequiredSize() (see AK::SpeakerVolumes::Matrix services).
);
}
}
}

以下示例显示如何注册到总线回调。在本例中,AkSpeakerVolumeMatrixCallbackInfo::pContext 暴露出总线相关信息,我们要将("My_Bus")注册到这条总线,而 AkSpeakerVolumeMatrixCallbackInfo::pMixerContext 也对总线的父总线(或信号链中的下一条混音总线)暴露出总线相关信息,该总线是要将信号混音进去的总线。

static void BusCallback(
AkSpeakerVolumeMatrixCallbackInfo* in_pCallbackInfo // 包含所需总线信息的结构。
)
{
// 从总线调用:无法关联到播放 ID(playing ID)。
AKASSERT( in_pCallbackInfo->playingID == AK_INVALID_PLAYING_ID );
// 在此总线混音到其父总线前,更改其总线输出处的缩混信号的声像平移音量;
// 使用混音服务将输入转混(transmix)到 3 立体声配置,并且静音掉父总线对其他所有声道的作用。
// 分配音量矩阵以获取转混增益(input_config -> 3-stereo)。
AkChannelConfig cfgThreeStereo;
cfgThreeStereo.SetStandard( AK_SPEAKER_SETUP_3STEREO );
AkUInt32 uSize = AK::SpeakerVolumes::Matrix::GetRequiredSize( in_pCallbackInfo->inputConfig.uNumChannels, cfgThreeStereo.uNumChannels );
in_pCallbackInfo->inputConfig, // 输入的声道配置。
cfgThreeStereo, // 混音器输出的声道配置。
in_pCallbackInfo->pContext->GetCenterPerc(),// Center%:使用 Wwise 计算的 center% 值。
mxTransmix );
// 将结果复制到真正的混音矩阵,并清除后置声道和 LFE(如适用的话)。
// 警告:我们不能假定混音总线有中置声道,因此我们需要证实一下。
AkChannelConfig cfgThreeStereoANDBus;
cfgThreeStereoANDBus.SetStandard( AK_SPEAKER_SETUP_3STEREO & in_pCallbackInfo->outputConfig.uChannelMask );
AkUInt32 uNumOutputChannelsToCopy = cfgThreeStereoANDBus.uNumChannels;
for ( AkUInt32 uChanIn = 0; uChanIn < in_pCallbackInfo->inputConfig.uNumChannels; uChanIn++ )
{
// 为各个输入声道获取输出音量向量。
AK::SpeakerVolumes::VectorPtr vTransmixOut = AK::SpeakerVolumes::Matrix::GetChannel( mxTransmix, uChanIn, cfgThreeStereo.uNumChannels );
// 将声像平移复制到前声道。
AkUInt32 uChanOut = 0;
while ( uChanOut < uNumOutputChannelsToCopy )
{
vMixOut[uChanOut] = vTransmixOut[uChanOut];
++uChanOut;
}
// 清除其他声道。
while ( uChanOut < in_pCallbackInfo->outputConfig.uNumChannels )
{
vMixOut[uChanOut] = 0;
++uChanOut;
}
}
}

下一示例显示如何注册到总线以查询它的电平表数据。

// 注册到总线电平表。注意:注册到电平表特别是 True Peak(真峰值)和 K-Weighted Power(K加权功率电平表)需要相当大的性能消耗。
AK::SoundEngine::RegisterBusMeteringCallback( AK::SoundEngine::GetIDFromString( "My_Bus" ), MeterCallback, (AkMeteringFlags)( AK_EnableBusMeter_TruePeak | AK_EnableBusMeter_KPower ) );
static void MeterCallback(
AK::IAkMetering * in_pMetering, // AK::IAkMetering 接口用于获取电平表信息。
AkChannelConfig in_channelConfig, // 总线的声道配置。
AkMeteringFlags in_eMeteringFlags // RegisterBusMeteringCallback() 中请求的电平表标识。您只可从 in_pMeteringInfo 获取相应的电平表值。尝试获取不对应的参数将失败。
)
{
// 由于我们注册了此回调,所以必须启用至少 True Peak 和 K-Weighted Power 电平表。
AKASSERT( ( in_eMeteringFlags & AK_EnableBusMeter_TruePeak ) && ( in_eMeteringFlags & AK_EnableBusMeter_KPower ) );
// 获取 K-Weighted Power,并使用它执行某项操作。
AkReal32 fPower = in_pMetering->GetKWeightedPower();
// 获取 True Peak,并使用它执行某项操作。
// 每个声道有一个值。
AK::SpeakerVolumes::ConstVectorPtr vTruePeak = in_pMetering->GetTruePeak();
for ( AkUInt32 uChannel = 0; uChannel < in_channelConfig.uNumChannels; uChannel++ )
{
AkReal32 fChannelPeak = vTruePeak[uChannel];
...
}
...
}
AK::IAkMixerInputContext * pContext
Context of the current voice/bus about to be mixed into the output bus with specified base volume and...
Definition: AkCallback.h:170
AKSOUNDENGINE_API AKRESULT __cdecl RegisterBusVolumeCallback(AkUniqueID in_busID, AkBusCallbackFunc in_pfnCallback)
Interface to retrieve metering information about a buffer.
Definition: AkCommonDefs.h:207
AkGameObjectID gameObjID
Game object ID
Definition: AkCallback.h:88
virtual AkReal32 GetSpread(AkUInt32 in_uIndex)=0
AkReal32 * pfBaseVolume
Base volume, common to all channels.
Definition: AkCallback.h:168
AkChannelConfig outputConfig
Channel configuration of the output bus.
Definition: AkCallback.h:167
AkUInt32 uNumChannels
Number of channels.
Definition: AkSpeakerConfig.h:510
AkChannelConfig inputConfig
Channel configuration of the voice/bus.
Definition: AkCallback.h:166
virtual AkReal32 GetKWeightedPower()=0
const AkVector & OrientationFront() const
Get orientation front vector.
Definition: AkTypes.h:335
const AkVector & OrientationTop() const
Get orientation top vector.
Definition: AkTypes.h:341
AkUInt32 uChannelMask
Channel mask (configuration).
Definition: AkSpeakerConfig.h:512
AkForceInline AkUInt32 GetRequiredSize(AkUInt32 in_uNumChannelsIn, AkUInt32 in_uNumChannelsOut)
Compute size (in bytes) required for given channel configurations.
AK::IAkMixerPluginContext * pMixerContext
Output mixing bus context. Use it to access a few useful panning and mixing services,...
Definition: AkCallback.h:171
virtual AKRESULT GetGameObjectPosition(AkUInt32 in_uIndex, AkSoundPosition &out_position) const =0
AkUniqueID eventID
Unique ID of Event, passed to PostEvent()
Definition: AkCallback.h:98
virtual IAkVoicePluginInfo * GetVoiceInfo()=0
AkReal32 * VectorPtr
Volume vector. Access each element with the standard bracket [] operator.
Definition: AkSpeakerVolumes.h:49
AkReal32 Y
Y Position
Definition: AkTypes.h:316
virtual AK::SpeakerVolumes::ConstVectorPtr GetTruePeak()=0
virtual AkReal32 GetFocus(AkUInt32 in_uIndex)=0
AkReal32 X
X Position
Definition: AkTypes.h:315
AKSOUNDENGINE_API AKRESULT __cdecl RegisterBusMeteringCallback(AkUniqueID in_busID, AkBusMeteringCallbackFunc in_pfnCallback, AkMeteringFlags in_eMeteringFlags)
AkForceInline VectorPtr GetChannel(MatrixPtr in_pVolumeMx, AkUInt32 in_uIdxChannelIn, AkUInt32 in_uNumChannelsOut)
Get pointer to volume distribution for input channel in_uIdxChannelIn.
virtual AkUInt32 GetNum3DPositions()=0
AkReal32 Z
Z Position
Definition: AkTypes.h:317
void SetOrientation(const AkVector &in_orientationFront, const AkVector &in_orientationTop)
Set orientation. Orientation front and top should be orthogonal and normalized.
Definition: AkTypes.h:407
AkReal32 * pfEmitterListenerVolume
Emitter-listener pair-specific gain. When there are multiple emitter-listener pairs,...
Definition: AkCallback.h:169
virtual AKRESULT Compute3DPositioning(AkReal32 in_fAngle, AkReal32 in_fElevation, AkReal32 in_fSpread, AkReal32 in_fFocus, AkChannelConfig in_inputConfig, AkChannelMask in_uInputChanSel, AkChannelConfig in_outputConfig, AkReal32 in_fCenterPerc, AK::SpeakerVolumes::MatrixPtr out_mxVolumes)=0
virtual AkUniqueID GetBusID()=0
virtual AKRESULT ComputeSpeakerVolumesDirect(AkChannelConfig in_inputConfig, AkChannelConfig in_outputConfig, AkReal32 in_fCenterPerc, AK::SpeakerVolumes::MatrixPtr out_mxVolumes)=0
Compute a direct speaker assignment volume matrix with proper downmixing rules between two channel co...
virtual IAkGameObjectPluginInfo * GetGameObjectInfo()=0
AKSOUNDENGINE_API AkUInt32 __cdecl GetIDFromString(const char *in_pszString)
AkForceInline void SetStandard(AkUInt32 in_uChannelMask)
Set channel config as a standard configuration specified with given channel mask.
Definition: AkSpeakerConfig.h:544
AkReal32 * MatrixPtr
Volume matrix. Access each input channel vector with AK::SpeakerVolumes::Matrix::GetChannel().
Definition: AkSpeakerVolumes.h:50
virtual AkReal32 GetCenterPerc()=0
Game object information available to plugins.
Definition: IAkPlugin.h:91
3D vector.
Definition: AkTypes.h:297
const typedef AkReal32 * ConstVectorPtr
Constant volume vector. Access each element with the standard bracket [] operator.
Definition: AkSpeakerVolumes.h:51
AK::SpeakerVolumes::MatrixPtr pVolumes
Pointer to volume matrix describing the contribution of each source channel to destination channels....
Definition: AkCallback.h:165
Position and orientation of game objects.
Definition: AkTypes.h:321
AkPlayingID playingID
Playing ID of Event, returned by PostEvent()
Definition: AkCallback.h:97