XACT supports 3D audio ouput on cues using the X3DAudio library. This section describes how to get started using X3DAudio and its associated XACT helper functions to add 3D positioning to an XACT-enabled title.
The X3DAudio library is a 3D audio geometry library that provides positional audio calculation between sound emitters and sound listeners. XACT uses X3DAudio to calculate and apply 3D positional information to cues and their associated sound playback, so that users will hear sounds, in stereo or 5.1 configurations, with realistic positioning effects.
XACT also uses the 3D information to set the values of implicit variables on cues, so that the audio designer can create effects based on positional information, such as attenuation of volume based on distance between emitter and listener, etc.
X3DAudio is strictly a 3D math library with no signal processing capability. In order to easily integrate the X3DAudio library into XACT so that positional information can be calculated and applied to cues, XACT provides two helper functions:
To use X3DAudio to apply 3D sounds to an XACT cue, follow these steps:
To calculate 3D positional information, X3DAudio must be given initial data about the configuration of the sound channels held by the sound emitter, and the number of sound channels held by the listener. These two values, stored in the X3DAUDIO_DSP_SETTINGS structure as SrcChannelCount and DstChannelCount determine how the calculations will be mapped to the listener's sound output format (such as stereo or 5.1 sound).
Once the count has been set, a matrix of coefficients must be allocated. The matrix must be large enough to hold the mapping data from the source channels to the destination channels. This matrix is one-dimensional, and must contain a number of elements equal to SrcChannelCount x DstChannelCount. The matrix should not be filled in with values manually, as this will be done when XACT3DCalculate is called.
The following code configures a X3DAUDIO_DSP_SETTINGS structure with mappings for either stereo or 5.1 destination sound, from either a mono or stereo source:
UINT32 srcChannelCount; // number of points on the emitter. (DSPSettings.SrcChannelCount) UINT32 speakerconfig; // either SPEAKER_STEREO or SPEAKER_5POINT1 (Should match the speaker configuration of the user's system) // Set up DSP settings based on your desired speaker configuration and emitter channel count X3DAUDIO_DSP_SETTINGS DSPSettings; // Set source channel and matrix coeeficients DSPSettings.SrcChannelCount = srcChannelCount; switch( speakerconfig ) { case SPEAKER_STEREO: //Set destination //Destination channels must be 2 for stereo DSPSettings.DstChannelCount = 2; // must match number of channels of SpeakerChannelMask sent to XACT3DCalculate DSPSettings.pMatrixCoefficients = new FLOAT32[DSPSettings.SrcChannelCount * DSPSettings.DstChannelCount]; break; case SPEAKER_5POINT1: //Set destination //Destination channels must be 6 for 5.1 sound DSPSettings.DstChannelCount = 6; // must match number of channels of SpeakerChannelMask sent to XACT3DCalculate DSPSettings.pMatrixCoefficients = new FLOAT32[DSPSettings.SrcChannelCount * DSPSettings.DstChannelCount]; default: // HANDLE FAILURE break; }
Note that this code only handles 1- or 2-channel sources. In more complicated scenarios, source material may be 5.1 format, and so the source channel count may be 6, increasing the size of the matrix. Since XACT acts on cues and not individual waves, it may not be possible to know the source channel count in advance. In the case that the source channel count specified does not match the actual source content channels, XACT will approximate the mix.
When choosing either SPEAKER_STEREO or SPEAKER_5POINT1 for speaker configuration (shown in the above code as the speakerconfig variable), you should match the user's speaker configuration as set in mmsys.cpl. You can use IDirectSound8::GetSpeakerConfig to retrieve the user's speaker configuration.
X3DAudio functions by calculating positional information between emitters and listeners. The XACT implementation of X3DAudio uses one emitter and one listener for every call to XACT3DCalculate.
Your title will need to provide the positioning information that will be used to fill in the emitter and listener structures. The following code sets up a simple emitter and listener:
// generic listener that's not moving X3DAUDIO_LISTENER listener = { Z_AXIS_VECTOR, // z axis {0,0,1}, orient front Y_AXIS_VECTOR, // y axis {0,1,0}, orient top POSITION_VECTOR, // user defined vector for position ZERO_VECTOR }; // {0,0,0}, listener not moving // Audio cone. Ignored in multi-point emitters (channel count > 1) X3DAUDIO_CONE cone = { X3DAUDIO_PI/2.0f, // InnerAngle X3DAUDIO_PI, // OuterAngle 2.0f, // InnerVolume 1.0f, // OuterVolume 0.0f, // InnerLPF 0.0f, // OuterLPF 0.0f, // InnerReverb 0.0f }; // OuterReverb //set up emitter X3DAUDIO_EMITTER emitter; emitter.pCone = &cone; // the following need to be orthonormal emitter.OrientFront = Z_AXIS_VECTOR; emitter.OrientTop = Y_AXIS_VECTOR; emitter.Position = ZERO_VECTOR; emitter.Velocity = ZERO_VECTOR; // needs to not be zero if you want to hear Doppler effect emitter.ChannelCount = pDSPSettings->SrcChannelCount; // emitter ChannelCount and DSP Setting's SrcChannelCount must match emitter.ChannelRadius = 0.0f; // this will be set by XACT3DCalculate if ChannelCount > 1. // will be set by XACT3DCalculate emitter.pChannelAzimuths = NULL; // will be set by XACT3DCalculate emitter.pVolumeCurve = emitter.pLFECurve = emitter.pLPFDirectCurve = emitter.pLPFReverbCurve = emitter.pReverbCurve = NULL; emitter.CurveDistanceScaler = FLT_MIN; emitter.DopplerScaler = 1.0f;
Note that several fields of the emitter are set to NULL to use default values, or values provided by the XACT3DCalculate function.
The X3DAUDIO_CONE structure used in the above example is optional. On a single-channel emitter, setting the pCone value to NULL will result in an omnidirectional emitter.
The final steps are to call XACT3DCalculate to calculate the final channel mapping that will be applied, and then to call XACT3DApply to then apply this mapping to a cue, and copy over 3D information, such as distance, to the cue's implicit variables.
The following code assumes the XACT engine is initialized, and a cue is available:
// call calculate and apply. It doesn't matter if the cue is already playing or just prepared. hr = XACT3DCalculate(speakerconfig, &listener, &emitter, &DSPSettings, g_pEngine); if(S_OK == hr) { hr = XACT3DApply( &DSPSettings, pCue); }
When a call to XACT3DApply is successful, the cue that is the target of the call will be updated by XACT with values for several of its implicit variables:
Variable | Meaning |
---|---|
Distance | The distance from the emitter to the listener. Corresponds with the value of X3DAUDIO_DSP_SETTINGS.EmitterToListenerDistance returned by XACT3DCalculate. |
OrientationAngle | The interior angle from emitter to listener, expressed in degrees with respect to the emitter's front orientation. Corresponds with the value of X3DAUDIO_DSP_SETTINGS.EmitterToListenerAngle returned by XACT3DCalculate, converted to degrees. |
DopplerPitchScalar | The doppler shift factor between the source and the emitter. Corresponds with the value of X3DAUDIO_DSP_SETTINGS.DopplerFactor returned by XACT3DCalculate. |
If XACT's 3D functionality is to be used in a title, the audio designer can use RPCs to relate the changes in these implicit variables to values of sound parameters such as pitch or volume.