sfxALDevice.cpp
Engine/source/sfx/openal/sfxALDevice.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "sfx/openal/sfxALDevice.h" 25#include "sfx/openal/sfxALBuffer.h" 26#include "platform/async/asyncUpdate.h" 27 28 29//----------------------------------------------------------------------------- 30 31SFXALDevice::SFXALDevice( SFXProvider *provider, 32 const OPENALFNTABLE &openal, 33 String name, 34 bool useHardware, 35 S32 maxBuffers ) 36 : Parent( name, provider, useHardware, maxBuffers ), 37 mOpenAL( openal ), 38 mContext( NULL ), 39 mDevice( NULL ), 40 mDistanceModel(SFXDistanceModelLinear), 41 mDistanceFactor(1.0f), 42 mRolloffFactor( 1.0f ), 43 mUserRolloffFactor(1.0f) 44{ 45 mMaxBuffers = getMax( maxBuffers, 8 ); 46 47 // TODO: The OpenAL device doesn't set the primary buffer 48 // $pref::SFX::frequency or $pref::SFX::bitrate! 49 //check auxiliary device sends 4 and add them to the device 50 ALint attribs[4] = { 0 }; 51#if defined(AL_ALEXT_PROTOTYPES) 52 ALCint iSends = 0; 53 attribs[0] = ALC_MAX_AUXILIARY_SENDS; 54#endif 55 attribs[1] = 4; 56 57 mDevice = mOpenAL.alcOpenDevice( name ); 58 mOpenAL.alcGetError( mDevice ); 59 if( mDevice ) 60 { 61 mContext = mOpenAL.alcCreateContext( mDevice, attribs ); 62 63 if( mContext ) 64 mOpenAL.alcMakeContextCurrent( mContext ); 65#if defined(AL_ALEXT_PROTOTYPES) 66 mOpenAL.alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &iSends); 67#endif 68 U32 err = mOpenAL.alcGetError( mDevice ); 69 70 if( err != ALC_NO_ERROR ) 71 Con::errorf( "SFXALDevice - Initialization Error: %s", mOpenAL.alcGetString( mDevice, err ) ); 72 } 73 74 AssertFatal( mDevice != NULL && mContext != NULL, "Failed to create OpenAL device and/or context!" ); 75 76 // Start the update thread. 77 // TODO AsyncPeriodicUpdateThread support for Linux/Mac 78#ifdef TORQUE_OS_WIN 79 if( !Con::getBoolVariable( "$_forceAllMainThread" ) ) 80 { 81 SFXInternal::gUpdateThread = new AsyncPeriodicUpdateThread 82 ( "OpenAL Update Thread", SFXInternal::gBufferUpdateList, 83 Con::getIntVariable( "$pref::SFX::updateInterval", SFXInternal::DEFAULT_UPDATE_INTERVAL ) ); 84 SFXInternal::gUpdateThread->start(); 85 } 86#endif 87 88#if defined(AL_ALEXT_PROTOTYPES) 89 dMemset(effectSlot, 0, sizeof(effectSlot)); 90 dMemset(effect, 0, sizeof(effect)); 91 uLoop = 0; 92#endif 93} 94 95//----------------------------------------------------------------------------- 96 97SFXALDevice::~SFXALDevice() 98{ 99 _releaseAllResources(); 100 ///cleanup our effects 101#if defined(AL_ALEXT_PROTOTYPES) 102 mOpenAL.alDeleteAuxiliaryEffectSlots(4, effectSlot); 103 mOpenAL.alDeleteEffects(2, effect); 104#endif 105 ///cleanup of effects ends 106 mOpenAL.alcMakeContextCurrent( NULL ); 107 mOpenAL.alcDestroyContext( mContext ); 108 mOpenAL.alcCloseDevice( mDevice ); 109} 110 111//----------------------------------------------------------------------------- 112 113SFXBuffer* SFXALDevice::createBuffer( const ThreadSafeRef< SFXStream>& stream, SFXDescription* description ) 114{ 115 AssertFatal( stream, "SFXALDevice::createBuffer() - Got null stream!" ); 116 AssertFatal( description, "SFXALDevice::createBuffer() - Got null description!" ); 117 118 SFXALBuffer* buffer = SFXALBuffer::create( mOpenAL, 119 stream, 120 description, 121 mUseHardware ); 122 if ( !buffer ) 123 return NULL; 124 125 _addBuffer( buffer ); 126 return buffer; 127} 128 129//----------------------------------------------------------------------------- 130 131SFXVoice* SFXALDevice::createVoice( bool is3D, SFXBuffer *buffer ) 132{ 133 // Don't bother going any further if we've 134 // exceeded the maximum voices. 135 if ( mVoices.size() >= mMaxBuffers ) 136 return NULL; 137 138 AssertFatal( buffer, "SFXALDevice::createVoice() - Got null buffer!" ); 139 140 SFXALBuffer* alBuffer = dynamic_cast<SFXALBuffer*>( buffer ); 141 AssertFatal( alBuffer, "SFXALDevice::createVoice() - Got bad buffer!" ); 142 143 SFXALVoice* voice = SFXALVoice::create( this, alBuffer ); 144 if ( !voice ) 145 return NULL; 146 147 _addVoice( voice ); 148 return voice; 149} 150 151//----------------------------------------------------------------------------- 152 153void SFXALDevice::setListener( U32 index, const SFXListenerProperties& listener ) 154{ 155 if( index != 0 ) 156 return; 157 158 // Torque and OpenAL are both right handed 159 // systems, so no coordinate flipping is needed. 160 161 const MatrixF &transform = listener.getTransform(); 162 Point3F pos, tupple[2]; 163 transform.getColumn( 3, &pos ); 164 transform.getColumn( 1, &tupple[0] ); 165 transform.getColumn( 2, &tupple[1] ); 166 167 const VectorF &velocity = listener.getVelocity(); 168 169 mOpenAL.alListenerfv( AL_POSITION, pos ); 170 mOpenAL.alListenerfv( AL_VELOCITY, velocity ); 171 mOpenAL.alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] ); 172 ///Pass a unit size to openal, 1.0 assumes 1 meter to 1 game unit. 173 ///Crucial for air absorbtion calculations. 174#if defined(AL_ALEXT_PROTOTYPES) 175 mOpenAL.alListenerf(AL_METERS_PER_UNIT, 1.0f); 176#endif 177} 178 179//----------------------------------------------------------------------------- 180 181void SFXALDevice::setDistanceModel( SFXDistanceModel model ) 182{ 183 switch( model ) 184 { 185 case SFXDistanceModelLinear: 186 mOpenAL.alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED ); 187 if( mRolloffFactor != 1.0f ) 188 _setRolloffFactor( 1.0f ); // No rolloff on linear. 189 break; 190 191 case SFXDistanceModelLogarithmic: 192 mOpenAL.alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED ); 193 if( mUserRolloffFactor != mRolloffFactor ) 194 _setRolloffFactor( mUserRolloffFactor ); 195 break; 196 /// create a case for our exponential distance model 197 case SFXDistanceModelExponent: 198 mOpenAL.alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED); 199 if (mUserRolloffFactor != mRolloffFactor) 200 _setRolloffFactor(mUserRolloffFactor); 201 break; 202 203 default: 204 AssertWarn( false, "SFXALDevice::setDistanceModel - distance model not implemented" ); 205 } 206 207 mDistanceModel = model; 208} 209 210//----------------------------------------------------------------------------- 211 212void SFXALDevice::setDopplerFactor( F32 factor ) 213{ 214 mOpenAL.alDopplerFactor( factor ); 215} 216 217//----------------------------------------------------------------------------- 218 219void SFXALDevice::_setRolloffFactor( F32 factor ) 220{ 221 mRolloffFactor = factor; 222 223 for( U32 i = 0, num = mVoices.size(); i < num; ++ i ) 224 mOpenAL.alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor ); 225} 226 227//----------------------------------------------------------------------------- 228 229void SFXALDevice::setRolloffFactor( F32 factor ) 230{ 231 if( mDistanceModel == SFXDistanceModelLinear && factor != 1.0f ) 232 Con::errorf( "SFXALDevice::setRolloffFactor - rolloff factor <> 1.0f ignored in linear distance model" ); 233 else 234 _setRolloffFactor( factor ); 235 236 mUserRolloffFactor = factor; 237} 238 239#if defined(AL_ALEXT_PROTOTYPES) 240void SFXALDevice::openSlots() 241{ 242 for (uLoop = 0; uLoop < 4; uLoop++) 243 { 244 mOpenAL.alGenAuxiliaryEffectSlots(1, &effectSlot[uLoop]); 245 } 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 255///create reverb effect 256void SFXALDevice::setReverb(const SFXReverbProperties& reverb) 257{ 258 ///output a debug string so we know each time the reverb changes 259 Platform::outputDebugString("Updated"); 260 261 ///load an efxeaxreverb default and add our values from 262 ///sfxreverbproperties to it 263 EFXEAXREVERBPROPERTIES prop = EFX_REVERB_PRESET_GENERIC; 264 265 prop.flDensity = reverb.flDensity; 266 prop.flDiffusion = reverb.flDiffusion; 267 prop.flGain = reverb.flGain; 268 prop.flGainHF = reverb.flGainHF; 269 prop.flGainLF = reverb.flGainLF; 270 prop.flDecayTime = reverb.flDecayTime; 271 prop.flDecayHFRatio = reverb.flDecayHFRatio; 272 prop.flDecayLFRatio = reverb.flDecayLFRatio; 273 prop.flReflectionsGain = reverb.flReflectionsGain; 274 prop.flReflectionsDelay = reverb.flReflectionsDelay; 275 prop.flLateReverbGain = reverb.flLateReverbGain; 276 prop.flLateReverbDelay = reverb.flLateReverbDelay; 277 prop.flEchoTime = reverb.flEchoTime; 278 prop.flEchoDepth = reverb.flEchoDepth; 279 prop.flModulationTime = reverb.flModulationTime; 280 prop.flModulationDepth = reverb.flModulationDepth; 281 prop.flAirAbsorptionGainHF = reverb.flAirAbsorptionGainHF; 282 prop.flHFReference = reverb.flHFReference; 283 prop.flLFReference = reverb.flLFReference; 284 prop.flRoomRolloffFactor = reverb.flRoomRolloffFactor; 285 prop.iDecayHFLimit = reverb.iDecayHFLimit; 286 287 if (mOpenAL.alGetEnumValue("AL_EFFECT_EAXREVERB") != 0) 288 { 289 290 /// EAX Reverb is available. Set the EAX effect type 291 292 mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB); 293 294 ///add our values to the setup of the reverb 295 296 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DENSITY, prop.flDensity); 297 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DIFFUSION, prop.flDiffusion); 298 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAIN, prop.flGain); 299 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINHF, prop.flGainHF); 300 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINLF, prop.flGainLF); 301 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_TIME, prop.flDecayTime); 302 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_HFRATIO, prop.flDecayHFRatio); 303 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_LFRATIO, prop.flDecayLFRatio); 304 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_GAIN, prop.flReflectionsGain); 305 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay); 306 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_GAIN, prop.flLateReverbGain); 307 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay); 308 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_TIME, prop.flEchoTime); 309 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_DEPTH, prop.flEchoDepth); 310 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_TIME, prop.flModulationTime); 311 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_DEPTH, prop.flModulationDepth); 312 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF); 313 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_HFREFERENCE, prop.flHFReference); 314 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LFREFERENCE, prop.flLFReference); 315 mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor); 316 mOpenAL.alEffecti(effect[0], AL_EAXREVERB_DECAY_HFLIMIT, prop.iDecayHFLimit); 317 mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]); 318 Platform::outputDebugString("eax reverb properties set"); 319 320 } 321 else 322 { 323 324 /// No EAX Reverb. Set the standard reverb effect 325 mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB); 326 327 mOpenAL.alEffectf(effect[0], AL_REVERB_DENSITY, prop.flDensity); 328 mOpenAL.alEffectf(effect[0], AL_REVERB_DIFFUSION, prop.flDiffusion); 329 mOpenAL.alEffectf(effect[0], AL_REVERB_GAIN, prop.flGain); 330 mOpenAL.alEffectf(effect[0], AL_REVERB_GAINHF, prop.flGainHF); 331 mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_TIME, prop.flDecayTime); 332 mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_HFRATIO, prop.flDecayHFRatio); 333 mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_GAIN, prop.flReflectionsGain); 334 mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay); 335 mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_GAIN, prop.flLateReverbGain); 336 mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay); 337 mOpenAL.alEffectf(effect[0], AL_REVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF); 338 mOpenAL.alEffectf(effect[0], AL_REVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor); 339 mOpenAL.alEffecti(effect[0], AL_REVERB_DECAY_HFLIMIT, prop.iDecayHFLimit); 340 mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]); 341 342 } 343 344} 345#endif 346