sfxDSDevice.cpp
Engine/source/sfx/dsound/sfxDSDevice.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/dsound/sfxDSDevice.h" 25#include "sfx/dsound/sfxDSBuffer.h" 26#include "sfx/dsound/sfxDSVoice.h" 27#include "platformWin32/platformWin32.h" 28#include "core/util/safeRelease.h" 29#include "platform/async/asyncUpdate.h" 30#include "console/console.h" 31 32 33SFXDSDevice::SFXDSDevice( SFXProvider* provider, 34 DSoundFNTable *dsFnTbl, 35 GUID* guid, 36 String name, 37 bool useHardware, 38 S32 maxBuffers ) 39 : SFXDevice( name, provider, useHardware, maxBuffers ), 40 mDSound( NULL ), 41 mPrimaryBuffer( NULL ), 42 mListener( NULL ), 43 mDSoundTbl( dsFnTbl ), 44 mGUID( guid ) 45{ 46} 47 48bool SFXDSDevice::_init() 49{ 50 HRESULT hr = mDSoundTbl->DirectSoundCreate8( mGUID, &mDSound, NULL ); 51 if ( FAILED( hr ) || !mDSound ) 52 { 53 Con::errorf( "SFXDSDevice::SFXDSDevice() - DirectSoundCreate8 failed" ); 54 return false; 55 } 56 57 hr = mDSound->SetCooperativeLevel( getWin32WindowHandle(), DSSCL_PRIORITY ); 58 if ( FAILED( hr ) ) 59 { 60 Con::errorf( "SFXDSDevice::SFXDSDevice() - SetCooperativeLevel failed" ); 61 return false; 62 } 63 64 // Get the primary buffer. 65 DSBUFFERDESC dsbd; 66 dMemset( &dsbd, 0, sizeof( DSBUFFERDESC ) ); 67 dsbd.dwSize = sizeof( DSBUFFERDESC ); 68 dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER; 69 hr = mDSound->CreateSoundBuffer( &dsbd, &mPrimaryBuffer, NULL ); 70 if ( FAILED( hr ) ) 71 { 72 Con::errorf( "SFXDSDevice::SFXDSDevice - Creating primary sound buffer failed" ); 73 return false; 74 } 75 76 // Set the format and bitrate on the primary buffer. 77 S32 frequency = Con::getIntVariable( "$pref::SFX::frequency", 44100 ); 78 S32 bitrate = Con::getIntVariable( "$pref::SFX::bitrate", 32 ); 79 80 WAVEFORMATEX wfx; 81 dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) ); 82 wfx.wFormatTag = WAVE_FORMAT_PCM; 83 wfx.nChannels = 2; 84 wfx.nSamplesPerSec = frequency; 85 wfx.wBitsPerSample = bitrate; 86 wfx.nBlockAlign = ( wfx.nChannels * wfx.wBitsPerSample ) / 8; 87 wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign; 88 hr = mPrimaryBuffer->SetFormat( &wfx ); 89 if( FAILED( hr ) ) 90 { 91 Con::errorf( "SFXDSDevice::SFXDSDevice() - Setting format of primary buffer failed" ); 92 return false; 93 } 94 95 // Grab the 3d listener. 96 hr = mPrimaryBuffer->QueryInterface( IID_IDirectSound3DListener8, (LPVOID*)&mListener ); 97 if ( FAILED( hr ) ) 98 { 99 Con::errorf( "SFXDSDevice::SFXDevice() - Querying the listener interface failed!" ); 100 mListener = NULL; 101 } 102 103 mCaps.dwSize = sizeof( DSCAPS ); 104 mDSound->GetCaps( &mCaps ); 105 106 // If the device reports no hardware buffers then 107 // we have no choice but to disable hardware. 108 if ( mCaps.dwMaxHw3DAllBuffers == 0 ) 109 mUseHardware = false; 110 111 // If mMaxBuffers is negative then use the caps 112 // to decide on a good maximum value... or set 8. 113 if ( mMaxBuffers < 0 ) 114 mMaxBuffers = getMax( mCaps.dwMaxHw3DAllBuffers, 8 ); 115 116 // Start the stream thread. 117 118 if( !Con::getBoolVariable( "$_forceAllMainThread" ) ) 119 { 120 SFXInternal::gUpdateThread = 121 new AsyncUpdateThread( "DirectSound Update Thread", SFXInternal::gBufferUpdateList ); 122 SFXInternal::gUpdateThread->start(); 123 } 124 125 return true; 126} 127 128SFXDSDevice::~SFXDSDevice() 129{ 130 // And release our resources. 131 SAFE_RELEASE( mListener ); 132 SAFE_RELEASE( mPrimaryBuffer ); 133 SAFE_RELEASE( mDSound ); 134} 135 136SFXBuffer* SFXDSDevice::createBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 137{ 138 AssertFatal( stream, "SFXDSDevice::createBuffer() - Got null stream!" ); 139 AssertFatal( description, "SFXDSDevice::createBuffer() - Got null description!" ); 140 141 SFXDSBuffer* buffer = SFXDSBuffer::create( mDSound, 142 stream, 143 description, 144 mUseHardware ); 145 146 if( buffer ) 147 _addBuffer( buffer ); 148 149 return buffer; 150} 151 152SFXVoice* SFXDSDevice::createVoice( bool is3D, SFXBuffer *buffer ) 153{ 154 // Don't bother going any further if we've 155 // exceeded the maximum voices. 156 if ( mVoices.size() >= mMaxBuffers ) 157 return NULL; 158 159 AssertFatal( buffer, "SFXDSDevice::createVoice() - Got null buffer!" ); 160 161 SFXDSBuffer* dsBuffer = dynamic_cast<SFXDSBuffer*>( buffer ); 162 AssertFatal( dsBuffer, "SFXDSDevice::createVoice() - Got bad buffer!" ); 163 164 SFXDSVoice* voice = SFXDSVoice::create( this, dsBuffer ); 165 if ( !voice ) 166 return NULL; 167 168 _addVoice( voice ); 169 return voice; 170} 171 172void SFXDSDevice::_commitDeferred() 173{ 174 if( mListener ) 175 mListener->CommitDeferredSettings(); 176} 177 178void SFXDSDevice::update() 179{ 180 Parent::update(); 181 182 // Apply the deferred settings that changed between updates. 183 mListener->CommitDeferredSettings(); 184} 185 186void SFXDSDevice::setListener( U32 index, const SFXListenerProperties& listener ) 187{ 188 // Get the transform from the listener. 189 const MatrixF& transform = listener.getTransform(); 190 Point3F pos, dir, up; 191 transform.getColumn( 3, &pos ); 192 transform.getColumn( 1, &dir ); 193 transform.getColumn( 2, &up ); 194 195 // And the velocity... 196 const VectorF& velocity = listener.getVelocity(); 197 198 // Finally, set it all to DSound! 199 mListener->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED ); 200 mListener->SetOrientation( dir.x, dir.z, dir.y, up.x, up.z, up.y, DS3D_DEFERRED ); 201 mListener->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED ); 202} 203 204void SFXDSDevice::setDistanceModel( SFXDistanceModel model ) 205{ 206 switch( model ) 207 { 208 case SFXDistanceModelLinear: 209 Con::errorf( "SFXDSDevice::setDistanceModel - 'linear' distance attenuation not supported by DirectSound" ); 210 break; 211 212 case SFXDistanceModelLogarithmic: 213 break; // Nothing to do. 214 215 default: 216 AssertWarn( false, "SFXDSDevice::setDistanceModel() - model not implemented" ); 217 } 218} 219 220void SFXDSDevice::setDopplerFactor( F32 factor ) 221{ 222 if( mListener ) 223 mListener->SetDopplerFactor( factor, DS3D_DEFERRED ); // Committed in update. 224} 225 226void SFXDSDevice::setRolloffFactor( F32 factor ) 227{ 228 if( mListener ) 229 mListener->SetRolloffFactor( factor, DS3D_DEFERRED ); // Committed in update. 230} 231