Torque3D/Engine/source/sfx/xaudio/sfxXAudioDevice.cpp
2012-09-19 11:15:01 -04:00

246 lines
8.2 KiB
C++

//-----------------------------------------------------------------------------
// Copyright (c) 2012 GarageGames, LLC
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to
// deal in the Software without restriction, including without limitation the
// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
// sell copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
// IN THE SOFTWARE.
//-----------------------------------------------------------------------------
#include "sfx/xaudio/sfxXAudioDevice.h"
#include "platform/async/asyncUpdate.h"
#include "core/stringTable.h"
#include "console/console.h"
#include "core/util/safeRelease.h"
#include "core/tAlgorithm.h"
#include "platform/profiler.h"
SFXXAudioDevice::SFXXAudioDevice( SFXProvider* provider,
const String& name,
IXAudio2 *xaudio,
U32 deviceIndex,
U32 speakerChannelMask,
U32 maxBuffers )
: Parent( name, provider, false, maxBuffers ),
mXAudio( xaudio ),
mMasterVoice( NULL )
{
dMemset( &mListener, 0, sizeof( mListener ) );
// If mMaxBuffers is negative then use some default value.
// to decide on a good maximum value... or set 8.
//
// TODO: We should change the terminology to voices!
if ( mMaxBuffers < 0 )
mMaxBuffers = 64;
// Create the mastering voice.
HRESULT hr = mXAudio->CreateMasteringVoice( &mMasterVoice,
XAUDIO2_DEFAULT_CHANNELS,
XAUDIO2_DEFAULT_SAMPLERATE,
0,
deviceIndex,
NULL );
if ( FAILED( hr ) || !mMasterVoice )
{
Con::errorf( "SFXXAudioDevice - Failed creating master voice!" );
return;
}
mMasterVoice->GetVoiceDetails( &mMasterVoiceDetails );
// Init X3DAudio.
X3DAudioInitialize( speakerChannelMask,
X3DAUDIO_SPEED_OF_SOUND,
mX3DAudio );
// Start the update thread.
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
{
SFXInternal::gUpdateThread = new AsyncUpdateThread
( "XAudio Update Thread", SFXInternal::gBufferUpdateList );
SFXInternal::gUpdateThread->start();
}
}
SFXXAudioDevice::~SFXXAudioDevice()
{
_releaseAllResources();
if ( mMasterVoice )
{
mMasterVoice->DestroyVoice();
mMasterVoice = NULL;
}
// Kill the engine.
SAFE_RELEASE( mXAudio );
}
SFXBuffer* SFXXAudioDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
{
SFXXAudioBuffer* buffer = SFXXAudioBuffer::create( stream, description );
if ( !buffer )
return NULL;
_addBuffer( buffer );
return buffer;
}
SFXVoice* SFXXAudioDevice::createVoice( bool is3D, SFXBuffer *buffer )
{
// Don't bother going any further if we've
// exceeded the maximum voices.
if ( mVoices.size() >= mMaxBuffers )
return NULL;
AssertFatal( buffer, "SFXXAudioDevice::createVoice() - Got null buffer!" );
SFXXAudioBuffer* xaBuffer = dynamic_cast<SFXXAudioBuffer*>( buffer );
AssertFatal( xaBuffer, "SFXXAudioDevice::createVoice() - Got bad buffer!" );
SFXXAudioVoice* voice = SFXXAudioVoice::create( mXAudio, is3D, xaBuffer );
if ( !voice )
return NULL;
voice->mXAudioDevice = this;
_addVoice( voice );
return voice;
}
void SFXXAudioDevice::_setOutputMatrix( SFXXAudioVoice *voice )
{
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
FLOAT32 matrix[12] = { 0 };
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
dspSettings.pMatrixCoefficients = matrix;
const X3DAUDIO_EMITTER &emitter = voice->getEmitter();
dspSettings.SrcChannelCount = emitter.ChannelCount;
// Calculate the output volumes and doppler.
X3DAudioCalculate( mX3DAudio,
&mListener,
&emitter,
X3DAUDIO_CALCULATE_MATRIX |
X3DAUDIO_CALCULATE_DOPPLER,
&dspSettings );
voice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
dspSettings.SrcChannelCount,
dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients,
4321 );
voice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * voice->mPitch,
4321 );
// Commit the changes.
mXAudio->CommitChanges( 4321 );
}
void SFXXAudioDevice::update()
{
PROFILE_SCOPE( SFXXAudioDevice_Update );
Parent::update();
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
FLOAT32 matrix[12] = { 0 };
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
dspSettings.pMatrixCoefficients = matrix;
dspSettings.DopplerFactor = mDopplerFactor;
// Now update the volume and frequency of
// all the active 3D voices.
VoiceVector::iterator voice = mVoices.begin();
for ( ; voice != mVoices.end(); voice++ )
{
SFXXAudioVoice* xaVoice = ( SFXXAudioVoice* ) *voice;
// Skip 2D or stopped voices.
if ( !xaVoice->is3D() ||
xaVoice->getStatus() != SFXStatusPlaying )
continue;
const X3DAUDIO_EMITTER &emitter = xaVoice->getEmitter();
dspSettings.SrcChannelCount = emitter.ChannelCount;
// Calculate the output volumes and doppler.
X3DAudioCalculate( mX3DAudio,
&mListener,
&emitter,
X3DAUDIO_CALCULATE_MATRIX |
X3DAUDIO_CALCULATE_DOPPLER,
&dspSettings );
xaVoice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
dspSettings.SrcChannelCount,
dspSettings.DstChannelCount,
dspSettings.pMatrixCoefficients,
4321 ) ;
xaVoice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * xaVoice->mPitch,
4321 );
}
// Commit the changes.
mXAudio->CommitChanges( 4321 );
}
void SFXXAudioDevice::setListener( U32 index, const SFXListenerProperties& listener )
{
// Get the transform from the listener.
const MatrixF& transform = listener.getTransform();
transform.getColumn( 3, (Point3F*)&mListener.Position );
transform.getColumn( 1, (Point3F*)&mListener.OrientFront );
transform.getColumn( 2, (Point3F*)&mListener.OrientTop );
// And the velocity...
const VectorF& velocity = listener.getVelocity();
mListener.Velocity.x = velocity.x;
mListener.Velocity.y = velocity.y;
mListener.Velocity.z = velocity.z;
// XAudio and Torque use opposite handedness, so
// flip the z coord to account for that.
mListener.Position.z *= -1.0f;
mListener.OrientFront.z *= -1.0f;
mListener.OrientTop.z *= -1.0f;
mListener.Velocity.z *= -1.0f;
}
void SFXXAudioDevice::setDistanceModel( SFXDistanceModel model )
{
mDistanceModel = model;
}
void SFXXAudioDevice::setDopplerFactor( F32 factor )
{
mDopplerFactor = factor;
}
void SFXXAudioDevice::setRolloffFactor( F32 factor )
{
mRolloffFactor = factor;
}