Table of Contents

Wwise SDK 2019.2.10
Advanced Mix Customization Using the Speaker Matrix Callback

Some games have very specific needs in terms of routing and panning, which may not be readily available in Wwise. One way to work around this limitation is to register to the "speaker matrix callback". This callback is called when a voice or a bus is about to be mixed into another bus. From this callback, you can change the global and channel specific level of the voice or bus, thus modifying the mix or panning.

The following example shows how you can register to this callback for a voice. This happens when you post the event that will play this voice.

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

The callback VoiceCallback illustrates how you can identify the output bus, change the base volume of the voice as it gets mixed into the output bus, and change the panning volumes to simulate a different angle of incidence. AkSpeakerVolumeMatrixCallbackInfo::pContext exposes information relative to the voice, and AkSpeakerVolumeMatrixCallbackInfo::pMixerContext exposes information relative to the bus into which it is mixed (the dry output bus, or an auxiliary send).

static void VoiceCallback(
AkCallbackType in_eType, // Callback type.
AkCallbackInfo* in_pCallbackInfo // Structure containing desired information. You can cast it to the proper sub-type, depending on the callback type.
)
{
// We know this is a speaker volume matrix callback. Cast to proper subtype.
AkSpeakerVolumeMatrixCallbackInfo* pVolumeCallbackInfo = (AkSpeakerVolumeMatrixCallbackInfo*)in_pCallbackInfo;
// Event, game object and playing ID correspond to the IDs passed to / returned from PostEvent().
AkUniqueID eventID = pVolumeCallbackInfo->eventID;
AkGameObjectID objID = pVolumeCallbackInfo->gameObjID;
AkPlayingID playingID = pVolumeCallbackInfo->playingID;
AKASSERT( eventID == AK::EVENTS::PLAY_HELLO );
// This callback gets called for each bus into which the voice is routed. In this example, we want to customize mix into the "My_Dry_Bus" bus only.
if ( pVolumeCallbackInfo->pMixerContext->GetBusID() != AK::SoundEngine::GetIDFromString( "My_Dry_Bus" ) )
return;
// Apply arbitrary changes to "base" volumes (i.e. common to all channels).
// ---------------------------------------------------------------------------------
// Double the volume (+6dB) of the voice into "My_Dry_Bus".
*pVolumeCallbackInfo->pfBaseVolume *= 2.f;
// Undo distance attenuation of the voice into "My_Dry_Bus" (in the single position case).
*pVolumeCallbackInfo->pfEmitterListenerVolume = 1.f;
// Change panning of the voice into "My_Dry_Bus". Say the sound uses 3D positioning.
// ---------------------------------------------------------------------------------
AkUInt32 uNumPosition = pVolumeCallbackInfo->pContext->GetNum3DPositions();
// A 3D sound may have multiple positions (see AK::SoundEngine::SetMultiplePositions()). In this example, consider first one only.
if ( uNumPosition > 0 )
{
// Query the listener position. Typically, the bus into which the voice is mixed is tied to the listener. So, get the game object associated with the mixer.
AkTransform posListener;
AK::IAkGameObjectPluginInfo * pBusObject = pVolumeCallbackInfo->pMixerContext->GetGameObjectInfo();
if (pBusObject)
{
pBusObject->GetGameObjectPosition(0, posListener);
// Flip the listener upside down, for fun.
AkVector listenerTop = posListener.OrientationTop();
listenerTop.X = -listenerTop.X;
listenerTop.Y = -listenerTop.Y;
listenerTop.Z = -listenerTop.Z;
posListener.SetOrientation(posListener.OrientationFront(), listenerTop);
// Get the emitter game object position.
AkTransform posEmitter;
pVolumeCallbackInfo->pContext->GetVoiceInfo()->GetGameObjectPosition(0, posEmitter);
// Use mixing services of the bus/mixer to compute new panning volumes.
pVolumeCallbackInfo->pMixerContext->Compute3DPositioning(
posEmitter, // Emitter transform.
posListener, // Listener transform.
pVolumeCallbackInfo->pContext->GetCenterPerc(), // Center percentage. Only applies to mono inputs to outputs that have a center.
pVolumeCallbackInfo->pContext->GetSpread(0), // Spread.
pVolumeCallbackInfo->pContext->GetFocus(0), // Focus.
pVolumeCallbackInfo->inputConfig, // Channel configuration of the input.
pVolumeCallbackInfo->inputConfig.uChannelMask, // Mask of input channels selected for panning (excluded input channels don't contribute to the output).
pVolumeCallbackInfo->outputConfig, // Desired output configuration.
pVolumeCallbackInfo->pVolumes // Returned volumes matrix. Must be preallocated using AK::SpeakerVolumes::Matrix::GetRequiredSize() (see AK::SpeakerVolumes::Matrix services).
);
}
}
}

