sfxALVoice.cpp 7.6 KB

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