123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238 |
- //-----------------------------------------------------------------------------
- // Copyright (c) 2012 GarageGames, LLC
- //
- // Permission is hereby granted, free of charge, to any person obtaining a copy
- // of this software and associated documentation files (the "Software"), to
- // deal in the Software without restriction, including without limitation the
- // rights to use, copy, modify, merge, publish, distribute, sublicense, and/or
- // sell copies of the Software, and to permit persons to whom the Software is
- // furnished to do so, subject to the following conditions:
- //
- // The above copyright notice and this permission notice shall be included in
- // all copies or substantial portions of the Software.
- //
- // THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
- // IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
- // FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
- // AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
- // LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
- // FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS
- // IN THE SOFTWARE.
- //-----------------------------------------------------------------------------
- #include "sfx/openal/sfxALBuffer.h"
- #include "sfx/openal/sfxALVoice.h"
- #include "sfx/openal/sfxALDevice.h"
- #include "sfx/sfxDescription.h"
- #include "console/console.h"
- //#define DEBUG_SPEW
- SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
- const ThreadSafeRef< SFXStream >& stream,
- SFXDescription* description,
- bool useHardware )
- {
- if( !_sfxFormatToALFormat( stream->getFormat() ) )
- {
- Con::errorf( "SFXALBuffer::create() - SFXFormat not supported by OpenAL" );
- return NULL;
- }
- SFXALBuffer *buffer = new SFXALBuffer( oalft,
- stream,
- description,
- useHardware );
- return buffer;
- }
- SFXALBuffer::SFXALBuffer( const OPENALFNTABLE &oalft,
- const ThreadSafeRef< SFXStream >& stream,
- SFXDescription* description,
- bool useHardware )
- : Parent( stream, description ),
- mOpenAL( oalft ),
- mUseHardware( useHardware ),
- mIs3d( description->mIs3D )
- {
- // Set up device buffers.
- if( !isStreaming() )
- mOpenAL.alGenBuffers( 1, &mALBuffer );
- }
- SFXALBuffer::~SFXALBuffer()
- {
- if( _getUniqueVoice() )
- _getUniqueVoice()->stop();
- // Release buffers.
- if ( mOpenAL.alIsBuffer( mALBuffer ))
- mOpenAL.alDeleteBuffers( 1, &mALBuffer );
- while( mFreeBuffers.size() )
- {
- ALuint buffer = mFreeBuffers.last();
- mOpenAL.alDeleteBuffers( 1, &buffer );
- mFreeBuffers.pop_back();
- }
- }
- void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
- {
- using namespace SFXInternal;
-
- if( !num )
- return;
-
- // If this is not a streaming buffer, just load the data into our single
- // static buffer.
-
- if( !isStreaming() )
- {
- SFXStreamPacket* packet = packets[ num - 1 ];
-
- ALenum alFormat = _sfxFormatToALFormat( getFormat() );
- AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
-
- mOpenAL.alBufferData( mALBuffer, alFormat,
- packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
-
- destructSingle( packet );
- return;
- }
- MutexHandle mutex;
- mutex.lock( &_getUniqueVoice()->mMutex, true );
- // Unqueue processed packets.
- ALuint source = _getUniqueVoice()->mSourceName;
- ALint numProcessed;
- mOpenAL.alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
-
- for( U32 i = 0; i < numProcessed; ++ i )
- {
- // Unqueue the buffer.
-
- ALuint buffer;
- mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
-
- // Update the sample offset on the voice.
-
- ALint size;
- mOpenAL.alGetBufferi( buffer, AL_SIZE, &size );
- _getUniqueVoice()->mSampleOffset += size / getFormat().getBytesPerSample();
-
- // Push the buffer onto the freelist.
-
- mFreeBuffers.push_back( buffer );
- }
- // Queue buffers.
- for( U32 i = 0; i < num; ++ i )
- {
- SFXStreamPacket* packet = packets[ i ];
-
- // Allocate a buffer.
-
- ALuint buffer;
- if( mFreeBuffers.size() )
- {
- buffer = mFreeBuffers.last();
- mFreeBuffers.pop_back();
- }
- else
- mOpenAL.alGenBuffers( 1, &buffer );
-
- // Upload the data.
-
- ALenum alFormat = _sfxFormatToALFormat( getFormat() );
- AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
- AssertFatal( mOpenAL.alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
-
- mOpenAL.alBufferData( buffer, alFormat,
- packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
-
- destructSingle( packet );
-
- // Queue the buffer.
-
- mOpenAL.alSourceQueueBuffers( source, 1, &buffer );
- }
- }
- void SFXALBuffer::_flush()
- {
- AssertFatal( isStreaming(), "SFXALBuffer::_flush() - not a streaming buffer" );
- AssertFatal( SFXInternal::isSFXThread(), "SFXALBuffer::_flush() - not on SFX thread" );
- #ifdef DEBUG_SPEW
- Platform::outputDebugString( "[SFXALBuffer] Flushing buffer" );
- #endif
- _getUniqueVoice()->_stop();
- MutexHandle mutex;
- mutex.lock( &_getUniqueVoice()->mMutex, true );
- ALuint source = _getUniqueVoice()->mSourceName;
- ALint numQueued;
- mOpenAL.alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
- for( U32 i = 0; i < numQueued; ++ i )
- {
- ALuint buffer;
- mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
- mFreeBuffers.push_back( buffer );
- }
- _getUniqueVoice()->mSampleOffset = 0;
-
- //RD: disabling hack for now; rewritten queueing should be able to cope
- #if 0 //def TORQUE_OS_MAC
-
- //WORKAROUND: Ugly hack on Mac. Apparently there's a bug in the OpenAL implementation
- // that will cause AL_BUFFERS_PROCESSED to not be reset as it should be causing write()
- // to fail. Brute-force this and just re-create the source. Let's pray that nobody
- // issues any concurrent state changes on the voice resulting in us losing state here.
-
- ALuint newSource;
- mOpenAL.alGenSources( 1, &newSource );
-
- #define COPY_F( name ) \
- { \
- F32 val; \
- mOpenAL.alGetSourcef( source, name, &val ); \
- mOpenAL.alSourcef( source, name, val ); \
- }
-
- #define COPY_FV( name ) \
- { \
- VectorF val; \
- mOpenAL.alGetSourcefv( source, name, val ); \
- mOpenAL.alSourcefv( source, name, val ); \
- }
-
- COPY_F( AL_REFERENCE_DISTANCE );
- COPY_F( AL_MAX_DISTANCE );
- COPY_F( AL_GAIN );
- COPY_F( AL_PITCH );
- COPY_F( AL_CONE_INNER_ANGLE );
- COPY_F( AL_CONE_OUTER_ANGLE );
- COPY_F( AL_CONE_OUTER_GAIN );
-
- COPY_FV( AL_VELOCITY );
- COPY_FV( AL_POSITION );
- COPY_FV( AL_DIRECTION );
-
- _getUniqueVoice()->mSourceName = newSource;
- mOpenAL.alDeleteSources( 1, &source );
- #endif
- }
|