mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 12:44:46 +00:00
246 lines
8.2 KiB
C++
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;
|
|
}
|