sfxALDevice.cpp 13 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325
  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/openal/sfxALDevice.h"
  23. #include "sfx/openal/sfxALBuffer.h"
  24. #include "platform/async/asyncUpdate.h"
  25. //-----------------------------------------------------------------------------
  26. SFXALDevice::SFXALDevice( SFXProvider *provider,
  27. const OPENALFNTABLE &openal,
  28. String name,
  29. bool useHardware,
  30. S32 maxBuffers )
  31. : Parent( name, provider, useHardware, maxBuffers ),
  32. mOpenAL( openal ),
  33. mContext( NULL ),
  34. mDevice( NULL ),
  35. mRolloffFactor( 1.0f )
  36. {
  37. mMaxBuffers = getMax( maxBuffers, 8 );
  38. // TODO: The OpenAL device doesn't set the primary buffer
  39. // $pref::SFX::frequency or $pref::SFX::bitrate!
  40. //check auxiliary device sends 4 and add them to the device
  41. ALint attribs[4] = { 0 };
  42. ALCint iSends = 0;
  43. attribs[0] = ALC_MAX_AUXILIARY_SENDS;
  44. attribs[1] = 4;
  45. mDevice = mOpenAL.alcOpenDevice( name );
  46. mOpenAL.alcGetError( mDevice );
  47. if( mDevice )
  48. {
  49. mContext = mOpenAL.alcCreateContext( mDevice, attribs );
  50. if( mContext )
  51. mOpenAL.alcMakeContextCurrent( mContext );
  52. mOpenAL.alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &iSends);
  53. U32 err = mOpenAL.alcGetError( mDevice );
  54. if( err != ALC_NO_ERROR )
  55. Con::errorf( "SFXALDevice - Initialization Error: %s", mOpenAL.alcGetString( mDevice, err ) );
  56. }
  57. AssertFatal( mDevice != NULL && mContext != NULL, "Failed to create OpenAL device and/or context!" );
  58. // Start the update thread.
  59. // TODO AsyncPeriodicUpdateThread support for Linux/Mac
  60. #ifdef TORQUE_OS_WIN
  61. if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
  62. {
  63. SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread
  64. ( "OpenAL Update Thread", SFXInternal::gBufferUpdateList,
  65. Con::getIntVariable( "$pref::SFX::updateInterval", SFXInternal::DEFAULT_UPDATE_INTERVAL ) );
  66. SFXInternal::gUpdateThread->start();
  67. }
  68. #endif
  69. }
  70. //-----------------------------------------------------------------------------
  71. SFXALDevice::~SFXALDevice()
  72. {
  73. _releaseAllResources();
  74. ///cleanup our effects
  75. mOpenAL.alDeleteAuxiliaryEffectSlots(4, effectSlot);
  76. mOpenAL.alDeleteEffects(2, effect);
  77. ///cleanup of effects ends
  78. mOpenAL.alcMakeContextCurrent( NULL );
  79. mOpenAL.alcDestroyContext( mContext );
  80. mOpenAL.alcCloseDevice( mDevice );
  81. }
  82. //-----------------------------------------------------------------------------
  83. SFXBuffer* SFXALDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
  84. {
  85. AssertFatal( stream, "SFXALDevice::createBuffer() - Got null stream!" );
  86. AssertFatal( description, "SFXALDevice::createBuffer() - Got null description!" );
  87. SFXALBuffer* buffer = SFXALBuffer::create( mOpenAL,
  88. stream,
  89. description,
  90. mUseHardware );
  91. if ( !buffer )
  92. return NULL;
  93. _addBuffer( buffer );
  94. return buffer;
  95. }
  96. //-----------------------------------------------------------------------------
  97. SFXVoice* SFXALDevice::createVoice( bool is3D, SFXBuffer *buffer )
  98. {
  99. // Don't bother going any further if we've
  100. // exceeded the maximum voices.
  101. if ( mVoices.size() >= mMaxBuffers )
  102. return NULL;
  103. AssertFatal( buffer, "SFXALDevice::createVoice() - Got null buffer!" );
  104. SFXALBuffer* alBuffer = dynamic_cast<SFXALBuffer*>( buffer );
  105. AssertFatal( alBuffer, "SFXALDevice::createVoice() - Got bad buffer!" );
  106. SFXALVoice* voice = SFXALVoice::create( this, alBuffer );
  107. if ( !voice )
  108. return NULL;
  109. _addVoice( voice );
  110. return voice;
  111. }
  112. //-----------------------------------------------------------------------------
  113. void SFXALDevice::setListener( U32 index, const SFXListenerProperties& listener )
  114. {
  115. if( index != 0 )
  116. return;
  117. // Torque and OpenAL are both right handed
  118. // systems, so no coordinate flipping is needed.
  119. const MatrixF &transform = listener.getTransform();
  120. Point3F pos, tupple[2];
  121. transform.getColumn( 3, &pos );
  122. transform.getColumn( 1, &tupple[0] );
  123. transform.getColumn( 2, &tupple[1] );
  124. const VectorF &velocity = listener.getVelocity();
  125. mOpenAL.alListenerfv( AL_POSITION, pos );
  126. mOpenAL.alListenerfv( AL_VELOCITY, velocity );
  127. mOpenAL.alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] );
  128. ///Pass a unit size to openal, 1.0 assumes 1 meter to 1 game unit.
  129. ///Crucial for air absorbtion calculations.
  130. mOpenAL.alListenerf(AL_METERS_PER_UNIT, 1.0f);
  131. }
  132. //-----------------------------------------------------------------------------
  133. void SFXALDevice::setDistanceModel( SFXDistanceModel model )
  134. {
  135. switch( model )
  136. {
  137. case SFXDistanceModelLinear:
  138. mOpenAL.alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED );
  139. if( mRolloffFactor != 1.0f )
  140. _setRolloffFactor( 1.0f ); // No rolloff on linear.
  141. break;
  142. case SFXDistanceModelLogarithmic:
  143. mOpenAL.alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
  144. if( mUserRolloffFactor != mRolloffFactor )
  145. _setRolloffFactor( mUserRolloffFactor );
  146. break;
  147. /// create a case for our exponential distance model
  148. case SFXDistanceModelExponent:
  149. mOpenAL.alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
  150. if (mUserRolloffFactor != mRolloffFactor)
  151. _setRolloffFactor(mUserRolloffFactor);
  152. break;
  153. default:
  154. AssertWarn( false, "SFXALDevice::setDistanceModel - distance model not implemented" );
  155. }
  156. mDistanceModel = model;
  157. }
  158. //-----------------------------------------------------------------------------
  159. void SFXALDevice::setDopplerFactor( F32 factor )
  160. {
  161. mOpenAL.alDopplerFactor( factor );
  162. }
  163. //-----------------------------------------------------------------------------
  164. void SFXALDevice::_setRolloffFactor( F32 factor )
  165. {
  166. mRolloffFactor = factor;
  167. for( U32 i = 0, num = mVoices.size(); i < num; ++ i )
  168. mOpenAL.alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor );
  169. }
  170. //-----------------------------------------------------------------------------
  171. void SFXALDevice::setRolloffFactor( F32 factor )
  172. {
  173. if( mDistanceModel == SFXDistanceModelLinear && factor != 1.0f )
  174. Con::errorf( "SFXALDevice::setRolloffFactor - rolloff factor <> 1.0f ignored in linear distance model" );
  175. else
  176. _setRolloffFactor( factor );
  177. mUserRolloffFactor = factor;
  178. }
  179. void SFXALDevice::openSlots()
  180. {
  181. for (uLoop = 0; uLoop < 4; uLoop++)
  182. {
  183. mOpenAL.alGenAuxiliaryEffectSlots(1, &effectSlot[uLoop]);
  184. }
  185. for (uLoop = 0; uLoop < 2; uLoop++)
  186. {
  187. mOpenAL.alGenEffects(1, &effect[uLoop]);
  188. }
  189. ///debug string output so we know our slots are open
  190. Platform::outputDebugString("Slots Open");
  191. }
  192. ///create reverb effect
  193. void SFXALDevice::setReverb(const SFXReverbProperties& reverb)
  194. {
  195. ///output a debug string so we know each time the reverb changes
  196. Platform::outputDebugString("Updated");
  197. ///load an efxeaxreverb default and add our values from
  198. ///sfxreverbproperties to it
  199. EFXEAXREVERBPROPERTIES prop = EFX_REVERB_PRESET_GENERIC;
  200. prop.flDensity = reverb.flDensity;
  201. prop.flDiffusion = reverb.flDiffusion;
  202. prop.flGain = reverb.flGain;
  203. prop.flGainHF = reverb.flGainHF;
  204. prop.flGainLF = reverb.flGainLF;
  205. prop.flDecayTime = reverb.flDecayTime;
  206. prop.flDecayHFRatio = reverb.flDecayHFRatio;
  207. prop.flDecayLFRatio = reverb.flDecayLFRatio;
  208. prop.flReflectionsGain = reverb.flReflectionsGain;
  209. prop.flReflectionsDelay = reverb.flReflectionsDelay;
  210. prop.flLateReverbGain = reverb.flLateReverbGain;
  211. prop.flLateReverbDelay = reverb.flLateReverbDelay;
  212. prop.flEchoTime = reverb.flEchoTime;
  213. prop.flEchoDepth = reverb.flEchoDepth;
  214. prop.flModulationTime = reverb.flModulationTime;
  215. prop.flModulationDepth = reverb.flModulationDepth;
  216. prop.flAirAbsorptionGainHF = reverb.flAirAbsorptionGainHF;
  217. prop.flHFReference = reverb.flHFReference;
  218. prop.flLFReference = reverb.flLFReference;
  219. prop.flRoomRolloffFactor = reverb.flRoomRolloffFactor;
  220. prop.iDecayHFLimit = reverb.iDecayHFLimit;
  221. if (mOpenAL.alGetEnumValue("AL_EFFECT_EAXREVERB") != 0)
  222. {
  223. /// EAX Reverb is available. Set the EAX effect type
  224. mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
  225. ///add our values to the setup of the reverb
  226. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DENSITY, prop.flDensity);
  227. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DIFFUSION, prop.flDiffusion);
  228. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAIN, prop.flGain);
  229. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINHF, prop.flGainHF);
  230. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINLF, prop.flGainLF);
  231. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_TIME, prop.flDecayTime);
  232. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
  233. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_LFRATIO, prop.flDecayLFRatio);
  234. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
  235. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
  236. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
  237. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
  238. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_TIME, prop.flEchoTime);
  239. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_DEPTH, prop.flEchoDepth);
  240. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_TIME, prop.flModulationTime);
  241. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_DEPTH, prop.flModulationDepth);
  242. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
  243. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_HFREFERENCE, prop.flHFReference);
  244. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LFREFERENCE, prop.flLFReference);
  245. mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
  246. mOpenAL.alEffecti(effect[0], AL_EAXREVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
  247. mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
  248. Platform::outputDebugString("eax reverb properties set");
  249. }
  250. else
  251. {
  252. /// No EAX Reverb. Set the standard reverb effect
  253. mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB);
  254. mOpenAL.alEffectf(effect[0], AL_REVERB_DENSITY, prop.flDensity);
  255. mOpenAL.alEffectf(effect[0], AL_REVERB_DIFFUSION, prop.flDiffusion);
  256. mOpenAL.alEffectf(effect[0], AL_REVERB_GAIN, prop.flGain);
  257. mOpenAL.alEffectf(effect[0], AL_REVERB_GAINHF, prop.flGainHF);
  258. mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_TIME, prop.flDecayTime);
  259. mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
  260. mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
  261. mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
  262. mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
  263. mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
  264. mOpenAL.alEffectf(effect[0], AL_REVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
  265. mOpenAL.alEffectf(effect[0], AL_REVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
  266. mOpenAL.alEffecti(effect[0], AL_REVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
  267. mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
  268. }
  269. }