sfxALVoice.cpp

Engine/source/sfx/openal/sfxALVoice.cpp

More...

Public Defines

Detailed Description

Public Defines

AL_SANITY_CHECK() 
  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 "platform/platform.h"
 25#include "sfx/openal/sfxALVoice.h"
 26#include "sfx/openal/sfxALBuffer.h"
 27#include "sfx/openal/sfxALDevice.h"
 28
 29
 30#ifdef TORQUE_DEBUG
 31#  define AL_SANITY_CHECK() \
 32      AssertFatal( mOpenAL.alIsSource( mSourceName ), "AL Source Sanity Check Failed!" );
 33#else
 34#  define AL_SANITY_CHECK()
 35#endif
 36
 37
 38//#define DEBUG_SPEW
 39
 40
 41SFXALVoice* SFXALVoice::create( SFXALDevice* device, SFXALBuffer *buffer )
 42{
 43   AssertFatal( buffer, "SFXALVoice::create() - Got null buffer!" );
 44 
 45   ALuint sourceName;
 46   device->mOpenAL.alGenSources( 1, &sourceName );
 47   AssertFatal( device->mOpenAL.alIsSource( sourceName ), "AL Source Sanity Check Failed!" );
 48
 49   // Is this 3d?
 50   // Okay, this looks odd, but bear with me for a moment.  AL_SOURCE_RELATIVE does NOT indicate
 51   // whether or not the volume of the sound should change depending on the position of the listener.
 52   // OpenAL assumes that the volume will ALWAYS depend on the position of the listener.  What AL_SOURCE_RELATIVE
 53   // does do is dictate if the position of THIS SOURCE is relative to the listener.  If AL_SOURCE_RELATIVE is AL_TRUE
 54   // and the source's position is 0, 0, 0, then the source is directly on top of the listener at all times, which is what
 55   // we want for non-3d sounds.
 56   device->mOpenAL.alSourcei( sourceName, AL_SOURCE_RELATIVE, ( buffer->mIs3d ? AL_FALSE : AL_TRUE ) );
 57   
 58   if( buffer->mIs3d )
 59      device->mOpenAL.alSourcef( sourceName, AL_ROLLOFF_FACTOR, device->mRolloffFactor );
 60
 61   SFXALVoice *voice = new SFXALVoice( device->mOpenAL,
 62                                       buffer,
 63                                       sourceName );
 64
 65   return voice;
 66}
 67
 68SFXALVoice::SFXALVoice( const OPENALFNTABLE &oalft,
 69                        SFXALBuffer *buffer, 
 70                        ALuint sourceName )
 71
 72   :  Parent( buffer ),
 73      mSourceName( sourceName ),
 74      mResumeAtSampleOffset( -1.0f ),
 75      mSampleOffset( 0 ),
 76      mOpenAL( oalft )
 77{
 78   AL_SANITY_CHECK();
 79}
 80
 81SFXALVoice::~SFXALVoice()
 82{
 83   mOpenAL.alDeleteSources( 1, &mSourceName );
 84}
 85
 86void SFXALVoice::_lateBindStaticBufferIfNecessary()
 87{
 88   if( !mBuffer->isStreaming() )
 89   {
 90      ALint bufferId;
 91      mOpenAL.alGetSourcei( mSourceName, AL_BUFFER, &bufferId );
 92      if( !bufferId )
 93         mOpenAL.alSourcei( mSourceName, AL_BUFFER, _getBuffer()->mALBuffer );
 94   }
 95}
 96
 97
 98SFXStatus SFXALVoice::_status() const
 99{
100   AL_SANITY_CHECK();
101
102   ALint state;
103   mOpenAL.alGetSourcei( mSourceName, AL_SOURCE_STATE, &state );
104
105   switch( state )
106   {
107      case AL_PLAYING:  return SFXStatusPlaying;
108      case AL_PAUSED:   return SFXStatusPaused;
109      default:          return SFXStatusStopped;
110   }
111}
112
113void SFXALVoice::_play()
114{
115   AL_SANITY_CHECK();
116
117   _lateBindStaticBufferIfNecessary();
118
119   #ifdef DEBUG_SPEW
120   Platform::outputDebugString( "[SFXALVoice] Starting playback" );
121   #endif
122#if defined(AL_ALEXT_PROTOTYPES)
123   //send every voice that plays to the alauxiliary slot that has the reverb
124   mOpenAL.alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);
125#endif
126   mOpenAL.alSourcePlay( mSourceName );
127   
128   //WORKAROUND: Adjust play cursor for buggy OAL when resuming playback.  Do this after alSourcePlay
129   // as it is the play function that will cause the cursor to jump.
130   
131   if( mResumeAtSampleOffset != -1.0f )
132   {
133      mOpenAL.alSourcef( mSourceName, AL_SAMPLE_OFFSET, mResumeAtSampleOffset );
134      mResumeAtSampleOffset = -1.0f;
135   }
136}
137
138void SFXALVoice::_pause()
139{   
140   AL_SANITY_CHECK();
141
142   #ifdef DEBUG_SPEW
143   Platform::outputDebugString( "[SFXALVoice] Pausing playback" );
144   #endif
145
146   mOpenAL.alSourcePause( mSourceName );
147   
148   //WORKAROUND: Another workaround for buggy OAL.  Resuming playback of a paused source will cause the 
149   // play cursor to jump.  Save the cursor so we can manually move it into position in _play().  Sigh.
150   
151   mOpenAL.alGetSourcef( mSourceName, AL_SAMPLE_OFFSET, &mResumeAtSampleOffset );
152}
153
154void SFXALVoice::_stop()
155{
156   AL_SANITY_CHECK();
157   
158   #ifdef DEBUG_SPEW
159   Platform::outputDebugString( "[SFXALVoice] Stopping playback" );
160   #endif
161
162   mOpenAL.alSourceStop( mSourceName );
163   mSampleOffset = 0;
164   
165   mResumeAtSampleOffset = -1.0f;
166}
167
168void SFXALVoice::_seek( U32 sample )
169{
170   AL_SANITY_CHECK();
171   
172   _lateBindStaticBufferIfNecessary();
173   mOpenAL.alSourcei( mSourceName, AL_SAMPLE_OFFSET, sample );
174
175   mResumeAtSampleOffset = -1.0f;
176}
177
178U32 SFXALVoice::_tell() const
179{
180   // Flush processed buffers as AL_SAMPLE_OFFSET will snap back to zero as soon
181   // as the queue is processed in whole.
182
183   if( mBuffer->isStreaming() )
184      mBuffer->write( NULL, 0 );
185
186   ALint pos;
187   mOpenAL.alGetSourcei( mSourceName, AL_SAMPLE_OFFSET, &pos );
188   return ( pos + mSampleOffset );
189}
190
191void SFXALVoice::setMinMaxDistance( F32 min, F32 max )
192{
193   AL_SANITY_CHECK();
194
195   mOpenAL.alSourcef( mSourceName, AL_REFERENCE_DISTANCE, min );
196   mOpenAL.alSourcef( mSourceName, AL_MAX_DISTANCE, max );
197}
198
199void SFXALVoice::play( bool looping )
200{
201   AL_SANITY_CHECK();
202
203   mOpenAL.alSourceStop( mSourceName );
204   if( !mBuffer->isStreaming() )
205      mOpenAL.alSourcei( mSourceName, AL_LOOPING, ( looping ? AL_TRUE : AL_FALSE ) );
206
207   Parent::play( looping );
208}
209
210void SFXALVoice::setVelocity( const VectorF& velocity )
211{
212   AL_SANITY_CHECK();
213
214   // Torque and OpenAL are both right handed 
215   // systems, so no coordinate flipping is needed.
216
217   mOpenAL.alSourcefv( mSourceName, AL_VELOCITY, velocity );
218}
219
220void SFXALVoice::setTransform( const MatrixF& transform )
221{
222   AL_SANITY_CHECK();
223
224   // Torque and OpenAL are both right handed 
225   // systems, so no coordinate flipping is needed.
226
227   Point3F pos, dir;
228   transform.getColumn( 3, &pos );
229   transform.getColumn( 1, &dir );
230
231   mOpenAL.alSourcefv( mSourceName, AL_POSITION, pos );
232   mOpenAL.alSourcefv( mSourceName, AL_DIRECTION, dir );
233}
234
235void SFXALVoice::setVolume( F32 volume )
236{
237   AL_SANITY_CHECK();
238
239   mOpenAL.alSourcef( mSourceName, AL_GAIN, volume );
240}
241
242void SFXALVoice::setPitch( F32 pitch )
243{ 
244   AL_SANITY_CHECK();
245
246   mOpenAL.alSourcef( mSourceName, AL_PITCH, pitch );
247}
248
249void SFXALVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
250{
251   AL_SANITY_CHECK();
252
253   mOpenAL.alSourcef( mSourceName, AL_CONE_INNER_ANGLE, innerAngle );
254   mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_ANGLE, outerAngle );
255   mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_GAIN, outerVolume );
256}
257
258void SFXALVoice::setRolloffFactor( F32 factor )
259{
260   mOpenAL.alSourcef( mSourceName, AL_ROLLOFF_FACTOR, factor );
261}
262