sfxFMODVoice.cpp 9.1 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303
  1. //-----------------------------------------------------------------------------
  2. // Copyright (c) 2012 GarageGames, LLC
  3. //
  4. // Permission is hereby granted, free of charge, to any person obtaining a copy
  5. // of this software and associated documentation files (the "Software"), to
  6. // deal in the Software without restriction, including without limitation the
  7. // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
  8. // sell copies of the Software, and to permit persons to whom the Software is
  9. // furnished to do so, subject to the following conditions:
  10. //
  11. // The above copyright notice and this permission notice shall be included in
  12. // all copies or substantial portions of the Software.
  13. //
  14. // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
  15. // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  16. // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  17. // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  18. // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  19. // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
  20. // IN THE SOFTWARE.
  21. //-----------------------------------------------------------------------------
  22. #include "platform/platform.h"
  23. #include "sfx/fmod/sfxFMODVoice.h"
  24. #include "sfx/fmod/sfxFMODBuffer.h"
  25. #include "sfx/fmod/sfxFMODDevice.h"
  26. #include "core/tAlgorithm.h"
  27. SFXFMODVoice* SFXFMODVoice::create( SFXFMODDevice *device,
  28. SFXFMODBuffer *buffer )
  29. {
  30. AssertFatal( device, "SFXFMODVoice::create() - Got null device!" );
  31. AssertFatal( buffer, "SFXFMODVoice::create() - Got null buffer!" );
  32. return new SFXFMODVoice( device, buffer );
  33. }
  34. SFXFMODVoice::SFXFMODVoice( SFXFMODDevice *device,
  35. SFXFMODBuffer *buffer )
  36. : Parent( buffer ),
  37. mDevice( device ),
  38. mChannel( NULL )
  39. {
  40. AssertFatal( device, "SFXFMODVoice::SFXFMODVoice() - No device assigned!" );
  41. AssertFatal( buffer, "SFXFMODVoice::SFXFMODVoice() - No buffer assigned!" );
  42. AssertFatal( _getBuffer()->mSound != NULL, "SFXFMODVoice::SFXFMODVoice() - No sound assigned!" );
  43. }
  44. SFXFMODVoice::~SFXFMODVoice()
  45. {
  46. _stop();
  47. }
  48. SFXStatus SFXFMODVoice::_status() const
  49. {
  50. if( mChannel )
  51. {
  52. FMOD_BOOL isTrue = false;
  53. SFXFMODDevice::smFunc->FMOD_Channel_GetPaused( mChannel, &isTrue );
  54. if ( isTrue )
  55. return SFXStatusPaused;
  56. SFXFMODDevice::smFunc->FMOD_Channel_IsPlaying( mChannel, &isTrue );
  57. if ( isTrue )
  58. return SFXStatusPlaying;
  59. }
  60. SFXFMODDevice::smFunc->FMOD_Channel_Stop( mChannel );
  61. mChannel = NULL;
  62. return SFXStatusStopped;
  63. }
  64. void SFXFMODVoice::_play()
  65. {
  66. if( !mChannel )
  67. _assignChannel();
  68. SFXFMODDevice::smFunc->FMOD_Channel_SetPaused( mChannel, false );
  69. }
  70. void SFXFMODVoice::_pause()
  71. {
  72. if( mChannel )
  73. SFXFMODDevice::smFunc->FMOD_Channel_SetPaused( mChannel, true );
  74. }
  75. void SFXFMODVoice::_stop()
  76. {
  77. if( mChannel )
  78. SFXFMODDevice::smFunc->FMOD_Channel_Stop(mChannel);
  79. mChannel = NULL;
  80. }
  81. void SFXFMODVoice::_seek( U32 sample )
  82. {
  83. if( !mChannel )
  84. _assignChannel();
  85. SFXFMODDevice::smFunc->FMOD_Channel_SetPosition
  86. ( mChannel, sample, FMOD_TIMEUNIT_PCM );
  87. }
  88. bool SFXFMODVoice::_assignChannel()
  89. {
  90. AssertFatal( _getBuffer()->mSound != NULL, "SFXFMODVoice::_assignChannel() - No sound assigned!" );
  91. // we start playing it now in the paused state, so that we can immediately set attributes that
  92. // depend on having a channel (position, volume, etc). According to the FMod docs
  93. // it is ok to do this.
  94. bool success = SFXFMODDevice::smFunc->FMOD_System_PlaySound(
  95. SFXFMODDevice::smSystem,
  96. FMOD_CHANNEL_FREE,
  97. _getBuffer()->mSound,
  98. true,
  99. &mChannel ) == FMOD_OK;
  100. if( success )
  101. {
  102. SFXFMODDevice::smFunc->FMOD_Channel_SetMode( mChannel, mMode );
  103. SFXFMODDevice::smFunc->FMOD_Channel_SetLoopCount( mChannel, mMode & FMOD_LOOP_NORMAL ? -1 : 0 );
  104. if( mSetFlags.test( SET_Velocity ) )
  105. SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, ( const FMOD_VECTOR* ) NULL, &mVelocity );
  106. if( mSetFlags.test( SET_MinMaxDistance ) )
  107. SFXFMODDevice::smFunc->FMOD_Channel_Set3DMinMaxDistance(mChannel, mMinDistance, mMaxDistance);
  108. if( mSetFlags.test( SET_Transform ) )
  109. {
  110. SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, &mPosition, ( const FMOD_VECTOR* ) NULL );
  111. SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeOrientation( mChannel, &mDirection );
  112. }
  113. if( mSetFlags.test( SET_Volume ) )
  114. SFXFMODDevice::smFunc->FMOD_Channel_SetVolume(mChannel, mVolume);
  115. if( mSetFlags.test( SET_Pitch ) )
  116. SFXFMODDevice::smFunc->FMOD_Channel_SetFrequency( mChannel, mFrequency );
  117. if( mSetFlags.test( SET_Cone ) )
  118. SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeSettings(
  119. mChannel,
  120. mConeInnerAngle,
  121. mConeOuterAngle,
  122. mConeOuterVolume );
  123. if( mSetFlags.test( SET_Priority ) )
  124. SFXFMODDevice::smFunc->FMOD_Channel_SetPriority( mChannel, TorquePriorityToFMODPriority( mPriority ) );
  125. if( mSetFlags.test( SET_Reverb ) )
  126. SFXFMODDevice::smFunc->FMOD_Channel_SetReverbProperties( mChannel, &mReverb );
  127. }
  128. return success;
  129. }
  130. U32 SFXFMODVoice::_tell() const
  131. {
  132. if( !mChannel )
  133. return 0;
  134. U32 pos;
  135. SFXFMODDevice::smFunc->FMOD_Channel_GetPosition( mChannel, &pos, ( FMOD_TIMEUNIT ) FMOD_TIMEUNIT_PCMBYTES );
  136. return _getBuffer()->getSamplePos( pos );
  137. }
  138. void SFXFMODVoice::setMinMaxDistance( F32 min, F32 max )
  139. {
  140. if ( !( _getBuffer()->mMode & FMOD_3D ) )
  141. return;
  142. mMinDistance = min;
  143. mMaxDistance = max;
  144. mSetFlags.set( SET_MinMaxDistance );
  145. if( mChannel )
  146. SFXFMODDevice::smFunc->FMOD_Channel_Set3DMinMaxDistance(mChannel, mMinDistance, mMaxDistance);
  147. }
  148. void SFXFMODVoice::play( bool looping )
  149. {
  150. if( mBuffer->isStreaming() )
  151. looping = true;
  152. mMode = mDevice->get3dRollOffMode();
  153. mMode |= (looping ? FMOD_LOOP_NORMAL : FMOD_LOOP_OFF);
  154. Parent::play( looping );
  155. }
  156. void SFXFMODVoice::setVelocity( const VectorF& velocity )
  157. {
  158. if( !( _getBuffer()->mMode & FMOD_3D ) )
  159. return;
  160. // Note we have to do a handedness swap; see the
  161. // listener update code in SFXFMODDevice for details.
  162. mVelocity.x = velocity.x;
  163. mVelocity.y = velocity.z;
  164. mVelocity.z = velocity.y;
  165. mSetFlags.set( SET_Velocity );
  166. if( mChannel )
  167. SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, ( const FMOD_VECTOR* ) NULL, &mVelocity );
  168. }
  169. void SFXFMODVoice::setTransform( const MatrixF& transform )
  170. {
  171. if ( !( _getBuffer()->mMode & FMOD_3D ) )
  172. return;
  173. transform.getColumn( 3, (Point3F*)&mPosition );
  174. transform.getColumn( 1, (Point3F*)&mDirection );
  175. // Note we have to do a handedness swap; see the
  176. // listener update code in SFXFMODDevice for details.
  177. swap( mPosition.y, mPosition.z );
  178. swap( mDirection.y, mDirection.z );
  179. mSetFlags.set( SET_Transform );
  180. if( mChannel )
  181. {
  182. // This can fail safe, so don't assert if it fails.
  183. SFXFMODDevice::smFunc->FMOD_Channel_Set3DAttributes( mChannel, &mPosition, ( const FMOD_VECTOR* ) NULL );
  184. SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeOrientation( mChannel, &mDirection );
  185. }
  186. }
  187. void SFXFMODVoice::setVolume( F32 volume )
  188. {
  189. mVolume = volume;
  190. mSetFlags.set( SET_Volume );
  191. if( mChannel )
  192. SFXFMODDevice::smFunc->FMOD_Channel_SetVolume( mChannel, volume );
  193. }
  194. void SFXFMODVoice::setPriority( F32 priority )
  195. {
  196. mPriority = priority;
  197. mSetFlags.set( SET_Priority );
  198. if( mChannel )
  199. SFXFMODDevice::smFunc->FMOD_Channel_SetPriority( mChannel, TorquePriorityToFMODPriority( priority ) );
  200. }
  201. void SFXFMODVoice::setPitch( F32 pitch )
  202. {
  203. // if we do not know the frequency, we cannot change the pitch
  204. F32 frequency = _getBuffer()->getFormat().getSamplesPerSecond();
  205. if ( frequency == 0 )
  206. return;
  207. mFrequency = frequency * pitch;
  208. mSetFlags.set( SET_Pitch );
  209. // Scale the original frequency by the pitch factor.
  210. if( mChannel )
  211. SFXFMODDevice::smFunc->FMOD_Channel_SetFrequency(mChannel, mFrequency);
  212. }
  213. void SFXFMODVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
  214. {
  215. mConeInnerAngle = innerAngle;
  216. mConeOuterAngle = outerAngle;
  217. mConeOuterVolume = outerVolume;
  218. mSetFlags.set( SET_Cone );
  219. if( mChannel )
  220. SFXFMODDevice::smFunc->FMOD_Channel_Set3DConeSettings(
  221. mChannel,
  222. mConeInnerAngle,
  223. mConeOuterAngle,
  224. mConeOuterVolume );
  225. }
  226. void SFXFMODVoice::setReverb( const SFXSoundReverbProperties& reverb )
  227. {
  228. dMemset( &mReverb, 0, sizeof( mReverb ) );
  229. mReverb.Direct = reverb.mDirect;
  230. mReverb.Room = reverb.mRoom;
  231. mReverb.Flags = reverb.mFlags;
  232. mSetFlags.set( SET_Reverb );
  233. if( mChannel )
  234. SFXFMODDevice::smFunc->FMOD_Channel_SetReverbProperties( mChannel, &mReverb );
  235. }
  236. bool SFXFMODVoice::isVirtual() const
  237. {
  238. if( mChannel )
  239. {
  240. FMOD_BOOL result;
  241. SFXFMODDevice::smFunc->FMOD_Channel_IsVirtual( mChannel, &result );
  242. return result;
  243. }
  244. else
  245. return false;
  246. }