menu
版本
2017.1.9.6501
2024.1.6.8842
2023.1.14.8770
2022.1.19.8584
2021.1.14.8108
2019.2.15.7667
2019.1.11.7296
2018.1.11.6987
2017.2.10.6745
2017.1.9.6501
2016.2.6.6153
2015.1.9.5624
2024.1.6.8842
2023.1.14.8770
2022.1.19.8584
2021.1.14.8108
2019.2.15.7667
2019.1.11.7296
2018.1.11.6987
2017.2.10.6745
2017.1.9.6501
2016.2.6.6153
2015.1.9.5624
某些游戏对信号通路和声像平移有非常特殊的要求,而 Wwise 中可能无法满足这些要求。解决此限制的一种方法是注册到“Speaker Matrix Callback”(扬声器矩阵回调)。当 voice(声部)或总线将混入到另一条总线时,将调用此回调。通过此回调,您可以更改全局的和声道专用的声部或总线电平,从而修改混音或声像平移。
下面示例显示您可以如何为声部注册到此回调。注册是在发送播放此声部的事件时完成的。
‘AK::SoundEngine::PostEvent( AK::EVENTS::PLAY_HELLO, GAME_OBJECT_HUMAN, AK_SpeakerVolumeMatrix, VoiceCallback );
VoiceCallback 回调描述如何识别输出总线,更改声部混入输出总线时的基础音量,以及更改声像平移音量来模拟不同的入射角。AkSpeakerVolumeMatrixCallbackInfopContext 暴露出声部相关信息,而 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 // 返回的音量矩阵。须使用 AK::SpeakerVolumes::Matrix::GetRequiredSize() 预分配(参阅AK::SpeakerVolumes::Matrix 服务)。 ); } } }
以下示例显示如何注册到总线回调。在本例中,AkSpeakerVolumeMatrixCallbackInfopContext 暴露出总线相关信息,我们要将("My_Bus")注册到这条总线,而 AkSpeakerVolumeMatrixCallbackInfo::pMixerContext 也对总线的父总线(或信号链中的下一条混音总线)暴露出总线相关信息,该总线是要将信号混音进去的总线。
AK::SoundEngine::RegisterBusVolumeCallback( AK::SoundEngine::GetIDFromString( "My_Bus" ), BusCallback );
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 ); AK::SpeakerVolumes::MatrixPtr mxTransmix = (AK::SpeakerVolumes::MatrixPtr)AkAlloca( uSize ); in_pCallbackInfo->pMixerContext->ComputeSpeakerVolumesDirect( 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 ); AK::SpeakerVolumes::VectorPtr vMixOut = AK::SpeakerVolumes::Matrix::GetChannel( in_pCallbackInfo->pVolumes, uChanIn, in_pCallbackInfo->outputConfig.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]; ... } ... }