The following example shows how you can register to a bus callback. In this case, AkSpeakerVolumeMatrixCallbackInfo::pContext exposes information relative to the bus to which we registered ("My_Bus"), and AkSpeakerVolumeMatrixCallbackInfo::pMixerContext exposes information relative to the bus into which it is mixed, its parent bus (or the next mixing bus in the signal chain).

static void BusCallback(
AkSpeakerVolumeMatrixCallbackInfo* in_pCallbackInfo // Structure containing desired bus information.
)
{
// Called from a bus: cannot be associated to a playing ID.
AKASSERT( in_pCallbackInfo->playingID == AK_INVALID_PLAYING_ID );
// Change panning volumes of the mixdown signal at the output of this bus before it gets mixed into its parent;
// Using mixing services, transmix input into a 3-stereo configuration, and silence out contribution to all other channels of the parent bus.
// Allocate a volume matrix to obtain transmix gains (input_config -> 3-stereo).
AkChannelConfig cfgThreeStereo;
in_pCallbackInfo->inputConfig, // Channel configuration of the input.
cfgThreeStereo, // Channel configuration of the mixer output.
in_pCallbackInfo->pContext->GetCenterPerc(),// Center%: Use center% value computed by Wwise.
mxTransmix );
// Copy result into real mixing matrix and clear out the back channels and LFE (if applicable).
// Warning: we cannot assume that the mixing bus has a center channel, so we need to verify it.
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++ )
{
// Get output volume vector for each input channel.
AK::SpeakerVolumes::VectorPtr vTransmixOut = AK::SpeakerVolumes::Matrix::GetChannel( mxTransmix, uChanIn, cfgThreeStereo.uNumChannels );
// Copy panning to front channels.
AkUInt32 uChanOut = 0;
while ( uChanOut < uNumOutputChannelsToCopy )
{
vMixOut[uChanOut] = vTransmixOut[uChanOut];
++uChanOut;
}
// Clear out other channels.
while ( uChanOut < in_pCallbackInfo->outputConfig.uNumChannels )
{
vMixOut[uChanOut] = 0;
++uChanOut;
}
}
}

The next example shows how you can register to a bus to query its metering data.

