Torque3D Documentation / _generateds / sfxALDevice.cpp

sfxALDevice.cpp

Engine/source/sfx/openal/sfxALDevice.cpp

More...

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