sfxDSDevice.cpp 7.4 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "sfx/dsound/sfxDSDevice.h"
  23. #include "sfx/dsound/sfxDSBuffer.h"
  24. #include "sfx/dsound/sfxDSVoice.h"
  25. #include "platformWin32/platformWin32.h"
  26. #include "core/util/safeRelease.h"
  27. #include "platform/async/asyncUpdate.h"
  28. #include "console/console.h"
  29. SFXDSDevice::SFXDSDevice( SFXProvider* provider,
  30. DSoundFNTable *dsFnTbl,
  31. GUID* guid,
  32. String name,
  33. bool useHardware,
  34. S32 maxBuffers )
  35. : SFXDevice( name, provider, useHardware, maxBuffers ),
  36. mDSound( NULL ),
  37. mPrimaryBuffer( NULL ),
  38. mListener( NULL ),
  39. mDSoundTbl( dsFnTbl ),
  40. mGUID( guid )
  41. {
  42. }
  43. bool SFXDSDevice::_init()
  44. {
  45. HRESULT hr = mDSoundTbl->DirectSoundCreate8( mGUID, &mDSound, NULL );
  46. if ( FAILED( hr ) || !mDSound )
  47. {
  48. Con::errorf( "SFXDSDevice::SFXDSDevice() - DirectSoundCreate8 failed" );
  49. return false;
  50. }
  51. hr = mDSound->SetCooperativeLevel( getWin32WindowHandle(), DSSCL_PRIORITY );
  52. if ( FAILED( hr ) )
  53. {
  54. Con::errorf( "SFXDSDevice::SFXDSDevice() - SetCooperativeLevel failed" );
  55. return false;
  56. }
  57. // Get the primary buffer.
  58. DSBUFFERDESC dsbd;
  59. dMemset( &dsbd, 0, sizeof( DSBUFFERDESC ) );
  60. dsbd.dwSize = sizeof( DSBUFFERDESC );
  61. dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
  62. hr = mDSound->CreateSoundBuffer( &dsbd, &mPrimaryBuffer, NULL );
  63. if ( FAILED( hr ) )
  64. {
  65. Con::errorf( "SFXDSDevice::SFXDSDevice - Creating primary sound buffer failed" );
  66. return false;
  67. }
  68. // Set the format and bitrate on the primary buffer.
  69. S32 frequency = Con::getIntVariable( "$pref::SFX::frequency", 44100 );
  70. S32 bitrate = Con::getIntVariable( "$pref::SFX::bitrate", 32 );
  71. WAVEFORMATEX wfx;
  72. dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) );
  73. wfx.wFormatTag = WAVE_FORMAT_PCM;
  74. wfx.nChannels = 2;
  75. wfx.nSamplesPerSec = frequency;
  76. wfx.wBitsPerSample = bitrate;
  77. wfx.nBlockAlign = ( wfx.nChannels * wfx.wBitsPerSample ) / 8;
  78. wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
  79. hr = mPrimaryBuffer->SetFormat( &wfx );
  80. if( FAILED( hr ) )
  81. {
  82. Con::errorf( "SFXDSDevice::SFXDSDevice() - Setting format of primary buffer failed" );
  83. return false;
  84. }
  85. // Grab the 3d listener.
  86. hr = mPrimaryBuffer->QueryInterface( IID_IDirectSound3DListener8, (LPVOID*)&mListener );
  87. if ( FAILED( hr ) )
  88. {
  89. Con::errorf( "SFXDSDevice::SFXDevice() - Querying the listener interface failed!" );
  90. mListener = NULL;
  91. }
  92. mCaps.dwSize = sizeof( DSCAPS );
  93. mDSound->GetCaps( &mCaps );
  94. // If the device reports no hardware buffers then
  95. // we have no choice but to disable hardware.
  96. if ( mCaps.dwMaxHw3DAllBuffers == 0 )
  97. mUseHardware = false;
  98. // If mMaxBuffers is negative then use the caps
  99. // to decide on a good maximum value... or set 8.
  100. if ( mMaxBuffers < 0 )
  101. mMaxBuffers = getMax( mCaps.dwMaxHw3DAllBuffers, 8 );
  102. // Start the stream thread.
  103. if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
  104. {
  105. SFXInternal::gUpdateThread =
  106. new AsyncUpdateThread( "DirectSound Update Thread", SFXInternal::gBufferUpdateList );
  107. SFXInternal::gUpdateThread->start();
  108. }
  109. return true;
  110. }
  111. SFXDSDevice::~SFXDSDevice()
  112. {
  113. // And release our resources.
  114. SAFE_RELEASE( mListener );
  115. SAFE_RELEASE( mPrimaryBuffer );
  116. SAFE_RELEASE( mDSound );
  117. }
  118. SFXBuffer* SFXDSDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
  119. {
  120. AssertFatal( stream, "SFXDSDevice::createBuffer() - Got null stream!" );
  121. AssertFatal( description, "SFXDSDevice::createBuffer() - Got null description!" );
  122. SFXDSBuffer* buffer = SFXDSBuffer::create( mDSound,
  123. stream,
  124. description,
  125. mUseHardware );
  126. if( buffer )
  127. _addBuffer( buffer );
  128. return buffer;
  129. }
  130. SFXVoice* SFXDSDevice::createVoice( bool is3D, SFXBuffer *buffer )
  131. {
  132. // Don't bother going any further if we've
  133. // exceeded the maximum voices.
  134. if ( mVoices.size() >= mMaxBuffers )
  135. return NULL;
  136. AssertFatal( buffer, "SFXDSDevice::createVoice() - Got null buffer!" );
  137. SFXDSBuffer* dsBuffer = dynamic_cast<SFXDSBuffer*>( buffer );
  138. AssertFatal( dsBuffer, "SFXDSDevice::createVoice() - Got bad buffer!" );
  139. SFXDSVoice* voice = SFXDSVoice::create( this, dsBuffer );
  140. if ( !voice )
  141. return NULL;
  142. _addVoice( voice );
  143. return voice;
  144. }
  145. void SFXDSDevice::_commitDeferred()
  146. {
  147. if( mListener )
  148. mListener->CommitDeferredSettings();
  149. }
  150. void SFXDSDevice::update()
  151. {
  152. Parent::update();
  153. // Apply the deferred settings that changed between updates.
  154. mListener->CommitDeferredSettings();
  155. }
  156. void SFXDSDevice::setListener( U32 index, const SFXListenerProperties& listener )
  157. {
  158. // Get the transform from the listener.
  159. const MatrixF& transform = listener.getTransform();
  160. Point3F pos, dir, up;
  161. transform.getColumn( 3, &pos );
  162. transform.getColumn( 1, &dir );
  163. transform.getColumn( 2, &up );
  164. // And the velocity...
  165. const VectorF& velocity = listener.getVelocity();
  166. // Finally, set it all to DSound!
  167. mListener->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED );
  168. mListener->SetOrientation( dir.x, dir.z, dir.y, up.x, up.z, up.y, DS3D_DEFERRED );
  169. mListener->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED );
  170. }
  171. void SFXDSDevice::setDistanceModel( SFXDistanceModel model )
  172. {
  173. switch( model )
  174. {
  175. case SFXDistanceModelLinear:
  176. Con::errorf( "SFXDSDevice::setDistanceModel - 'linear' distance attenuation not supported by DirectSound" );
  177. break;
  178. case SFXDistanceModelLogarithmic:
  179. break; // Nothing to do.
  180. default:
  181. AssertWarn( false, "SFXDSDevice::setDistanceModel() - model not implemented" );
  182. }
  183. }
  184. void SFXDSDevice::setDopplerFactor( F32 factor )
  185. {
  186. if( mListener )
  187. mListener->SetDopplerFactor( factor, DS3D_DEFERRED ); // Committed in update.
  188. }
  189. void SFXDSDevice::setRolloffFactor( F32 factor )
  190. {
  191. if( mListener )
  192. mListener->SetRolloffFactor( factor, DS3D_DEFERRED ); // Committed in update.
  193. }