// Register to bus metering. Note: there is a significant cost to registering to metering, especially True Peak and K-Weighted Power.
static void MeterCallback(
AK::IAkMetering * in_pMetering, // AK::IAkMetering interface for retrieving metering information.
AkChannelConfig in_channelConfig, // Channel configuration of the bus.
AkMeteringFlags in_eMeteringFlags // Metering flags that were asked for in RegisterBusMeteringCallback(). You may only access corresponding meter values from in_pMeteringInfo. Others will fail.
)
{
// At least true peak and K-weighted power metering must be enabled since we registered for this callback.
AKASSERT( ( in_eMeteringFlags & AK_EnableBusMeter_TruePeak ) && ( in_eMeteringFlags & AK_EnableBusMeter_KPower ) );
// Get K-weighted power and do something with it.
AkReal32 fPower = in_pMetering->GetKWeightedPower();
// Get true peak and do something with it.
// There is one value per channel.
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
Interface to retrieve metering information about a buffer.
Definition: AkCommonDefs.h:208
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
AkUInt64 AkGameObjectID
Game object ID.
Definition: AkTypes.h:65
virtual AkReal32 GetKWeightedPower()=0
const AkVector & OrientationFront() const
Get orientation front vector.
Definition: AkTypes.h:337
const AkVector & OrientationTop() const
Get orientation top vector.
Definition: AkTypes.h:343
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
AkCallbackType
Type of callback. Used as a bitfield in methods AK::SoundEngine::PostEvent() and AK::SoundEngine::Dyn...
Definition: AkCallback.h:49
virtual AKRESULT GetGameObjectPosition(AkUInt32 in_uIndex, AkSoundPosition &out_position) const =0
AKSOUNDENGINE_API AKRESULT RegisterBusMeteringCallback(AkUniqueID in_busID, AkBusMeteringCallbackFunc in_pfnCallback, AkMeteringFlags in_eMeteringFlags)
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:318
virtual AK::SpeakerVolumes::ConstVectorPtr GetTruePeak()=0
AkUInt32 AkUniqueID
Unique 32-bit ID.
Definition: AkTypes.h:57
virtual AkReal32 GetFocus(AkUInt32 in_uIndex)=0
AkReal32 X
X Position.
Definition: AkTypes.h:317
AkForceInline VectorPtr GetChannel(MatrixPtr in_pVolumeMx, AkUInt32 in_uIdxChannelIn, AkUInt32 in_uNumChannelsOut)
Get pointer to volume distribution for input channel in_uIdxChannelIn.
#define AK_SPEAKER_SETUP_3STEREO
3.0 setup channel mask
Definition: AkSpeakerConfig.h:62
virtual AkUInt32 GetNum3DPositions()=0
#define AKASSERT(Condition)
Definition: AkAssert.h:76
AkMeteringFlags
Metering flags. Used for specifying bus metering, through AK::SoundEngine::RegisterBusVolumeCallback(...
Definition: AkTypes.h:785
#define AkAlloca(_size_)
Stack allocations.
Definition: AkPlatformFuncs.h:117
AkReal32 Z
Z Position.
Definition: AkTypes.h:319
void SetOrientation(const AkVector &in_orientationFront, const AkVector &in_orientationTop)
Set orientation. Orientation front and top should be orthogonal and normalized.
Definition: AkTypes.h:409
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
@ AK_EnableBusMeter_KPower
Enable computation of K-weighted power metering (used as a basis for computing loudness,...
Definition: AkTypes.h:791
virtual AkUniqueID GetBusID()=0
static const AkPlayingID AK_INVALID_PLAYING_ID
Invalid playing ID.
Definition: AkTypes.h:96
virtual AKRESULT ComputeSpeakerVolumesDirect(AkChannelConfig in_inputConfig, AkChannelConfig in_outputConfig, AkReal32 in_fCenterPerc, AK::SpeakerVolumes::MatrixPtr out_mxVolumes)=0
AKSOUNDENGINE_API AkUInt32 GetIDFromString(const char *in_pszString)
virtual IAkGameObjectPluginInfo * GetGameObjectInfo()=0
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
float AkReal32
32-bit floating point
Definition: AkTypes.h:103
@ AK_EnableBusMeter_TruePeak
Enable computation of true peak metering (most CPU and memory intensive).
Definition: AkTypes.h:788
Game object information available to plugins.
Definition: IAkPlugin.h:92
3D vector.
Definition: AkTypes.h:300
uint32_t AkUInt32
Unsigned 32-bit integer.
Definition: AkTypes.h:85
AKSOUNDENGINE_API AkPlayingID PostEvent(AkUniqueID in_eventID, AkGameObjectID in_gameObjectID, AkUInt32 in_uFlags=0, AkCallbackFunc in_pfnCallback=NULL, void *in_pCookie=NULL, AkUInt32 in_cExternals=0, AkExternalSourceInfo *in_pExternalSources=NULL, AkPlayingID in_PlayingID=AK_INVALID_PLAYING_ID)
@ AK_SpeakerVolumeMatrix
Callback triggered at each frame, letting the client modify the speaker volume matrix....
Definition: AkCallback.h:55
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:324
AkUInt32 AkPlayingID
Playing ID.
Definition: AkTypes.h:60
AkPlayingID playingID
Playing ID of Event, returned by PostEvent()
Definition: AkCallback.h:97
const AkReal32 * ConstVectorPtr
Constant volume vector. Access each element with the standard bracket [] operator.
Definition: AkSpeakerVolumes.h:51
AKSOUNDENGINE_API AKRESULT RegisterBusVolumeCallback(AkUniqueID in_busID, AkBusCallbackFunc in_pfnCallback)