sfxALVoice.cpp
Engine/source/sfx/openal/sfxALVoice.cpp
Public Defines
define
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