sfxXAudioDevice.cpp
Engine/source/sfx/xaudio/sfxXAudioDevice.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "sfx/xaudio/sfxXAudioDevice.h" 25#include "platform/async/asyncUpdate.h" 26#include "core/stringTable.h" 27#include "console/console.h" 28#include "core/util/safeRelease.h" 29#include "core/tAlgorithm.h" 30#include "platform/profiler.h" 31 32 33SFXXAudioDevice::SFXXAudioDevice( SFXProvider* provider, 34 const String& name, 35 IXAudio2 *xaudio, 36 U32 deviceIndex, 37 U32 speakerChannelMask, 38 U32 maxBuffers ) 39 : Parent( name, provider, false, maxBuffers ), 40 mXAudio( xaudio ), 41 mMasterVoice( NULL ) 42{ 43 dMemset( &mListener, 0, sizeof( mListener ) ); 44 45 // If mMaxBuffers is negative then use some default value. 46 // to decide on a good maximum value... or set 8. 47 // 48 // TODO: We should change the terminology to voices! 49 if ( mMaxBuffers < 0 ) 50 mMaxBuffers = 64; 51 52 // Create the mastering voice. 53 HRESULT hr = mXAudio->CreateMasteringVoice( &mMasterVoice, 54 XAUDIO2_DEFAULT_CHANNELS, 55 XAUDIO2_DEFAULT_SAMPLERATE, 56 0, 57 deviceIndex, 58 NULL ); 59 if ( FAILED( hr ) || !mMasterVoice ) 60 { 61 Con::errorf( "SFXXAudioDevice - Failed creating master voice!" ); 62 return; 63 } 64 65 mMasterVoice->GetVoiceDetails( &mMasterVoiceDetails ); 66 67 // Init X3DAudio. 68 X3DAudioInitialize( speakerChannelMask, 69 X3DAUDIO_SPEED_OF_SOUND, 70 mX3DAudio ); 71 72 // Start the update thread. 73 74 if( !Con::getBoolVariable( "$_forceAllMainThread" ) ) 75 { 76 SFXInternal::gUpdateThread = new AsyncUpdateThread 77 ( "XAudio Update Thread", SFXInternal::gBufferUpdateList ); 78 SFXInternal::gUpdateThread->start(); 79 } 80} 81 82 83SFXXAudioDevice::~SFXXAudioDevice() 84{ 85 _releaseAllResources(); 86 87 if ( mMasterVoice ) 88 { 89 mMasterVoice->DestroyVoice(); 90 mMasterVoice = NULL; 91 } 92 93 // Kill the engine. 94 SAFE_RELEASE( mXAudio ); 95} 96 97 98SFXBuffer* SFXXAudioDevice::createBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 99{ 100 SFXXAudioBuffer* buffer = SFXXAudioBuffer::create( stream, description ); 101 if ( !buffer ) 102 return NULL; 103 104 _addBuffer( buffer ); 105 return buffer; 106} 107 108SFXVoice* SFXXAudioDevice::createVoice( bool is3D, SFXBuffer *buffer ) 109{ 110 // Don't bother going any further if we've 111 // exceeded the maximum voices. 112 if ( mVoices.size() >= mMaxBuffers ) 113 return NULL; 114 115 AssertFatal( buffer, "SFXXAudioDevice::createVoice() - Got null buffer!" ); 116 117 SFXXAudioBuffer* xaBuffer = dynamic_cast<SFXXAudioBuffer*>( buffer ); 118 AssertFatal( xaBuffer, "SFXXAudioDevice::createVoice() - Got bad buffer!" ); 119 120 SFXXAudioVoice* voice = SFXXAudioVoice::create( mXAudio, is3D, xaBuffer ); 121 if ( !voice ) 122 return NULL; 123 124 voice->mXAudioDevice = this; 125 126 _addVoice( voice ); 127 return voice; 128} 129 130void SFXXAudioDevice::_setOutputMatrix( SFXXAudioVoice *voice ) 131{ 132 X3DAUDIO_DSP_SETTINGS dspSettings = {0}; 133 FLOAT32 matrix[12] = { 0 }; 134 dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels; 135 dspSettings.pMatrixCoefficients = matrix; 136 137 const X3DAUDIO_EMITTER &emitter = voice->getEmitter(); 138 dspSettings.SrcChannelCount = emitter.ChannelCount; 139 140 // Calculate the output volumes and doppler. 141 X3DAudioCalculate( mX3DAudio, 142 &mListener, 143 &emitter, 144 X3DAUDIO_CALCULATE_MATRIX | 145 X3DAUDIO_CALCULATE_DOPPLER, 146 &dspSettings ); 147 148 voice->mXAudioVoice->SetOutputMatrix( mMasterVoice, 149 dspSettings.SrcChannelCount, 150 dspSettings.DstChannelCount, 151 dspSettings.pMatrixCoefficients, 152 4321 ); 153 154 voice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * voice->mPitch, 155 4321 ); 156 157 // Commit the changes. 158 mXAudio->CommitChanges( 4321 ); 159} 160 161void SFXXAudioDevice::update() 162{ 163 PROFILE_SCOPE( SFXXAudioDevice_Update ); 164 165 Parent::update(); 166 167 X3DAUDIO_DSP_SETTINGS dspSettings = {0}; 168 FLOAT32 matrix[12] = { 0 }; 169 dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels; 170 dspSettings.pMatrixCoefficients = matrix; 171 172 dspSettings.DopplerFactor = mDopplerFactor; 173 174 // Now update the volume and frequency of 175 // all the active 3D voices. 176 VoiceVector::iterator voice = mVoices.begin(); 177 for ( ; voice != mVoices.end(); voice++ ) 178 { 179 SFXXAudioVoice* xaVoice = ( SFXXAudioVoice* ) *voice; 180 181 // Skip 2D or stopped voices. 182 if ( !xaVoice->is3D() || 183 xaVoice->getStatus() != SFXStatusPlaying ) 184 continue; 185 186 const X3DAUDIO_EMITTER &emitter = xaVoice->getEmitter(); 187 dspSettings.SrcChannelCount = emitter.ChannelCount; 188 189 // Calculate the output volumes and doppler. 190 X3DAudioCalculate( mX3DAudio, 191 &mListener, 192 &emitter, 193 X3DAUDIO_CALCULATE_MATRIX | 194 X3DAUDIO_CALCULATE_DOPPLER, 195 &dspSettings ); 196 197 xaVoice->mXAudioVoice->SetOutputMatrix( mMasterVoice, 198 dspSettings.SrcChannelCount, 199 dspSettings.DstChannelCount, 200 dspSettings.pMatrixCoefficients, 201 4321 ) ; 202 203 xaVoice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * xaVoice->mPitch, 204 4321 ); 205 } 206 207 // Commit the changes. 208 mXAudio->CommitChanges( 4321 ); 209} 210 211void SFXXAudioDevice::setListener( U32 index, const SFXListenerProperties& listener ) 212{ 213 // Get the transform from the listener. 214 const MatrixF& transform = listener.getTransform(); 215 transform.getColumn( 3, (Point3F*)&mListener.Position ); 216 transform.getColumn( 1, (Point3F*)&mListener.OrientFront ); 217 transform.getColumn( 2, (Point3F*)&mListener.OrientTop ); 218 219 // And the velocity... 220 const VectorF& velocity = listener.getVelocity(); 221 mListener.Velocity.x = velocity.x; 222 mListener.Velocity.y = velocity.y; 223 mListener.Velocity.z = velocity.z; 224 225 // XAudio and Torque use opposite handedness, so 226 // flip the z coord to account for that. 227 mListener.Position.z *= -1.0f; 228 mListener.OrientFront.z *= -1.0f; 229 mListener.OrientTop.z *= -1.0f; 230 mListener.Velocity.z *= -1.0f; 231} 232 233void SFXXAudioDevice::setDistanceModel( SFXDistanceModel model ) 234{ 235 mDistanceModel = model; 236} 237 238void SFXXAudioDevice::setDopplerFactor( F32 factor ) 239{ 240 mDopplerFactor = factor; 241} 242 243void SFXXAudioDevice::setRolloffFactor( F32 factor ) 244{ 245 mRolloffFactor = factor; 246} 247