sfxALDevice.cpp 15 KB

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