sfxALDevice.cpp 15 KB

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