sfxALDevice.cpp 13 KB

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