Integrating X3Daudio with XAudio2

353 Views Asked by At

I am currently struggling with implementing 3D positional sound with XAudio2 library. I somehow managed to got it working when listener's and source's position are exactly 0.0f on all axis. When I move listener or source even a little bit, sound is no longer heard but is still playing. What am I missing here? Thanks :)

uint32_t sourceInputChannels = 2;
uint32_t masterInputChannels = 8;

float* outputMatrix = new float[masterInputChannels * sourceInputChannels];

// Listener
X3DAUDIO_LISTENER listener{};
listener.Position = { 0.0f, 0.0f, 0.0f };
listener.Velocity = { 0.0f, 0.0f, 0.0f };
listener.OrientFront = { 1.0f, 0.0f, 0.0f };
listener.OrientTop = { 0.0f, 0.0f, 1.0f };

// Emitter
X3DAUDIO_EMITTER sourceEmitter{};
sourceEmitter.ChannelCount = 1;
sourceEmitter.CurveDistanceScaler = FLT_MIN;
sourceEmitter.Position = { 0.0f, 0.0f, 0.0f };
sourceEmitter.Velocity = { 0.0f, 0.0f, 0.0f };
sourceEmitter.OrientFront = { 1.0f, 0.0f, 0.0f };
sourceEmitter.OrientTop = { 0.0f, 0.0f, 1.0f };
sourceEmitter.ChannelRadius = 2.0f;
sourceEmitter.InnerRadius = 2.0f;
sourceEmitter.InnerRadiusAngle = X3DAUDIO_PI / 4.0f;

X3DAUDIO_DSP_SETTINGS dspSettings{};
dspSettings.SrcChannelCount = sourceEmitter.ChannelCount; // 1

// 8 * 2, OUTPUT_CHANNELS is also present in CreateMasteringVoice
dspSettings.DstChannelCount = OUTPUT_CHANNELS * sourceVoiceDetails.InputChannels; 
dspSettings.pMatrixCoefficients = outputMatrix;

// Calculating
X3DAudioCalculate(g_CealContext->X3DInstance, &listener, &sourceEmitter, X3DAUDIO_CALCULATE_MATRIX | 
                X3DAUDIO_CALCULATE_DOPPLER | X3DAUDIO_CALCULATE_LPF_DIRECT | X3DAUDIO_CALCULATE_REVERB, &dspSettings);

sourceVoice->SetOutputMatrix(g_CealContext->XMasterVoice, sourceInputChannels, masterInputChannels, outputMatrix);
delete[] outputMatrix;
2

There are 2 best solutions below

1
ezyn On BEST ANSWER

Okay, thanks to @chuck-walbourn I managed to get it working.
The problem was that X3DAUDIO_EMITTER's member CurveDistanceScaler was set to FLT_MIN instead of some not-so-small value.
Weird thing is I was following official Microsoft documention How to integrate X3DAudio with XAudio2 and the example code uses FLT_MIN, so I do not really understand what is going on.

8
Chuck Walbourn On

X3DAudio has a lot of parameters, but I'm guessing the problem is that you have a stereo (2 channel) source voice and are trying to use 1 channel DSP settings. You are also passing a number of X3DAUDIO_CALCULATE_ flags which need more data than you are providing.

You should take a look at the original legacy DirectX SDK XAudio2 samples which are hosted on GitHub. In particular, see XAudio2Sound3D.

You should also take a look at DirectX Tool Kit for Audio.

Also, the sourceEmitter.CurveDistanceScaler and sourceEmitter.DopplerScaler should generally be 1.0.

UPDATE: If SrcChannelCount is greater than 1, then you must provide emitter azimuths. I have a helper method in DirectX Tool Kit for Audio AudioEmitter::EnableDefaultMultiChannel that sets these up based on simple speaker geometry--this is how legacy XACT handled them.

// **Note these constants came from xact3d3.h in the legacy DirectX SDK**
//
// Supported speaker positions, represented as azimuth angles.
//
// Here's a picture of the azimuth angles for the 8 cardinal points,
// seen from above.  The emitter's base position is at the origin 0.
//
//           FRONT
//             | 0  <-- azimuth
//             |
//    7pi/4 \  |  / pi/4
//           \ | /
// LEFT       \|/      RIGHT
// 3pi/2-------0-------pi/2
//            /|\
//           / | \
//    5pi/4 /  |  \ 3pi/4
//             |
//             | pi
//           BACK
//

constexpr float LEFT_AZIMUTH = 3 * X3DAUDIO_PI / 2;
constexpr float RIGHT_AZIMUTH = X3DAUDIO_PI / 2;
constexpr float FRONT_LEFT_AZIMUTH = 7 * X3DAUDIO_PI / 4;
constexpr float FRONT_RIGHT_AZIMUTH = X3DAUDIO_PI / 4;
constexpr float FRONT_CENTER_AZIMUTH = 0.0f;
constexpr float LOW_FREQUENCY_AZIMUTH = X3DAUDIO_2PI;
constexpr float BACK_LEFT_AZIMUTH = 5 * X3DAUDIO_PI / 4;
constexpr float BACK_RIGHT_AZIMUTH = 3 * X3DAUDIO_PI / 4;
constexpr float BACK_CENTER_AZIMUTH = X3DAUDIO_PI;

constexpr float c_channelAzimuths[9][8] =
{
    /* 0 */   { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f },
    /* 1 */   { 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f },
    /* 2 */   { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, 0.f, 0.f, 0.f, 0.f, 0.f, 0.f },
    /* 2.1 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, LOW_FREQUENCY_AZIMUTH, 0.f, 0.f, 0.f, 0.f, 0.f },
    /* 4.0 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, BACK_LEFT_AZIMUTH, BACK_RIGHT_AZIMUTH, 0.f, 0.f, 0.f, 0.f },
    /* 4.1 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, LOW_FREQUENCY_AZIMUTH, BACK_LEFT_AZIMUTH, BACK_RIGHT_AZIMUTH, 0.f, 0.f, 0.f },
    /* 5.1 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, FRONT_CENTER_AZIMUTH, LOW_FREQUENCY_AZIMUTH, BACK_LEFT_AZIMUTH, BACK_RIGHT_AZIMUTH, 0.f, 0.f },
    /* 6.1 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, FRONT_CENTER_AZIMUTH, LOW_FREQUENCY_AZIMUTH, BACK_LEFT_AZIMUTH, BACK_RIGHT_AZIMUTH, BACK_CENTER_AZIMUTH, 0.f },
    /* 7.1 */ { FRONT_LEFT_AZIMUTH, FRONT_RIGHT_AZIMUTH, FRONT_CENTER_AZIMUTH, LOW_FREQUENCY_AZIMUTH, BACK_LEFT_AZIMUTH, BACK_RIGHT_AZIMUTH, LEFT_AZIMUTH, RIGHT_AZIMUTH }
};

...

emitter.ChannelCount = channels;

emitter.ChannelRadius = 1.f;

emitter.pChannelAzimuths = (channels <= 8)
    ? &c_channelAzimuths[channels] : nullptr;