sfxALDevice.cpp 13 KB

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