sfxFMODVoice.cpp
Engine/source/sfx/fmod/sfxFMODVoice.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 "platform/platform.h" 25#include "sfx/fmod/sfxFMODVoice.h" 26 27#include "sfx/fmod/sfxFMODBuffer.h" 28#include "sfx/fmod/sfxFMODDevice.h" 29#include "core/tAlgorithm.h" 30 31 32SFXFMODVoice* SFXFMODVoice::create( SFXFMODDevice *device, 33 SFXFMODBuffer *buffer ) 34{ 35 AssertFatal( device, "SFXFMODVoice::create() - Got null device!" ); 36 AssertFatal( buffer, "SFXFMODVoice::create() - Got null buffer!" ); 37 38 return new SFXFMODVoice( device, buffer ); 39} 40 41SFXFMODVoice::SFXFMODVoice( SFXFMODDevice *device, 42 SFXFMODBuffer *buffer ) 43 : Parent( buffer ), 44 mDevice( device ), 45 mChannel( NULL ) 46{ 47 AssertFatal( device, "SFXFMODVoice::SFXFMODVoice() - No device assigned!" ); 48 AssertFatal( buffer, "SFXFMODVoice::SFXFMODVoice() - No buffer assigned!" ); 49 AssertFatal( _getBuffer()->mSound != NULL, "SFXFMODVoice::SFXFMODVoice() - No sound assigned!" ); 50} 51 52SFXFMODVoice::~SFXFMODVoice() 53{ 54 _stop(); 55} 56 57SFXStatus SFXFMODVoice::_status() const 58{ 59 if( mChannel ) 60 { 61 FMOD_BOOL isTrue = false; 62 SFXFMODDevice::smFunc->FMOD_Channel_GetPaused( mChannel, &isTrue ); 63 if ( isTrue ) 64 return SFXStatusPaused; 65 66 SFXFMODDevice::smFunc->FMOD_Channel_IsPlaying( mChannel, &isTrue ); 67 if ( isTrue ) 68 return SFXStatusPlaying; 69 } 70 71 SFXFMODDevice::smFunc->FMOD_Channel_Stop( mChannel ); 72 mChannel = NULL; 73 74 return SFXStatusStopped; 75} 76 77void SFXFMODVoice::_play() 78{ 79 if( !mChannel ) 80 _assignChannel(); 81 82 SFXFMODDevice::smFunc->FMOD_Channel_SetPaused( mChannel, false ); 83} 84 85void SFXFMODVoice::_pause() 86{ 87 if( mChannel ) 88 SFXFMODDevice::smFunc->FMOD_Channel_SetPaused( mChannel, true ); 89} 90 91void SFXFMODVoice::_stop() 92{ 93 if( mChannel ) 94 SFXFMODDevice::smFunc->FMOD_Channel_Stop(mChannel); 95 96 mChannel = NULL; 97} 98 99void SFXFMODVoice::_seek( U32 sample ) 100{ 101 if( !mChannel ) 102 _assignChannel(); 103 104 SFXFMODDevice::smFunc->FMOD_Channel_SetPosition 105 ( mChannel, sample, FMOD_TIMEUNIT_PCM ); 106} 107 108bool SFXFMODVoice::_assignChannel() 109{ 110 AssertFatal( _getBuffer()->mSound != NULL, "SFXFMODVoice::_assignChannel() - No sound assigned!" ); 111 112 // we start playing it now in the paused state, so that we can immediately set attributes that 113 // depend on having a channel (position, volume, etc). According to the FMod docs 114 // it is ok to do this. 115 bool success = SFXFMODDevice::smFunc->FMOD_System_PlaySound( 116 SFXFMODDevice::smSystem, 117 FMOD_CHANNEL_FREE, 118 _getBuffer()->mSound, 119 true, 120 &mChannel ) == FMOD_OK; 121 122 if( success ) 123 { 124 SFXFMODDevice::smFunc->FMOD_Channel_SetMode( mChannel, mMode ); 125 SFXFMODDevice::smFunc->FMOD_Channel_SetLoopCount( mChannel, mMode & FMOD_LOOP_NORMAL ? -1 : 0 ); 126 127 if( mSetFlags.test( SET_Velocity ) ) 128 SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, ( const FMOD_VECTOR* ) NULL, &mVelocity ); 129 if( mSetFlags.test( SET_MinMaxDistance ) ) 130 SFXFMODDevice::smFunc->FMOD_Channel_Set3DMinMaxDistance(mChannel, mMinDistance, mMaxDistance); 131 if( mSetFlags.test( SET_Transform ) ) 132 { 133 SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, &mPosition, ( const FMOD_VECTOR* ) NULL ); 134 SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeOrientation( mChannel, &mDirection ); 135 } 136 if( mSetFlags.test( SET_Volume ) ) 137 SFXFMODDevice::smFunc->FMOD_Channel_SetVolume(mChannel, mVolume); 138 if( mSetFlags.test( SET_Pitch ) ) 139 SFXFMODDevice::smFunc->FMOD_Channel_SetFrequency( mChannel, mFrequency ); 140 if( mSetFlags.test( SET_Cone ) ) 141 SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeSettings( 142 mChannel, 143 mConeInnerAngle, 144 mConeOuterAngle, 145 mConeOuterVolume ); 146 if( mSetFlags.test( SET_Priority ) ) 147 SFXFMODDevice::smFunc->FMOD_Channel_SetPriority( mChannel, TorquePriorityToFMODPriority( mPriority ) ); 148 if( mSetFlags.test( SET_Reverb ) ) 149 SFXFMODDevice::smFunc->FMOD_Channel_SetReverbProperties( mChannel, &mReverb ); 150 } 151 152 return success; 153} 154 155U32 SFXFMODVoice::_tell() const 156{ 157 if( !mChannel ) 158 return 0; 159 160 U32 pos; 161 SFXFMODDevice::smFunc->FMOD_Channel_GetPosition( mChannel, &pos, ( FMOD_TIMEUNIT ) FMOD_TIMEUNIT_PCMBYTES ); 162 return _getBuffer()->getSamplePos( pos ); 163} 164 165void SFXFMODVoice::setMinMaxDistance( F32 min, F32 max ) 166{ 167 if ( !( _getBuffer()->mMode & FMOD_3D ) ) 168 return; 169 170 mMinDistance = min; 171 mMaxDistance = max; 172 173 mSetFlags.set( SET_MinMaxDistance ); 174 175 if( mChannel ) 176 SFXFMODDevice::smFunc->FMOD_Channel_Set3DMinMaxDistance(mChannel, mMinDistance, mMaxDistance); 177} 178 179void SFXFMODVoice::play( bool looping ) 180{ 181 if( mBuffer->isStreaming() ) 182 looping = true; 183 184 mMode = mDevice->get3dRollOffMode(); 185 mMode |= (looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF); 186 187 Parent::play( looping ); 188} 189 190void SFXFMODVoice::setVelocity( const VectorF& velocity ) 191{ 192 if( !( _getBuffer()->mMode & FMOD_3D ) ) 193 return; 194 195 // Note we have to do a handedness swap; see the 196 // listener update code in SFXFMODDevice for details. 197 mVelocity.x = velocity.x; 198 mVelocity.y = velocity.z; 199 mVelocity.z = velocity.y; 200 201 mSetFlags.set( SET_Velocity ); 202 203 if( mChannel ) 204 SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, ( const FMOD_VECTOR* ) NULL, &mVelocity ); 205} 206 207void SFXFMODVoice::setTransform( const MatrixF& transform ) 208{ 209 if ( !( _getBuffer()->mMode & FMOD_3D ) ) 210 return; 211 212 transform.getColumn( 3, (Point3F*)&mPosition ); 213 transform.getColumn( 1, (Point3F*)&mDirection ); 214 215 // Note we have to do a handedness swap; see the 216 // listener update code in SFXFMODDevice for details. 217 swap( mPosition.y, mPosition.z ); 218 swap( mDirection.y, mDirection.z ); 219 220 mSetFlags.set( SET_Transform ); 221 222 if( mChannel ) 223 { 224 // This can fail safe, so don't assert if it fails. 225 SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, &mPosition, ( const FMOD_VECTOR* ) NULL ); 226 SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeOrientation( mChannel, &mDirection ); 227 } 228} 229 230void SFXFMODVoice::setVolume( F32 volume ) 231{ 232 mVolume = volume; 233 mSetFlags.set( SET_Volume ); 234 235 if( mChannel ) 236 SFXFMODDevice::smFunc->FMOD_Channel_SetVolume( mChannel, volume ); 237} 238 239void SFXFMODVoice::setPriority( F32 priority ) 240{ 241 mPriority = priority; 242 mSetFlags.set( SET_Priority ); 243 244 if( mChannel ) 245 SFXFMODDevice::smFunc->FMOD_Channel_SetPriority( mChannel, TorquePriorityToFMODPriority( priority ) ); 246} 247 248void SFXFMODVoice::setPitch( F32 pitch ) 249{ 250 // if we do not know the frequency, we cannot change the pitch 251 F32 frequency = _getBuffer()->getFormat().getSamplesPerSecond(); 252 if ( frequency == 0 ) 253 return; 254 255 mFrequency = frequency * pitch; 256 257 mSetFlags.set( SET_Pitch ); 258 259 // Scale the original frequency by the pitch factor. 260 if( mChannel ) 261 SFXFMODDevice::smFunc->FMOD_Channel_SetFrequency(mChannel, mFrequency); 262} 263 264void SFXFMODVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume ) 265{ 266 mConeInnerAngle = innerAngle; 267 mConeOuterAngle = outerAngle; 268 mConeOuterVolume = outerVolume; 269 270 mSetFlags.set( SET_Cone ); 271 272 if( mChannel ) 273 SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeSettings( 274 mChannel, 275 mConeInnerAngle, 276 mConeOuterAngle, 277 mConeOuterVolume ); 278} 279 280void SFXFMODVoice::setReverb( const SFXSoundReverbProperties& reverb ) 281{ 282 dMemset( &mReverb, 0, sizeof( mReverb ) ); 283 284 mReverb.Direct = reverb.mDirect; 285 mReverb.Room = reverb.mRoom; 286 mReverb.Flags = reverb.mFlags; 287 288 mSetFlags.set( SET_Reverb ); 289 290 if( mChannel ) 291 SFXFMODDevice::smFunc->FMOD_Channel_SetReverbProperties( mChannel, &mReverb ); 292} 293 294bool SFXFMODVoice::isVirtual() const 295{ 296 if( mChannel ) 297 { 298 FMOD_BOOL result; 299 SFXFMODDevice::smFunc->FMOD_Channel_IsVirtual( mChannel, &result ); 300 return result; 301 } 302 else 303 return false; 304} 305