mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-01-20 20:54:46 +00:00
239 lines
7.2 KiB
C++
239 lines
7.2 KiB
C++
//-----------------------------------------------------------------------------
|
|
// 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 ),
|
|
mIs3d( description->mIs3D ),
|
|
mUseHardware( useHardware ),
|
|
mOpenAL( oalft )
|
|
{
|
|
// 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
|
|
}
|