sfxALBuffer.cpp 7.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238
  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 "sfx/openal/sfxALBuffer.h"
  23. #include "sfx/openal/sfxALVoice.h"
  24. #include "sfx/openal/sfxALDevice.h"
  25. #include "sfx/sfxDescription.h"
  26. #include "console/console.h"
  27. //#define DEBUG_SPEW
  28. SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
  29. const ThreadSafeRef< SFXStream >& stream,
  30. SFXDescription* description,
  31. bool useHardware )
  32. {
  33. if( !_sfxFormatToALFormat( stream->getFormat() ) )
  34. {
  35. Con::errorf( "SFXALBuffer::create() - SFXFormat not supported by OpenAL" );
  36. return NULL;
  37. }
  38. SFXALBuffer *buffer = new SFXALBuffer( oalft,
  39. stream,
  40. description,
  41. useHardware );
  42. return buffer;
  43. }
  44. SFXALBuffer::SFXALBuffer( const OPENALFNTABLE &oalft,
  45. const ThreadSafeRef< SFXStream >& stream,
  46. SFXDescription* description,
  47. bool useHardware )
  48. : Parent( stream, description ),
  49. mIs3d( description->mIs3D ),
  50. mUseHardware( useHardware ),
  51. mOpenAL( oalft )
  52. {
  53. // Set up device buffers.
  54. if( !isStreaming() )
  55. mOpenAL.alGenBuffers( 1, &mALBuffer );
  56. }
  57. SFXALBuffer::~SFXALBuffer()
  58. {
  59. if( _getUniqueVoice() )
  60. _getUniqueVoice()->stop();
  61. // Release buffers.
  62. if ( mOpenAL.alIsBuffer( mALBuffer ))
  63. mOpenAL.alDeleteBuffers( 1, &mALBuffer );
  64. while( mFreeBuffers.size() )
  65. {
  66. ALuint buffer = mFreeBuffers.last();
  67. mOpenAL.alDeleteBuffers( 1, &buffer );
  68. mFreeBuffers.pop_back();
  69. }
  70. }
  71. void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
  72. {
  73. using namespace SFXInternal;
  74. if( !num )
  75. return;
  76. // If this is not a streaming buffer, just load the data into our single
  77. // static buffer.
  78. if( !isStreaming() )
  79. {
  80. SFXStreamPacket* packet = packets[ num - 1 ];
  81. ALenum alFormat = _sfxFormatToALFormat( getFormat() );
  82. AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
  83. mOpenAL.alBufferData( mALBuffer, alFormat,
  84. packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
  85. destructSingle( packet );
  86. return;
  87. }
  88. MutexHandle mutex;
  89. mutex.lock( &_getUniqueVoice()->mMutex, true );
  90. // Unqueue processed packets.
  91. ALuint source = _getUniqueVoice()->mSourceName;
  92. ALint numProcessed;
  93. mOpenAL.alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
  94. for( U32 i = 0; i < numProcessed; ++ i )
  95. {
  96. // Unqueue the buffer.
  97. ALuint buffer;
  98. mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
  99. // Update the sample offset on the voice.
  100. ALint size;
  101. mOpenAL.alGetBufferi( buffer, AL_SIZE, &size );
  102. _getUniqueVoice()->mSampleOffset += size / getFormat().getBytesPerSample();
  103. // Push the buffer onto the freelist.
  104. mFreeBuffers.push_back( buffer );
  105. }
  106. // Queue buffers.
  107. for( U32 i = 0; i < num; ++ i )
  108. {
  109. SFXStreamPacket* packet = packets[ i ];
  110. // Allocate a buffer.
  111. ALuint buffer;
  112. if( mFreeBuffers.size() )
  113. {
  114. buffer = mFreeBuffers.last();
  115. mFreeBuffers.pop_back();
  116. }
  117. else
  118. mOpenAL.alGenBuffers( 1, &buffer );
  119. // Upload the data.
  120. ALenum alFormat = _sfxFormatToALFormat( getFormat() );
  121. AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
  122. AssertFatal( mOpenAL.alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
  123. mOpenAL.alBufferData( buffer, alFormat,
  124. packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
  125. destructSingle( packet );
  126. // Queue the buffer.
  127. mOpenAL.alSourceQueueBuffers( source, 1, &buffer );
  128. }
  129. }
  130. void SFXALBuffer::_flush()
  131. {
  132. AssertFatal( isStreaming(), "SFXALBuffer::_flush() - not a streaming buffer" );
  133. AssertFatal( SFXInternal::isSFXThread(), "SFXALBuffer::_flush() - not on SFX thread" );
  134. #ifdef DEBUG_SPEW
  135. Platform::outputDebugString( "[SFXALBuffer] Flushing buffer" );
  136. #endif
  137. _getUniqueVoice()->_stop();
  138. MutexHandle mutex;
  139. mutex.lock( &_getUniqueVoice()->mMutex, true );
  140. ALuint source = _getUniqueVoice()->mSourceName;
  141. ALint numQueued;
  142. mOpenAL.alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
  143. for( U32 i = 0; i < numQueued; ++ i )
  144. {
  145. ALuint buffer;
  146. mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
  147. mFreeBuffers.push_back( buffer );
  148. }
  149. _getUniqueVoice()->mSampleOffset = 0;
  150. //RD: disabling hack for now; rewritten queueing should be able to cope
  151. #if 0 //def TORQUE_OS_MAC
  152. //WORKAROUND: Ugly hack on Mac. Apparently there's a bug in the OpenAL implementation
  153. // that will cause AL_BUFFERS_PROCESSED to not be reset as it should be causing write()
  154. // to fail. Brute-force this and just re-create the source. Let's pray that nobody
  155. // issues any concurrent state changes on the voice resulting in us losing state here.
  156. ALuint newSource;
  157. mOpenAL.alGenSources( 1, &newSource );
  158. #define COPY_F( name ) \
  159. { \
  160. F32 val; \
  161. mOpenAL.alGetSourcef( source, name, &val ); \
  162. mOpenAL.alSourcef( source, name, val ); \
  163. }
  164. #define COPY_FV( name ) \
  165. { \
  166. VectorF val; \
  167. mOpenAL.alGetSourcefv( source, name, val ); \
  168. mOpenAL.alSourcefv( source, name, val ); \
  169. }
  170. COPY_F( AL_REFERENCE_DISTANCE );
  171. COPY_F( AL_MAX_DISTANCE );
  172. COPY_F( AL_GAIN );
  173. COPY_F( AL_PITCH );
  174. COPY_F( AL_CONE_INNER_ANGLE );
  175. COPY_F( AL_CONE_OUTER_ANGLE );
  176. COPY_F( AL_CONE_OUTER_GAIN );
  177. COPY_FV( AL_VELOCITY );
  178. COPY_FV( AL_POSITION );
  179. COPY_FV( AL_DIRECTION );
  180. _getUniqueVoice()->mSourceName = newSource;
  181. mOpenAL.alDeleteSources( 1, &source );
  182. #endif
  183. }