Monday, 16 January 2012

3D XACT using C++

Today is a heavy tech session.
I have spent a lot of time looking about on how to do 3D sound within XACT.
There are quite a few articles about the C#/XNA version, but very little in the C++ land.  Oh, and those of you who may have looked at the DirectX SDK examples know how little use they are. (I mean, the two examples they have are 500 and 600 lines of code each!)

The basics can be found at http://msdn.microsoft.com/en-us/library/ee416190.aspx
I have been working on it all day & this is what I have found so far (its not perfect, but it works).

Variables
I'm going to assume that you already have XACT working.  If not, try looking at the DX SDK examples, The XACT tutorial 1 was not too bad, though I needed to read the other examples to get it working perfectly.

You will need the following sets of variables:
// you need one set of these:
X3DAUDIO_HANDLE xact3dInstance;
X3DAUDIO_DSP_SETTINGS dspSettings;
X3DAUDIO_LISTENER listener;

// and one set of these PER 3D sound
// probably put it into a struct or similar
X3DAUDIO_EMITTER emitter;
IXACT3Cue* pCue;

The Setup
Once you have your XACT setup, you will need the following extra code, to turn on the X3DAudio:
// Assuming you have the IXACT3Engine* pEngine:

// setup the XACT3D
XACT3DInitialize(pEngine,xact3dInstance);

// check how many output channels are supported
WAVEFORMATEXTENSIBLE format;
pEngine->GetFinalMixFormat(&format);

// fill the DSP
ZeroMemory(&dspSettings,sizeof(dspSettings));
// different code's seem to suggest 1 or 2 channels for the emitter
// i'm going for 1
dspSettings.SrcChannelCount = 1;
dspSettings.DstChannelCount = format.Format.nChannels;  // as supported  
dspSettings.pMatrixCoefficients = new FLOAT32[dspSettings.SrcChannelCount * dspSettings.DstChannelCount];
ZeroMemory(dspSettings.pMatrixCoefficients ,sizeof(FLOAT32)*dspSettings.SrcChannelCount * dspSettings.DstChannelCount);

// could probably set some of the default values
// for the emitter and listener here
// (you can do this yourself) 

Playing the sound
This is just about the same as normal XACT, you just need to remember to keep a pointer to the IXACT3Cue:
// Assuming you have the IXACT3SoundBank* pSoundBank
// and you have the XACTINDEX cueIdx:

// play the sound
pSoundBank->Play(cueIdx,0,0,&pCue);
// the documentation is a little value,
// but I think you need to remember to call pCue->Release() yourself 

Making the sound 3D
To make the sound 3D, you need to specify two basic things: Where the sound is coming from and where the listener is.  Then you need to update the cue with this information.
The documentation for this seems to suggest you only need to do it once every 2-3 frames.  But here is the code:
// Set the listener information
ZeroMemory(&listener,sizeof(listener));
// set the XYZ of the camera
listener.Position = camPos;
// set the direction the camera looks in
// this must be a unit vector
listener.OrientFront = camLook;
// set the up-direction of the camera
// again, this must be a unit vector and orthogonal to camLook
listener.OrientTop = camUp;
// assuming no doppler effect 
listener.Velocity = D3DXVECTOR3(0,0,0);

// Set the emitter information
ZeroMemory(&emitter,sizeof(emitter));

// only worrying about its position, just giving fixed other info
emitter.OrientFront = D3DXVECTOR3(0,0,1);
emitter.OrientTop = D3DXVECTOR3(0,1,0);
emitter.Position = emitterPos;
emitter.Velocity = D3DXVECTOR3(0,0,0);

// emitter ChannelCount and DSP Setting's SrcChannelCount must match
emitter.ChannelCount = dspSettings.SrcChannelCount;
// computer the effects on the sound and apply it
XACT3DCalculate( xact3dInstance, &listener, &emitter, &dspSettings );
XACT3DApply( &dspSettings, pCue);

And that's the basics.
If you try this with sound sources which move around the listener, you should hear it louder on one side and quieter on the other.

Making the sound attenuate
Once I got this working, I moved on to the getting the sound to fade off.
This is where is all went wrong.
What happened is my code did not follow the documentation and I have little idea why.

According to the documentation, there should be a simple falloff of sound built it, but I could not make it work.  So I experimented until I got something working.
What I really wanted was something like this:
If you are within a certain distance of the emitter (minDistance), the sound is 100%, and after that it drops until another distance (maxDistance) where the sound reaches 0%.
According to the documentation, it should be built in, but I can I make it work, can I heck!

Therefore I had to code it myself.  At least it wasn't too much code:
// assuming a pair of float's MIN_SOUND_DIST & MAX_SOUND_DIST
// listener code unchanged:

// emitter code has the following extra lines
...
// the falloff curve:
// at range 0=>100%, MIN_SOUND_DIST=>100%, MAX_SOUND_DIST=>0%
X3DAUDIO_DISTANCE_CURVE_POINT soundFalloffPt[] = { 0.0f, 1.0f, MIN_SOUND_DIST, 1.0f, MAX_SOUND_DIST, 0.0f  };
X3DAUDIO_DISTANCE_CURVE       soundFalloff          = { &soundFalloffPt[0], 3 };
// set the falloff curve
emitter.pVolumeCurve =(X3DAUDIO_DISTANCE_CURVE*)&soundFalloff;
emitter.CurveDistanceScaler = 1.0; // this is a multiplier on all distances

// perform the XACT3DCalculate & XACT3DApply as before
Now we have sound falloff and stereo playback working
I'm a little disappointed that the default behaviour didn't work (there is a InnerRadius parameter which I could never get working), but at least the code works now.

Hope this helps
Happy Coding:
Mark

1 comment:

  1. Just wanted to say thanks for sharing your experiances with XACT in c++. As you noted there is next to nothing in terms of c++ examples and tutorials out there for XACT. I'm not sure if I really want to use XACT at the moment but I didn't want to completely dismiss it, and I had completely forgotten about the samples included in the SDK.

    Although looking through the samples wouldn't be that difficult, the thing that ticks me off the most at the moment is that XACT documentation has been removed from MSDN online due to its being already depreciated with windows 8. It has been so long since I last used a non-online resource that wasn't a hard printed book as a reference it may take so time getting used to again.

    Anyways thanks for the point in the right direction and the start point.

    -JLBShecky

    ReplyDelete