mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-05-07 06:16:04 +00:00
SFX API Changes
DSound has since been deprecated and xaudio2 would require us to write our own 3d spatialization and mixer Load devices the same way we load in the gfx end setup sfx provider run sfx devices on startup various fixes around sfx null device added the bitrate and samplerate globals added the hrtf global code is in to use this but not setup yet Adds speed of sound to the sound system SFXAmbience now has a property for speed of sound for different mediums, can also be set directly
This commit is contained in:
parent
1c6409a485
commit
974f217b96
53 changed files with 1885 additions and 6409 deletions
|
|
@ -231,6 +231,12 @@ bool GuiCanvas::onAdd()
|
|||
{
|
||||
// ensure that we have a cursor
|
||||
setCursor(dynamic_cast<GuiCursor*>(Sim::findObject("DefaultCursor")));
|
||||
|
||||
SFXSystem::enumerateProviders();
|
||||
SFXProvider* p = SFXSystem::getBestProviderChoice();
|
||||
|
||||
if (p)
|
||||
SFX->createDevice(p);
|
||||
|
||||
// Enumerate things for GFX before we have an active device.
|
||||
GFXInit::enumerateAdapters();
|
||||
|
|
|
|||
|
|
@ -1,27 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// The various functions we need to grab from DSound.dll
|
||||
DS_FUNCTION( DirectSoundEnumerateA, HRESULT, (LPDSENUMCALLBACKA pDSEnumCallback, LPVOID pContext) )
|
||||
DS_FUNCTION( DirectSoundEnumerateW, HRESULT, (LPDSENUMCALLBACKW pDSEnumCallback, LPVOID pContext) )
|
||||
DS_FUNCTION( DirectSoundCreate8, HRESULT, (LPCGUID pcGuidDevice, LPDIRECTSOUND8 *ppDS8, LPUNKNOWN pUnkOuter) )
|
||||
|
||||
|
|
@ -1,277 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/dsound/sfxDSBuffer.h"
|
||||
#include "sfx/sfxStream.h"
|
||||
#include "sfx/sfxDescription.h"
|
||||
#include "sfx/sfxInternal.h"
|
||||
#include "platform/async/asyncUpdate.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
#include "core/util/safeCast.h"
|
||||
|
||||
|
||||
SFXDSBuffer* SFXDSBuffer::create( IDirectSound8 *dsound,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware )
|
||||
{
|
||||
AssertFatal( dsound, "SFXDSBuffer::create() - Got null dsound!" );
|
||||
AssertFatal( stream, "SFXDSBuffer::create() - Got a null stream!" );
|
||||
AssertFatal( description, "SFXDSBuffer::create() - Got a null description" );
|
||||
|
||||
SFXDSBuffer* buffer = new SFXDSBuffer( dsound,
|
||||
stream,
|
||||
description,
|
||||
useHardware );
|
||||
|
||||
|
||||
if( !buffer->_createBuffer( &buffer->mBuffer ) )
|
||||
SAFE_DELETE( buffer );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
SFXDSBuffer::SFXDSBuffer( IDirectSound8* dsound,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware )
|
||||
: Parent( stream, description ),
|
||||
mDSound( dsound ),
|
||||
mIs3d( description->mIs3D ),
|
||||
mUseHardware( useHardware ),
|
||||
mBuffer( NULL ),
|
||||
mDuplicate( false )
|
||||
{
|
||||
AssertFatal( mDSound, "SFXDSBuffer::SFXDSBuffer() - Got null dsound!" );
|
||||
|
||||
mDSound->AddRef();
|
||||
}
|
||||
|
||||
SFXDSBuffer::~SFXDSBuffer()
|
||||
{
|
||||
SAFE_RELEASE( mBuffer );
|
||||
SAFE_RELEASE( mDSound );
|
||||
}
|
||||
|
||||
bool SFXDSBuffer::_createBuffer( IDirectSoundBuffer8 **buffer8 )
|
||||
{
|
||||
AssertFatal( mAsyncState != NULL,
|
||||
"SFXDSBuffer::_createBuffer() - Can't create buffer when not connected to stream!" );
|
||||
|
||||
const SFXFormat& format = getFormat();
|
||||
|
||||
// Set up WAV format structure.
|
||||
WAVEFORMATEX wfx;
|
||||
dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) );
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = format.getChannels();
|
||||
wfx.nSamplesPerSec = format.getSamplesPerSecond();
|
||||
wfx.wBitsPerSample = format.getBitsPerChannel();
|
||||
wfx.nBlockAlign = wfx.nChannels * wfx.wBitsPerSample / 8;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
|
||||
// Set up DSBUFFERDESC structure.
|
||||
DSBUFFERDESC dsbdesc;
|
||||
dMemset( &dsbdesc, 0, sizeof( DSBUFFERDESC ) );
|
||||
dsbdesc.dwSize = sizeof( DSBUFFERDESC );
|
||||
dsbdesc.dwFlags =
|
||||
( mIs3d ? DSBCAPS_CTRL3D | DSBCAPS_MUTE3DATMAXDISTANCE : DSBCAPS_CTRLPAN ) |
|
||||
( isStreaming() ? DSBCAPS_CTRLPOSITIONNOTIFY : 0 ) |
|
||||
DSBCAPS_CTRLFREQUENCY |
|
||||
DSBCAPS_CTRLVOLUME |
|
||||
DSBCAPS_GETCURRENTPOSITION2 |
|
||||
DSBCAPS_GLOBALFOCUS |
|
||||
DSBCAPS_STATIC |
|
||||
( mUseHardware ? DSBCAPS_LOCHARDWARE : DSBCAPS_LOCSOFTWARE );
|
||||
dsbdesc.dwBufferBytes = mBufferSize;
|
||||
if ( mIs3d )
|
||||
dsbdesc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
|
||||
dsbdesc.lpwfxFormat = &wfx;
|
||||
|
||||
// Create the buffer.
|
||||
IDirectSoundBuffer *buffer = NULL;
|
||||
HRESULT hr = mDSound->CreateSoundBuffer( &dsbdesc, &buffer, NULL );
|
||||
if ( FAILED( hr ) || !buffer )
|
||||
return false;
|
||||
|
||||
// Grab the version 8 interface.
|
||||
IDirectSoundBuffer8* buffer8Ptr;
|
||||
hr = buffer->QueryInterface( IID_IDirectSoundBuffer8, ( LPVOID* ) &buffer8Ptr );
|
||||
|
||||
// Release the original interface.
|
||||
buffer->Release();
|
||||
|
||||
// If we failed to get the 8 interface... exit.
|
||||
if ( FAILED( hr ) || !buffer8Ptr )
|
||||
return false;
|
||||
|
||||
// Set up notification positions, if this is a streaming buffer.
|
||||
|
||||
if( isStreaming() )
|
||||
{
|
||||
using namespace SFXInternal;
|
||||
|
||||
const U32 maxQueuedPackets = SFXAsyncQueue::DEFAULT_STREAM_QUEUE_LENGTH;
|
||||
const U32 packetSize = mAsyncState->mStream->getPacketSize();
|
||||
|
||||
LPDIRECTSOUNDNOTIFY8 lpDsNotify;
|
||||
if( FAILED( hr = buffer8Ptr->QueryInterface( IID_IDirectSoundNotify8, ( LPVOID* ) &lpDsNotify ) ) )
|
||||
{
|
||||
SAFE_RELEASE( buffer8Ptr );
|
||||
return false;
|
||||
}
|
||||
|
||||
const U32 numNotifies = maxQueuedPackets + 1; // Add one for end-of-stream notification pos.
|
||||
DSBPOSITIONNOTIFY* dsbNotifyPos =
|
||||
( DSBPOSITIONNOTIFY* ) _alloca( numNotifies * sizeof( DSBPOSITIONNOTIFY ) );
|
||||
|
||||
// Events seem to be triggered way too early by DS causing the playback queues to
|
||||
// reject updates, so we nudge the update markers "somewhat" to the right here.
|
||||
// This value here is based on experimentation. No harm should result if we don't
|
||||
// hit it other than updates happening in sub-optimal timing.
|
||||
enum { OFFSET_DELTA = 5000 };
|
||||
|
||||
U32 offset = ( packetSize + OFFSET_DELTA ) % mBufferSize;
|
||||
HANDLE updateEvent = ( HANDLE ) UPDATE_THREAD()->getUpdateEvent();
|
||||
for( U32 i = 0; i < maxQueuedPackets; ++ i, offset = ( offset + packetSize ) % mBufferSize )
|
||||
{
|
||||
dsbNotifyPos[ i ].dwOffset = offset;
|
||||
dsbNotifyPos[ i ].hEventNotify = updateEvent;
|
||||
}
|
||||
|
||||
// A end-of-stream notification position.
|
||||
|
||||
//FIXME: this position will start to be wrong when doing stream seeks
|
||||
|
||||
dsbNotifyPos[ numNotifies - 1 ].dwOffset = ( format.getDataLength( getDuration() ) + OFFSET_DELTA ) % mBufferSize;
|
||||
dsbNotifyPos[ numNotifies - 1 ].hEventNotify = updateEvent;
|
||||
|
||||
// Install the notifications.
|
||||
|
||||
lpDsNotify->SetNotificationPositions( numNotifies, dsbNotifyPos );
|
||||
SAFE_RELEASE( lpDsNotify );
|
||||
|
||||
// Don't need to notify on stop as when playback is stopped,
|
||||
// the packet buffers will just fill up and stop updating
|
||||
// when saturated.
|
||||
}
|
||||
|
||||
*buffer8 = buffer8Ptr;
|
||||
return true;
|
||||
}
|
||||
|
||||
bool SFXDSBuffer::_copyData( U32 offset,
|
||||
const U8 *data,
|
||||
U32 length )
|
||||
{
|
||||
AssertFatal( mBuffer, "SFXDSBuffer::_copyData() - no buffer" );
|
||||
|
||||
// Fill the buffer with the resource data.
|
||||
VOID* lpvWrite;
|
||||
DWORD dwLength;
|
||||
VOID* lpvWrite2;
|
||||
DWORD dwLength2;
|
||||
HRESULT hr = mBuffer->Lock(
|
||||
offset, // Offset at which to start lock.
|
||||
length, // Size of lock.
|
||||
&lpvWrite, // Gets address of first part of lock.
|
||||
&dwLength, // Gets size of first part of lock.
|
||||
&lpvWrite2, // Address of wraparound not needed.
|
||||
&dwLength2, // Size of wraparound not needed.
|
||||
0 );
|
||||
if ( FAILED( hr ) )
|
||||
return false;
|
||||
|
||||
// Copy the first part.
|
||||
dMemcpy( lpvWrite, data, dwLength );
|
||||
|
||||
// Do we have a wrap?
|
||||
if ( lpvWrite2 )
|
||||
dMemcpy( lpvWrite2, data + dwLength, dwLength2 );
|
||||
|
||||
// And finally, unlock.
|
||||
hr = mBuffer->Unlock(
|
||||
lpvWrite, // Address of lock start.
|
||||
dwLength, // Size of lock.
|
||||
lpvWrite2, // No wraparound portion.
|
||||
dwLength2 ); // No wraparound size.
|
||||
|
||||
// Return success code.
|
||||
return SUCCEEDED(hr);
|
||||
}
|
||||
|
||||
void SFXDSBuffer::_flush()
|
||||
{
|
||||
AssertFatal( isStreaming(), "SFXDSBuffer::_flush() - not a streaming buffer" );
|
||||
AssertFatal( SFXInternal::isSFXThread(), "SFXDSBuffer::_flush() - not on SFX thread" );
|
||||
|
||||
Parent::_flush();
|
||||
mBuffer->SetCurrentPosition( 0 );
|
||||
}
|
||||
|
||||
bool SFXDSBuffer::_duplicateBuffer( IDirectSoundBuffer8 **buffer8 )
|
||||
{
|
||||
AssertFatal( mBuffer, "SFXDSBuffer::_duplicateBuffer() - Duplicate buffer is null!" );
|
||||
|
||||
// If this is the first duplicate then
|
||||
// give the caller our original buffer.
|
||||
if ( !mDuplicate )
|
||||
{
|
||||
mDuplicate = true;
|
||||
|
||||
*buffer8 = mBuffer;
|
||||
(*buffer8)->AddRef();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
IDirectSoundBuffer *buffer1 = NULL;
|
||||
HRESULT hr = mDSound->DuplicateSoundBuffer( mBuffer, &buffer1 );
|
||||
if ( FAILED( hr ) || !buffer1 )
|
||||
return false;
|
||||
|
||||
// Grab the version 8 interface.
|
||||
hr = buffer1->QueryInterface( IID_IDirectSoundBuffer8, (LPVOID*)buffer8 );
|
||||
|
||||
// Release the original interface.
|
||||
buffer1->Release();
|
||||
|
||||
return SUCCEEDED( hr ) && (*buffer8);
|
||||
}
|
||||
|
||||
bool SFXDSBuffer::createVoice( IDirectSoundBuffer8 **buffer8 )
|
||||
{
|
||||
return ( mBuffer && _duplicateBuffer( buffer8 ) && *buffer8 );
|
||||
}
|
||||
|
||||
void SFXDSBuffer::releaseVoice( IDirectSoundBuffer8 **buffer )
|
||||
{
|
||||
AssertFatal( *buffer, "SFXDSBuffer::releaseVoice() - Got null buffer!" );
|
||||
|
||||
if ( *buffer == mBuffer )
|
||||
{
|
||||
mDuplicate = false;
|
||||
(*buffer)->Stop();
|
||||
}
|
||||
|
||||
SAFE_RELEASE( (*buffer) );
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXDSBUFFER_H_
|
||||
#define _SFXDSBUFFER_H_
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
#ifndef _SFXINTERNAL_H_
|
||||
# include "sfx/sfxInternal.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// DirectSound SFXBuffer implementation.
|
||||
///
|
||||
/// Note that the actual sound buffer held by the buffer may
|
||||
/// get duplicated around for individual voices. This is kind
|
||||
/// of ugly as the resulting buffers aren't tied to a SFXDSBuffer
|
||||
/// anymore.
|
||||
class SFXDSBuffer : public SFXInternal::SFXWrapAroundBuffer
|
||||
{
|
||||
typedef SFXInternal::SFXWrapAroundBuffer Parent;
|
||||
|
||||
friend class SFXDSDevice;
|
||||
friend class SFXDSVoice;
|
||||
|
||||
protected:
|
||||
|
||||
///
|
||||
bool mIs3d;
|
||||
|
||||
///
|
||||
bool mUseHardware;
|
||||
|
||||
IDirectSound8 *mDSound;
|
||||
|
||||
/// The buffer used when duplication is allowed.
|
||||
IDirectSoundBuffer8 *mBuffer;
|
||||
|
||||
/// We set this to true when the original buffer has
|
||||
/// been handed out and duplicates need to be made.
|
||||
bool mDuplicate;
|
||||
|
||||
///
|
||||
SFXDSBuffer( IDirectSound8 *dsound,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware );
|
||||
|
||||
virtual ~SFXDSBuffer();
|
||||
|
||||
/// Set up a DirectSound buffer.
|
||||
/// @note This method will not fill the buffer with data.
|
||||
/// @note If this is a streaming buffer, the resulting buffer
|
||||
/// will have its notification positions set up and already
|
||||
/// be registered with SFXDSStreamThread.
|
||||
bool _createBuffer( IDirectSoundBuffer8 **buffer8 );
|
||||
|
||||
///
|
||||
bool _duplicateBuffer( IDirectSoundBuffer8 **buffer8 );
|
||||
|
||||
// SFXWrapAroundBuffer.
|
||||
virtual bool _copyData( U32 offset, const U8* data, U32 length );
|
||||
virtual void _flush();
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
static SFXDSBuffer* create( IDirectSound8* dsound,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware );
|
||||
|
||||
//
|
||||
bool createVoice( IDirectSoundBuffer8 **buffer );
|
||||
|
||||
//
|
||||
void releaseVoice( IDirectSoundBuffer8 **buffer );
|
||||
|
||||
};
|
||||
|
||||
#endif // _SFXDSBUFFER_H_
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/dsound/sfxDSDevice.h"
|
||||
#include "sfx/dsound/sfxDSBuffer.h"
|
||||
#include "sfx/dsound/sfxDSVoice.h"
|
||||
#include "platformWin32/platformWin32.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
#include "platform/async/asyncUpdate.h"
|
||||
#include "console/console.h"
|
||||
|
||||
|
||||
SFXDSDevice::SFXDSDevice( SFXProvider* provider,
|
||||
DSoundFNTable *dsFnTbl,
|
||||
GUID* guid,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers )
|
||||
: SFXDevice( name, provider, useHardware, maxBuffers ),
|
||||
mDSound( NULL ),
|
||||
mPrimaryBuffer( NULL ),
|
||||
mListener( NULL ),
|
||||
mDSoundTbl( dsFnTbl ),
|
||||
mGUID( guid )
|
||||
{
|
||||
}
|
||||
|
||||
bool SFXDSDevice::_init()
|
||||
{
|
||||
HRESULT hr = mDSoundTbl->DirectSoundCreate8( mGUID, &mDSound, NULL );
|
||||
if ( FAILED( hr ) || !mDSound )
|
||||
{
|
||||
Con::errorf( "SFXDSDevice::SFXDSDevice() - DirectSoundCreate8 failed" );
|
||||
return false;
|
||||
}
|
||||
|
||||
hr = mDSound->SetCooperativeLevel( getWin32WindowHandle(), DSSCL_PRIORITY );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
Con::errorf( "SFXDSDevice::SFXDSDevice() - SetCooperativeLevel failed" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Get the primary buffer.
|
||||
DSBUFFERDESC dsbd;
|
||||
dMemset( &dsbd, 0, sizeof( DSBUFFERDESC ) );
|
||||
dsbd.dwSize = sizeof( DSBUFFERDESC );
|
||||
dsbd.dwFlags = DSBCAPS_CTRL3D | DSBCAPS_PRIMARYBUFFER;
|
||||
hr = mDSound->CreateSoundBuffer( &dsbd, &mPrimaryBuffer, NULL );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
Con::errorf( "SFXDSDevice::SFXDSDevice - Creating primary sound buffer failed" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Set the format and bitrate on the primary buffer.
|
||||
S32 frequency = Con::getIntVariable( "$pref::SFX::frequency", 44100 );
|
||||
S32 bitrate = Con::getIntVariable( "$pref::SFX::bitrate", 32 );
|
||||
|
||||
WAVEFORMATEX wfx;
|
||||
dMemset( &wfx, 0, sizeof( WAVEFORMATEX ) );
|
||||
wfx.wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx.nChannels = 2;
|
||||
wfx.nSamplesPerSec = frequency;
|
||||
wfx.wBitsPerSample = bitrate;
|
||||
wfx.nBlockAlign = ( wfx.nChannels * wfx.wBitsPerSample ) / 8;
|
||||
wfx.nAvgBytesPerSec = wfx.nSamplesPerSec * wfx.nBlockAlign;
|
||||
hr = mPrimaryBuffer->SetFormat( &wfx );
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
Con::errorf( "SFXDSDevice::SFXDSDevice() - Setting format of primary buffer failed" );
|
||||
return false;
|
||||
}
|
||||
|
||||
// Grab the 3d listener.
|
||||
hr = mPrimaryBuffer->QueryInterface( IID_IDirectSound3DListener8, (LPVOID*)&mListener );
|
||||
if ( FAILED( hr ) )
|
||||
{
|
||||
Con::errorf( "SFXDSDevice::SFXDevice() - Querying the listener interface failed!" );
|
||||
mListener = NULL;
|
||||
}
|
||||
|
||||
mCaps.dwSize = sizeof( DSCAPS );
|
||||
mDSound->GetCaps( &mCaps );
|
||||
|
||||
// If the device reports no hardware buffers then
|
||||
// we have no choice but to disable hardware.
|
||||
if ( mCaps.dwMaxHw3DAllBuffers == 0 )
|
||||
mUseHardware = false;
|
||||
|
||||
// If mMaxBuffers is negative then use the caps
|
||||
// to decide on a good maximum value... or set 8.
|
||||
if ( mMaxBuffers < 0 )
|
||||
mMaxBuffers = getMax( mCaps.dwMaxHw3DAllBuffers, 8 );
|
||||
|
||||
// Start the stream thread.
|
||||
|
||||
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
|
||||
{
|
||||
SFXInternal::gUpdateThread =
|
||||
new AsyncUpdateThread( "DirectSound Update Thread", SFXInternal::gBufferUpdateList );
|
||||
SFXInternal::gUpdateThread->start();
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
SFXDSDevice::~SFXDSDevice()
|
||||
{
|
||||
// And release our resources.
|
||||
SAFE_RELEASE( mListener );
|
||||
SAFE_RELEASE( mPrimaryBuffer );
|
||||
SAFE_RELEASE( mDSound );
|
||||
}
|
||||
|
||||
SFXBuffer* SFXDSDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
|
||||
{
|
||||
AssertFatal( stream, "SFXDSDevice::createBuffer() - Got null stream!" );
|
||||
AssertFatal( description, "SFXDSDevice::createBuffer() - Got null description!" );
|
||||
|
||||
SFXDSBuffer* buffer = SFXDSBuffer::create( mDSound,
|
||||
stream,
|
||||
description,
|
||||
mUseHardware );
|
||||
|
||||
if( buffer )
|
||||
_addBuffer( buffer );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
SFXVoice* SFXDSDevice::createVoice( bool is3D, SFXBuffer *buffer )
|
||||
{
|
||||
// Don't bother going any further if we've
|
||||
// exceeded the maximum voices.
|
||||
if ( mVoices.size() >= mMaxBuffers )
|
||||
return NULL;
|
||||
|
||||
AssertFatal( buffer, "SFXDSDevice::createVoice() - Got null buffer!" );
|
||||
|
||||
SFXDSBuffer* dsBuffer = dynamic_cast<SFXDSBuffer*>( buffer );
|
||||
AssertFatal( dsBuffer, "SFXDSDevice::createVoice() - Got bad buffer!" );
|
||||
|
||||
SFXDSVoice* voice = SFXDSVoice::create( this, dsBuffer );
|
||||
if ( !voice )
|
||||
return NULL;
|
||||
|
||||
_addVoice( voice );
|
||||
return voice;
|
||||
}
|
||||
|
||||
void SFXDSDevice::_commitDeferred()
|
||||
{
|
||||
if( mListener )
|
||||
mListener->CommitDeferredSettings();
|
||||
}
|
||||
|
||||
void SFXDSDevice::update()
|
||||
{
|
||||
Parent::update();
|
||||
|
||||
// Apply the deferred settings that changed between updates.
|
||||
mListener->CommitDeferredSettings();
|
||||
}
|
||||
|
||||
void SFXDSDevice::setListener( U32 index, const SFXListenerProperties& listener )
|
||||
{
|
||||
// Get the transform from the listener.
|
||||
const MatrixF& transform = listener.getTransform();
|
||||
Point3F pos, dir, up;
|
||||
transform.getColumn( 3, &pos );
|
||||
transform.getColumn( 1, &dir );
|
||||
transform.getColumn( 2, &up );
|
||||
|
||||
// And the velocity...
|
||||
const VectorF& velocity = listener.getVelocity();
|
||||
|
||||
// Finally, set it all to DSound!
|
||||
mListener->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED );
|
||||
mListener->SetOrientation( dir.x, dir.z, dir.y, up.x, up.z, up.y, DS3D_DEFERRED );
|
||||
mListener->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED );
|
||||
}
|
||||
|
||||
void SFXDSDevice::setDistanceModel( SFXDistanceModel model )
|
||||
{
|
||||
switch( model )
|
||||
{
|
||||
case SFXDistanceModelLinear:
|
||||
Con::errorf( "SFXDSDevice::setDistanceModel - 'linear' distance attenuation not supported by DirectSound" );
|
||||
break;
|
||||
|
||||
case SFXDistanceModelLogarithmic:
|
||||
break; // Nothing to do.
|
||||
|
||||
default:
|
||||
AssertWarn( false, "SFXDSDevice::setDistanceModel() - model not implemented" );
|
||||
}
|
||||
}
|
||||
|
||||
void SFXDSDevice::setDopplerFactor( F32 factor )
|
||||
{
|
||||
if( mListener )
|
||||
mListener->SetDopplerFactor( factor, DS3D_DEFERRED ); // Committed in update.
|
||||
}
|
||||
|
||||
void SFXDSDevice::setRolloffFactor( F32 factor )
|
||||
{
|
||||
if( mListener )
|
||||
mListener->SetRolloffFactor( factor, DS3D_DEFERRED ); // Committed in update.
|
||||
}
|
||||
|
|
@ -1,142 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXDSDEVICE_H_
|
||||
#define _SFXDSDEVICE_H_
|
||||
|
||||
#ifndef _STRINGFUNCTIONS_H_
|
||||
# include "core/strings/stringFunctions.h"
|
||||
#endif
|
||||
#ifndef _SFXDEVICE_H_
|
||||
#include "sfx/sfxDevice.h"
|
||||
#endif
|
||||
#ifndef _SFXDSVOICE_H_
|
||||
#include "sfx/dsound/sfxDSVoice.h"
|
||||
#endif
|
||||
#ifndef OS_DLIBRARY_H
|
||||
#include "platform/platformDlibrary.h"
|
||||
#endif
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
// Typedefs
|
||||
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
|
||||
typedef fn_return (WINAPI *DSFNPTR##fn_name##)##fn_args##;
|
||||
#include "sfx/dsound/dsFunctions.h"
|
||||
#undef DS_FUNCTION
|
||||
|
||||
// Function table
|
||||
struct DSoundFNTable
|
||||
{
|
||||
DSoundFNTable() : isLoaded( false ) {};
|
||||
bool isLoaded;
|
||||
DLibraryRef dllRef;
|
||||
|
||||
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
|
||||
DSFNPTR##fn_name fn_name;
|
||||
#include "sfx/dsound/dsFunctions.h"
|
||||
#undef DS_FUNCTION
|
||||
};
|
||||
|
||||
|
||||
/// Helper for asserting on dsound HRESULTS.
|
||||
inline void DSAssert( HRESULT hr, const char *info )
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
|
||||
if( FAILED( hr ) )
|
||||
{
|
||||
char buf[256];
|
||||
dSprintf( buf, 256, "Error code: %x\n%s", hr, info );
|
||||
AssertFatal( false, buf );
|
||||
}
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
/// The DirectSound device implementation exposes a couple
|
||||
/// of settings to script that you should be aware of:
|
||||
///
|
||||
/// $DirectSound::dopplerFactor - This controls the scale of
|
||||
/// the doppler effect. Valid factors are 0.0 to 10.0 and it
|
||||
/// defaults to 0.75.
|
||||
///
|
||||
/// $DirectSound::distanceFactor - This sets the unit conversion
|
||||
/// for
|
||||
///
|
||||
/// $DirectSound::rolloffFactor - ;
|
||||
///
|
||||
///
|
||||
class SFXDSDevice : public SFXDevice
|
||||
{
|
||||
typedef SFXDevice Parent;
|
||||
|
||||
friend class SFXDSVoice;
|
||||
friend class SFXDSProvider; // _init
|
||||
|
||||
public:
|
||||
|
||||
//explicit SFXDSDevice();
|
||||
|
||||
SFXDSDevice( SFXProvider* provider,
|
||||
DSoundFNTable *dsFnTbl,
|
||||
GUID* guid,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers );
|
||||
|
||||
virtual ~SFXDSDevice();
|
||||
|
||||
protected:
|
||||
|
||||
IDirectSound8 *mDSound;
|
||||
|
||||
IDirectSound3DListener8 *mListener;
|
||||
|
||||
IDirectSoundBuffer *mPrimaryBuffer;
|
||||
|
||||
DSoundFNTable *mDSoundTbl;
|
||||
|
||||
DSCAPS mCaps;
|
||||
|
||||
GUID* mGUID;
|
||||
|
||||
bool _init();
|
||||
|
||||
/// Called from SFXDSVoice to commit any deferred
|
||||
/// settings before playback begins.
|
||||
void _commitDeferred();
|
||||
|
||||
public:
|
||||
|
||||
// SFXDevice
|
||||
virtual SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
virtual SFXVoice* createVoice( bool is3D, SFXBuffer *buffer );
|
||||
virtual void update();
|
||||
virtual void setListener( U32 index, const SFXListenerProperties& listener );
|
||||
virtual void setDistanceModel( SFXDistanceModel mode );
|
||||
virtual void setDopplerFactor( F32 factor );
|
||||
virtual void setRolloffFactor( F32 factor );
|
||||
};
|
||||
|
||||
#endif // _SFXDSDEVICE_H_
|
||||
|
|
@ -1,198 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/sfxProvider.h"
|
||||
#include "sfx/dsound/sfxDSDevice.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
#include "console/console.h"
|
||||
#include "core/strings/unicode.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
class SFXDSProvider : public SFXProvider
|
||||
{
|
||||
public:
|
||||
|
||||
SFXDSProvider()
|
||||
: SFXProvider( "DirectSound" ) {}
|
||||
virtual ~SFXDSProvider();
|
||||
|
||||
void init();
|
||||
|
||||
protected:
|
||||
DSoundFNTable mDSound;
|
||||
|
||||
struct DSDeviceInfo : SFXDeviceInfo
|
||||
{
|
||||
GUID* guid;
|
||||
DSCAPS caps;
|
||||
};
|
||||
|
||||
static BOOL CALLBACK dsEnumProc(
|
||||
LPGUID lpGUID,
|
||||
LPCTSTR lpszDesc,
|
||||
LPCTSTR lpszDrvName,
|
||||
LPVOID lpContext );
|
||||
|
||||
void addDeviceDesc( GUID* guid, const String& name, const String& desc );
|
||||
|
||||
public:
|
||||
|
||||
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
|
||||
|
||||
};
|
||||
|
||||
MODULE_BEGIN( DirectSound )
|
||||
|
||||
MODULE_INIT_BEFORE( SFX )
|
||||
MODULE_SHUTDOWN_AFTER( SFX )
|
||||
|
||||
SFXDSProvider* mProvider;
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
mProvider = new SFXDSProvider;
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
delete mProvider;
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
// Helper
|
||||
|
||||
bool dsBindFunction( DLibrary *dll, void *&fnAddress, const char *name )
|
||||
{
|
||||
fnAddress = dll->bind( name );
|
||||
|
||||
if (!fnAddress)
|
||||
Con::warnf( "DSound Loader: DLL bind failed for %s", name );
|
||||
|
||||
return fnAddress != 0;
|
||||
}
|
||||
|
||||
//------------------------------------------------------------------------------
|
||||
|
||||
SFXDSProvider::~SFXDSProvider()
|
||||
{
|
||||
}
|
||||
|
||||
void SFXDSProvider::init()
|
||||
{
|
||||
// Grab the functions we'll want from the dsound DLL.
|
||||
mDSound.dllRef = OsLoadLibrary( "dsound.dll" );
|
||||
mDSound.isLoaded = true;
|
||||
#define DS_FUNCTION(fn_name, fn_return, fn_args) \
|
||||
mDSound.isLoaded &= dsBindFunction(mDSound.dllRef, *(void**)&mDSound.fn_name, #fn_name);
|
||||
#include "sfx/dsound/dsFunctions.h"
|
||||
#undef DS_FUNCTION
|
||||
|
||||
AssertISV( mDSound.isLoaded, "DirectSound failed to load." );
|
||||
|
||||
// All we need to do to init is enumerate the
|
||||
// devices... if this fails then don't register
|
||||
// the provider as it's broken in some way.
|
||||
if ( FAILED( mDSound.DirectSoundEnumerate( dsEnumProc, (VOID*)this ) ) )
|
||||
{
|
||||
Con::errorf( "SFXDSProvider - Device enumeration failed!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Did we get any devices?
|
||||
if ( mDeviceInfo.empty() )
|
||||
{
|
||||
Con::errorf( "SFXDSProvider - No valid devices found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Wow, we made it - register the provider.
|
||||
regProvider( this );
|
||||
}
|
||||
|
||||
|
||||
BOOL CALLBACK SFXDSProvider::dsEnumProc(
|
||||
LPGUID lpGUID,
|
||||
LPCTSTR lpszDesc,
|
||||
LPCTSTR lpszDrvName,
|
||||
LPVOID lpContext )
|
||||
{
|
||||
SFXDSProvider* provider = (SFXDSProvider*)lpContext;
|
||||
provider->addDeviceDesc( lpGUID, lpszDrvName, lpszDesc );
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
void SFXDSProvider::addDeviceDesc( GUID* guid, const String& name, const String& desc )
|
||||
{
|
||||
// Create a dummy device to get the caps.
|
||||
IDirectSound8* dsound;
|
||||
HRESULT hr = mDSound.DirectSoundCreate8( guid, &dsound, NULL );
|
||||
if ( FAILED( hr ) || !dsound )
|
||||
return;
|
||||
|
||||
// Init the caps structure and have the device fill it out.
|
||||
DSCAPS caps;
|
||||
dMemset( &caps, 0, sizeof( caps ) );
|
||||
caps.dwSize = sizeof( caps );
|
||||
hr = dsound->GetCaps( &caps );
|
||||
|
||||
// Clean up and handle errors.
|
||||
SAFE_RELEASE( dsound );
|
||||
|
||||
if ( FAILED( hr ) )
|
||||
return;
|
||||
|
||||
// Now, record the desc info into our own internal list.
|
||||
DSDeviceInfo* info = new DSDeviceInfo;
|
||||
info->name = desc;
|
||||
info->driver = name;
|
||||
info->hasHardware = caps.dwMaxHw3DAllBuffers > 0;
|
||||
info->maxBuffers = caps.dwMaxHw3DAllBuffers;
|
||||
info->guid = guid;
|
||||
info->caps = caps;
|
||||
|
||||
mDeviceInfo.push_back( info );
|
||||
}
|
||||
|
||||
SFXDevice* SFXDSProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
|
||||
{
|
||||
DSDeviceInfo* info = dynamic_cast< DSDeviceInfo* >
|
||||
( _findDeviceInfo( deviceName ) );
|
||||
|
||||
if( !info )
|
||||
return NULL;
|
||||
|
||||
SFXDSDevice* device = new SFXDSDevice( this,
|
||||
&mDSound,
|
||||
info->guid,
|
||||
info->name,
|
||||
useHardware,
|
||||
maxBuffers );
|
||||
|
||||
if( !device->_init() )
|
||||
SAFE_DELETE( device );
|
||||
|
||||
return device;
|
||||
}
|
||||
|
|
@ -1,229 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/dsound/sfxDSVoice.h"
|
||||
#include "sfx/dsound/sfxDSDevice.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
|
||||
|
||||
SFXDSVoice* SFXDSVoice::create( SFXDSDevice *device, SFXDSBuffer *buffer )
|
||||
{
|
||||
AssertFatal( buffer, "SFXDSVoice::create() - Got null buffer!" );
|
||||
|
||||
IDirectSoundBuffer8 *dsBuffer8 = NULL;
|
||||
if ( !buffer->createVoice( &dsBuffer8 ) || !dsBuffer8 )
|
||||
return NULL;
|
||||
|
||||
// Now try to grab a 3D interface... if we don't
|
||||
// get one its probably because its not a 3d sound.
|
||||
IDirectSound3DBuffer8* dsBuffer3d8 = NULL;
|
||||
dsBuffer8->QueryInterface( IID_IDirectSound3DBuffer8, (LPVOID*)&dsBuffer3d8 );
|
||||
|
||||
// Create the voice and return!
|
||||
SFXDSVoice* voice = new SFXDSVoice( device,
|
||||
buffer,
|
||||
dsBuffer8,
|
||||
dsBuffer3d8 );
|
||||
|
||||
// Now set the voice to a default state.
|
||||
// The buffer from which we have duplicated may have been assigned different
|
||||
// properties and we don't want to inherit these.
|
||||
|
||||
voice->setVolume( 1.0 );
|
||||
voice->setPitch( 1.0 );
|
||||
|
||||
return voice;
|
||||
}
|
||||
|
||||
SFXDSVoice::SFXDSVoice( SFXDSDevice *device,
|
||||
SFXDSBuffer *buffer,
|
||||
IDirectSoundBuffer8 *dsBuffer,
|
||||
IDirectSound3DBuffer8 *dsBuffer3d )
|
||||
: Parent( buffer ),
|
||||
mDevice( device ),
|
||||
mDSBuffer( dsBuffer ),
|
||||
mDSBuffer3D( dsBuffer3d ),
|
||||
mIsLooping( false )
|
||||
{
|
||||
AssertFatal( mDevice, "SFXDSVoice::SFXDSVoice() - SFXDSDevice is null!" );
|
||||
AssertFatal( mBuffer, "SFXDSVoice::SFXDSVoice() - SFXDSBuffer is null!" );
|
||||
AssertFatal( mDSBuffer, "SFXDSVoice::SFXDSVoice() - Dsound buffer is null!" );
|
||||
}
|
||||
|
||||
SFXDSVoice::~SFXDSVoice()
|
||||
{
|
||||
SAFE_RELEASE( mDSBuffer3D );
|
||||
|
||||
SFXDSBuffer* dsBuffer = _getBuffer();
|
||||
if( dsBuffer )
|
||||
dsBuffer->releaseVoice( &mDSBuffer );
|
||||
|
||||
mBuffer = NULL;
|
||||
}
|
||||
|
||||
SFXStatus SFXDSVoice::_status() const
|
||||
{
|
||||
DWORD status = 0;
|
||||
mDSBuffer->GetStatus( &status );
|
||||
|
||||
if ( status & DSBSTATUS_PLAYING )
|
||||
return SFXStatusPlaying;
|
||||
else
|
||||
return SFXStatusStopped;
|
||||
}
|
||||
|
||||
void SFXDSVoice::_play()
|
||||
{
|
||||
DSAssert( mDSBuffer->Play( 0, 0, mIsLooping ? DSBPLAY_LOOPING : 0 ),
|
||||
"SFXDSVoice::_play() - Playback failed!" );
|
||||
}
|
||||
|
||||
void SFXDSVoice::_stop()
|
||||
{
|
||||
DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" );
|
||||
mDSBuffer->SetCurrentPosition( 0 );
|
||||
}
|
||||
|
||||
void SFXDSVoice::_pause()
|
||||
{
|
||||
DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" );
|
||||
}
|
||||
|
||||
void SFXDSVoice::_seek( U32 sample )
|
||||
{
|
||||
U32 pos = mBuffer->getFormat().getBytesPerSample() * sample;
|
||||
mDSBuffer->SetCurrentPosition( pos );
|
||||
}
|
||||
|
||||
U32 SFXDSVoice::_tell() const
|
||||
{
|
||||
DWORD position = 0;
|
||||
mDSBuffer->GetCurrentPosition( &position, NULL );
|
||||
U32 samplePos = _getBuffer()->getSamplePos( position );
|
||||
return samplePos;
|
||||
}
|
||||
|
||||
void SFXDSVoice::setMinMaxDistance( F32 min, F32 max )
|
||||
{
|
||||
if ( !mDSBuffer3D )
|
||||
return;
|
||||
|
||||
mDSBuffer3D->SetMinDistance( min, DS3D_DEFERRED );
|
||||
mDSBuffer3D->SetMaxDistance( max, DS3D_DEFERRED );
|
||||
}
|
||||
|
||||
void SFXDSVoice::play( bool looping )
|
||||
{
|
||||
// If this is a 3d sound then we need
|
||||
// to commit any deferred settings before
|
||||
// we start playback else we can get some
|
||||
// glitches.
|
||||
|
||||
if ( mDSBuffer3D )
|
||||
mDevice->_commitDeferred();
|
||||
|
||||
// If this is a streaming buffer,
|
||||
// force looping.
|
||||
|
||||
const bool isStreaming = mBuffer->isStreaming();
|
||||
if( isStreaming )
|
||||
looping = true;
|
||||
mIsLooping = looping;
|
||||
|
||||
Parent::play( looping );
|
||||
}
|
||||
|
||||
void SFXDSVoice::setVelocity( const VectorF& velocity )
|
||||
{
|
||||
if ( !mDSBuffer3D )
|
||||
return;
|
||||
|
||||
DSAssert( mDSBuffer3D->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED ),
|
||||
"SFXDSVoice::setVelocity - couldn't update buffer!" );
|
||||
}
|
||||
|
||||
void SFXDSVoice::setTransform( const MatrixF& transform )
|
||||
{
|
||||
if ( !mDSBuffer3D )
|
||||
return;
|
||||
|
||||
Point3F pos, dir;
|
||||
transform.getColumn( 3, &pos );
|
||||
transform.getColumn( 1, &dir );
|
||||
DSAssert( mDSBuffer3D->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED ),
|
||||
"SFXDSVoice::setTransform - couldn't set position of the buffer." );
|
||||
|
||||
DSAssert( mDSBuffer3D->SetConeOrientation( dir.x, dir.z, dir.y, DS3D_DEFERRED ),
|
||||
"SFXDSVoice::setTransform - couldn't set cone orientation of the buffer." );
|
||||
}
|
||||
|
||||
/// Helper for converting floating point linear volume
|
||||
/// to a logrithmic integer volume for dsound.
|
||||
LONG SFXDSVoice::_linearToLogVolume( F32 linVolume )
|
||||
{
|
||||
LONG logVolume;
|
||||
|
||||
if ( linVolume <= 0.0f )
|
||||
logVolume = DSBVOLUME_MIN;
|
||||
else
|
||||
{
|
||||
logVolume = -2000.0 * mLog( 1.0f / linVolume );
|
||||
logVolume = mClamp( logVolume, DSBVOLUME_MIN, DSBVOLUME_MAX );
|
||||
}
|
||||
|
||||
return logVolume;
|
||||
}
|
||||
|
||||
void SFXDSVoice::setVolume( F32 volume )
|
||||
{
|
||||
LONG logVolume = _linearToLogVolume( volume );
|
||||
|
||||
HRESULT hr = mDSBuffer->SetVolume( logVolume );
|
||||
DSAssert( hr, "SFXDSVoice::setVolume - couldn't set volume!" );
|
||||
}
|
||||
|
||||
void SFXDSVoice::setPitch( F32 pitch )
|
||||
{
|
||||
F32 sampleRate = _getBuffer()->getFormat().getSamplesPerSecond();
|
||||
F32 frequency = mFloor( mClampF( sampleRate * pitch, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX ) );
|
||||
|
||||
DSAssert( mDSBuffer->SetFrequency( ( U32 )frequency ),
|
||||
"SFXDSVoice::setPitch - couldn't set playback frequency.");
|
||||
}
|
||||
|
||||
void SFXDSVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
|
||||
{
|
||||
if ( !mDSBuffer3D )
|
||||
return;
|
||||
|
||||
DSAssert( mDSBuffer3D->SetConeAngles( innerAngle,
|
||||
outerAngle,
|
||||
DS3D_DEFERRED ),
|
||||
"SFXDSVoice::setCone - couldn't set cone angles!" );
|
||||
|
||||
|
||||
LONG logVolume = _linearToLogVolume( outerVolume );
|
||||
|
||||
DSAssert( mDSBuffer3D->SetConeOutsideVolume( logVolume,
|
||||
DS3D_DEFERRED ),
|
||||
"SFXDSVoice::setCone - couldn't set cone outside volume!" );
|
||||
}
|
||||
|
|
@ -1,92 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXDSVOICE_H_
|
||||
#define _SFXDSVOICE_H_
|
||||
|
||||
#ifndef _SFXVOICE_H_
|
||||
#include "sfx/sfxVoice.h"
|
||||
#endif
|
||||
#ifndef _SFXDSBUFFER_H_
|
||||
#include "sfx/dsound/sfxDSBuffer.h"
|
||||
#endif
|
||||
|
||||
#include <dsound.h>
|
||||
|
||||
class SFXDSDevice;
|
||||
|
||||
|
||||
class SFXDSVoice : public SFXVoice
|
||||
{
|
||||
typedef SFXVoice Parent;
|
||||
|
||||
protected:
|
||||
|
||||
SFXDSVoice( SFXDSDevice *device,
|
||||
SFXDSBuffer *buffer,
|
||||
IDirectSoundBuffer8 *dsBuffer,
|
||||
IDirectSound3DBuffer8 *dsBuffer3d );
|
||||
|
||||
/// The device used to commit deferred settings.
|
||||
SFXDSDevice *mDevice;
|
||||
|
||||
IDirectSoundBuffer8 *mDSBuffer;
|
||||
|
||||
IDirectSound3DBuffer8 *mDSBuffer3D;
|
||||
|
||||
bool mIsLooping;
|
||||
|
||||
SFXDSBuffer* _getBuffer() const { return ( SFXDSBuffer* ) mBuffer.getPointer(); }
|
||||
|
||||
/// Helper for converting floating point linear volume
|
||||
/// to a logrithmic integer volume for dsound.
|
||||
static LONG _linearToLogVolume( F32 linVolume );
|
||||
|
||||
// SFXVoice
|
||||
virtual SFXStatus _status() const;
|
||||
virtual void _play();
|
||||
virtual void _pause();
|
||||
virtual void _stop();
|
||||
virtual void _seek( U32 sample );
|
||||
virtual U32 _tell() const;
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
static SFXDSVoice* create( SFXDSDevice *device,
|
||||
SFXDSBuffer *buffer );
|
||||
|
||||
///
|
||||
virtual ~SFXDSVoice();
|
||||
|
||||
// SFXVoice
|
||||
void setMinMaxDistance( F32 min, F32 max );
|
||||
void play( bool looping );
|
||||
void setVelocity( const VectorF& velocity );
|
||||
void setTransform( const MatrixF& transform );
|
||||
void setVolume( F32 volume );
|
||||
void setPitch( F32 pitch );
|
||||
void setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume );
|
||||
|
||||
};
|
||||
|
||||
#endif // _SFXDSBUFFER_H_
|
||||
|
|
@ -33,46 +33,127 @@ bool SFXSndStream::_readHeader()
|
|||
|
||||
dMemset(&sfinfo, 0, sizeof(SF_INFO));
|
||||
|
||||
vio.get_filelen = sndFileLen;
|
||||
vio.seek = sndSeek;
|
||||
vio.read = sndRead;
|
||||
vio.write = sndWrite;
|
||||
vio.tell = sndTell;
|
||||
vio.get_filelen = sndFileLen;
|
||||
vio.seek = sndSeek;
|
||||
vio.read = sndRead;
|
||||
vio.write = sndWrite;
|
||||
vio.tell = sndTell;
|
||||
|
||||
vio_data.length = 0;
|
||||
vio_data.offset = 0;
|
||||
vio_data.data = mStream;
|
||||
|
||||
vio_data.sampleBlockAlign = 1;
|
||||
vio_data.byteBlockAlign = 0;
|
||||
|
||||
if ((sndFile = sf_open_virtual(&vio, SFM_READ, &sfinfo, &vio_data)) == NULL)
|
||||
{
|
||||
Con::printf("SFXSndStream - _readHeader failed: %s", sf_strerror(sndFile));
|
||||
return false;
|
||||
}
|
||||
|
||||
S32 bitsPerSample = 0;
|
||||
switch ((sfinfo.format & SF_FORMAT_SUBMASK))
|
||||
S32 bitsPerSample = 16;
|
||||
|
||||
switch (sfinfo.format & SF_FORMAT_SUBMASK)
|
||||
{
|
||||
case SF_FORMAT_PCM_S8:
|
||||
case SF_FORMAT_PCM_U8:
|
||||
bitsPerSample = 8;
|
||||
mSampleType = Sample_Int8; // Still decode using sf_readf_short()
|
||||
break;
|
||||
|
||||
case SF_FORMAT_PCM_16:
|
||||
bitsPerSample = 16;
|
||||
mSampleType = Sample_Int16;
|
||||
break;
|
||||
case SF_FORMAT_VORBIS:
|
||||
|
||||
case SF_FORMAT_PCM_24:
|
||||
case SF_FORMAT_PCM_32:
|
||||
case SF_FORMAT_FLOAT:
|
||||
bitsPerSample = 16;
|
||||
sf_command(sndFile, SFC_SET_SCALE_FLOAT_INT_READ, NULL, SF_TRUE);
|
||||
case SF_FORMAT_DOUBLE:
|
||||
case SF_FORMAT_VORBIS:
|
||||
case SF_FORMAT_OPUS:
|
||||
case SF_FORMAT_ALAC_20:
|
||||
case SF_FORMAT_ALAC_24:
|
||||
case SF_FORMAT_ALAC_32:
|
||||
case 0x0080/*SF_FORMAT_MPEG_LAYER_I*/:
|
||||
case 0x0081/*SF_FORMAT_MPEG_LAYER_II*/:
|
||||
case 0x0082/*SF_FORMAT_MPEG_LAYER_III*/:
|
||||
bitsPerSample = 32;
|
||||
mSampleType = Sample_Float;
|
||||
break;
|
||||
default:
|
||||
// missed, set it to 16 anyway.
|
||||
|
||||
case SF_FORMAT_IMA_ADPCM:
|
||||
bitsPerSample = 16;
|
||||
mSampleType = Sample_IMA4;
|
||||
break;
|
||||
|
||||
case SF_FORMAT_MS_ADPCM:
|
||||
bitsPerSample = 16;
|
||||
mSampleType = Sample_MSADPCM;
|
||||
break;
|
||||
|
||||
default:
|
||||
bitsPerSample = 16;
|
||||
mSampleType = Sample_Int16;
|
||||
break;
|
||||
}
|
||||
|
||||
mFormat.set(sfinfo.channels, bitsPerSample * sfinfo.channels, sfinfo.samplerate);
|
||||
//------------------------------------------------------------
|
||||
// Block alignment logic for ADPCM formats
|
||||
//------------------------------------------------------------
|
||||
int byteBlockAlign = 0;
|
||||
int sampleBlockAlign = 1;
|
||||
|
||||
if (mSampleType == Sample_IMA4 || mSampleType == Sample_MSADPCM)
|
||||
{
|
||||
SF_CHUNK_INFO inf = { "fmt ", 4, 0, NULL };
|
||||
SF_CHUNK_ITERATOR* iter = sf_get_chunk_iterator(sndFile, &inf);
|
||||
|
||||
if (!iter || sf_get_chunk_size(iter, &inf) != SF_ERR_NO_ERROR || inf.datalen < 14)
|
||||
mSampleType = Sample_Int16;
|
||||
else
|
||||
{
|
||||
uint8_t* fmtbuf = (uint8_t*)malloc(inf.datalen);
|
||||
inf.data = fmtbuf;
|
||||
|
||||
if (sf_get_chunk_data(iter, &inf) != SF_ERR_NO_ERROR)
|
||||
mSampleType = Sample_Int16;
|
||||
else
|
||||
{
|
||||
byteBlockAlign = fmtbuf[12] | (fmtbuf[13] << 8);
|
||||
int ch = sfinfo.channels;
|
||||
|
||||
if (mSampleType == Sample_IMA4)
|
||||
sampleBlockAlign = (byteBlockAlign / ch - 4) / 4 * 8 + 1;
|
||||
else
|
||||
sampleBlockAlign = (byteBlockAlign / ch - 7) * 2 + 2;
|
||||
}
|
||||
dFree(fmtbuf);
|
||||
}
|
||||
}
|
||||
|
||||
//------------------------------------------------------------
|
||||
// Commit alignment to class + VIO data
|
||||
//------------------------------------------------------------
|
||||
if (mSampleType == Sample_Int16)
|
||||
{
|
||||
sampleBlockAlign = 1;
|
||||
byteBlockAlign = sfinfo.channels * 2;
|
||||
}
|
||||
else if (mSampleType == Sample_Float)
|
||||
{
|
||||
sampleBlockAlign = 1;
|
||||
byteBlockAlign = sfinfo.channels * 4;
|
||||
}
|
||||
|
||||
vio_data.sampleBlockAlign = sampleBlockAlign;
|
||||
vio_data.byteBlockAlign = byteBlockAlign;
|
||||
|
||||
mSampleBlockAlign = sampleBlockAlign;
|
||||
mByteBlockAlign = byteBlockAlign;
|
||||
|
||||
mFormat.set(sfinfo.channels, bitsPerSample * sfinfo.channels, sfinfo.samplerate, mSampleType);
|
||||
|
||||
mSamples = sfinfo.frames;
|
||||
|
||||
|
|
@ -110,25 +191,32 @@ U32 SFXSndStream::read(U8* buffer, U32 length)
|
|||
return 0;
|
||||
}
|
||||
|
||||
U32 framesToRead = length / mFormat.getBytesPerSample();
|
||||
const U32 bytesPerFrame = mFormat.getBytesPerSample();
|
||||
U32 framesToRead = length / bytesPerFrame;
|
||||
|
||||
// Enforce sample block alignment (important for ADPCM / compressed)
|
||||
if (mSampleBlockAlign > 1)
|
||||
framesToRead -= (framesToRead % mSampleBlockAlign);
|
||||
|
||||
if (framesToRead == 0)
|
||||
return 0;
|
||||
|
||||
U32 framesRead = 0;
|
||||
|
||||
switch (sfinfo.format & SF_FORMAT_SUBMASK)
|
||||
switch (mSampleType)
|
||||
{
|
||||
case SF_FORMAT_PCM_S8:
|
||||
case SF_FORMAT_PCM_U8:
|
||||
framesRead = sf_readf_int(sndFile, (int*)buffer, framesToRead);
|
||||
case SFXSampleType::Sample_Int8: framesRead = sf_readf_int(sndFile, (int*)buffer, framesToRead);
|
||||
break;
|
||||
case SF_FORMAT_PCM_16:
|
||||
case SF_FORMAT_VORBIS:
|
||||
case SF_FORMAT_PCM_24:
|
||||
case SF_FORMAT_PCM_32:
|
||||
case SF_FORMAT_FLOAT:
|
||||
framesRead = sf_readf_short(sndFile, (short*)buffer, framesToRead);
|
||||
case SFXSampleType::Sample_Int16: framesRead = sf_readf_short(sndFile, (short*)buffer, framesToRead);
|
||||
break;
|
||||
case SFXSampleType::Sample_Float: framesRead = sf_readf_float(sndFile, (float*)buffer, framesToRead);
|
||||
break;
|
||||
case SFXSampleType::Sample_IMA4:
|
||||
case SFXSampleType::Sample_MSADPCM:
|
||||
framesRead = sf_read_raw(sndFile, buffer, framesToRead);
|
||||
break;
|
||||
default:
|
||||
Con::errorf("SFXSndStream - read: Unsupported format.");
|
||||
return 0;
|
||||
break;
|
||||
}
|
||||
|
||||
if (framesRead != framesToRead)
|
||||
|
|
@ -142,7 +230,6 @@ U32 SFXSndStream::read(U8* buffer, U32 length)
|
|||
// reset stream
|
||||
setPosition(0);
|
||||
}
|
||||
|
||||
|
||||
return framesRead * mFormat.getBytesPerSample();
|
||||
}
|
||||
|
|
@ -221,4 +308,3 @@ sf_count_t SFXSndStream::sndFileLen(void* user_data)
|
|||
|
||||
return vf->length;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -39,11 +39,18 @@ public:
|
|||
|
||||
protected:
|
||||
|
||||
SFXSampleType mSampleType;
|
||||
S32 mSampleBlockAlign;
|
||||
S32 mByteBlockAlign;
|
||||
|
||||
// setup our vio_data struct.
|
||||
typedef struct
|
||||
{
|
||||
sf_count_t offset, length;
|
||||
Stream* data;
|
||||
|
||||
S32 sampleBlockAlign;
|
||||
S32 byteBlockAlign;
|
||||
} VIO_DATA;
|
||||
|
||||
/// Total number of bytes read from the stream so far.
|
||||
|
|
@ -58,11 +65,11 @@ protected:
|
|||
|
||||
// vio callbacks
|
||||
static sf_count_t sndSeek(sf_count_t offset, int whence, void* user_data);
|
||||
static sf_count_t sndRead(void *ptr, sf_count_t count, void* user_data);
|
||||
static sf_count_t sndRead(void* ptr, sf_count_t count, void* user_data);
|
||||
static sf_count_t sndWrite(const void* ptr, sf_count_t count, void* user_data);
|
||||
static sf_count_t sndTell(void* user_data);
|
||||
static sf_count_t sndFileLen(void* user_data);
|
||||
|
||||
|
||||
// SFXStream
|
||||
bool _readHeader() override;
|
||||
void _close() override;
|
||||
|
|
|
|||
|
|
@ -24,15 +24,30 @@
|
|||
#include "sfx/null/sfxNullBuffer.h"
|
||||
#include "sfx/sfxInternal.h"
|
||||
|
||||
|
||||
SFXNullDevice::SFXNullDevice( SFXProvider* provider,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers )
|
||||
|
||||
: SFXDevice( name, provider, useHardware, maxBuffers )
|
||||
class SFXNULLRegisterProvider
|
||||
{
|
||||
mMaxBuffers = getMax( maxBuffers, 8 );
|
||||
public:
|
||||
SFXNULLRegisterProvider()
|
||||
{
|
||||
SFXSystem::getRegisterProviderSignal().notify(&SFXNullDevice::enumerateProviders);
|
||||
}
|
||||
};
|
||||
|
||||
static SFXNULLRegisterProvider pSFXNULLRegisterProvider;
|
||||
|
||||
|
||||
SFXProvider::CreateProviderInstanceDelegate SFXNullDevice::mCreateDeviceInstance(SFXNullDevice::createInstance);
|
||||
|
||||
SFXDevice* SFXNullDevice::createInstance(U32 providerIndex)
|
||||
{
|
||||
SFXNullDevice* dev = new SFXNullDevice(providerIndex);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
SFXNullDevice::SFXNullDevice( U32 providerIndex )
|
||||
{
|
||||
mMaxBuffers = 8;
|
||||
}
|
||||
|
||||
SFXNullDevice::~SFXNullDevice()
|
||||
|
|
@ -65,6 +80,17 @@ SFXVoice* SFXNullDevice::createVoice( bool is3D, SFXBuffer *buffer )
|
|||
return voice;
|
||||
}
|
||||
|
||||
void SFXNullDevice::enumerateProviders(Vector<SFXProvider*>& providerList)
|
||||
{
|
||||
SFXProvider* toAdd = new SFXProvider;
|
||||
toAdd->mName = String::ToString("SFX Null Device");
|
||||
toAdd->mIndex = providerList.size();
|
||||
toAdd->mDeviceType = Output;
|
||||
toAdd->mType = NullProvider;
|
||||
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
|
||||
providerList.push_back(toAdd);
|
||||
}
|
||||
|
||||
void SFXNullDevice::update()
|
||||
{
|
||||
// Do nothing. Prevent SFXDevice from running
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#ifndef _SFXNULLDEVICE_H_
|
||||
#define _SFXNULLDEVICE_H_
|
||||
|
||||
class SFXProvider;
|
||||
|
||||
#ifndef _SFXDEVICE_H_
|
||||
#include "sfx/sfxDevice.h"
|
||||
#endif
|
||||
|
|
@ -37,27 +35,28 @@ class SFXProvider;
|
|||
#ifndef _SFXNULLVOICE_H_
|
||||
#include "sfx/null/sfxNullVoice.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SFXSYSTEM_H_
|
||||
#include "sfx/sfxSystem.h"
|
||||
#endif
|
||||
|
||||
class SFXNullDevice : public SFXDevice
|
||||
{
|
||||
typedef SFXDevice Parent;
|
||||
protected:
|
||||
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
|
||||
|
||||
public:
|
||||
public:
|
||||
static void enumerateProviders(Vector<SFXProvider*>& providerList);
|
||||
SFXNullDevice( U32 providerIndex );
|
||||
static SFXDevice* createInstance(U32 adapterIndex);
|
||||
virtual ~SFXNullDevice();
|
||||
|
||||
SFXNullDevice( SFXProvider* provider,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers );
|
||||
public:
|
||||
|
||||
virtual ~SFXNullDevice();
|
||||
|
||||
public:
|
||||
|
||||
// SFXDevice.
|
||||
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
|
||||
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
|
||||
void update() override;
|
||||
// SFXDevice.
|
||||
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
|
||||
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
|
||||
void update() override;
|
||||
};
|
||||
|
||||
#endif // _SFXNULLDEVICE_H_
|
||||
#endif // _SFXNULLDEVICE_H_
|
||||
|
|
|
|||
|
|
@ -1,98 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/sfxProvider.h"
|
||||
#include "sfx/null/sfxNullDevice.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
class SFXNullProvider : public SFXProvider
|
||||
{
|
||||
public:
|
||||
|
||||
SFXNullProvider()
|
||||
: SFXProvider( "Null" ) {}
|
||||
virtual ~SFXNullProvider();
|
||||
|
||||
protected:
|
||||
void addDeviceDesc( const String& name, const String& desc );
|
||||
void init() override;
|
||||
|
||||
public:
|
||||
|
||||
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) override;
|
||||
|
||||
};
|
||||
|
||||
MODULE_BEGIN( SFXNull )
|
||||
|
||||
MODULE_INIT_BEFORE( SFX )
|
||||
MODULE_SHUTDOWN_AFTER( SFX )
|
||||
|
||||
SFXNullProvider* mProvider;
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
mProvider = new SFXNullProvider;
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
delete mProvider;
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
void SFXNullProvider::init()
|
||||
{
|
||||
regProvider( this );
|
||||
addDeviceDesc( "Null", "SFX Null Device" );
|
||||
}
|
||||
|
||||
SFXNullProvider::~SFXNullProvider()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
void SFXNullProvider::addDeviceDesc( const String& name, const String& desc )
|
||||
{
|
||||
SFXDeviceInfo* info = new SFXDeviceInfo;
|
||||
info->internalName = desc;
|
||||
info->name = "Null Device";
|
||||
info->driver = name;
|
||||
info->hasHardware = false;
|
||||
info->maxBuffers = 8;
|
||||
|
||||
mDeviceInfo.push_back( info );
|
||||
}
|
||||
|
||||
SFXDevice* SFXNullProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
|
||||
{
|
||||
SFXDeviceInfo* info = _findDeviceInfo( deviceName );
|
||||
|
||||
// Do we find one to create?
|
||||
if ( info )
|
||||
return new SFXNullDevice( this, info->internalName, useHardware, maxBuffers );
|
||||
|
||||
return NULL;
|
||||
}
|
||||
176
Engine/source/sfx/openal/LoadOAL.cpp
Normal file
176
Engine/source/sfx/openal/LoadOAL.cpp
Normal file
|
|
@ -0,0 +1,176 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Creative Labs Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
|
||||
* the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
// Based on Openal-soft router code.
|
||||
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
#include "console/console.h"
|
||||
|
||||
#if defined(TORQUE_OS_WIN)
|
||||
#include <windows.h>
|
||||
#else
|
||||
#include <dirent.h>
|
||||
#include <sys/types.h>
|
||||
#endif
|
||||
|
||||
LIB_HANDLE openaAlDll = NULL;
|
||||
|
||||
#define LOAD_REQUIRED(table, x) \
|
||||
table->x = reinterpret_cast<decltype(table->x)>(reinterpret_cast<void*>( \
|
||||
GET_PROC_ADDRESS(openaAlDll, #x))); \
|
||||
if(!table->x) \
|
||||
{ \
|
||||
Con::warnf("Failed to find entry point :%s\n", #x); \
|
||||
loadok = false; \
|
||||
}
|
||||
|
||||
|
||||
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE oal)
|
||||
{
|
||||
if (!oal)
|
||||
return AL_FALSE;
|
||||
|
||||
if (szOALFullPathName)
|
||||
openaAlDll = LOAD_LIBRARY(szOALFullPathName);
|
||||
else
|
||||
{
|
||||
#if defined(TORQUE_OS_WIN)
|
||||
openaAlDll = LOAD_LIBRARY("openal32.dll");
|
||||
#elif defined(TORQUE_OS_LINUX)
|
||||
openaAlDll = LOAD_LIBRARY("libopenal.so");
|
||||
#elif defined(TORQUE_OS_MAC)
|
||||
openaAlDll = LOAD_LIBRARY("@rpath/libopenal.1.24.3.dylib");
|
||||
#endif
|
||||
}
|
||||
|
||||
if (!openaAlDll)
|
||||
return AL_FALSE;
|
||||
|
||||
bool loadok = true;
|
||||
|
||||
LOAD_REQUIRED(oal, alcCreateContext);
|
||||
LOAD_REQUIRED(oal, alcMakeContextCurrent);
|
||||
LOAD_REQUIRED(oal, alcProcessContext);
|
||||
LOAD_REQUIRED(oal, alcSuspendContext);
|
||||
LOAD_REQUIRED(oal, alcDestroyContext);
|
||||
LOAD_REQUIRED(oal, alcGetCurrentContext);
|
||||
LOAD_REQUIRED(oal, alcGetContextsDevice);
|
||||
LOAD_REQUIRED(oal, alcOpenDevice);
|
||||
LOAD_REQUIRED(oal, alcCloseDevice);
|
||||
LOAD_REQUIRED(oal, alcGetError);
|
||||
LOAD_REQUIRED(oal, alcIsExtensionPresent);
|
||||
LOAD_REQUIRED(oal, alcGetProcAddress);
|
||||
LOAD_REQUIRED(oal, alcGetEnumValue);
|
||||
LOAD_REQUIRED(oal, alcGetString);
|
||||
LOAD_REQUIRED(oal, alcGetIntegerv);
|
||||
LOAD_REQUIRED(oal, alcCaptureOpenDevice);
|
||||
LOAD_REQUIRED(oal, alcCaptureCloseDevice);
|
||||
LOAD_REQUIRED(oal, alcCaptureStart);
|
||||
LOAD_REQUIRED(oal, alcCaptureStop);
|
||||
LOAD_REQUIRED(oal, alcCaptureSamples);
|
||||
|
||||
LOAD_REQUIRED(oal, alEnable);
|
||||
LOAD_REQUIRED(oal, alDisable);
|
||||
LOAD_REQUIRED(oal, alIsEnabled);
|
||||
LOAD_REQUIRED(oal, alGetString);
|
||||
LOAD_REQUIRED(oal, alGetBooleanv);
|
||||
LOAD_REQUIRED(oal, alGetIntegerv);
|
||||
LOAD_REQUIRED(oal, alGetFloatv);
|
||||
LOAD_REQUIRED(oal, alGetDoublev);
|
||||
LOAD_REQUIRED(oal, alGetBoolean);
|
||||
LOAD_REQUIRED(oal, alGetInteger);
|
||||
LOAD_REQUIRED(oal, alGetFloat);
|
||||
LOAD_REQUIRED(oal, alGetDouble);
|
||||
LOAD_REQUIRED(oal, alGetError);
|
||||
LOAD_REQUIRED(oal, alIsExtensionPresent);
|
||||
LOAD_REQUIRED(oal, alGetProcAddress);
|
||||
LOAD_REQUIRED(oal, alGetEnumValue);
|
||||
LOAD_REQUIRED(oal, alListenerf);
|
||||
LOAD_REQUIRED(oal, alListener3f);
|
||||
LOAD_REQUIRED(oal, alListenerfv);
|
||||
LOAD_REQUIRED(oal, alListeneri);
|
||||
LOAD_REQUIRED(oal, alListener3i);
|
||||
LOAD_REQUIRED(oal, alListeneriv);
|
||||
LOAD_REQUIRED(oal, alGetListenerf);
|
||||
LOAD_REQUIRED(oal, alGetListener3f);
|
||||
LOAD_REQUIRED(oal, alGetListenerfv);
|
||||
LOAD_REQUIRED(oal, alGetListeneri);
|
||||
LOAD_REQUIRED(oal, alGetListener3i);
|
||||
LOAD_REQUIRED(oal, alGetListeneriv);
|
||||
LOAD_REQUIRED(oal, alGenSources);
|
||||
LOAD_REQUIRED(oal, alDeleteSources);
|
||||
LOAD_REQUIRED(oal, alIsSource);
|
||||
LOAD_REQUIRED(oal, alSourcef);
|
||||
LOAD_REQUIRED(oal, alSource3f);
|
||||
LOAD_REQUIRED(oal, alSourcefv);
|
||||
LOAD_REQUIRED(oal, alSourcei);
|
||||
LOAD_REQUIRED(oal, alSource3i);
|
||||
LOAD_REQUIRED(oal, alSourceiv);
|
||||
LOAD_REQUIRED(oal, alGetSourcef);
|
||||
LOAD_REQUIRED(oal, alGetSource3f);
|
||||
LOAD_REQUIRED(oal, alGetSourcefv);
|
||||
LOAD_REQUIRED(oal, alGetSourcei);
|
||||
LOAD_REQUIRED(oal, alGetSource3i);
|
||||
LOAD_REQUIRED(oal, alGetSourceiv);
|
||||
LOAD_REQUIRED(oal, alSourcePlayv);
|
||||
LOAD_REQUIRED(oal, alSourceStopv);
|
||||
LOAD_REQUIRED(oal, alSourceRewindv);
|
||||
LOAD_REQUIRED(oal, alSourcePausev);
|
||||
LOAD_REQUIRED(oal, alSourcePlay);
|
||||
LOAD_REQUIRED(oal, alSourceStop);
|
||||
LOAD_REQUIRED(oal, alSourceRewind);
|
||||
LOAD_REQUIRED(oal, alSourcePause);
|
||||
LOAD_REQUIRED(oal, alSourceQueueBuffers);
|
||||
LOAD_REQUIRED(oal, alSourceUnqueueBuffers);
|
||||
LOAD_REQUIRED(oal, alGenBuffers);
|
||||
LOAD_REQUIRED(oal, alDeleteBuffers);
|
||||
LOAD_REQUIRED(oal, alIsBuffer);
|
||||
LOAD_REQUIRED(oal, alBufferData);
|
||||
LOAD_REQUIRED(oal, alDopplerFactor);
|
||||
LOAD_REQUIRED(oal, alDopplerVelocity);
|
||||
LOAD_REQUIRED(oal, alSpeedOfSound);
|
||||
LOAD_REQUIRED(oal, alDistanceModel);
|
||||
|
||||
// these are optional.
|
||||
LOAD_REQUIRED(oal, alBufferf);
|
||||
LOAD_REQUIRED(oal, alBuffer3f);
|
||||
LOAD_REQUIRED(oal, alBufferfv);
|
||||
LOAD_REQUIRED(oal, alBufferi);
|
||||
LOAD_REQUIRED(oal, alBuffer3i);
|
||||
LOAD_REQUIRED(oal, alBufferiv);
|
||||
LOAD_REQUIRED(oal, alGetBufferf);
|
||||
LOAD_REQUIRED(oal, alGetBuffer3f);
|
||||
LOAD_REQUIRED(oal, alGetBufferfv);
|
||||
LOAD_REQUIRED(oal, alGetBufferi);
|
||||
LOAD_REQUIRED(oal, alGetBuffer3i);
|
||||
LOAD_REQUIRED(oal, alGetBufferiv);
|
||||
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALvoid UnloadOAL10Library()
|
||||
{
|
||||
// Unload the dll
|
||||
if (openaAlDll)
|
||||
CLOSE_LIBRARY(openaAlDll);
|
||||
}
|
||||
|
|
@ -24,26 +24,52 @@
|
|||
#define _LOADOAL_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
# include "platform/platform.h"
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
#undef AL_ALEXT_PROTOTYPES
|
||||
# include <OpenAL/al.h>
|
||||
# include <OpenAL/alc.h>
|
||||
#elif defined(TORQUE_OS_LINUX)
|
||||
# include <AL/al.h>
|
||||
# include <AL/alc.h>
|
||||
# include <AL/alext.h>
|
||||
# include <AL/efx.h>
|
||||
# include <AL/efx-presets.h>
|
||||
#else
|
||||
# include <al/al.h>
|
||||
# include <al/alc.h>
|
||||
# include <AL/alext.h>
|
||||
# include <AL/efx-presets.h>
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _PATH_H_
|
||||
#include "core/util/path.h"
|
||||
#endif
|
||||
|
||||
// Since openal is deprecated and we pack the lib into the mac bundle, all
|
||||
// platforms now support all of these.
|
||||
#include <AL/al.h>
|
||||
#include <AL/alc.h>
|
||||
#include <AL/alext.h>
|
||||
#include <AL/efx.h>
|
||||
#include <AL/efx-presets.h>
|
||||
|
||||
#ifndef _OPENALFNTABLE
|
||||
#define _OPENALFNTABLE
|
||||
|
||||
#if defined(TORQUE_OS_WIN)
|
||||
#include <windows.h>
|
||||
#define LIB_HANDLE HINSTANCE
|
||||
#define LOAD_LIBRARY(path) LoadLibraryA(path)
|
||||
#define GET_PROC_ADDRESS(lib, name) GetProcAddress(lib, name)
|
||||
#define CLOSE_LIBRARY(lib) FreeLibrary(lib)
|
||||
#define LIB_EXTENSION L".dll"
|
||||
#else
|
||||
#include <dlfcn.h>
|
||||
#define LIB_HANDLE void*
|
||||
#define LOAD_LIBRARY(path) dlopen(path, RTLD_LAZY)
|
||||
#define GET_PROC_ADDRESS(lib, name) dlsym(lib, name)
|
||||
#define CLOSE_LIBRARY(lib) dlclose(lib)
|
||||
#ifdef __APPLE__
|
||||
#define LIB_EXTENSION ".dylib"
|
||||
#else
|
||||
#define LIB_EXTENSION ".so"
|
||||
#endif
|
||||
#endif
|
||||
|
||||
constexpr auto MakeALCVer(int major, int minor) noexcept -> int {
|
||||
return (major << 8) | minor;
|
||||
}
|
||||
|
||||
#ifndef ALAPIENTRY
|
||||
#define ALAPIENTRY
|
||||
#endif
|
||||
|
|
@ -52,11 +78,6 @@
|
|||
#define ALCAPIENTRY
|
||||
#endif
|
||||
|
||||
// Open AL Function table definition
|
||||
|
||||
#ifndef _OPENALFNTABLE
|
||||
#define _OPENALFNTABLE
|
||||
|
||||
// AL 1.0 did not define the ALchar and ALCchar types, so define them here
|
||||
// if they don't exist
|
||||
|
||||
|
|
@ -68,110 +89,148 @@
|
|||
#define ALCchar char
|
||||
#endif
|
||||
|
||||
typedef struct
|
||||
struct OPENALFNTABLE
|
||||
{
|
||||
LPALENABLE alEnable;
|
||||
LPALDISABLE alDisable;
|
||||
LPALISENABLED alIsEnabled;
|
||||
LPALGETBOOLEAN alGetBoolean;
|
||||
LPALGETINTEGER alGetInteger;
|
||||
LPALGETFLOAT alGetFloat;
|
||||
LPALGETDOUBLE alGetDouble;
|
||||
LPALGETBOOLEANV alGetBooleanv;
|
||||
LPALGETINTEGERV alGetIntegerv;
|
||||
LPALGETFLOATV alGetFloatv;
|
||||
LPALGETDOUBLEV alGetDoublev;
|
||||
LPALGETSTRING alGetString;
|
||||
LPALGETERROR alGetError;
|
||||
LPALISEXTENSIONPRESENT alIsExtensionPresent;
|
||||
LPALGETPROCADDRESS alGetProcAddress;
|
||||
LPALGETENUMVALUE alGetEnumValue;
|
||||
LPALLISTENERI alListeneri;
|
||||
LPALLISTENERF alListenerf;
|
||||
LPALLISTENER3F alListener3f;
|
||||
LPALLISTENERFV alListenerfv;
|
||||
LPALGETLISTENERI alGetListeneri;
|
||||
LPALGETLISTENERF alGetListenerf;
|
||||
LPALGETLISTENER3F alGetListener3f;
|
||||
LPALGETLISTENERFV alGetListenerfv;
|
||||
LPALGENSOURCES alGenSources;
|
||||
LPALDELETESOURCES alDeleteSources;
|
||||
LPALISSOURCE alIsSource;
|
||||
LPALSOURCEI alSourcei;
|
||||
LPALSOURCEF alSourcef;
|
||||
LPALSOURCE3I alSource3i;
|
||||
LPALSOURCE3F alSource3f;
|
||||
LPALSOURCEFV alSourcefv;
|
||||
LPALGETSOURCEI alGetSourcei;
|
||||
LPALGETSOURCEF alGetSourcef;
|
||||
LPALGETSOURCEFV alGetSourcefv;
|
||||
LPALSOURCEPLAYV alSourcePlayv;
|
||||
LPALSOURCESTOPV alSourceStopv;
|
||||
LPALSOURCEPLAY alSourcePlay;
|
||||
LPALSOURCEPAUSE alSourcePause;
|
||||
LPALSOURCESTOP alSourceStop;
|
||||
LPALSOURCEREWIND alSourceRewind;
|
||||
LPALGENBUFFERS alGenBuffers;
|
||||
LPALDELETEBUFFERS alDeleteBuffers;
|
||||
LPALISBUFFER alIsBuffer;
|
||||
LPALBUFFERDATA alBufferData;
|
||||
LPALGETBUFFERI alGetBufferi;
|
||||
LPALGETBUFFERF alGetBufferf;
|
||||
LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers;
|
||||
LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers;
|
||||
LPALDISTANCEMODEL alDistanceModel;
|
||||
LPALDOPPLERFACTOR alDopplerFactor;
|
||||
LPALDOPPLERVELOCITY alDopplerVelocity;
|
||||
LPALCGETSTRING alcGetString;
|
||||
LPALCGETINTEGERV alcGetIntegerv;
|
||||
LPALCOPENDEVICE alcOpenDevice;
|
||||
LPALCCLOSEDEVICE alcCloseDevice;
|
||||
LPALCCREATECONTEXT alcCreateContext;
|
||||
LPALCMAKECONTEXTCURRENT alcMakeContextCurrent;
|
||||
LPALCPROCESSCONTEXT alcProcessContext;
|
||||
LPALCGETCURRENTCONTEXT alcGetCurrentContext;
|
||||
LPALCGETCONTEXTSDEVICE alcGetContextsDevice;
|
||||
LPALCSUSPENDCONTEXT alcSuspendContext;
|
||||
LPALCDESTROYCONTEXT alcDestroyContext;
|
||||
LPALCGETERROR alcGetError;
|
||||
LPALCISEXTENSIONPRESENT alcIsExtensionPresent;
|
||||
LPALCGETPROCADDRESS alcGetProcAddress;
|
||||
LPALCGETENUMVALUE alcGetEnumValue;
|
||||
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
LPALGENEFFECTS alGenEffects;
|
||||
LPALDELETEEFFECTS alDeleteEffects;
|
||||
LPALISEFFECT alIsEffect;
|
||||
LPALEFFECTI alEffecti;
|
||||
LPALEFFECTIV alEffectiv;
|
||||
LPALEFFECTF alEffectf;
|
||||
LPALEFFECTFV alEffectfv;
|
||||
LPALGETEFFECTI alGetEffecti;
|
||||
LPALGETEFFECTIV alGetEffectiv;
|
||||
LPALGETEFFECTF alGetEffectf;
|
||||
LPALGETEFFECTFV alGetEffectfv;
|
||||
LPALRELEASEALEFFECTS alReleaseEffects;
|
||||
LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots;
|
||||
LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots;
|
||||
LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot;
|
||||
LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti;
|
||||
LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv;
|
||||
LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf;
|
||||
LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv;
|
||||
LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti;
|
||||
LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv;
|
||||
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf;
|
||||
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv;
|
||||
LPALGENFILTERS alGenFilters;
|
||||
LPALDELETEFILTERS alDeleteFilters;
|
||||
LPALFILTERI alFilteri;
|
||||
LPALCGETSTRINGISOFT alcGetStringiSOFT;
|
||||
LPALCCREATECONTEXT alcCreateContext{ nullptr };
|
||||
LPALCMAKECONTEXTCURRENT alcMakeContextCurrent{ nullptr };
|
||||
LPALCPROCESSCONTEXT alcProcessContext{ nullptr };
|
||||
LPALCSUSPENDCONTEXT alcSuspendContext{ nullptr };
|
||||
LPALCDESTROYCONTEXT alcDestroyContext{ nullptr };
|
||||
LPALCGETCURRENTCONTEXT alcGetCurrentContext{ nullptr };
|
||||
LPALCGETCONTEXTSDEVICE alcGetContextsDevice{ nullptr };
|
||||
LPALCOPENDEVICE alcOpenDevice{ nullptr };
|
||||
LPALCCLOSEDEVICE alcCloseDevice{ nullptr };
|
||||
LPALCGETERROR alcGetError{ nullptr };
|
||||
LPALCISEXTENSIONPRESENT alcIsExtensionPresent{ nullptr };
|
||||
LPALCGETPROCADDRESS alcGetProcAddress{ nullptr };
|
||||
LPALCGETENUMVALUE alcGetEnumValue{ nullptr };
|
||||
LPALCGETSTRING alcGetString{ nullptr };
|
||||
LPALCGETINTEGERV alcGetIntegerv{ nullptr };
|
||||
LPALCCAPTUREOPENDEVICE alcCaptureOpenDevice{ nullptr };
|
||||
LPALCCAPTURECLOSEDEVICE alcCaptureCloseDevice{ nullptr };
|
||||
LPALCCAPTURESTART alcCaptureStart{ nullptr };
|
||||
LPALCCAPTURESTOP alcCaptureStop{ nullptr };
|
||||
LPALCCAPTURESAMPLES alcCaptureSamples{ nullptr };
|
||||
|
||||
PFNALCSETTHREADCONTEXTPROC alcSetThreadContext{ nullptr };
|
||||
PFNALCGETTHREADCONTEXTPROC alcGetThreadContext{ nullptr };
|
||||
|
||||
LPALENABLE alEnable{ nullptr };
|
||||
LPALDISABLE alDisable{ nullptr };
|
||||
LPALISENABLED alIsEnabled{ nullptr };
|
||||
LPALGETSTRING alGetString{ nullptr };
|
||||
LPALGETBOOLEANV alGetBooleanv{ nullptr };
|
||||
LPALGETINTEGERV alGetIntegerv{ nullptr };
|
||||
LPALGETFLOATV alGetFloatv{ nullptr };
|
||||
LPALGETDOUBLEV alGetDoublev{ nullptr };
|
||||
LPALGETBOOLEAN alGetBoolean{ nullptr };
|
||||
LPALGETINTEGER alGetInteger{ nullptr };
|
||||
LPALGETFLOAT alGetFloat{ nullptr };
|
||||
LPALGETDOUBLE alGetDouble{ nullptr };
|
||||
LPALGETERROR alGetError{ nullptr };
|
||||
LPALISEXTENSIONPRESENT alIsExtensionPresent{ nullptr };
|
||||
LPALGETPROCADDRESS alGetProcAddress{ nullptr };
|
||||
LPALGETENUMVALUE alGetEnumValue{ nullptr };
|
||||
LPALLISTENERF alListenerf{ nullptr };
|
||||
LPALLISTENER3F alListener3f{ nullptr };
|
||||
LPALLISTENERFV alListenerfv{ nullptr };
|
||||
LPALLISTENERI alListeneri{ nullptr };
|
||||
LPALLISTENER3I alListener3i{ nullptr };
|
||||
LPALLISTENERIV alListeneriv{ nullptr };
|
||||
LPALGETLISTENERF alGetListenerf{ nullptr };
|
||||
LPALGETLISTENER3F alGetListener3f{ nullptr };
|
||||
LPALGETLISTENERFV alGetListenerfv{ nullptr };
|
||||
LPALGETLISTENERI alGetListeneri{ nullptr };
|
||||
LPALGETLISTENER3I alGetListener3i{ nullptr };
|
||||
LPALGETLISTENERIV alGetListeneriv{ nullptr };
|
||||
LPALGENSOURCES alGenSources{ nullptr };
|
||||
LPALDELETESOURCES alDeleteSources{ nullptr };
|
||||
LPALISSOURCE alIsSource{ nullptr };
|
||||
LPALSOURCEF alSourcef{ nullptr };
|
||||
LPALSOURCE3F alSource3f{ nullptr };
|
||||
LPALSOURCEFV alSourcefv{ nullptr };
|
||||
LPALSOURCEI alSourcei{ nullptr };
|
||||
LPALSOURCE3I alSource3i{ nullptr };
|
||||
LPALSOURCEIV alSourceiv{ nullptr };
|
||||
LPALGETSOURCEF alGetSourcef{ nullptr };
|
||||
LPALGETSOURCE3F alGetSource3f{ nullptr };
|
||||
LPALGETSOURCEFV alGetSourcefv{ nullptr };
|
||||
LPALGETSOURCEI alGetSourcei{ nullptr };
|
||||
LPALGETSOURCE3I alGetSource3i{ nullptr };
|
||||
LPALGETSOURCEIV alGetSourceiv{ nullptr };
|
||||
LPALSOURCEPLAYV alSourcePlayv{ nullptr };
|
||||
LPALSOURCESTOPV alSourceStopv{ nullptr };
|
||||
LPALSOURCEREWINDV alSourceRewindv{ nullptr };
|
||||
LPALSOURCEPAUSEV alSourcePausev{ nullptr };
|
||||
LPALSOURCEPLAY alSourcePlay{ nullptr };
|
||||
LPALSOURCESTOP alSourceStop{ nullptr };
|
||||
LPALSOURCEREWIND alSourceRewind{ nullptr };
|
||||
LPALSOURCEPAUSE alSourcePause{ nullptr };
|
||||
LPALSOURCEQUEUEBUFFERS alSourceQueueBuffers{ nullptr };
|
||||
LPALSOURCEUNQUEUEBUFFERS alSourceUnqueueBuffers{ nullptr };
|
||||
LPALGENBUFFERS alGenBuffers{ nullptr };
|
||||
LPALDELETEBUFFERS alDeleteBuffers{ nullptr };
|
||||
LPALISBUFFER alIsBuffer{ nullptr };
|
||||
LPALBUFFERF alBufferf{ nullptr };
|
||||
LPALBUFFER3F alBuffer3f{ nullptr };
|
||||
LPALBUFFERFV alBufferfv{ nullptr };
|
||||
LPALBUFFERI alBufferi{ nullptr };
|
||||
LPALBUFFER3I alBuffer3i{ nullptr };
|
||||
LPALBUFFERIV alBufferiv{ nullptr };
|
||||
LPALGETBUFFERF alGetBufferf{ nullptr };
|
||||
LPALGETBUFFER3F alGetBuffer3f{ nullptr };
|
||||
LPALGETBUFFERFV alGetBufferfv{ nullptr };
|
||||
LPALGETBUFFERI alGetBufferi{ nullptr };
|
||||
LPALGETBUFFER3I alGetBuffer3i{ nullptr };
|
||||
LPALGETBUFFERIV alGetBufferiv{ nullptr };
|
||||
LPALBUFFERDATA alBufferData{ nullptr };
|
||||
LPALDOPPLERFACTOR alDopplerFactor{ nullptr };
|
||||
LPALDOPPLERVELOCITY alDopplerVelocity{ nullptr };
|
||||
LPALSPEEDOFSOUND alSpeedOfSound{ nullptr };
|
||||
LPALDISTANCEMODEL alDistanceModel{ nullptr };
|
||||
|
||||
/* Functions to load after first context creation. */
|
||||
LPALGENFILTERS alGenFilters{ nullptr };
|
||||
LPALDELETEFILTERS alDeleteFilters{ nullptr };
|
||||
LPALISFILTER alIsFilter{ nullptr };
|
||||
LPALFILTERF alFilterf{ nullptr };
|
||||
LPALFILTERFV alFilterfv{ nullptr };
|
||||
LPALFILTERI alFilteri{ nullptr };
|
||||
LPALFILTERIV alFilteriv{ nullptr };
|
||||
LPALGETFILTERF alGetFilterf{ nullptr };
|
||||
LPALGETFILTERFV alGetFilterfv{ nullptr };
|
||||
LPALGETFILTERI alGetFilteri{ nullptr };
|
||||
LPALGETFILTERIV alGetFilteriv{ nullptr };
|
||||
LPALGENEFFECTS alGenEffects{ nullptr };
|
||||
LPALDELETEEFFECTS alDeleteEffects{ nullptr };
|
||||
LPALISEFFECT alIsEffect{ nullptr };
|
||||
LPALEFFECTF alEffectf{ nullptr };
|
||||
LPALEFFECTFV alEffectfv{ nullptr };
|
||||
LPALEFFECTI alEffecti{ nullptr };
|
||||
LPALEFFECTIV alEffectiv{ nullptr };
|
||||
LPALGETEFFECTF alGetEffectf{ nullptr };
|
||||
LPALGETEFFECTFV alGetEffectfv{ nullptr };
|
||||
LPALGETEFFECTI alGetEffecti{ nullptr };
|
||||
LPALGETEFFECTIV alGetEffectiv{ nullptr };
|
||||
LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{ nullptr };
|
||||
LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{ nullptr };
|
||||
LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{ nullptr };
|
||||
LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{ nullptr };
|
||||
LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{ nullptr };
|
||||
LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{ nullptr };
|
||||
LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{ nullptr };
|
||||
LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{ nullptr };
|
||||
LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{ nullptr };
|
||||
LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{ nullptr };
|
||||
LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{ nullptr };
|
||||
|
||||
};
|
||||
|
||||
using LPOPENALFNTABLE = OPENALFNTABLE*;
|
||||
|
||||
#endif
|
||||
|
||||
} OPENALFNTABLE, *LPOPENALFNTABLE;
|
||||
#endif
|
||||
|
||||
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable);
|
||||
ALboolean LoadOAL10Library(char* szOALFullPathName, LPOPENALFNTABLE lpOALFnTable);
|
||||
ALvoid UnloadOAL10Library();
|
||||
|
||||
#endif // _LOADOAL_H_
|
||||
|
|
|
|||
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Creative Labs Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
|
||||
* the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include "core/strings/stringFunctions.h"
|
||||
|
||||
#include "aldlist.h"
|
||||
#if defined(TORQUE_OS_MAC)
|
||||
#include <OpenAL/alc.h>
|
||||
#elif defined(TORQUE_OS_LINUX)
|
||||
#include <AL/alc.h>
|
||||
#else
|
||||
#include <al/alc.h>
|
||||
#endif
|
||||
|
||||
|
||||
/*
|
||||
* Init call
|
||||
*/
|
||||
ALDeviceList::ALDeviceList( const OPENALFNTABLE& oalft )
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( vDeviceInfo );
|
||||
|
||||
ALDEVICEINFO ALDeviceInfo;
|
||||
char *devices;
|
||||
int index;
|
||||
const char *defaultDeviceName;
|
||||
const char *actualDeviceName;
|
||||
|
||||
dMemcpy( &ALFunction, &oalft, sizeof(OPENALFNTABLE) );
|
||||
|
||||
// DeviceInfo vector stores, for each enumerated device, it's device name, selection status, spec version #, and extension support
|
||||
vDeviceInfo.clear();
|
||||
vDeviceInfo.reserve(10);
|
||||
|
||||
defaultDeviceIndex = 0;
|
||||
|
||||
// grab function pointers for 1.0-API functions, and if successful proceed to enumerate all devices
|
||||
if (ALFunction.alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT")) {
|
||||
devices = (char *)ALFunction.alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
|
||||
}
|
||||
else
|
||||
{
|
||||
devices = (char *)ALFunction.alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
defaultDeviceName = (char *)ALFunction.alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
}
|
||||
|
||||
index = 0;
|
||||
// go through device list (each device terminated with a single NULL, list terminated with double NULL)
|
||||
while (*devices != '\0') {
|
||||
if (String::compare(defaultDeviceName, devices) == 0) {
|
||||
defaultDeviceIndex = index;
|
||||
}
|
||||
|
||||
ALCdevice* device = ALFunction.alcOpenDevice(devices);
|
||||
if (device)
|
||||
{
|
||||
ALCcontext* ctx = ALFunction.alcCreateContext(device, nullptr);
|
||||
|
||||
if (ctx)
|
||||
{
|
||||
ALFunction.alcMakeContextCurrent(ctx);
|
||||
actualDeviceName = ALFunction.alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||
bool bNewName = true;
|
||||
|
||||
if (actualDeviceName)
|
||||
{
|
||||
for (int i = 0; i < GetNumDevices(); i++) {
|
||||
if (String::compare(GetDeviceName(i), devices) == 0) {
|
||||
bNewName = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if ((bNewName) && (actualDeviceName != NULL) && (dStrlen(actualDeviceName) > 0))
|
||||
{
|
||||
dMemset(&ALDeviceInfo, 0, sizeof(ALDEVICEINFO));
|
||||
ALDeviceInfo.bSelected = true;
|
||||
dStrncpy(ALDeviceInfo.strDeviceName, actualDeviceName, sizeof(ALDeviceInfo.strDeviceName));
|
||||
char deviceExternal[256];
|
||||
dStrcpy(deviceExternal, devices, 256);
|
||||
|
||||
vDeviceInfo.push_back(ALDeviceInfo);
|
||||
}
|
||||
|
||||
ALFunction.alcMakeContextCurrent(nullptr);
|
||||
ALFunction.alcDestroyContext(ctx);
|
||||
}
|
||||
ALFunction.alcCloseDevice(device);
|
||||
}
|
||||
|
||||
devices += dStrlen(devices) + 1;
|
||||
index += 1;
|
||||
}
|
||||
|
||||
ResetFilters();
|
||||
}
|
||||
|
||||
/*
|
||||
* Exit call
|
||||
*/
|
||||
ALDeviceList::~ALDeviceList()
|
||||
{
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the number of devices in the complete device list
|
||||
*/
|
||||
int ALDeviceList::GetNumDevices()
|
||||
{
|
||||
return (int)vDeviceInfo.size();
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the device name at an index in the complete device list
|
||||
*/
|
||||
const char* ALDeviceList::GetDeviceName(int index)
|
||||
{
|
||||
if (index < GetNumDevices())
|
||||
return vDeviceInfo[index].strDeviceName;
|
||||
else
|
||||
return NULL;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* Returns the major and minor version numbers for a device at a specified index in the complete list
|
||||
*/
|
||||
void ALDeviceList::GetDeviceVersion(int index, int *major, int *minor)
|
||||
{
|
||||
if (index < GetNumDevices()) {
|
||||
if (major)
|
||||
*major = vDeviceInfo[index].iMajorVersion;
|
||||
if (minor)
|
||||
*minor = vDeviceInfo[index].iMinorVersion;
|
||||
}
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* Returns the maximum number of Sources that can be generate on the given device
|
||||
*/
|
||||
U32 ALDeviceList::GetMaxNumSources(S32 index)
|
||||
{
|
||||
if (index < GetNumDevices())
|
||||
return vDeviceInfo[index].uiSourceCount;
|
||||
else
|
||||
return 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Checks if the extension is supported on the given device
|
||||
*/
|
||||
bool ALDeviceList::IsExtensionSupported(int index, SFXALCaps cap)
|
||||
{
|
||||
bool bReturn = false;
|
||||
|
||||
if (index < GetNumDevices())
|
||||
bReturn = vDeviceInfo[index].iCapsFlags & cap;
|
||||
|
||||
return bReturn;
|
||||
}
|
||||
|
||||
/*
|
||||
* returns the index of the default device in the complete device list
|
||||
*/
|
||||
int ALDeviceList::GetDefaultDevice()
|
||||
{
|
||||
return defaultDeviceIndex;
|
||||
}
|
||||
|
||||
/*
|
||||
* Deselects devices which don't have the specified minimum version
|
||||
*/
|
||||
void ALDeviceList::FilterDevicesMinVer(S32 major, S32 minor)
|
||||
{
|
||||
int dMajor, dMinor;
|
||||
for (U32 i = 0; i < vDeviceInfo.size(); i++) {
|
||||
GetDeviceVersion(i, &dMajor, &dMinor);
|
||||
if ((dMajor < major) || ((dMajor == major) && (dMinor < minor))) {
|
||||
vDeviceInfo[i].bSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deselects devices which don't have the specified maximum version
|
||||
*/
|
||||
void ALDeviceList::FilterDevicesMaxVer(S32 major, S32 minor)
|
||||
{
|
||||
S32 dMajor, dMinor;
|
||||
for (U32 i = 0; i < vDeviceInfo.size(); i++) {
|
||||
GetDeviceVersion(i, &dMajor, &dMinor);
|
||||
if ((dMajor > major) || ((dMajor == major) && (dMinor > minor))) {
|
||||
vDeviceInfo[i].bSelected = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Deselects device which don't support the given extension name
|
||||
*/
|
||||
void ALDeviceList::FilterDevicesExtension(SFXALCaps cap)
|
||||
{
|
||||
for (U32 i = 0; i < vDeviceInfo.size(); i++)
|
||||
vDeviceInfo[i].bSelected = vDeviceInfo[i].iCapsFlags & cap;
|
||||
}
|
||||
|
||||
/*
|
||||
* Resets all filtering, such that all devices are in the list
|
||||
*/
|
||||
void ALDeviceList::ResetFilters()
|
||||
{
|
||||
for (S32 i = 0; i < GetNumDevices(); i++) {
|
||||
vDeviceInfo[i].bSelected = true;
|
||||
}
|
||||
filterIndex = 0;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets index of first filtered device
|
||||
*/
|
||||
int ALDeviceList::GetFirstFilteredDevice()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i < GetNumDevices(); i++) {
|
||||
if (vDeviceInfo[i].bSelected == true) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
filterIndex = i + 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Gets index of next filtered device
|
||||
*/
|
||||
int ALDeviceList::GetNextFilteredDevice()
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = filterIndex; i < GetNumDevices(); i++) {
|
||||
if (vDeviceInfo[i].bSelected == true) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
filterIndex = i + 1;
|
||||
return i;
|
||||
}
|
||||
|
||||
/*
|
||||
* Internal function to detemine max number of Sources that can be generated
|
||||
*/
|
||||
unsigned int ALDeviceList::GetMaxNumSources()
|
||||
{
|
||||
ALuint uiSources[256];
|
||||
U32 iSourceCount = 0;
|
||||
|
||||
// Clear AL Error Code
|
||||
ALFunction.alGetError();
|
||||
|
||||
// Generate up to 256 Sources, checking for any errors
|
||||
for (iSourceCount = 0; iSourceCount < 256; iSourceCount++)
|
||||
{
|
||||
ALFunction.alGenSources(1, &uiSources[iSourceCount]);
|
||||
if (ALFunction.alGetError() != AL_NO_ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
// Release the Sources
|
||||
ALFunction.alDeleteSources(iSourceCount, uiSources);
|
||||
if (ALFunction.alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
for (U32 i = 0; i < 256; i++)
|
||||
{
|
||||
ALFunction.alDeleteSources(1, &uiSources[i]);
|
||||
}
|
||||
}
|
||||
|
||||
return iSourceCount;
|
||||
}
|
||||
|
|
@ -1,71 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef ALDEVICELIST_H
|
||||
#define ALDEVICELIST_H
|
||||
|
||||
#pragma warning(disable: 4786) //disable warning "identifier was truncated to '255' characters in the browser information"
|
||||
#include "core/util/tVector.h"
|
||||
#include "core/stringTable.h"
|
||||
#include "sfx/openal/sfxALCaps.h"
|
||||
#include "LoadOAL.h"
|
||||
|
||||
typedef struct
|
||||
{
|
||||
char strDeviceName[256];
|
||||
char strInternalDeviceName[256];
|
||||
S32 iMajorVersion;
|
||||
S32 iMinorVersion;
|
||||
U32 uiSourceCount;
|
||||
S32 iCapsFlags;
|
||||
bool bSelected;
|
||||
} ALDEVICEINFO, *LPALDEVICEINFO;
|
||||
|
||||
class ALDeviceList
|
||||
{
|
||||
private:
|
||||
OPENALFNTABLE ALFunction;
|
||||
Vector<ALDEVICEINFO> vDeviceInfo;
|
||||
S32 defaultDeviceIndex;
|
||||
S32 filterIndex;
|
||||
|
||||
public:
|
||||
ALDeviceList ( const OPENALFNTABLE &oalft );
|
||||
~ALDeviceList ();
|
||||
S32 GetNumDevices();
|
||||
const char *GetDeviceName(S32 index);
|
||||
void GetDeviceVersion(S32 index, S32 *major, S32 *minor);
|
||||
U32 GetMaxNumSources(S32 index);
|
||||
bool IsExtensionSupported(S32 index, SFXALCaps caps);
|
||||
S32 GetDefaultDevice();
|
||||
void FilterDevicesMinVer(S32 major, S32 minor);
|
||||
void FilterDevicesMaxVer(S32 major, S32 minor);
|
||||
void FilterDevicesExtension(SFXALCaps caps);
|
||||
void ResetFilters();
|
||||
S32 GetFirstFilteredDevice();
|
||||
S32 GetNextFilteredDevice();
|
||||
|
||||
private:
|
||||
U32 GetMaxNumSources();
|
||||
};
|
||||
|
||||
#endif // ALDEVICELIST_H
|
||||
|
|
@ -1,616 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Implement OpenAL loading code which is currently stubbed out.
|
||||
|
||||
#if defined(__linux__) && !defined(TORQUE_OS_LINUX)
|
||||
#define TORQUE_OS_LINUX
|
||||
#endif
|
||||
|
||||
#include <dlfcn.h>
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
#include "console/console.h"
|
||||
|
||||
void* openal_library = NULL;
|
||||
|
||||
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
|
||||
{
|
||||
if (!lpOALFnTable)
|
||||
return AL_FALSE;
|
||||
|
||||
if (szOALFullPathName)
|
||||
openal_library = dlopen(szOALFullPathName, RTLD_NOW);
|
||||
else
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
openal_library = dlopen("libopenald.so.1", RTLD_NOW);
|
||||
|
||||
// If the .1 library is not found, try the normal filename
|
||||
if (openal_library == NULL)
|
||||
{
|
||||
openal_library = dlopen("libopenald.so", RTLD_NOW);
|
||||
}
|
||||
#else
|
||||
openal_library = dlopen("libopenal.so.1", RTLD_NOW);
|
||||
|
||||
// If the .1 library is not found, try the normal filename
|
||||
if (openal_library == NULL)
|
||||
{
|
||||
openal_library = dlopen("libopenal.so", RTLD_NOW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (openal_library == NULL) {
|
||||
Con::errorf("Failed to load OpenAL shared library. Sound will not be available");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
|
||||
|
||||
lpOALFnTable->alEnable = (LPALENABLE)dlsym(openal_library,"alEnable");
|
||||
if (lpOALFnTable->alEnable == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEnable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDisable = (LPALDISABLE)dlsym(openal_library,"alDisable");
|
||||
if (lpOALFnTable->alDisable == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDisable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsEnabled = (LPALISENABLED)dlsym(openal_library,"alIsEnabled");
|
||||
if (lpOALFnTable->alIsEnabled == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsEnabled' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)dlsym(openal_library,"alGetBoolean");
|
||||
if (lpOALFnTable->alGetBoolean == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBoolean' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetInteger = (LPALGETINTEGER)dlsym(openal_library,"alGetInteger");
|
||||
if (lpOALFnTable->alGetInteger == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetInteger' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloat = (LPALGETFLOAT)dlsym(openal_library,"alGetFloat");
|
||||
if (lpOALFnTable->alGetFloat == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetFloat' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)dlsym(openal_library,"alGetDouble");
|
||||
if (lpOALFnTable->alGetDouble == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetDouble' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)dlsym(openal_library,"alGetBooleanv");
|
||||
if (lpOALFnTable->alGetBooleanv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBooleanv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)dlsym(openal_library,"alGetIntegerv");
|
||||
if (lpOALFnTable->alGetIntegerv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)dlsym(openal_library,"alGetFloatv");
|
||||
if (lpOALFnTable->alGetFloatv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetFloatv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)dlsym(openal_library,"alGetDoublev");
|
||||
if (lpOALFnTable->alGetDoublev == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetDoublev' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetString = (LPALGETSTRING)dlsym(openal_library,"alGetString");
|
||||
if (lpOALFnTable->alGetString == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetError = (LPALGETERROR)dlsym(openal_library,"alGetError");
|
||||
if (lpOALFnTable->alGetError == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)dlsym(openal_library,"alIsExtensionPresent");
|
||||
if (lpOALFnTable->alIsExtensionPresent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)dlsym(openal_library,"alGetProcAddress");
|
||||
if (lpOALFnTable->alGetProcAddress == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)dlsym(openal_library,"alGetEnumValue");
|
||||
if (lpOALFnTable->alGetEnumValue == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListeneri = (LPALLISTENERI)dlsym(openal_library,"alListeneri");
|
||||
if (lpOALFnTable->alListeneri == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerf = (LPALLISTENERF)dlsym(openal_library,"alListenerf");
|
||||
if (lpOALFnTable->alListenerf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListener3f = (LPALLISTENER3F)dlsym(openal_library,"alListener3f");
|
||||
if (lpOALFnTable->alListener3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerfv = (LPALLISTENERFV)dlsym(openal_library,"alListenerfv");
|
||||
if (lpOALFnTable->alListenerfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)dlsym(openal_library,"alGetListeneri");
|
||||
if (lpOALFnTable->alGetListeneri == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)dlsym(openal_library,"alGetListenerf");
|
||||
if (lpOALFnTable->alGetListenerf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)dlsym(openal_library,"alGetListener3f");
|
||||
if (lpOALFnTable->alGetListener3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)dlsym(openal_library,"alGetListenerfv");
|
||||
if (lpOALFnTable->alGetListenerfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenSources = (LPALGENSOURCES)dlsym(openal_library,"alGenSources");
|
||||
if (lpOALFnTable->alGenSources == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)dlsym(openal_library,"alDeleteSources");
|
||||
if (lpOALFnTable->alDeleteSources == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsSource = (LPALISSOURCE)dlsym(openal_library,"alIsSource");
|
||||
if (lpOALFnTable->alIsSource == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsSource' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcei = (LPALSOURCEI)dlsym(openal_library,"alSourcei");
|
||||
if (lpOALFnTable->alSourcei == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcef = (LPALSOURCEF)dlsym(openal_library,"alSourcef");
|
||||
if (lpOALFnTable->alSourcef == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSource3f = (LPALSOURCE3F)dlsym(openal_library,"alSource3f");
|
||||
if (lpOALFnTable->alSource3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSource3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcefv = (LPALSOURCEFV)dlsym(openal_library,"alSourcefv");
|
||||
if (lpOALFnTable->alSourcefv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)dlsym(openal_library,"alGetSourcei");
|
||||
if (lpOALFnTable->alGetSourcei == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)dlsym(openal_library,"alGetSourcef");
|
||||
if (lpOALFnTable->alGetSourcef == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)dlsym(openal_library,"alGetSourcefv");
|
||||
if (lpOALFnTable->alGetSourcefv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)dlsym(openal_library,"alSourcePlayv");
|
||||
if (lpOALFnTable->alSourcePlayv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePlayv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)dlsym(openal_library,"alSourceStopv");
|
||||
if (lpOALFnTable->alSourceStopv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceStopv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)dlsym(openal_library,"alSourcePlay");
|
||||
if (lpOALFnTable->alSourcePlay == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePlay' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)dlsym(openal_library,"alSourcePause");
|
||||
if (lpOALFnTable->alSourcePause == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePause' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)dlsym(openal_library,"alSourceStop");
|
||||
if (lpOALFnTable->alSourceStop == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceStop' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)dlsym(openal_library,"alSourceRewind");
|
||||
if (lpOALFnTable->alSourceRewind == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceRewind' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)dlsym(openal_library,"alGenBuffers");
|
||||
if (lpOALFnTable->alGenBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)dlsym(openal_library,"alDeleteBuffers");
|
||||
if (lpOALFnTable->alDeleteBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsBuffer = (LPALISBUFFER)dlsym(openal_library,"alIsBuffer");
|
||||
if (lpOALFnTable->alIsBuffer == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsBuffer' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alBufferData = (LPALBUFFERDATA)dlsym(openal_library,"alBufferData");
|
||||
if (lpOALFnTable->alBufferData == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alBufferData' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)dlsym(openal_library,"alGetBufferi");
|
||||
if (lpOALFnTable->alGetBufferi == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBufferi' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)dlsym(openal_library,"alGetBufferf");
|
||||
if (lpOALFnTable->alGetBufferf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBufferf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)dlsym(openal_library,"alSourceQueueBuffers");
|
||||
if (lpOALFnTable->alSourceQueueBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceQueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)dlsym(openal_library,"alSourceUnqueueBuffers");
|
||||
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)dlsym(openal_library,"alDistanceModel");
|
||||
if (lpOALFnTable->alDistanceModel == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDistanceModel' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)dlsym(openal_library,"alDopplerFactor");
|
||||
if (lpOALFnTable->alDopplerFactor == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDopplerFactor' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)dlsym(openal_library,"alDopplerVelocity");
|
||||
if (lpOALFnTable->alDopplerVelocity == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDopplerVelocity' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetString = (LPALCGETSTRING)dlsym(openal_library,"alcGetString");
|
||||
if (lpOALFnTable->alcGetString == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)dlsym(openal_library,"alcGetIntegerv");
|
||||
if (lpOALFnTable->alcGetIntegerv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)dlsym(openal_library,"alcOpenDevice");
|
||||
if (lpOALFnTable->alcOpenDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcOpenDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)dlsym(openal_library,"alcCloseDevice");
|
||||
if (lpOALFnTable->alcCloseDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcCloseDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)dlsym(openal_library,"alcCreateContext");
|
||||
if (lpOALFnTable->alcCreateContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcCreateContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)dlsym(openal_library,"alcMakeContextCurrent");
|
||||
if (lpOALFnTable->alcMakeContextCurrent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcMakeContextCurrent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)dlsym(openal_library,"alcProcessContext");
|
||||
if (lpOALFnTable->alcProcessContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcProcessContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)dlsym(openal_library,"alcGetCurrentContext");
|
||||
if (lpOALFnTable->alcGetCurrentContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetCurrentContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)dlsym(openal_library,"alcGetContextsDevice");
|
||||
if (lpOALFnTable->alcGetContextsDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetContextsDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)dlsym(openal_library,"alcSuspendContext");
|
||||
if (lpOALFnTable->alcSuspendContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcSuspendContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)dlsym(openal_library,"alcDestroyContext");
|
||||
if (lpOALFnTable->alcDestroyContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcDestroyContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetError = (LPALCGETERROR)dlsym(openal_library,"alcGetError");
|
||||
if (lpOALFnTable->alcGetError == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)dlsym(openal_library,"alcIsExtensionPresent");
|
||||
if (lpOALFnTable->alcIsExtensionPresent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)dlsym(openal_library,"alcGetProcAddress");
|
||||
if (lpOALFnTable->alcGetProcAddress == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)dlsym(openal_library,"alcGetEnumValue");
|
||||
if (lpOALFnTable->alcGetEnumValue == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
//efx
|
||||
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)dlsym(openal_library, "alGenEffects");
|
||||
if (lpOALFnTable->alGenEffects == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenEffects' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffecti = (LPALEFFECTI)dlsym(openal_library, "alEffecti");
|
||||
if (lpOALFnTable->alEffecti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffecti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectiv = (LPALEFFECTIV)dlsym(openal_library, "alEffectiv");
|
||||
if (lpOALFnTable->alEffectiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectf = (LPALEFFECTF)dlsym(openal_library, "alEffectf");
|
||||
if (lpOALFnTable->alEffectf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectfv = (LPALEFFECTFV)dlsym(openal_library, "alEffectfv");
|
||||
if (lpOALFnTable->alEffectfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)dlsym(openal_library, "alGetEffecti");
|
||||
if (lpOALFnTable->alGetEffecti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffecti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)dlsym(openal_library, "alGetEffectiv");
|
||||
if (lpOALFnTable->alGetEffectiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)dlsym(openal_library, "alGetEffectf");
|
||||
if (lpOALFnTable->alGetEffectf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)dlsym(openal_library, "alGetEffectfv");
|
||||
if (lpOALFnTable->alGetEffectfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)dlsym(openal_library, "alDeleteEffects");
|
||||
if (lpOALFnTable->alDeleteEffects == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteEffects' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsEffect = (LPALISEFFECT)dlsym(openal_library, "alIsEffect");
|
||||
if (lpOALFnTable->alIsEffect == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsEffect' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)dlsym(openal_library, "alIsAuxiliaryEffectSlot");
|
||||
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alGenAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alDeleteAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alGetAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alGetAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alGetAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alGetAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSource3i = (LPALSOURCE3I)dlsym(openal_library, "alSource3i");
|
||||
if (lpOALFnTable->alSource3i == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSource3i' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
#endif
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALvoid UnloadOAL10Library()
|
||||
{
|
||||
if (openal_library != NULL)
|
||||
dlclose(openal_library);
|
||||
}
|
||||
|
|
@ -1,618 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// TODO: Implement OpenAL loading code which is currently stubbed out.
|
||||
|
||||
#if defined(__MACOSX__) && !defined(TORQUE_OS_MAC)
|
||||
#define TORQUE_OS_MAC
|
||||
#endif
|
||||
|
||||
#include "console/console.h"
|
||||
|
||||
#include <err.h>
|
||||
#include <string.h>
|
||||
#include <dlfcn.h>
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
|
||||
void* openal_library = NULL;
|
||||
|
||||
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
|
||||
{
|
||||
// TODO: Implement this.
|
||||
if (!lpOALFnTable)
|
||||
return AL_FALSE;
|
||||
|
||||
if (szOALFullPathName)
|
||||
openal_library = dlopen(szOALFullPathName, RTLD_NOW);
|
||||
else
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
openal_library = dlopen("@rpath/libopenald.1.23.1.dylib", RTLD_NOW);
|
||||
|
||||
if (openal_library == NULL)
|
||||
{
|
||||
openal_library = dlopen("@rpath/libopenald.1.dylib", RTLD_NOW);
|
||||
}
|
||||
#else
|
||||
openal_library = dlopen("@rpath/libopenal.1.23.1.dylib", RTLD_NOW);
|
||||
|
||||
if (openal_library == NULL)
|
||||
{
|
||||
openal_library = dlopen("@rpath/libopenal .1.dylib", RTLD_NOW);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
if (openal_library == NULL)
|
||||
{
|
||||
Con::errorf("Failed to load OpenAL shared library. Sound will not be available");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
|
||||
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
|
||||
|
||||
lpOALFnTable->alEnable = (LPALENABLE)dlsym(openal_library,"alEnable");
|
||||
if (lpOALFnTable->alEnable == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEnable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDisable = (LPALDISABLE)dlsym(openal_library,"alDisable");
|
||||
if (lpOALFnTable->alDisable == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDisable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsEnabled = (LPALISENABLED)dlsym(openal_library,"alIsEnabled");
|
||||
if (lpOALFnTable->alIsEnabled == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsEnabled' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)dlsym(openal_library,"alGetBoolean");
|
||||
if (lpOALFnTable->alGetBoolean == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBoolean' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetInteger = (LPALGETINTEGER)dlsym(openal_library,"alGetInteger");
|
||||
if (lpOALFnTable->alGetInteger == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetInteger' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloat = (LPALGETFLOAT)dlsym(openal_library,"alGetFloat");
|
||||
if (lpOALFnTable->alGetFloat == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetFloat' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)dlsym(openal_library,"alGetDouble");
|
||||
if (lpOALFnTable->alGetDouble == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetDouble' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)dlsym(openal_library,"alGetBooleanv");
|
||||
if (lpOALFnTable->alGetBooleanv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBooleanv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)dlsym(openal_library,"alGetIntegerv");
|
||||
if (lpOALFnTable->alGetIntegerv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)dlsym(openal_library,"alGetFloatv");
|
||||
if (lpOALFnTable->alGetFloatv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetFloatv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)dlsym(openal_library,"alGetDoublev");
|
||||
if (lpOALFnTable->alGetDoublev == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetDoublev' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetString = (LPALGETSTRING)dlsym(openal_library,"alGetString");
|
||||
if (lpOALFnTable->alGetString == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetError = (LPALGETERROR)dlsym(openal_library,"alGetError");
|
||||
if (lpOALFnTable->alGetError == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)dlsym(openal_library,"alIsExtensionPresent");
|
||||
if (lpOALFnTable->alIsExtensionPresent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)dlsym(openal_library,"alGetProcAddress");
|
||||
if (lpOALFnTable->alGetProcAddress == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)dlsym(openal_library,"alGetEnumValue");
|
||||
if (lpOALFnTable->alGetEnumValue == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListeneri = (LPALLISTENERI)dlsym(openal_library,"alListeneri");
|
||||
if (lpOALFnTable->alListeneri == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerf = (LPALLISTENERF)dlsym(openal_library,"alListenerf");
|
||||
if (lpOALFnTable->alListenerf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListener3f = (LPALLISTENER3F)dlsym(openal_library,"alListener3f");
|
||||
if (lpOALFnTable->alListener3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerfv = (LPALLISTENERFV)dlsym(openal_library,"alListenerfv");
|
||||
if (lpOALFnTable->alListenerfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)dlsym(openal_library,"alGetListeneri");
|
||||
if (lpOALFnTable->alGetListeneri == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)dlsym(openal_library,"alGetListenerf");
|
||||
if (lpOALFnTable->alGetListenerf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)dlsym(openal_library,"alGetListener3f");
|
||||
if (lpOALFnTable->alGetListener3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)dlsym(openal_library,"alGetListenerfv");
|
||||
if (lpOALFnTable->alGetListenerfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenSources = (LPALGENSOURCES)dlsym(openal_library,"alGenSources");
|
||||
if (lpOALFnTable->alGenSources == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)dlsym(openal_library,"alDeleteSources");
|
||||
if (lpOALFnTable->alDeleteSources == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsSource = (LPALISSOURCE)dlsym(openal_library,"alIsSource");
|
||||
if (lpOALFnTable->alIsSource == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsSource' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcei = (LPALSOURCEI)dlsym(openal_library,"alSourcei");
|
||||
if (lpOALFnTable->alSourcei == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcef = (LPALSOURCEF)dlsym(openal_library,"alSourcef");
|
||||
if (lpOALFnTable->alSourcef == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSource3f = (LPALSOURCE3F)dlsym(openal_library,"alSource3f");
|
||||
if (lpOALFnTable->alSource3f == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSource3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcefv = (LPALSOURCEFV)dlsym(openal_library,"alSourcefv");
|
||||
if (lpOALFnTable->alSourcefv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)dlsym(openal_library,"alGetSourcei");
|
||||
if (lpOALFnTable->alGetSourcei == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)dlsym(openal_library,"alGetSourcef");
|
||||
if (lpOALFnTable->alGetSourcef == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)dlsym(openal_library,"alGetSourcefv");
|
||||
if (lpOALFnTable->alGetSourcefv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)dlsym(openal_library,"alSourcePlayv");
|
||||
if (lpOALFnTable->alSourcePlayv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePlayv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)dlsym(openal_library,"alSourceStopv");
|
||||
if (lpOALFnTable->alSourceStopv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceStopv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)dlsym(openal_library,"alSourcePlay");
|
||||
if (lpOALFnTable->alSourcePlay == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePlay' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)dlsym(openal_library,"alSourcePause");
|
||||
if (lpOALFnTable->alSourcePause == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourcePause' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)dlsym(openal_library,"alSourceStop");
|
||||
if (lpOALFnTable->alSourceStop == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceStop' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)dlsym(openal_library,"alSourceRewind");
|
||||
if (lpOALFnTable->alSourceRewind == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceRewind' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)dlsym(openal_library,"alGenBuffers");
|
||||
if (lpOALFnTable->alGenBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)dlsym(openal_library,"alDeleteBuffers");
|
||||
if (lpOALFnTable->alDeleteBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsBuffer = (LPALISBUFFER)dlsym(openal_library,"alIsBuffer");
|
||||
if (lpOALFnTable->alIsBuffer == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsBuffer' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alBufferData = (LPALBUFFERDATA)dlsym(openal_library,"alBufferData");
|
||||
if (lpOALFnTable->alBufferData == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alBufferData' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)dlsym(openal_library,"alGetBufferi");
|
||||
if (lpOALFnTable->alGetBufferi == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBufferi' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)dlsym(openal_library,"alGetBufferf");
|
||||
if (lpOALFnTable->alGetBufferf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetBufferf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)dlsym(openal_library,"alSourceQueueBuffers");
|
||||
if (lpOALFnTable->alSourceQueueBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceQueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)dlsym(openal_library,"alSourceUnqueueBuffers");
|
||||
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)dlsym(openal_library,"alDistanceModel");
|
||||
if (lpOALFnTable->alDistanceModel == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDistanceModel' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)dlsym(openal_library,"alDopplerFactor");
|
||||
if (lpOALFnTable->alDopplerFactor == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDopplerFactor' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)dlsym(openal_library,"alDopplerVelocity");
|
||||
if (lpOALFnTable->alDopplerVelocity == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDopplerVelocity' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetString = (LPALCGETSTRING)dlsym(openal_library,"alcGetString");
|
||||
if (lpOALFnTable->alcGetString == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)dlsym(openal_library,"alcGetIntegerv");
|
||||
if (lpOALFnTable->alcGetIntegerv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)dlsym(openal_library,"alcOpenDevice");
|
||||
if (lpOALFnTable->alcOpenDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcOpenDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)dlsym(openal_library,"alcCloseDevice");
|
||||
if (lpOALFnTable->alcCloseDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcCloseDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)dlsym(openal_library,"alcCreateContext");
|
||||
if (lpOALFnTable->alcCreateContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcCreateContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)dlsym(openal_library,"alcMakeContextCurrent");
|
||||
if (lpOALFnTable->alcMakeContextCurrent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcMakeContextCurrent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)dlsym(openal_library,"alcProcessContext");
|
||||
if (lpOALFnTable->alcProcessContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcProcessContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)dlsym(openal_library,"alcGetCurrentContext");
|
||||
if (lpOALFnTable->alcGetCurrentContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetCurrentContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)dlsym(openal_library,"alcGetContextsDevice");
|
||||
if (lpOALFnTable->alcGetContextsDevice == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetContextsDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)dlsym(openal_library,"alcSuspendContext");
|
||||
if (lpOALFnTable->alcSuspendContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcSuspendContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)dlsym(openal_library,"alcDestroyContext");
|
||||
if (lpOALFnTable->alcDestroyContext == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcDestroyContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetError = (LPALCGETERROR)dlsym(openal_library,"alcGetError");
|
||||
if (lpOALFnTable->alcGetError == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)dlsym(openal_library,"alcIsExtensionPresent");
|
||||
if (lpOALFnTable->alcIsExtensionPresent == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)dlsym(openal_library,"alcGetProcAddress");
|
||||
if (lpOALFnTable->alcGetProcAddress == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)dlsym(openal_library,"alcGetEnumValue");
|
||||
if (lpOALFnTable->alcGetEnumValue == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alcGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
//efx
|
||||
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)dlsym(openal_library, "alGenEffects");
|
||||
if (lpOALFnTable->alGenEffects == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenEffects' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffecti = (LPALEFFECTI)dlsym(openal_library, "alEffecti");
|
||||
if (lpOALFnTable->alEffecti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffecti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectiv = (LPALEFFECTIV)dlsym(openal_library, "alEffectiv");
|
||||
if (lpOALFnTable->alEffectiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectf = (LPALEFFECTF)dlsym(openal_library, "alEffectf");
|
||||
if (lpOALFnTable->alEffectf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alEffectfv = (LPALEFFECTFV)dlsym(openal_library, "alEffectfv");
|
||||
if (lpOALFnTable->alEffectfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alEffectfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)dlsym(openal_library, "alGetEffecti");
|
||||
if (lpOALFnTable->alGetEffecti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffecti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)dlsym(openal_library, "alGetEffectiv");
|
||||
if (lpOALFnTable->alGetEffectiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)dlsym(openal_library, "alGetEffectf");
|
||||
if (lpOALFnTable->alGetEffectf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)dlsym(openal_library, "alGetEffectfv");
|
||||
if (lpOALFnTable->alGetEffectfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetEffectfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)dlsym(openal_library, "alDeleteEffects");
|
||||
if (lpOALFnTable->alDeleteEffects == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteEffects' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsEffect = (LPALISEFFECT)dlsym(openal_library, "alIsEffect");
|
||||
if (lpOALFnTable->alIsEffect == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsEffect' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)dlsym(openal_library, "alIsAuxiliaryEffectSlot");
|
||||
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alGenAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)dlsym(openal_library, "alDeleteAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)dlsym(openal_library, "alGetAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)dlsym(openal_library, "alGetAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)dlsym(openal_library, "alGetAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)dlsym(openal_library, "alGetAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSource3i = (LPALSOURCE3I)dlsym(openal_library, "alSource3i");
|
||||
if (lpOALFnTable->alSource3i == NULL)
|
||||
{
|
||||
warn("Failed to retrieve 'alSource3i' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
#endif
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALvoid UnloadOAL10Library()
|
||||
{
|
||||
if (openal_library != NULL)
|
||||
dlclose(openal_library);
|
||||
}
|
||||
|
|
@ -30,8 +30,7 @@
|
|||
//#define DEBUG_SPEW
|
||||
|
||||
|
||||
SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXALBuffer* SFXALBuffer::create( const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware )
|
||||
{
|
||||
|
|
@ -41,27 +40,24 @@ SFXALBuffer* SFXALBuffer::create( const OPENALFNTABLE &oalft,
|
|||
return NULL;
|
||||
}
|
||||
|
||||
SFXALBuffer *buffer = new SFXALBuffer( oalft,
|
||||
stream,
|
||||
SFXALBuffer *buffer = new SFXALBuffer( stream,
|
||||
description,
|
||||
useHardware );
|
||||
|
||||
return buffer;
|
||||
}
|
||||
|
||||
SFXALBuffer::SFXALBuffer( const OPENALFNTABLE &oalft,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXALBuffer::SFXALBuffer( const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware )
|
||||
: Parent( stream, description ),
|
||||
mIs3d( description->mIs3D ),
|
||||
mUseHardware( useHardware ),
|
||||
mOpenAL( oalft )
|
||||
mUseHardware( useHardware )
|
||||
{
|
||||
// Set up device buffers.
|
||||
|
||||
if( !isStreaming() )
|
||||
mOpenAL.alGenBuffers( 1, &mALBuffer );
|
||||
alGenBuffers( 1, &mALBuffer );
|
||||
}
|
||||
|
||||
SFXALBuffer::~SFXALBuffer()
|
||||
|
|
@ -70,13 +66,13 @@ SFXALBuffer::~SFXALBuffer()
|
|||
_getUniqueVoice()->stop();
|
||||
|
||||
// Release buffers.
|
||||
if ( mOpenAL.alIsBuffer( mALBuffer ))
|
||||
mOpenAL.alDeleteBuffers( 1, &mALBuffer );
|
||||
if ( alIsBuffer( mALBuffer ))
|
||||
alDeleteBuffers( 1, &mALBuffer );
|
||||
|
||||
while( mFreeBuffers.size() )
|
||||
{
|
||||
ALuint buffer = mFreeBuffers.last();
|
||||
mOpenAL.alDeleteBuffers( 1, &buffer );
|
||||
alDeleteBuffers( 1, &buffer );
|
||||
mFreeBuffers.pop_back();
|
||||
}
|
||||
}
|
||||
|
|
@ -98,7 +94,7 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
|
|||
ALenum alFormat = _sfxFormatToALFormat( getFormat() );
|
||||
AssertFatal( alFormat != 0, "SFXALBuffer::write() - format unsupported" );
|
||||
|
||||
mOpenAL.alBufferData( mALBuffer, alFormat,
|
||||
alBufferData( mALBuffer, alFormat,
|
||||
packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
|
||||
|
||||
destructSingle( packet );
|
||||
|
|
@ -112,19 +108,19 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
|
|||
|
||||
ALuint source = _getUniqueVoice()->mSourceName;
|
||||
ALint numProcessed;
|
||||
mOpenAL.alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
|
||||
alGetSourcei( source, AL_BUFFERS_PROCESSED, &numProcessed );
|
||||
|
||||
for( U32 i = 0; i < numProcessed; ++ i )
|
||||
{
|
||||
// Unqueue the buffer.
|
||||
|
||||
ALuint buffer;
|
||||
mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
|
||||
alSourceUnqueueBuffers( source, 1, &buffer );
|
||||
|
||||
// Update the sample offset on the voice.
|
||||
|
||||
ALint size;
|
||||
mOpenAL.alGetBufferi( buffer, AL_SIZE, &size );
|
||||
alGetBufferi( buffer, AL_SIZE, &size );
|
||||
_getUniqueVoice()->mSampleOffset += size / getFormat().getBytesPerSample();
|
||||
|
||||
// Push the buffer onto the freelist.
|
||||
|
|
@ -147,22 +143,22 @@ void SFXALBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
|
|||
mFreeBuffers.pop_back();
|
||||
}
|
||||
else
|
||||
mOpenAL.alGenBuffers( 1, &buffer );
|
||||
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" );
|
||||
AssertFatal( alIsBuffer( buffer ), "SFXALBuffer::write() - buffer invalid" );
|
||||
|
||||
mOpenAL.alBufferData( buffer, alFormat,
|
||||
alBufferData( buffer, alFormat,
|
||||
packet->data, packet->mSizeActual, getFormat().getSamplesPerSecond() );
|
||||
|
||||
destructSingle( packet );
|
||||
|
||||
// Queue the buffer.
|
||||
|
||||
mOpenAL.alSourceQueueBuffers( source, 1, &buffer );
|
||||
alSourceQueueBuffers( source, 1, &buffer );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -183,12 +179,12 @@ void SFXALBuffer::_flush()
|
|||
ALuint source = _getUniqueVoice()->mSourceName;
|
||||
|
||||
ALint numQueued;
|
||||
mOpenAL.alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
|
||||
alGetSourcei( source, AL_BUFFERS_QUEUED, &numQueued );
|
||||
|
||||
for( U32 i = 0; i < numQueued; ++ i )
|
||||
{
|
||||
ALuint buffer;
|
||||
mOpenAL.alSourceUnqueueBuffers( source, 1, &buffer );
|
||||
alSourceUnqueueBuffers( source, 1, &buffer );
|
||||
mFreeBuffers.push_back( buffer );
|
||||
}
|
||||
|
||||
|
|
@ -203,20 +199,20 @@ void SFXALBuffer::_flush()
|
|||
// issues any concurrent state changes on the voice resulting in us losing state here.
|
||||
|
||||
ALuint newSource;
|
||||
mOpenAL.alGenSources( 1, &newSource );
|
||||
alGenSources( 1, &newSource );
|
||||
|
||||
#define COPY_F( name ) \
|
||||
{ \
|
||||
F32 val; \
|
||||
mOpenAL.alGetSourcef( source, name, &val ); \
|
||||
mOpenAL.alSourcef( source, name, val ); \
|
||||
alGetSourcef( source, name, &val ); \
|
||||
alSourcef( source, name, val ); \
|
||||
}
|
||||
|
||||
#define COPY_FV( name ) \
|
||||
{ \
|
||||
VectorF val; \
|
||||
mOpenAL.alGetSourcefv( source, name, val ); \
|
||||
mOpenAL.alSourcefv( source, name, val ); \
|
||||
alGetSourcefv( source, name, val ); \
|
||||
alSourcefv( source, name, val ); \
|
||||
}
|
||||
|
||||
COPY_F( AL_REFERENCE_DISTANCE );
|
||||
|
|
@ -232,7 +228,7 @@ void SFXALBuffer::_flush()
|
|||
COPY_FV( AL_DIRECTION );
|
||||
|
||||
_getUniqueVoice()->mSourceName = newSource;
|
||||
mOpenAL.alDeleteSources( 1, &source );
|
||||
alDeleteSources( 1, &source );
|
||||
|
||||
#endif
|
||||
}
|
||||
|
|
|
|||
|
|
@ -24,13 +24,13 @@
|
|||
#define _SFXALBUFFER_H_
|
||||
|
||||
#ifndef _LOADOAL_H
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
#endif
|
||||
#ifndef _SFXINTERNAL_H_
|
||||
#include "sfx/sfxInternal.h"
|
||||
#include "sfx/sfxInternal.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -39,81 +39,95 @@ class SFXALVoice;
|
|||
|
||||
class SFXALBuffer : public SFXBuffer
|
||||
{
|
||||
public:
|
||||
public:
|
||||
|
||||
typedef SFXBuffer Parent;
|
||||
typedef SFXBuffer Parent;
|
||||
|
||||
friend class SFXALDevice;
|
||||
friend class SFXALVoice;
|
||||
friend class SFXALDevice;
|
||||
friend class SFXALVoice;
|
||||
|
||||
protected:
|
||||
|
||||
/// AL buffer in case this is a static, non-streaming buffer.
|
||||
ALuint mALBuffer;
|
||||
|
||||
/// Free buffers for use in queuing in case this is a streaming buffer.
|
||||
Vector< ALuint > mFreeBuffers;
|
||||
protected:
|
||||
|
||||
///
|
||||
SFXALBuffer( const OPENALFNTABLE &oalft,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware );
|
||||
/// AL buffer in case this is a static, non-streaming buffer.
|
||||
ALuint mALBuffer;
|
||||
|
||||
///
|
||||
bool mIs3d;
|
||||
/// Free buffers for use in queuing in case this is a streaming buffer.
|
||||
Vector< ALuint > mFreeBuffers;
|
||||
|
||||
///
|
||||
bool mUseHardware;
|
||||
///
|
||||
SFXALBuffer(const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware);
|
||||
|
||||
const OPENALFNTABLE &mOpenAL;
|
||||
///
|
||||
bool mIs3d;
|
||||
|
||||
///
|
||||
ALenum _getALFormat() const
|
||||
///
|
||||
bool mUseHardware;
|
||||
///
|
||||
ALenum _getALFormat() const
|
||||
{
|
||||
return _sfxFormatToALFormat(getFormat());
|
||||
}
|
||||
|
||||
///
|
||||
static ALenum _sfxFormatToALFormat(const SFXFormat& format)
|
||||
{
|
||||
const U32 channels = format.getChannels();
|
||||
const SFXSampleType type = format.getSampleType();
|
||||
|
||||
switch (type)
|
||||
{
|
||||
return _sfxFormatToALFormat( getFormat() );
|
||||
case Sample_Int8:
|
||||
if (channels == 1) return AL_FORMAT_MONO8;
|
||||
if (channels == 2) return AL_FORMAT_STEREO8;
|
||||
break;
|
||||
|
||||
case Sample_Int16:
|
||||
if (channels == 1) return AL_FORMAT_MONO16;
|
||||
if (channels == 2) return AL_FORMAT_STEREO16;
|
||||
break;
|
||||
|
||||
case Sample_Float:
|
||||
if (channels == 1) return AL_FORMAT_MONO_FLOAT32;
|
||||
if (channels == 2) return AL_FORMAT_STEREO_FLOAT32;
|
||||
break;
|
||||
|
||||
case Sample_IMA4:
|
||||
if (channels == 1) return AL_FORMAT_MONO_IMA4;
|
||||
if (channels == 2) return AL_FORMAT_STEREO_IMA4;
|
||||
break;
|
||||
|
||||
case Sample_MSADPCM:
|
||||
// Requires OpenAL Soft MSADPCM extension
|
||||
if (channels == 1) return AL_FORMAT_MONO_MSADPCM_SOFT;
|
||||
if (channels == 2) return AL_FORMAT_STEREO_MSADPCM_SOFT;
|
||||
break;
|
||||
}
|
||||
|
||||
///
|
||||
static ALenum _sfxFormatToALFormat( const SFXFormat& format )
|
||||
{
|
||||
if( format.getChannels() == 2 )
|
||||
{
|
||||
const U32 bps = format.getBitsPerSample();
|
||||
if( bps == 16 )
|
||||
return AL_FORMAT_STEREO8;
|
||||
else if( bps == 32 )
|
||||
return AL_FORMAT_STEREO16;
|
||||
}
|
||||
else if( format.getChannels() == 1 )
|
||||
{
|
||||
const U32 bps = format.getBitsPerSample();
|
||||
if( bps == 8 )
|
||||
return AL_FORMAT_MONO8;
|
||||
else if( bps == 16 )
|
||||
return AL_FORMAT_MONO16;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
// Unsupported channel count or layout
|
||||
Con::errorf("_sfxFormatToALFormat - Unsupported format: channels=%d, type=%d",
|
||||
channels, type);
|
||||
return 0;
|
||||
}
|
||||
|
||||
///
|
||||
SFXALVoice* _getUniqueVoice() const
|
||||
{
|
||||
return ( SFXALVoice* ) mUniqueVoice.getPointer();
|
||||
}
|
||||
///
|
||||
SFXALVoice* _getUniqueVoice() const
|
||||
{
|
||||
return (SFXALVoice*)mUniqueVoice.getPointer();
|
||||
}
|
||||
|
||||
// SFXBuffer.
|
||||
void write( SFXInternal::SFXStreamPacket* const* packets, U32 num ) override;
|
||||
void _flush() override;
|
||||
// SFXBuffer.
|
||||
void write(SFXInternal::SFXStreamPacket* const* packets, U32 num) override;
|
||||
void _flush() override;
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
static SFXALBuffer* create( const OPENALFNTABLE &oalft,
|
||||
const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware );
|
||||
static SFXALBuffer* create(const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description,
|
||||
bool useHardware);
|
||||
|
||||
virtual ~SFXALBuffer();
|
||||
virtual ~SFXALBuffer();
|
||||
};
|
||||
|
||||
#endif // _SFXALBUFFER_H_
|
||||
#endif // _SFXALBUFFER_H_
|
||||
|
|
|
|||
|
|
@ -24,6 +24,90 @@
|
|||
#include "sfx/openal/sfxALBuffer.h"
|
||||
#include "platform/async/asyncUpdate.h"
|
||||
|
||||
#include "AL/al.h"
|
||||
#include "AL/alc.h"
|
||||
#include "AL/efx.h"
|
||||
#include "AL/alext.h"
|
||||
|
||||
#ifndef ALC_CONNECTED
|
||||
#define ALC_CONNECTED 0x313
|
||||
#endif
|
||||
|
||||
#ifndef ALC_DEVICE_CLOCK_SOFT
|
||||
#define ALC_DEVICE_CLOCK_SOFT 0x1600
|
||||
#endif
|
||||
|
||||
#ifndef ALC_DEVICE_LATENCY_SOFT
|
||||
#define ALC_DEVICE_LATENCY_SOFT 0x1601
|
||||
#endif
|
||||
|
||||
#if defined(__STDC_VERSION__) && __STDC_VERSION__ >= 199901L
|
||||
#define FUNCTION_CAST(T, ptr) (union{void *p; T f;}){ptr}.f
|
||||
#elif defined(__cplusplus)
|
||||
#define FUNCTION_CAST(T, ptr) reinterpret_cast<T>(ptr)
|
||||
#else
|
||||
#define FUNCTION_CAST(T, ptr) (T)(ptr)
|
||||
#endif
|
||||
|
||||
/* Effect object functions */
|
||||
static LPALGENFILTERS alGenFilters{ nullptr };
|
||||
static LPALDELETEFILTERS alDeleteFilters{ nullptr };
|
||||
static LPALISFILTER alIsFilter{ nullptr };
|
||||
static LPALFILTERF alFilterf{ nullptr };
|
||||
static LPALFILTERFV alFilterfv{ nullptr };
|
||||
static LPALFILTERI alFilteri{ nullptr };
|
||||
static LPALFILTERIV alFilteriv{ nullptr };
|
||||
static LPALGETFILTERF alGetFilterf{ nullptr };
|
||||
static LPALGETFILTERFV alGetFilterfv{ nullptr };
|
||||
static LPALGETFILTERI alGetFilteri{ nullptr };
|
||||
static LPALGETFILTERIV alGetFilteriv{ nullptr };
|
||||
static LPALGENEFFECTS alGenEffects{ nullptr };
|
||||
static LPALDELETEEFFECTS alDeleteEffects{ nullptr };
|
||||
static LPALISEFFECT alIsEffect{ nullptr };
|
||||
static LPALEFFECTF alEffectf{ nullptr };
|
||||
static LPALEFFECTFV alEffectfv{ nullptr };
|
||||
static LPALEFFECTI alEffecti{ nullptr };
|
||||
static LPALEFFECTIV alEffectiv{ nullptr };
|
||||
static LPALGETEFFECTF alGetEffectf{ nullptr };
|
||||
static LPALGETEFFECTFV alGetEffectfv{ nullptr };
|
||||
static LPALGETEFFECTI alGetEffecti{ nullptr };
|
||||
static LPALGETEFFECTIV alGetEffectiv{ nullptr };
|
||||
static LPALGENAUXILIARYEFFECTSLOTS alGenAuxiliaryEffectSlots{ nullptr };
|
||||
static LPALDELETEAUXILIARYEFFECTSLOTS alDeleteAuxiliaryEffectSlots{ nullptr };
|
||||
static LPALISAUXILIARYEFFECTSLOT alIsAuxiliaryEffectSlot{ nullptr };
|
||||
static LPALAUXILIARYEFFECTSLOTF alAuxiliaryEffectSlotf{ nullptr };
|
||||
static LPALAUXILIARYEFFECTSLOTFV alAuxiliaryEffectSlotfv{ nullptr };
|
||||
static LPALAUXILIARYEFFECTSLOTI alAuxiliaryEffectSloti{ nullptr };
|
||||
static LPALAUXILIARYEFFECTSLOTIV alAuxiliaryEffectSlotiv{ nullptr };
|
||||
static LPALGETAUXILIARYEFFECTSLOTF alGetAuxiliaryEffectSlotf{ nullptr };
|
||||
static LPALGETAUXILIARYEFFECTSLOTFV alGetAuxiliaryEffectSlotfv{ nullptr };
|
||||
static LPALGETAUXILIARYEFFECTSLOTI alGetAuxiliaryEffectSloti{ nullptr };
|
||||
static LPALGETAUXILIARYEFFECTSLOTIV alGetAuxiliaryEffectSlotiv{ nullptr };
|
||||
static LPALCGETSTRINGISOFT alcGetStringiSOFT{ nullptr };
|
||||
static LPALCRESETDEVICESOFT alcResetDeviceSOFT{ nullptr };
|
||||
static LPALCREOPENDEVICESOFT alcReopenDeviceSOFT{ nullptr };
|
||||
static LPALCGETINTEGER64VSOFT alcGetInteger64vSOFT{ nullptr };
|
||||
|
||||
class SFXALRegisterProvider
|
||||
{
|
||||
public:
|
||||
SFXALRegisterProvider()
|
||||
{
|
||||
SFXSystem::getRegisterProviderSignal().notify(&SFXALDevice::enumerateProviders);
|
||||
}
|
||||
};
|
||||
|
||||
static SFXALRegisterProvider pSFXALRegisterProvider;
|
||||
|
||||
SFXProvider::CreateProviderInstanceDelegate SFXALDevice::mCreateDeviceInstance(SFXALDevice::createInstance);
|
||||
|
||||
SFXDevice* SFXALDevice::createInstance(U32 providerIndex)
|
||||
{
|
||||
SFXALDevice* dev = new SFXALDevice(providerIndex);
|
||||
return dev;
|
||||
}
|
||||
|
||||
|
||||
//----------------------------------------------------------------------------
|
||||
// STATIC OPENAL FUNCTIONS
|
||||
//----------------------------------------------------------------------------
|
||||
|
|
@ -35,39 +119,54 @@ void SFXALDevice::printALInfo(ALCdevice* device)
|
|||
const ALCchar* devname = NULL;
|
||||
Con::printBlankLine();
|
||||
|
||||
if (mOpenAL.alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
||||
if (alcIsExtensionPresent(device, "ALC_ENUMERATE_ALL_EXT") != AL_FALSE)
|
||||
{
|
||||
devname = mOpenAL.alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
|
||||
devname = alcGetString(device, ALC_ALL_DEVICES_SPECIFIER);
|
||||
}
|
||||
else
|
||||
{
|
||||
devname = mOpenAL.alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||
devname = alcGetString(device, ALC_DEVICE_SPECIFIER);
|
||||
}
|
||||
|
||||
Con::printf("| Device info for: %s ", devname);
|
||||
}
|
||||
|
||||
mOpenAL.alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
|
||||
mOpenAL.alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
|
||||
alcGetIntegerv(device, ALC_MAJOR_VERSION, 1, &major);
|
||||
alcGetIntegerv(device, ALC_MINOR_VERSION, 1, &minor);
|
||||
Con::printf("| OpenAL Version: %d.%d", major, minor);
|
||||
|
||||
if (device)
|
||||
{
|
||||
Con::printf("%s", mOpenAL.alcGetString(device, ALC_EXTENSIONS));
|
||||
const ALchar* extStr = alcGetString(device, ALC_EXTENSIONS);
|
||||
if (extStr)
|
||||
{
|
||||
Con::printf("| SFXALDevice - Supported ALC extensions:");
|
||||
|
||||
U32 err = mOpenAL.alcGetError(device);
|
||||
// Copy to a modifiable string.
|
||||
char* extCopy = dStrdup(extStr);
|
||||
char* token = dStrtok(extCopy, " ");
|
||||
while (token)
|
||||
{
|
||||
Con::printf("| %s", token);
|
||||
token = dStrtok(NULL, " ");
|
||||
}
|
||||
|
||||
dFree(extCopy);
|
||||
}
|
||||
|
||||
U32 err = alcGetError(device);
|
||||
if (err != ALC_NO_ERROR)
|
||||
Con::errorf("SFXALDevice - Error Retrieving ALC Extensions: %s", mOpenAL.alcGetString(device, err));
|
||||
Con::errorf("SFXALDevice - Error Retrieving ALC Extensions: %s", alcGetString(device, err));
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
S32 SFXALDevice::getMaxSources()
|
||||
{
|
||||
mOpenAL.alGetError();
|
||||
alGetError();
|
||||
|
||||
ALCint nummono;
|
||||
mOpenAL.alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &nummono);
|
||||
alcGetIntegerv(mDevice, ALC_MONO_SOURCES, 1, &nummono);
|
||||
|
||||
if(nummono == 0)
|
||||
nummono = getMaxSourcesOld();
|
||||
|
|
@ -81,21 +180,21 @@ S32 SFXALDevice::getMaxSourcesOld()
|
|||
S32 sourceCount = 0;
|
||||
|
||||
// clear errors.
|
||||
mOpenAL.alGetError();
|
||||
alGetError();
|
||||
|
||||
for(sourceCount = 0; sourceCount < 256; sourceCount++)
|
||||
{
|
||||
mOpenAL.alGenSources(1,&uiSource[sourceCount]);
|
||||
if(mOpenAL.alGetError() != AL_NO_ERROR)
|
||||
alGenSources(1,&uiSource[sourceCount]);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
break;
|
||||
}
|
||||
|
||||
mOpenAL.alDeleteSources(sourceCount, uiSource);
|
||||
if(mOpenAL.alGetError() != AL_NO_ERROR)
|
||||
alDeleteSources(sourceCount, uiSource);
|
||||
if(alGetError() != AL_NO_ERROR)
|
||||
{
|
||||
for(U32 i = 0; i < 256; i++)
|
||||
{
|
||||
mOpenAL.alDeleteSources(1,&uiSource[i]);
|
||||
alDeleteSources(1,&uiSource[i]);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -103,55 +202,31 @@ S32 SFXALDevice::getMaxSourcesOld()
|
|||
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
SFXALDevice::SFXALDevice( SFXProvider *provider,
|
||||
const OPENALFNTABLE &openal,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers )
|
||||
: Parent( name, provider, useHardware, maxBuffers ),
|
||||
mOpenAL( openal ),
|
||||
mContext( NULL ),
|
||||
mDevice( NULL ),
|
||||
SFXALDevice::SFXALDevice(U32 providerIndex)
|
||||
: mContext(NULL),
|
||||
mDevice(NULL),
|
||||
mDistanceModel(SFXDistanceModelLinear),
|
||||
mDistanceFactor(1.0f),
|
||||
mRolloffFactor( 1.0f ),
|
||||
mRolloffFactor(1.0f),
|
||||
mUserRolloffFactor(1.0f)
|
||||
{
|
||||
mMaxBuffers = getMax( maxBuffers, 8 );
|
||||
SFXProvider* p = SFXSystem::getProvider(providerIndex);
|
||||
|
||||
// TODO: The OpenAL device doesn't set the primary buffer
|
||||
// $pref::SFX::frequency or $pref::SFX::bitrate!
|
||||
//check auxiliary device sends 4 and add them to the device
|
||||
ALint attribs[4] = { 0 };
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
ALCint iSends = 0;
|
||||
attribs[0] = ALC_MAX_AUXILIARY_SENDS;
|
||||
#endif
|
||||
attribs[1] = 4;
|
||||
mDevice = alcOpenDevice(p->getName());
|
||||
|
||||
printALInfo(NULL);
|
||||
|
||||
mDevice = mOpenAL.alcOpenDevice( name );
|
||||
U32 err = mOpenAL.alcGetError(mDevice);
|
||||
U32 err = alcGetError(mDevice);
|
||||
if (err != ALC_NO_ERROR)
|
||||
Con::errorf("SFXALDevice - Device Initialization Error: %s", mOpenAL.alcGetString(mDevice, err));
|
||||
Con::errorf("SFXALDevice - Device Initialization Error: %s", alcGetString(mDevice, err));
|
||||
|
||||
if( mDevice )
|
||||
if (mDevice)
|
||||
{
|
||||
mContext = mOpenAL.alcCreateContext( mDevice, attribs );
|
||||
mContext = alcCreateContext(mDevice, NULL);
|
||||
|
||||
if( mContext )
|
||||
mOpenAL.alcMakeContextCurrent( mContext );
|
||||
if (mContext)
|
||||
alcMakeContextCurrent(mContext);
|
||||
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
mOpenAL.alcGetIntegerv(mDevice, ALC_MAX_AUXILIARY_SENDS, 1, &iSends);
|
||||
#endif
|
||||
err = mOpenAL.alcGetError( mDevice );
|
||||
|
||||
if( err != ALC_NO_ERROR )
|
||||
Con::errorf( "SFXALDevice - Context Initialization Error: %s", mOpenAL.alcGetString( mDevice, err ) );
|
||||
Con::errorf( "SFXALDevice - Context Initialization Error: %s", alcGetString( mDevice, err ) );
|
||||
}
|
||||
|
||||
AssertFatal( mDevice != NULL && mContext != NULL, "Failed to create OpenAL device and/or context!" );
|
||||
|
|
@ -168,20 +243,64 @@ SFXALDevice::SFXALDevice( SFXProvider *provider,
|
|||
}
|
||||
#endif
|
||||
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
dMemset(effectSlot, 0, sizeof(effectSlot));
|
||||
dMemset(effect, 0, sizeof(effect));
|
||||
uLoop = 0;
|
||||
#endif
|
||||
// --- Capabilities ---
|
||||
if (alcIsExtensionPresent(mDevice, "ALC_EXT_EFX") == AL_TRUE)
|
||||
mCaps |= CAPS_Reverb | CAPS_Occlusion;
|
||||
if (alcIsExtensionPresent(mDevice, "ALC_SOFT_HRTF") == AL_TRUE)
|
||||
mCaps |= CAPS_HRTF;
|
||||
if (alIsExtensionPresent("AL_EXT_float32") == AL_TRUE)
|
||||
mCaps |= CAPS_Float32;
|
||||
if (alIsExtensionPresent("AL_EXT_MCFORMATS") == AL_TRUE)
|
||||
mCaps |= CAPS_MonoStereo;
|
||||
|
||||
if (mCaps & CAPS_Reverb)
|
||||
{
|
||||
#define LOAD_PROC(T, x) ((x) = FUNCTION_CAST(T, alGetProcAddress(#x)))
|
||||
LOAD_PROC(LPALGENEFFECTS, alGenEffects);
|
||||
LOAD_PROC(LPALDELETEEFFECTS, alDeleteEffects);
|
||||
LOAD_PROC(LPALISEFFECT, alIsEffect);
|
||||
LOAD_PROC(LPALEFFECTI, alEffecti);
|
||||
LOAD_PROC(LPALEFFECTIV, alEffectiv);
|
||||
LOAD_PROC(LPALEFFECTF, alEffectf);
|
||||
LOAD_PROC(LPALEFFECTFV, alEffectfv);
|
||||
LOAD_PROC(LPALGETEFFECTI, alGetEffecti);
|
||||
LOAD_PROC(LPALGETEFFECTIV, alGetEffectiv);
|
||||
LOAD_PROC(LPALGETEFFECTF, alGetEffectf);
|
||||
LOAD_PROC(LPALGETEFFECTFV, alGetEffectfv);
|
||||
|
||||
LOAD_PROC(LPALGENAUXILIARYEFFECTSLOTS, alGenAuxiliaryEffectSlots);
|
||||
LOAD_PROC(LPALDELETEAUXILIARYEFFECTSLOTS, alDeleteAuxiliaryEffectSlots);
|
||||
LOAD_PROC(LPALISAUXILIARYEFFECTSLOT, alIsAuxiliaryEffectSlot);
|
||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTI, alAuxiliaryEffectSloti);
|
||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTIV, alAuxiliaryEffectSlotiv);
|
||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTF, alAuxiliaryEffectSlotf);
|
||||
LOAD_PROC(LPALAUXILIARYEFFECTSLOTFV, alAuxiliaryEffectSlotfv);
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTI, alGetAuxiliaryEffectSloti);
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTIV, alGetAuxiliaryEffectSlotiv);
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTF, alGetAuxiliaryEffectSlotf);
|
||||
LOAD_PROC(LPALGETAUXILIARYEFFECTSLOTFV, alGetAuxiliaryEffectSlotfv);
|
||||
#undef LOAD_PROC
|
||||
|
||||
// generate our auxiliary slot for the effects.
|
||||
// alGenAuxiliaryEffectSlots(1, &mAuxSlot);
|
||||
}
|
||||
|
||||
// --- Device frequency ---
|
||||
ALCint freq = 0;
|
||||
alcGetIntegerv(mDevice, ALC_FREQUENCY, 1, &freq);
|
||||
if (freq > 0)
|
||||
Con::setIntVariable("$pref::SFX::frequency", freq);
|
||||
else
|
||||
Con::setIntVariable("$pref::SFX::frequency", 44100); // default
|
||||
|
||||
// --- Bitrate approximation ---
|
||||
U32 bitrate = (mCaps & CAPS_Float32) ? 32 : 16;
|
||||
Con::setIntVariable("$pref::SFX::bitrate", bitrate);
|
||||
|
||||
printALInfo(mDevice);
|
||||
|
||||
|
||||
mMaxBuffers = getMaxSources();
|
||||
|
||||
// this should be max sources.
|
||||
Con::printf("| Max Sources: %d", mMaxBuffers);
|
||||
|
||||
Con::setIntVariable("$pref::SFX::maxSoftwareBuffers", mMaxBuffers);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -189,26 +308,60 @@ SFXALDevice::SFXALDevice( SFXProvider *provider,
|
|||
SFXALDevice::~SFXALDevice()
|
||||
{
|
||||
_releaseAllResources();
|
||||
///cleanup our effects
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
mOpenAL.alDeleteAuxiliaryEffectSlots(4, effectSlot);
|
||||
mOpenAL.alDeleteEffects(2, effect);
|
||||
#endif
|
||||
|
||||
///cleanup of effects ends
|
||||
mOpenAL.alcMakeContextCurrent( NULL );
|
||||
mOpenAL.alcDestroyContext( mContext );
|
||||
mOpenAL.alcCloseDevice( mDevice );
|
||||
alcMakeContextCurrent( NULL );
|
||||
alcDestroyContext( mContext );
|
||||
alcCloseDevice( mDevice );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SFXALDevice::enumerateProviders(Vector<SFXProvider*>& providerList)
|
||||
{
|
||||
const ALCchar* devices;
|
||||
U32 index = providerList.size();
|
||||
const ALCchar* defaultDeviceName;
|
||||
|
||||
if (alcIsExtensionPresent(NULL, "ALC_ENUMERATE_ALL_EXT") == AL_TRUE)
|
||||
{
|
||||
devices = alcGetString(NULL, ALC_ALL_DEVICES_SPECIFIER);
|
||||
defaultDeviceName = alcGetString(NULL, ALC_DEFAULT_ALL_DEVICES_SPECIFIER);
|
||||
}
|
||||
else
|
||||
{
|
||||
devices = alcGetString(NULL, ALC_DEVICE_SPECIFIER);
|
||||
defaultDeviceName = alcGetString(NULL, ALC_DEFAULT_DEVICE_SPECIFIER);
|
||||
}
|
||||
|
||||
const ALCchar* currentDevice = devices;
|
||||
|
||||
while (*currentDevice != '\0')
|
||||
{
|
||||
SFXProvider* toAdd = new SFXProvider;
|
||||
toAdd->mName = String::ToString(currentDevice);
|
||||
toAdd->mIndex = index;
|
||||
toAdd->mDeviceType = Output;
|
||||
toAdd->mType = OpenAL;
|
||||
toAdd->mCreateDeviceInstanceDelegate = mCreateDeviceInstance;
|
||||
|
||||
if (String::compare(currentDevice, defaultDeviceName) == 0)
|
||||
toAdd->mDefault = true;
|
||||
|
||||
currentDevice += dStrlen(currentDevice) + 1;
|
||||
index++;
|
||||
|
||||
providerList.push_back(toAdd);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SFXBuffer* SFXALDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
|
||||
{
|
||||
AssertFatal( stream, "SFXALDevice::createBuffer() - Got null stream!" );
|
||||
AssertFatal( description, "SFXALDevice::createBuffer() - Got null description!" );
|
||||
|
||||
SFXALBuffer* buffer = SFXALBuffer::create( mOpenAL,
|
||||
stream,
|
||||
SFXALBuffer* buffer = SFXALBuffer::create( stream,
|
||||
description,
|
||||
mUseHardware );
|
||||
if ( !buffer )
|
||||
|
|
@ -258,14 +411,9 @@ void SFXALDevice::setListener( U32 index, const SFXListenerProperties& listener
|
|||
|
||||
const VectorF &velocity = listener.getVelocity();
|
||||
|
||||
mOpenAL.alListenerfv( AL_POSITION, pos );
|
||||
mOpenAL.alListenerfv( AL_VELOCITY, velocity );
|
||||
mOpenAL.alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] );
|
||||
///Pass a unit size to openal, 1.0 assumes 1 meter to 1 game unit.
|
||||
///Crucial for air absorbtion calculations.
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
mOpenAL.alListenerf(AL_METERS_PER_UNIT, 1.0f);
|
||||
#endif
|
||||
alListenerfv( AL_POSITION, pos );
|
||||
alListenerfv( AL_VELOCITY, velocity );
|
||||
alListenerfv( AL_ORIENTATION, (const F32 *)&tupple[0] );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -275,19 +423,19 @@ void SFXALDevice::setDistanceModel( SFXDistanceModel model )
|
|||
switch( model )
|
||||
{
|
||||
case SFXDistanceModelLinear:
|
||||
mOpenAL.alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED );
|
||||
alDistanceModel( AL_LINEAR_DISTANCE_CLAMPED );
|
||||
if( mRolloffFactor != 1.0f )
|
||||
_setRolloffFactor( 1.0f ); // No rolloff on linear.
|
||||
break;
|
||||
|
||||
case SFXDistanceModelLogarithmic:
|
||||
mOpenAL.alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
|
||||
alDistanceModel( AL_INVERSE_DISTANCE_CLAMPED );
|
||||
if( mUserRolloffFactor != mRolloffFactor )
|
||||
_setRolloffFactor( mUserRolloffFactor );
|
||||
break;
|
||||
/// create a case for our exponential distance model
|
||||
case SFXDistanceModelExponent:
|
||||
mOpenAL.alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
|
||||
alDistanceModel(AL_EXPONENT_DISTANCE_CLAMPED);
|
||||
if (mUserRolloffFactor != mRolloffFactor)
|
||||
_setRolloffFactor(mUserRolloffFactor);
|
||||
break;
|
||||
|
|
@ -303,7 +451,7 @@ void SFXALDevice::setDistanceModel( SFXDistanceModel model )
|
|||
|
||||
void SFXALDevice::setDopplerFactor( F32 factor )
|
||||
{
|
||||
mOpenAL.alDopplerFactor( factor );
|
||||
alDopplerFactor( factor );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -313,7 +461,7 @@ void SFXALDevice::_setRolloffFactor( F32 factor )
|
|||
mRolloffFactor = factor;
|
||||
|
||||
for( U32 i = 0, num = mVoices.size(); i < num; ++ i )
|
||||
mOpenAL.alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor );
|
||||
alSourcef( ( ( SFXALVoice* ) mVoices[ i ] )->mSourceName, AL_ROLLOFF_FACTOR, factor );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -328,110 +476,7 @@ void SFXALDevice::setRolloffFactor( F32 factor )
|
|||
mUserRolloffFactor = factor;
|
||||
}
|
||||
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
void SFXALDevice::openSlots()
|
||||
void SFXALDevice::setSpeedOfSound(F32 speedOfSound)
|
||||
{
|
||||
for (uLoop = 0; uLoop < 4; uLoop++)
|
||||
{
|
||||
mOpenAL.alGenAuxiliaryEffectSlots(1, &effectSlot[uLoop]);
|
||||
}
|
||||
|
||||
for (uLoop = 0; uLoop < 2; uLoop++)
|
||||
{
|
||||
mOpenAL.alGenEffects(1, &effect[uLoop]);
|
||||
}
|
||||
///debug string output so we know our slots are open
|
||||
Platform::outputDebugString("Slots Open");
|
||||
alSpeedOfSound(speedOfSound);
|
||||
}
|
||||
|
||||
///create reverb effect
|
||||
void SFXALDevice::setReverb(const SFXReverbProperties& reverb)
|
||||
{
|
||||
///output a debug string so we know each time the reverb changes
|
||||
Platform::outputDebugString("Updated");
|
||||
|
||||
///load an efxeaxreverb default and add our values from
|
||||
///sfxreverbproperties to it
|
||||
EFXEAXREVERBPROPERTIES prop = EFX_REVERB_PRESET_GENERIC;
|
||||
|
||||
prop.flDensity = reverb.flDensity;
|
||||
prop.flDiffusion = reverb.flDiffusion;
|
||||
prop.flGain = reverb.flGain;
|
||||
prop.flGainHF = reverb.flGainHF;
|
||||
prop.flGainLF = reverb.flGainLF;
|
||||
prop.flDecayTime = reverb.flDecayTime;
|
||||
prop.flDecayHFRatio = reverb.flDecayHFRatio;
|
||||
prop.flDecayLFRatio = reverb.flDecayLFRatio;
|
||||
prop.flReflectionsGain = reverb.flReflectionsGain;
|
||||
prop.flReflectionsDelay = reverb.flReflectionsDelay;
|
||||
prop.flLateReverbGain = reverb.flLateReverbGain;
|
||||
prop.flLateReverbDelay = reverb.flLateReverbDelay;
|
||||
prop.flEchoTime = reverb.flEchoTime;
|
||||
prop.flEchoDepth = reverb.flEchoDepth;
|
||||
prop.flModulationTime = reverb.flModulationTime;
|
||||
prop.flModulationDepth = reverb.flModulationDepth;
|
||||
prop.flAirAbsorptionGainHF = reverb.flAirAbsorptionGainHF;
|
||||
prop.flHFReference = reverb.flHFReference;
|
||||
prop.flLFReference = reverb.flLFReference;
|
||||
prop.flRoomRolloffFactor = reverb.flRoomRolloffFactor;
|
||||
prop.iDecayHFLimit = reverb.iDecayHFLimit;
|
||||
|
||||
if (mOpenAL.alGetEnumValue("AL_EFFECT_EAXREVERB") != 0)
|
||||
{
|
||||
|
||||
/// EAX Reverb is available. Set the EAX effect type
|
||||
|
||||
mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_EAXREVERB);
|
||||
|
||||
///add our values to the setup of the reverb
|
||||
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DENSITY, prop.flDensity);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DIFFUSION, prop.flDiffusion);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAIN, prop.flGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINHF, prop.flGainHF);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_GAINLF, prop.flGainLF);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_TIME, prop.flDecayTime);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_DECAY_LFRATIO, prop.flDecayLFRatio);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_TIME, prop.flEchoTime);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ECHO_DEPTH, prop.flEchoDepth);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_TIME, prop.flModulationTime);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_MODULATION_DEPTH, prop.flModulationDepth);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_HFREFERENCE, prop.flHFReference);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_LFREFERENCE, prop.flLFReference);
|
||||
mOpenAL.alEffectf(effect[0], AL_EAXREVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
|
||||
mOpenAL.alEffecti(effect[0], AL_EAXREVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
|
||||
mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
|
||||
Platform::outputDebugString("eax reverb properties set");
|
||||
|
||||
}
|
||||
else
|
||||
{
|
||||
|
||||
/// No EAX Reverb. Set the standard reverb effect
|
||||
mOpenAL.alEffecti(effect[0], AL_EFFECT_TYPE, AL_EFFECT_REVERB);
|
||||
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_DENSITY, prop.flDensity);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_DIFFUSION, prop.flDiffusion);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_GAIN, prop.flGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_GAINHF, prop.flGainHF);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_TIME, prop.flDecayTime);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_DECAY_HFRATIO, prop.flDecayHFRatio);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_GAIN, prop.flReflectionsGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_REFLECTIONS_DELAY, prop.flReflectionsDelay);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_GAIN, prop.flLateReverbGain);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_LATE_REVERB_DELAY, prop.flLateReverbDelay);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_AIR_ABSORPTION_GAINHF, prop.flAirAbsorptionGainHF);
|
||||
mOpenAL.alEffectf(effect[0], AL_REVERB_ROOM_ROLLOFF_FACTOR, prop.flRoomRolloffFactor);
|
||||
mOpenAL.alEffecti(effect[0], AL_REVERB_DECAY_HFLIMIT, prop.iDecayHFLimit);
|
||||
mOpenAL.alAuxiliaryEffectSloti(1, AL_EFFECTSLOT_EFFECT, effect[0]);
|
||||
|
||||
}
|
||||
|
||||
}
|
||||
#endif
|
||||
|
|
|
|||
|
|
@ -23,8 +23,6 @@
|
|||
#ifndef _SFXALDEVICE_H_
|
||||
#define _SFXALDEVICE_H_
|
||||
|
||||
class SFXProvider;
|
||||
|
||||
#ifndef _SFXDEVICE_H_
|
||||
# include "sfx/sfxDevice.h"
|
||||
#endif
|
||||
|
|
@ -45,6 +43,9 @@ class SFXProvider;
|
|||
# include "sfx/openal/LoadOAL.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SFXSYSTEM_H_
|
||||
#include "sfx/sfxSystem.h"
|
||||
#endif
|
||||
|
||||
class SFXALDevice : public SFXDevice
|
||||
{
|
||||
|
|
@ -53,6 +54,8 @@ class SFXALDevice : public SFXDevice
|
|||
typedef SFXDevice Parent;
|
||||
friend class SFXALVoice; // mDistanceFactor, mRolloffFactor
|
||||
|
||||
static SFXDevice* createInstance(U32 adapterIndex);
|
||||
|
||||
void printALInfo(ALCdevice* device);
|
||||
void printHRTFInfo(ALCdevice* device);
|
||||
void getEFXInfo(ALCdevice* device);
|
||||
|
|
@ -61,16 +64,12 @@ class SFXALDevice : public SFXDevice
|
|||
// Compatibility with pre openal 1.2
|
||||
S32 getMaxSourcesOld();
|
||||
|
||||
SFXALDevice( SFXProvider *provider,
|
||||
const OPENALFNTABLE &openal,
|
||||
String name,
|
||||
bool useHardware,
|
||||
S32 maxBuffers );
|
||||
SFXALDevice(U32 providerIndex);
|
||||
|
||||
virtual ~SFXALDevice();
|
||||
|
||||
protected:
|
||||
|
||||
static SFXProvider::CreateProviderInstanceDelegate mCreateDeviceInstance;
|
||||
OPENALFNTABLE mOpenAL;
|
||||
|
||||
ALCcontext *mContext;
|
||||
|
|
@ -85,7 +84,7 @@ class SFXALDevice : public SFXDevice
|
|||
void _setRolloffFactor( F32 factor );
|
||||
|
||||
public:
|
||||
|
||||
static void enumerateProviders(Vector<SFXProvider*>& providerList);
|
||||
// SFXDevice.
|
||||
SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description ) override;
|
||||
SFXVoice* createVoice( bool is3D, SFXBuffer *buffer ) override;
|
||||
|
|
@ -93,17 +92,8 @@ class SFXALDevice : public SFXDevice
|
|||
void setDistanceModel( SFXDistanceModel model ) override;
|
||||
void setDopplerFactor( F32 factor ) override;
|
||||
void setRolloffFactor( F32 factor ) override;
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
//function for openAL to open slots
|
||||
virtual void openSlots();
|
||||
//slots
|
||||
ALuint effectSlot[4] = { 0 };
|
||||
ALuint effect[2] = { 0 };
|
||||
ALuint uLoop;
|
||||
//get values from sfxreverbproperties and pass it to openal device
|
||||
virtual void setReverb(const SFXReverbProperties& reverb);
|
||||
#endif
|
||||
void resetReverb() override {}
|
||||
void setSpeedOfSound(F32 speedOfSound) override;
|
||||
};
|
||||
|
||||
#endif // _SFXALDEVICE_H_
|
||||
|
|
|
|||
|
|
@ -1,127 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
|
||||
#include "sfx/sfxProvider.h"
|
||||
#include "sfx/openal/sfxALDevice.h"
|
||||
#include "sfx/openal/aldlist.h"
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "console/console.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
class SFXALProvider : public SFXProvider
|
||||
{
|
||||
public:
|
||||
|
||||
SFXALProvider()
|
||||
: SFXProvider( "OpenAL" ) { dMemset(&mOpenAL,0,sizeof(mOpenAL)); mALDL = NULL; }
|
||||
virtual ~SFXALProvider();
|
||||
|
||||
protected:
|
||||
OPENALFNTABLE mOpenAL;
|
||||
ALDeviceList *mALDL;
|
||||
|
||||
struct ALDeviceInfo : SFXDeviceInfo
|
||||
{
|
||||
|
||||
};
|
||||
|
||||
void init() override;
|
||||
|
||||
public:
|
||||
SFXDevice *createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) override;
|
||||
|
||||
};
|
||||
|
||||
MODULE_BEGIN( OpenAL )
|
||||
|
||||
MODULE_INIT_BEFORE( SFX )
|
||||
MODULE_SHUTDOWN_AFTER( SFX )
|
||||
|
||||
SFXALProvider* mProvider = NULL;
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
mProvider = new SFXALProvider;
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
delete mProvider;
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
void SFXALProvider::init()
|
||||
{
|
||||
if( LoadOAL10Library( NULL, &mOpenAL ) != AL_TRUE )
|
||||
{
|
||||
Con::printf( "SFXALProvider - OpenAL not available." );
|
||||
return;
|
||||
}
|
||||
mALDL = new ALDeviceList( mOpenAL );
|
||||
|
||||
// Did we get any devices?
|
||||
if ( mALDL->GetNumDevices() < 1 )
|
||||
{
|
||||
Con::printf( "SFXALProvider - No valid devices found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Cool, loop through them, and caps em
|
||||
//const char *deviceFormat = "OpenAL v%d.%d %s";
|
||||
|
||||
for( S32 i = 0; i < mALDL->GetNumDevices(); i++ )
|
||||
{
|
||||
ALDeviceInfo* info = new ALDeviceInfo;
|
||||
|
||||
//info->internalName = String( mALDL->GetInternalDeviceName( i ) );
|
||||
info->name = String( mALDL->GetDeviceName( i ) );
|
||||
|
||||
mDeviceInfo.push_back( info );
|
||||
}
|
||||
|
||||
regProvider( this );
|
||||
}
|
||||
|
||||
SFXALProvider::~SFXALProvider()
|
||||
{
|
||||
UnloadOAL10Library();
|
||||
|
||||
if (mALDL)
|
||||
delete mALDL;
|
||||
}
|
||||
|
||||
SFXDevice* SFXALProvider::createDevice(const String& deviceName, bool useHardware, S32 maxBuffers)
|
||||
{
|
||||
ALDeviceInfo* info = dynamic_cast<ALDeviceInfo*>
|
||||
(_findDeviceInfo(deviceName));
|
||||
|
||||
// Do we find one to create?
|
||||
if (info)
|
||||
return new SFXALDevice(this, mOpenAL, info->name, useHardware, maxBuffers);
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -28,7 +28,7 @@
|
|||
|
||||
#ifdef TORQUE_DEBUG
|
||||
# define AL_SANITY_CHECK() \
|
||||
AssertFatal( mOpenAL.alIsSource( mSourceName ), "AL Source Sanity Check Failed!" );
|
||||
AssertFatal( alIsSource( mSourceName ), "AL Source Sanity Check Failed!" );
|
||||
#else
|
||||
# define AL_SANITY_CHECK()
|
||||
#endif
|
||||
|
|
@ -42,8 +42,8 @@ SFXALVoice* SFXALVoice::create( SFXALDevice* device, SFXALBuffer *buffer )
|
|||
AssertFatal( buffer, "SFXALVoice::create() - Got null buffer!" );
|
||||
|
||||
ALuint sourceName;
|
||||
device->mOpenAL.alGenSources( 1, &sourceName );
|
||||
AssertFatal( device->mOpenAL.alIsSource( sourceName ), "AL Source Sanity Check Failed!" );
|
||||
alGenSources( 1, &sourceName );
|
||||
AssertFatal( alIsSource( sourceName ), "AL Source Sanity Check Failed!" );
|
||||
|
||||
// Is this 3d?
|
||||
// Okay, this looks odd, but bear with me for a moment. AL_SOURCE_RELATIVE does NOT indicate
|
||||
|
|
@ -52,34 +52,32 @@ SFXALVoice* SFXALVoice::create( SFXALDevice* device, SFXALBuffer *buffer )
|
|||
// does do is dictate if the position of THIS SOURCE is relative to the listener. If AL_SOURCE_RELATIVE is AL_TRUE
|
||||
// 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
|
||||
// we want for non-3d sounds.
|
||||
device->mOpenAL.alSourcei( sourceName, AL_SOURCE_RELATIVE, ( buffer->mIs3d ? AL_FALSE : AL_TRUE ) );
|
||||
alSourcei( sourceName, AL_SOURCE_RELATIVE, ( buffer->mIs3d ? AL_FALSE : AL_TRUE ) );
|
||||
|
||||
if( buffer->mIs3d )
|
||||
device->mOpenAL.alSourcef( sourceName, AL_ROLLOFF_FACTOR, device->mRolloffFactor );
|
||||
alSourcef( sourceName, AL_ROLLOFF_FACTOR, device->mRolloffFactor );
|
||||
|
||||
SFXALVoice *voice = new SFXALVoice( device->mOpenAL,
|
||||
buffer,
|
||||
SFXALVoice *voice = new SFXALVoice( buffer,
|
||||
sourceName );
|
||||
|
||||
return voice;
|
||||
}
|
||||
|
||||
SFXALVoice::SFXALVoice( const OPENALFNTABLE &oalft,
|
||||
SFXALBuffer *buffer,
|
||||
SFXALVoice::SFXALVoice( SFXALBuffer *buffer,
|
||||
ALuint sourceName )
|
||||
|
||||
: Parent( buffer ),
|
||||
mSourceName( sourceName ),
|
||||
mResumeAtSampleOffset( -1.0f ),
|
||||
mSampleOffset( 0 ),
|
||||
mOpenAL( oalft )
|
||||
mSampleOffset( 0 )
|
||||
{
|
||||
AL_SANITY_CHECK();
|
||||
}
|
||||
|
||||
SFXALVoice::~SFXALVoice()
|
||||
{
|
||||
mOpenAL.alDeleteSources( 1, &mSourceName );
|
||||
alSourcei(mSourceName, AL_BUFFER, 0);
|
||||
alDeleteSources( 1, &mSourceName );
|
||||
}
|
||||
|
||||
void SFXALVoice::_lateBindStaticBufferIfNecessary()
|
||||
|
|
@ -87,9 +85,9 @@ void SFXALVoice::_lateBindStaticBufferIfNecessary()
|
|||
if( !mBuffer->isStreaming() )
|
||||
{
|
||||
ALint bufferId;
|
||||
mOpenAL.alGetSourcei( mSourceName, AL_BUFFER, &bufferId );
|
||||
alGetSourcei( mSourceName, AL_BUFFER, &bufferId );
|
||||
if( !bufferId )
|
||||
mOpenAL.alSourcei( mSourceName, AL_BUFFER, _getBuffer()->mALBuffer );
|
||||
alSourcei( mSourceName, AL_BUFFER, _getBuffer()->mALBuffer );
|
||||
}
|
||||
}
|
||||
|
||||
|
|
@ -99,7 +97,7 @@ SFXStatus SFXALVoice::_status() const
|
|||
AL_SANITY_CHECK();
|
||||
|
||||
ALint state;
|
||||
mOpenAL.alGetSourcei( mSourceName, AL_SOURCE_STATE, &state );
|
||||
alGetSourcei( mSourceName, AL_SOURCE_STATE, &state );
|
||||
|
||||
switch( state )
|
||||
{
|
||||
|
|
@ -118,18 +116,15 @@ void SFXALVoice::_play()
|
|||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXALVoice] Starting playback" );
|
||||
#endif
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
//send every voice that plays to the alauxiliary slot that has the reverb
|
||||
mOpenAL.alSource3i(mSourceName, AL_AUXILIARY_SEND_FILTER, 1, 0, AL_FILTER_NULL);
|
||||
#endif
|
||||
mOpenAL.alSourcePlay( mSourceName );
|
||||
|
||||
alSourcePlay( mSourceName );
|
||||
|
||||
//WORKAROUND: Adjust play cursor for buggy OAL when resuming playback. Do this after alSourcePlay
|
||||
// as it is the play function that will cause the cursor to jump.
|
||||
|
||||
if( mResumeAtSampleOffset != -1.0f )
|
||||
{
|
||||
mOpenAL.alSourcef( mSourceName, AL_SAMPLE_OFFSET, mResumeAtSampleOffset );
|
||||
alSourcef( mSourceName, AL_SAMPLE_OFFSET, mResumeAtSampleOffset );
|
||||
mResumeAtSampleOffset = -1.0f;
|
||||
}
|
||||
}
|
||||
|
|
@ -142,12 +137,12 @@ void SFXALVoice::_pause()
|
|||
Platform::outputDebugString( "[SFXALVoice] Pausing playback" );
|
||||
#endif
|
||||
|
||||
mOpenAL.alSourcePause( mSourceName );
|
||||
alSourcePause( mSourceName );
|
||||
|
||||
//WORKAROUND: Another workaround for buggy OAL. Resuming playback of a paused source will cause the
|
||||
// play cursor to jump. Save the cursor so we can manually move it into position in _play(). Sigh.
|
||||
|
||||
mOpenAL.alGetSourcef( mSourceName, AL_SAMPLE_OFFSET, &mResumeAtSampleOffset );
|
||||
alGetSourcef( mSourceName, AL_SAMPLE_OFFSET, &mResumeAtSampleOffset );
|
||||
}
|
||||
|
||||
void SFXALVoice::_stop()
|
||||
|
|
@ -158,7 +153,7 @@ void SFXALVoice::_stop()
|
|||
Platform::outputDebugString( "[SFXALVoice] Stopping playback" );
|
||||
#endif
|
||||
|
||||
mOpenAL.alSourceStop( mSourceName );
|
||||
alSourceStop( mSourceName );
|
||||
mSampleOffset = 0;
|
||||
|
||||
mResumeAtSampleOffset = -1.0f;
|
||||
|
|
@ -169,7 +164,7 @@ void SFXALVoice::_seek( U32 sample )
|
|||
AL_SANITY_CHECK();
|
||||
|
||||
_lateBindStaticBufferIfNecessary();
|
||||
mOpenAL.alSourcei( mSourceName, AL_SAMPLE_OFFSET, sample );
|
||||
alSourcei( mSourceName, AL_SAMPLE_OFFSET, sample );
|
||||
|
||||
mResumeAtSampleOffset = -1.0f;
|
||||
}
|
||||
|
|
@ -183,7 +178,7 @@ U32 SFXALVoice::_tell() const
|
|||
mBuffer->write( NULL, 0 );
|
||||
|
||||
ALint pos;
|
||||
mOpenAL.alGetSourcei( mSourceName, AL_SAMPLE_OFFSET, &pos );
|
||||
alGetSourcei( mSourceName, AL_SAMPLE_OFFSET, &pos );
|
||||
return ( pos + mSampleOffset );
|
||||
}
|
||||
|
||||
|
|
@ -191,17 +186,17 @@ void SFXALVoice::setMinMaxDistance( F32 min, F32 max )
|
|||
{
|
||||
AL_SANITY_CHECK();
|
||||
|
||||
mOpenAL.alSourcef( mSourceName, AL_REFERENCE_DISTANCE, min );
|
||||
mOpenAL.alSourcef( mSourceName, AL_MAX_DISTANCE, max );
|
||||
alSourcef( mSourceName, AL_REFERENCE_DISTANCE, min );
|
||||
alSourcef( mSourceName, AL_MAX_DISTANCE, max );
|
||||
}
|
||||
|
||||
void SFXALVoice::play( bool looping )
|
||||
{
|
||||
AL_SANITY_CHECK();
|
||||
|
||||
mOpenAL.alSourceStop( mSourceName );
|
||||
alSourceStop( mSourceName );
|
||||
if( !mBuffer->isStreaming() )
|
||||
mOpenAL.alSourcei( mSourceName, AL_LOOPING, ( looping ? AL_TRUE : AL_FALSE ) );
|
||||
alSourcei( mSourceName, AL_LOOPING, ( looping ? AL_TRUE : AL_FALSE ) );
|
||||
|
||||
Parent::play( looping );
|
||||
}
|
||||
|
|
@ -213,7 +208,7 @@ void SFXALVoice::setVelocity( const VectorF& velocity )
|
|||
// Torque and OpenAL are both right handed
|
||||
// systems, so no coordinate flipping is needed.
|
||||
|
||||
mOpenAL.alSourcefv( mSourceName, AL_VELOCITY, velocity );
|
||||
alSourcefv( mSourceName, AL_VELOCITY, velocity );
|
||||
}
|
||||
|
||||
void SFXALVoice::setTransform( const MatrixF& transform )
|
||||
|
|
@ -227,34 +222,34 @@ void SFXALVoice::setTransform( const MatrixF& transform )
|
|||
transform.getColumn( 3, &pos );
|
||||
transform.getColumn( 1, &dir );
|
||||
|
||||
mOpenAL.alSourcefv( mSourceName, AL_POSITION, pos );
|
||||
mOpenAL.alSourcefv( mSourceName, AL_DIRECTION, dir );
|
||||
alSourcefv( mSourceName, AL_POSITION, pos );
|
||||
alSourcefv( mSourceName, AL_DIRECTION, dir );
|
||||
}
|
||||
|
||||
void SFXALVoice::setVolume( F32 volume )
|
||||
{
|
||||
AL_SANITY_CHECK();
|
||||
|
||||
mOpenAL.alSourcef( mSourceName, AL_GAIN, volume );
|
||||
alSourcef( mSourceName, AL_GAIN, volume );
|
||||
}
|
||||
|
||||
void SFXALVoice::setPitch( F32 pitch )
|
||||
{
|
||||
AL_SANITY_CHECK();
|
||||
|
||||
mOpenAL.alSourcef( mSourceName, AL_PITCH, pitch );
|
||||
alSourcef( mSourceName, AL_PITCH, pitch );
|
||||
}
|
||||
|
||||
void SFXALVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
|
||||
{
|
||||
AL_SANITY_CHECK();
|
||||
|
||||
mOpenAL.alSourcef( mSourceName, AL_CONE_INNER_ANGLE, innerAngle );
|
||||
mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_ANGLE, outerAngle );
|
||||
mOpenAL.alSourcef( mSourceName, AL_CONE_OUTER_GAIN, outerVolume );
|
||||
alSourcef( mSourceName, AL_CONE_INNER_ANGLE, innerAngle );
|
||||
alSourcef( mSourceName, AL_CONE_OUTER_ANGLE, outerAngle );
|
||||
alSourcef( mSourceName, AL_CONE_OUTER_GAIN, outerVolume );
|
||||
}
|
||||
|
||||
void SFXALVoice::setRolloffFactor( F32 factor )
|
||||
{
|
||||
mOpenAL.alSourcef( mSourceName, AL_ROLLOFF_FACTOR, factor );
|
||||
alSourcef( mSourceName, AL_ROLLOFF_FACTOR, factor );
|
||||
}
|
||||
|
|
|
|||
|
|
@ -47,8 +47,7 @@ class SFXALVoice : public SFXVoice
|
|||
|
||||
protected:
|
||||
|
||||
SFXALVoice( const OPENALFNTABLE &oalft,
|
||||
SFXALBuffer *buffer,
|
||||
SFXALVoice( SFXALBuffer *buffer,
|
||||
ALuint sourceName );
|
||||
|
||||
ALuint mSourceName;
|
||||
|
|
@ -65,8 +64,6 @@ class SFXALVoice : public SFXVoice
|
|||
|
||||
Mutex mMutex;
|
||||
|
||||
const OPENALFNTABLE &mOpenAL;
|
||||
|
||||
///
|
||||
SFXALBuffer* _getBuffer() const
|
||||
{
|
||||
|
|
@ -104,4 +101,4 @@ class SFXALVoice : public SFXVoice
|
|||
void setRolloffFactor( F32 factor ) override;
|
||||
};
|
||||
|
||||
#endif // _SFXALVOICE_H_
|
||||
#endif // _SFXALVOICE_H_
|
||||
|
|
|
|||
|
|
@ -1,601 +0,0 @@
|
|||
/*
|
||||
* Copyright (c) 2006, Creative Labs Inc.
|
||||
* All rights reserved.
|
||||
*
|
||||
* Redistribution and use in source and binary forms, with or without modification, are permitted provided
|
||||
* that the following conditions are met:
|
||||
*
|
||||
* * Redistributions of source code must retain the above copyright notice, this list of conditions and
|
||||
* the following disclaimer.
|
||||
* * Redistributions in binary form must reproduce the above copyright notice, this list of conditions
|
||||
* and the following disclaimer in the documentation and/or other materials provided with the distribution.
|
||||
* * Neither the name of Creative Labs Inc. nor the names of its contributors may be used to endorse or
|
||||
* promote products derived from this software without specific prior written permission.
|
||||
*
|
||||
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED
|
||||
* WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
|
||||
* PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR
|
||||
* ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED
|
||||
* TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
|
||||
* HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
|
||||
* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
|
||||
* POSSIBILITY OF SUCH DAMAGE.
|
||||
*/
|
||||
|
||||
#include <windows.h>
|
||||
#include "sfx/openal/LoadOAL.h"
|
||||
|
||||
HINSTANCE g_hOpenALDLL = NULL;
|
||||
|
||||
ALboolean LoadOAL10Library(char *szOALFullPathName, LPOPENALFNTABLE lpOALFnTable)
|
||||
{
|
||||
if (!lpOALFnTable)
|
||||
return AL_FALSE;
|
||||
|
||||
if (szOALFullPathName)
|
||||
g_hOpenALDLL = LoadLibraryA(szOALFullPathName);
|
||||
else
|
||||
{
|
||||
#ifdef TORQUE_DEBUG
|
||||
g_hOpenALDLL = LoadLibraryA("openal32d.dll");
|
||||
#else
|
||||
g_hOpenALDLL = LoadLibraryA("openal32.dll");
|
||||
#endif
|
||||
}
|
||||
if (!g_hOpenALDLL)
|
||||
return AL_FALSE;
|
||||
|
||||
memset(lpOALFnTable, 0, sizeof(OPENALFNTABLE));
|
||||
|
||||
// Get function pointers
|
||||
lpOALFnTable->alEnable = (LPALENABLE)GetProcAddress(g_hOpenALDLL, "alEnable");
|
||||
if (lpOALFnTable->alEnable == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alEnable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDisable = (LPALDISABLE)GetProcAddress(g_hOpenALDLL, "alDisable");
|
||||
if (lpOALFnTable->alDisable == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDisable' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsEnabled = (LPALISENABLED)GetProcAddress(g_hOpenALDLL, "alIsEnabled");
|
||||
if (lpOALFnTable->alIsEnabled == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsEnabled' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBoolean = (LPALGETBOOLEAN)GetProcAddress(g_hOpenALDLL, "alGetBoolean");
|
||||
if (lpOALFnTable->alGetBoolean == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetBoolean' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetInteger = (LPALGETINTEGER)GetProcAddress(g_hOpenALDLL, "alGetInteger");
|
||||
if (lpOALFnTable->alGetInteger == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetInteger' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloat = (LPALGETFLOAT)GetProcAddress(g_hOpenALDLL, "alGetFloat");
|
||||
if (lpOALFnTable->alGetFloat == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetFloat' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDouble = (LPALGETDOUBLE)GetProcAddress(g_hOpenALDLL, "alGetDouble");
|
||||
if (lpOALFnTable->alGetDouble == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetDouble' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBooleanv = (LPALGETBOOLEANV)GetProcAddress(g_hOpenALDLL, "alGetBooleanv");
|
||||
if (lpOALFnTable->alGetBooleanv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetBooleanv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetIntegerv = (LPALGETINTEGERV)GetProcAddress(g_hOpenALDLL, "alGetIntegerv");
|
||||
if (lpOALFnTable->alGetIntegerv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetFloatv = (LPALGETFLOATV)GetProcAddress(g_hOpenALDLL, "alGetFloatv");
|
||||
if (lpOALFnTable->alGetFloatv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetFloatv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetDoublev = (LPALGETDOUBLEV)GetProcAddress(g_hOpenALDLL, "alGetDoublev");
|
||||
if (lpOALFnTable->alGetDoublev == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetDoublev' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetString = (LPALGETSTRING)GetProcAddress(g_hOpenALDLL, "alGetString");
|
||||
if (lpOALFnTable->alGetString == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetError = (LPALGETERROR)GetProcAddress(g_hOpenALDLL, "alGetError");
|
||||
if (lpOALFnTable->alGetError == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsExtensionPresent = (LPALISEXTENSIONPRESENT)GetProcAddress(g_hOpenALDLL, "alIsExtensionPresent");
|
||||
if (lpOALFnTable->alIsExtensionPresent == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetProcAddress = (LPALGETPROCADDRESS)GetProcAddress(g_hOpenALDLL, "alGetProcAddress");
|
||||
if (lpOALFnTable->alGetProcAddress == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetEnumValue = (LPALGETENUMVALUE)GetProcAddress(g_hOpenALDLL, "alGetEnumValue");
|
||||
if (lpOALFnTable->alGetEnumValue == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListeneri = (LPALLISTENERI)GetProcAddress(g_hOpenALDLL, "alListeneri");
|
||||
if (lpOALFnTable->alListeneri == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerf = (LPALLISTENERF)GetProcAddress(g_hOpenALDLL, "alListenerf");
|
||||
if (lpOALFnTable->alListenerf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListener3f = (LPALLISTENER3F)GetProcAddress(g_hOpenALDLL, "alListener3f");
|
||||
if (lpOALFnTable->alListener3f == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alListenerfv = (LPALLISTENERFV)GetProcAddress(g_hOpenALDLL, "alListenerfv");
|
||||
if (lpOALFnTable->alListenerfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListeneri = (LPALGETLISTENERI)GetProcAddress(g_hOpenALDLL, "alGetListeneri");
|
||||
if (lpOALFnTable->alGetListeneri == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetListeneri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerf =(LPALGETLISTENERF)GetProcAddress(g_hOpenALDLL, "alGetListenerf");
|
||||
if (lpOALFnTable->alGetListenerf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetListenerf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListener3f = (LPALGETLISTENER3F)GetProcAddress(g_hOpenALDLL, "alGetListener3f");
|
||||
if (lpOALFnTable->alGetListener3f == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetListener3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetListenerfv = (LPALGETLISTENERFV)GetProcAddress(g_hOpenALDLL, "alGetListenerfv");
|
||||
if (lpOALFnTable->alGetListenerfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetListenerfv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenSources = (LPALGENSOURCES)GetProcAddress(g_hOpenALDLL, "alGenSources");
|
||||
if (lpOALFnTable->alGenSources == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGenSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteSources = (LPALDELETESOURCES)GetProcAddress(g_hOpenALDLL, "alDeleteSources");
|
||||
if (lpOALFnTable->alDeleteSources == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDeleteSources' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsSource = (LPALISSOURCE)GetProcAddress(g_hOpenALDLL, "alIsSource");
|
||||
if (lpOALFnTable->alIsSource == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsSource' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcei = (LPALSOURCEI)GetProcAddress(g_hOpenALDLL, "alSourcei");
|
||||
if (lpOALFnTable->alSourcei == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcef = (LPALSOURCEF)GetProcAddress(g_hOpenALDLL, "alSourcef");
|
||||
if (lpOALFnTable->alSourcef == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSource3f = (LPALSOURCE3F)GetProcAddress(g_hOpenALDLL, "alSource3f");
|
||||
if (lpOALFnTable->alSource3f == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSource3f' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcefv = (LPALSOURCEFV)GetProcAddress(g_hOpenALDLL, "alSourcefv");
|
||||
if (lpOALFnTable->alSourcefv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcei = (LPALGETSOURCEI)GetProcAddress(g_hOpenALDLL, "alGetSourcei");
|
||||
if (lpOALFnTable->alGetSourcei == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetSourcei' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcef = (LPALGETSOURCEF)GetProcAddress(g_hOpenALDLL, "alGetSourcef");
|
||||
if (lpOALFnTable->alGetSourcef == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetSourcef' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetSourcefv = (LPALGETSOURCEFV)GetProcAddress(g_hOpenALDLL, "alGetSourcefv");
|
||||
if (lpOALFnTable->alGetSourcefv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetSourcefv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlayv = (LPALSOURCEPLAYV)GetProcAddress(g_hOpenALDLL, "alSourcePlayv");
|
||||
if (lpOALFnTable->alSourcePlayv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcePlayv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStopv = (LPALSOURCESTOPV)GetProcAddress(g_hOpenALDLL, "alSourceStopv");
|
||||
if (lpOALFnTable->alSourceStopv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourceStopv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePlay = (LPALSOURCEPLAY)GetProcAddress(g_hOpenALDLL, "alSourcePlay");
|
||||
if (lpOALFnTable->alSourcePlay == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcePlay' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourcePause = (LPALSOURCEPAUSE)GetProcAddress(g_hOpenALDLL, "alSourcePause");
|
||||
if (lpOALFnTable->alSourcePause == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourcePause' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceStop = (LPALSOURCESTOP)GetProcAddress(g_hOpenALDLL, "alSourceStop");
|
||||
if (lpOALFnTable->alSourceStop == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourceStop' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceRewind = (LPALSOURCEREWIND)GetProcAddress(g_hOpenALDLL, "alSourceRewind");
|
||||
if (lpOALFnTable->alSourceRewind == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourceRewind' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGenBuffers = (LPALGENBUFFERS)GetProcAddress(g_hOpenALDLL, "alGenBuffers");
|
||||
if (lpOALFnTable->alGenBuffers == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGenBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDeleteBuffers = (LPALDELETEBUFFERS)GetProcAddress(g_hOpenALDLL, "alDeleteBuffers");
|
||||
if (lpOALFnTable->alDeleteBuffers == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDeleteBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alIsBuffer = (LPALISBUFFER)GetProcAddress(g_hOpenALDLL, "alIsBuffer");
|
||||
if (lpOALFnTable->alIsBuffer == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsBuffer' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alBufferData = (LPALBUFFERDATA)GetProcAddress(g_hOpenALDLL, "alBufferData");
|
||||
if (lpOALFnTable->alBufferData == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alBufferData' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferi = (LPALGETBUFFERI)GetProcAddress(g_hOpenALDLL, "alGetBufferi");
|
||||
if (lpOALFnTable->alGetBufferi == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetBufferi' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alGetBufferf = (LPALGETBUFFERF)GetProcAddress(g_hOpenALDLL, "alGetBufferf");
|
||||
if (lpOALFnTable->alGetBufferf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetBufferf' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceQueueBuffers = (LPALSOURCEQUEUEBUFFERS)GetProcAddress(g_hOpenALDLL, "alSourceQueueBuffers");
|
||||
if (lpOALFnTable->alSourceQueueBuffers == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourceQueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alSourceUnqueueBuffers = (LPALSOURCEUNQUEUEBUFFERS)GetProcAddress(g_hOpenALDLL, "alSourceUnqueueBuffers");
|
||||
if (lpOALFnTable->alSourceUnqueueBuffers == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alSourceUnqueueBuffers' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDistanceModel = (LPALDISTANCEMODEL)GetProcAddress(g_hOpenALDLL, "alDistanceModel");
|
||||
if (lpOALFnTable->alDistanceModel == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDistanceModel' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerFactor = (LPALDOPPLERFACTOR)GetProcAddress(g_hOpenALDLL, "alDopplerFactor");
|
||||
if (lpOALFnTable->alDopplerFactor == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDopplerFactor' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alDopplerVelocity = (LPALDOPPLERVELOCITY)GetProcAddress(g_hOpenALDLL, "alDopplerVelocity");
|
||||
if (lpOALFnTable->alDopplerVelocity == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDopplerVelocity' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetString = (LPALCGETSTRING)GetProcAddress(g_hOpenALDLL, "alcGetString");
|
||||
if (lpOALFnTable->alcGetString == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetString' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetIntegerv = (LPALCGETINTEGERV)GetProcAddress(g_hOpenALDLL, "alcGetIntegerv");
|
||||
if (lpOALFnTable->alcGetIntegerv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetIntegerv' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcOpenDevice = (LPALCOPENDEVICE)GetProcAddress(g_hOpenALDLL, "alcOpenDevice");
|
||||
if (lpOALFnTable->alcOpenDevice == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcOpenDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCloseDevice = (LPALCCLOSEDEVICE)GetProcAddress(g_hOpenALDLL, "alcCloseDevice");
|
||||
if (lpOALFnTable->alcCloseDevice == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcCloseDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcCreateContext = (LPALCCREATECONTEXT)GetProcAddress(g_hOpenALDLL, "alcCreateContext");
|
||||
if (lpOALFnTable->alcCreateContext == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcCreateContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcMakeContextCurrent = (LPALCMAKECONTEXTCURRENT)GetProcAddress(g_hOpenALDLL, "alcMakeContextCurrent");
|
||||
if (lpOALFnTable->alcMakeContextCurrent == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcMakeContextCurrent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcProcessContext = (LPALCPROCESSCONTEXT)GetProcAddress(g_hOpenALDLL, "alcProcessContext");
|
||||
if (lpOALFnTable->alcProcessContext == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcProcessContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetCurrentContext = (LPALCGETCURRENTCONTEXT)GetProcAddress(g_hOpenALDLL, "alcGetCurrentContext");
|
||||
if (lpOALFnTable->alcGetCurrentContext == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetCurrentContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetContextsDevice = (LPALCGETCONTEXTSDEVICE)GetProcAddress(g_hOpenALDLL, "alcGetContextsDevice");
|
||||
if (lpOALFnTable->alcGetContextsDevice == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetContextsDevice' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcSuspendContext = (LPALCSUSPENDCONTEXT)GetProcAddress(g_hOpenALDLL, "alcSuspendContext");
|
||||
if (lpOALFnTable->alcSuspendContext == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcSuspendContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcDestroyContext = (LPALCDESTROYCONTEXT)GetProcAddress(g_hOpenALDLL, "alcDestroyContext");
|
||||
if (lpOALFnTable->alcDestroyContext == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcDestroyContext' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetError = (LPALCGETERROR)GetProcAddress(g_hOpenALDLL, "alcGetError");
|
||||
if (lpOALFnTable->alcGetError == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetError' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcIsExtensionPresent = (LPALCISEXTENSIONPRESENT)GetProcAddress(g_hOpenALDLL, "alcIsExtensionPresent");
|
||||
if (lpOALFnTable->alcIsExtensionPresent == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcIsExtensionPresent' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetProcAddress = (LPALCGETPROCADDRESS)GetProcAddress(g_hOpenALDLL, "alcGetProcAddress");
|
||||
if (lpOALFnTable->alcGetProcAddress == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetProcAddress' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
lpOALFnTable->alcGetEnumValue = (LPALCGETENUMVALUE)GetProcAddress(g_hOpenALDLL, "alcGetEnumValue");
|
||||
if (lpOALFnTable->alcGetEnumValue == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetEnumValue' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
#if defined(AL_ALEXT_PROTOTYPES)
|
||||
lpOALFnTable->alGenEffects = (LPALGENEFFECTS)GetProcAddress(g_hOpenALDLL, "alGenEffects");
|
||||
if (lpOALFnTable->alGenEffects == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGenEffects' function address\n");
|
||||
}
|
||||
lpOALFnTable->alEffecti = (LPALEFFECTI)GetProcAddress(g_hOpenALDLL, "alEffecti");
|
||||
if (lpOALFnTable->alEffecti == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alEffecti' function address\n");
|
||||
}
|
||||
lpOALFnTable->alEffectiv = (LPALEFFECTIV)GetProcAddress(g_hOpenALDLL, "alEffectiv");
|
||||
if (lpOALFnTable->alEffectiv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alEffectiv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alEffectf = (LPALEFFECTF)GetProcAddress(g_hOpenALDLL, "alEffectf");
|
||||
if (lpOALFnTable->alEffectf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alEffectf' function address\n");
|
||||
}
|
||||
lpOALFnTable->alEffectfv = (LPALEFFECTFV)GetProcAddress(g_hOpenALDLL, "alEffectfv");
|
||||
if (lpOALFnTable->alEffectfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alEffectfv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetEffecti = (LPALGETEFFECTI)GetProcAddress(g_hOpenALDLL, "alGetEffecti");
|
||||
if (lpOALFnTable->alGetEffecti == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetEffecti' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetEffectiv = (LPALGETEFFECTIV)GetProcAddress(g_hOpenALDLL, "alGetEffectiv");
|
||||
if (lpOALFnTable->alGetEffectiv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetEffectiv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetEffectf = (LPALGETEFFECTF)GetProcAddress(g_hOpenALDLL, "alGetEffectf");
|
||||
if (lpOALFnTable->alGetEffectf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetEffectf' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetEffectfv = (LPALGETEFFECTFV)GetProcAddress(g_hOpenALDLL, "alGetEffectfv");
|
||||
if (lpOALFnTable->alGetEffectfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetEffectfv' function address\n");
|
||||
}
|
||||
|
||||
lpOALFnTable->alDeleteEffects = (LPALDELETEEFFECTS)GetProcAddress(g_hOpenALDLL, "alDeleteEffects");
|
||||
if (lpOALFnTable->alDeleteEffects == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDeleteEffects' function address\n");
|
||||
}
|
||||
lpOALFnTable->alIsEffect = (LPALISEFFECT)GetProcAddress(g_hOpenALDLL, "alIsEffect");
|
||||
if (lpOALFnTable->alIsEffect == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsEffect' function address\n");
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotf = (LPALAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotf' function address\n");
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotfv = (LPALAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotfv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSloti = (LPALAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSloti' function address\n");
|
||||
}
|
||||
lpOALFnTable->alAuxiliaryEffectSlotiv = (LPALAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alAuxiliaryEffectSlotiv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alIsAuxiliaryEffectSlot = (LPALISAUXILIARYEFFECTSLOT)GetProcAddress(g_hOpenALDLL, "alIsAuxiliaryEffectSlot");
|
||||
if (lpOALFnTable->alIsAuxiliaryEffectSlot == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alIsAuxiliaryEffectSlot' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGenAuxiliaryEffectSlots = (LPALGENAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alGenAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alGenAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGenAuxiliaryEffectSlots' function address\n");
|
||||
}
|
||||
lpOALFnTable->alDeleteAuxiliaryEffectSlots = (LPALDELETEAUXILIARYEFFECTSLOTS)GetProcAddress(g_hOpenALDLL, "alDeleteAuxiliaryEffectSlots");
|
||||
if (lpOALFnTable->alDeleteAuxiliaryEffectSlots == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDeleteAuxiliaryEffectSlots' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotf = (LPALGETAUXILIARYEFFECTSLOTF)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotf");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotf == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotf' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotfv = (LPALGETAUXILIARYEFFECTSLOTFV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotfv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotfv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotfv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSloti = (LPALGETAUXILIARYEFFECTSLOTI)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSloti");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSloti == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSloti' function address\n");
|
||||
}
|
||||
lpOALFnTable->alGetAuxiliaryEffectSlotiv = (LPALGETAUXILIARYEFFECTSLOTIV)GetProcAddress(g_hOpenALDLL, "alGetAuxiliaryEffectSlotiv");
|
||||
if (lpOALFnTable->alGetAuxiliaryEffectSlotiv == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGetAuxiliaryEffectSlotiv' function address\n");
|
||||
}
|
||||
lpOALFnTable->alSource3i = (LPALSOURCE3I)GetProcAddress(g_hOpenALDLL, "alSource3i");
|
||||
|
||||
lpOALFnTable->alGenFilters = (LPALGENFILTERS)GetProcAddress(g_hOpenALDLL, "alGenFilters");
|
||||
if (lpOALFnTable->alGenFilters == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alGenFilters' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
lpOALFnTable->alDeleteFilters = (LPALDELETEFILTERS)GetProcAddress(g_hOpenALDLL, "alDeleteFilters");
|
||||
if (lpOALFnTable->alGenFilters == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alDeleteFilters' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
lpOALFnTable->alFilteri = (LPALFILTERI)GetProcAddress(g_hOpenALDLL, "alFilteri");
|
||||
if (lpOALFnTable->alGenFilters == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alFilteri' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
lpOALFnTable->alcGetStringiSOFT = (LPALCGETSTRINGISOFT)GetProcAddress(g_hOpenALDLL, "alcGetStringiSOFT");
|
||||
if (lpOALFnTable->alcGetStringiSOFT == NULL)
|
||||
{
|
||||
OutputDebugStringA("Failed to retrieve 'alcGetStringiSOFT' function address\n");
|
||||
return AL_FALSE;
|
||||
}
|
||||
|
||||
#endif
|
||||
return AL_TRUE;
|
||||
}
|
||||
|
||||
ALvoid UnloadOAL10Library()
|
||||
{
|
||||
// Unload the dll
|
||||
if (g_hOpenALDLL)
|
||||
{
|
||||
FreeLibrary(g_hOpenALDLL);
|
||||
g_hOpenALDLL = NULL;
|
||||
}
|
||||
}
|
||||
|
|
@ -85,6 +85,7 @@ SFXAmbience::ChangeSignal SFXAmbience::smChangeSignal;
|
|||
SFXAmbience::SFXAmbience()
|
||||
: mDopplerFactor( 0.5f ),
|
||||
mRolloffFactor( 1.f ),
|
||||
mSpeedOfSound(343.3f),
|
||||
mEnvironment( NULL )
|
||||
{
|
||||
dMemset( mState, 0, sizeof( mState ) );
|
||||
|
|
@ -112,6 +113,10 @@ void SFXAmbience::initPersistFields()
|
|||
"The factor to apply to the doppler affect in this space.\n"
|
||||
"Defaults to 0.5.\n\n"
|
||||
"@ref SFXSource_doppler" );
|
||||
addFieldV("speedOfSound", TypeRangedF32, Offset(mSpeedOfSound, SFXAmbience), &CommonValidators::PositiveFloat,
|
||||
"The speed of sound in this space.\n"
|
||||
"Defaults to 343.3.\n\n"
|
||||
"@ref SFXSource_speedofsound");
|
||||
addField( "states", TypeSFXStateName, Offset( mState, SFXAmbience ),
|
||||
MaxStates,
|
||||
"States to activate when the ambient zone is entered.\n"
|
||||
|
|
@ -177,6 +182,7 @@ void SFXAmbience::packData( BitStream* stream )
|
|||
|
||||
stream->write( mRolloffFactor );
|
||||
stream->write( mDopplerFactor );
|
||||
stream->write(mSpeedOfSound);
|
||||
|
||||
for( U32 i = 0; i < MaxStates; ++ i )
|
||||
sfxWrite( stream, mState[ i ] );
|
||||
|
|
@ -193,6 +199,7 @@ void SFXAmbience::unpackData( BitStream* stream )
|
|||
|
||||
stream->read( &mRolloffFactor );
|
||||
stream->read( &mDopplerFactor );
|
||||
stream->read(&mSpeedOfSound);
|
||||
|
||||
for( U32 i = 0; i < MaxStates; ++ i )
|
||||
sfxRead( stream, &mState[ i ] );
|
||||
|
|
|
|||
|
|
@ -61,6 +61,9 @@ class SFXAmbience : public SimDataBlock
|
|||
|
||||
/// Doppler shift factor for this space.
|
||||
F32 mDopplerFactor;
|
||||
|
||||
/// Speed of sound for this space.
|
||||
F32 mSpeedOfSound;
|
||||
|
||||
/// Rolloff factor for this space. Only applies to logarithmic distance model.
|
||||
F32 mRolloffFactor;
|
||||
|
|
@ -90,6 +93,8 @@ class SFXAmbience : public SimDataBlock
|
|||
|
||||
/// Return the doppler shift factor to apply in this space.
|
||||
F32 getDopplerFactor() const { return mDopplerFactor; }
|
||||
|
||||
F32 getSpeedOfSound() const { return mSpeedOfSound; }
|
||||
|
||||
/// Return the reverb environment of the ambient space.
|
||||
SFXEnvironment* getEnvironment() const { return mEnvironment; }
|
||||
|
|
|
|||
|
|
@ -24,25 +24,25 @@
|
|||
#define _SFXCOMMON_H_
|
||||
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _MMATHFN_H_
|
||||
#include "math/mMathFn.h"
|
||||
#include "math/mMathFn.h"
|
||||
#endif
|
||||
#ifndef _MRANDOM_H_
|
||||
#include "math/mRandom.h"
|
||||
#include "math/mRandom.h"
|
||||
#endif
|
||||
#ifndef _MMATRIX_H_
|
||||
#include "math/mMatrix.h"
|
||||
#include "math/mMatrix.h"
|
||||
#endif
|
||||
#ifndef _MPOINT3_H_
|
||||
#include "math/mPoint3.h"
|
||||
#include "math/mPoint3.h"
|
||||
#endif
|
||||
#ifndef _TYPETRAITS_H_
|
||||
#include "platform/typetraits.h"
|
||||
#include "platform/typetraits.h"
|
||||
#endif
|
||||
#ifndef _DYNAMIC_CONSOLETYPES_H_
|
||||
#include "console/dynamicTypes.h"
|
||||
#include "console/dynamicTypes.h"
|
||||
#endif
|
||||
|
||||
|
||||
|
|
@ -51,13 +51,37 @@ class SFXEnvironment;
|
|||
class SFXPlayList;
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFXProviderType.
|
||||
//-----------------------------------------------------------------------------
|
||||
enum SFXProviderType
|
||||
{
|
||||
OpenAL,
|
||||
XAudio,
|
||||
DirectSound,
|
||||
NullProvider,
|
||||
SFXProviderType_Count
|
||||
};
|
||||
DefineEnumType(SFXProviderType);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFXDeviceType.
|
||||
//-----------------------------------------------------------------------------
|
||||
enum SFXDeviceType
|
||||
{
|
||||
Output,
|
||||
Input,
|
||||
SFXDeviceType_Count
|
||||
};
|
||||
DefineEnumType(SFXDeviceType);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFXStatus.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
/// The sound playback state.
|
||||
enum SFXStatus
|
||||
enum SFXStatus
|
||||
{
|
||||
/// Initial state; no operation yet performed on sound.
|
||||
SFXStatusNull,
|
||||
|
|
@ -83,23 +107,23 @@ enum SFXStatus
|
|||
SFXStatusTransition,
|
||||
};
|
||||
|
||||
DefineEnumType( SFXStatus );
|
||||
DefineEnumType(SFXStatus);
|
||||
|
||||
|
||||
inline const char* SFXStatusToString( SFXStatus status )
|
||||
inline const char* SFXStatusToString(SFXStatus status)
|
||||
{
|
||||
switch ( status )
|
||||
switch (status)
|
||||
{
|
||||
case SFXStatusPlaying: return "playing";
|
||||
case SFXStatusStopped: return "stopped";
|
||||
case SFXStatusPaused: return "paused";
|
||||
case SFXStatusBlocked: return "blocked";
|
||||
case SFXStatusTransition: return "transition";
|
||||
|
||||
case SFXStatusNull:
|
||||
default: ;
|
||||
case SFXStatusPlaying: return "playing";
|
||||
case SFXStatusStopped: return "stopped";
|
||||
case SFXStatusPaused: return "paused";
|
||||
case SFXStatusBlocked: return "blocked";
|
||||
case SFXStatusTransition: return "transition";
|
||||
|
||||
case SFXStatusNull:
|
||||
default:;
|
||||
}
|
||||
|
||||
|
||||
return "null";
|
||||
}
|
||||
|
||||
|
|
@ -135,12 +159,12 @@ enum SFXChannel
|
|||
SFXChannelUser1,
|
||||
SFXChannelUser2,
|
||||
SFXChannelUser3,
|
||||
|
||||
|
||||
/// Total number of animatable channels.
|
||||
SFX_NUM_CHANNELS
|
||||
};
|
||||
|
||||
DefineEnumType( SFXChannel );
|
||||
DefineEnumType(SFXChannel);
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -156,7 +180,7 @@ enum SFXDistanceModel
|
|||
SFXDistanceModelExponent, /// exponential falloff for distance attenuation.
|
||||
};
|
||||
|
||||
DefineEnumType( SFXDistanceModel );
|
||||
DefineEnumType(SFXDistanceModel);
|
||||
|
||||
/// Compute the distance attenuation based on the given distance model.
|
||||
///
|
||||
|
|
@ -167,46 +191,52 @@ DefineEnumType( SFXDistanceModel );
|
|||
/// @param rolloffFactor Rolloff curve scale factor.
|
||||
///
|
||||
/// @return The attenuated volume.
|
||||
inline F32 SFXDistanceAttenuation( SFXDistanceModel model, F32 minDistance, F32 maxDistance, F32 distance, F32 volume, F32 rolloffFactor )
|
||||
inline F32 SFXDistanceAttenuation(SFXDistanceModel model, F32 minDistance, F32 maxDistance, F32 distance, F32 volume, F32 rolloffFactor)
|
||||
{
|
||||
F32 gain = 1.0f;
|
||||
|
||||
switch( model )
|
||||
|
||||
switch (model)
|
||||
{
|
||||
case SFXDistanceModelLinear:
|
||||
|
||||
distance = getMax( distance, minDistance );
|
||||
distance = getMin( distance, maxDistance );
|
||||
|
||||
gain = ( 1 - ( distance - minDistance ) / ( maxDistance - minDistance ) );
|
||||
break;
|
||||
|
||||
case SFXDistanceModelLogarithmic:
|
||||
|
||||
distance = getMax( distance, minDistance );
|
||||
distance = getMin( distance, maxDistance );
|
||||
|
||||
gain = minDistance / ( minDistance + rolloffFactor * ( distance - minDistance ) );
|
||||
break;
|
||||
case SFXDistanceModelLinear:
|
||||
|
||||
///create exponential distance model
|
||||
case SFXDistanceModelExponent:
|
||||
distance = getMax(distance, minDistance);
|
||||
distance = getMin(distance, maxDistance);
|
||||
distance = getMax(distance, minDistance);
|
||||
distance = getMin(distance, maxDistance);
|
||||
|
||||
gain = (1 - rolloffFactor * (distance - minDistance) / (maxDistance - minDistance));
|
||||
break;
|
||||
|
||||
case SFXDistanceModelLogarithmic:
|
||||
|
||||
distance = getMax(distance, minDistance);
|
||||
distance = getMin(distance, maxDistance);
|
||||
|
||||
gain = minDistance / (minDistance + rolloffFactor * (distance - minDistance));
|
||||
break;
|
||||
|
||||
///create exponential distance model
|
||||
case SFXDistanceModelExponent:
|
||||
distance = getMax(distance, minDistance);
|
||||
distance = getMin(distance, maxDistance);
|
||||
|
||||
gain = pow((distance / minDistance), (-rolloffFactor));
|
||||
break;
|
||||
|
||||
gain = pow((distance / minDistance), (-rolloffFactor));
|
||||
break;
|
||||
|
||||
}
|
||||
|
||||
return ( volume * gain );
|
||||
|
||||
return (volume * gain);
|
||||
}
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// SFXFormat.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum SFXSampleType {
|
||||
Sample_Int8,
|
||||
Sample_Int16,
|
||||
Sample_Float,
|
||||
Sample_IMA4,
|
||||
Sample_MSADPCM
|
||||
};
|
||||
|
||||
/// This class defines the various types of sound data that may be
|
||||
/// used in the sound system.
|
||||
|
|
@ -216,101 +246,111 @@ inline F32 SFXDistanceAttenuation( SFXDistanceModel model, F32 minDistance, F32
|
|||
/// channel.
|
||||
class SFXFormat
|
||||
{
|
||||
protected:
|
||||
protected:
|
||||
|
||||
/// The number of sound channels in the data.
|
||||
U8 mChannels;
|
||||
/// The number of sound channels in the data.
|
||||
U8 mChannels;
|
||||
|
||||
/// The number of bits per sound sample.
|
||||
U8 mBitsPerSample;
|
||||
/// The number of bits per sound sample.
|
||||
U8 mBitsPerSample;
|
||||
|
||||
/// The frequency in samples per second.
|
||||
U32 mSamplesPerSecond;
|
||||
/// The frequency in samples per second.
|
||||
U32 mSamplesPerSecond;
|
||||
|
||||
public:
|
||||
SFXSampleType mSampleType;
|
||||
public:
|
||||
|
||||
SFXFormat( U8 channels = 0,
|
||||
U8 bitsPerSample = 0,
|
||||
U32 samplesPerSecond = 0 )
|
||||
: mChannels( channels ),
|
||||
mBitsPerSample( bitsPerSample ),
|
||||
mSamplesPerSecond( samplesPerSecond )
|
||||
{}
|
||||
SFXFormat(U8 channels = 0,
|
||||
U8 bitsPerSample = 0,
|
||||
U32 samplesPerSecond = 0)
|
||||
: mChannels(channels),
|
||||
mBitsPerSample(bitsPerSample),
|
||||
mSamplesPerSecond(samplesPerSecond),
|
||||
mSampleType(SFXSampleType::Sample_Int16)
|
||||
{
|
||||
}
|
||||
|
||||
/// Copy constructor.
|
||||
SFXFormat( const SFXFormat &format )
|
||||
: mChannels( format.mChannels ),
|
||||
mBitsPerSample( format.mBitsPerSample ),
|
||||
mSamplesPerSecond( format.mSamplesPerSecond )
|
||||
{}
|
||||
/// Copy constructor.
|
||||
SFXFormat(const SFXFormat& format)
|
||||
: mChannels(format.mChannels),
|
||||
mBitsPerSample(format.mBitsPerSample),
|
||||
mSamplesPerSecond(format.mSamplesPerSecond),
|
||||
mSampleType(format.mSampleType)
|
||||
{
|
||||
}
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/// Sets the format.
|
||||
void set( U8 channels,
|
||||
U8 bitsPerSample,
|
||||
U32 samplesPerSecond )
|
||||
{
|
||||
mChannels = channels;
|
||||
mBitsPerSample = bitsPerSample;
|
||||
mSamplesPerSecond = samplesPerSecond;
|
||||
}
|
||||
/// Sets the format.
|
||||
void set(U8 channels,
|
||||
U8 bitsPerSample,
|
||||
U32 samplesPerSecond,
|
||||
SFXSampleType sampleType = Sample_Int16)
|
||||
{
|
||||
mChannels = channels;
|
||||
mBitsPerSample = bitsPerSample;
|
||||
mSamplesPerSecond = samplesPerSecond;
|
||||
mSampleType = sampleType;
|
||||
}
|
||||
|
||||
/// Comparision between formats.
|
||||
bool operator == ( const SFXFormat& format ) const
|
||||
{
|
||||
return mChannels == format.mChannels &&
|
||||
mBitsPerSample == format.mBitsPerSample &&
|
||||
mSamplesPerSecond == format.mSamplesPerSecond;
|
||||
}
|
||||
/// Comparision between formats.
|
||||
bool operator == (const SFXFormat& format) const
|
||||
{
|
||||
return mChannels == format.mChannels &&
|
||||
mBitsPerSample == format.mBitsPerSample &&
|
||||
mSamplesPerSecond == format.mSamplesPerSecond &&
|
||||
mSampleType == format.mSampleType;
|
||||
}
|
||||
|
||||
/// Returns the number of sound channels.
|
||||
U8 getChannels() const { return mChannels; }
|
||||
/// Returns the number of sound channels.
|
||||
U8 getChannels() const { return mChannels; }
|
||||
|
||||
/// Returns true if there is a single sound channel.
|
||||
bool isMono() const { return mChannels == 1; }
|
||||
/// Returns true if there is a single sound channel.
|
||||
bool isMono() const { return mChannels == 1; }
|
||||
|
||||
/// Is true if there are two sound channels.
|
||||
bool isStereo() const { return mChannels == 2; }
|
||||
/// Is true if there are two sound channels.
|
||||
bool isStereo() const { return mChannels == 2; }
|
||||
|
||||
/// Is true if there are more than two sound channels.
|
||||
bool isMultiChannel() const { return mChannels > 2; }
|
||||
/// Is true if there are more than two sound channels.
|
||||
bool isMultiChannel() const { return mChannels > 2; }
|
||||
|
||||
///
|
||||
U32 getSamplesPerSecond() const { return mSamplesPerSecond; }
|
||||
///
|
||||
U32 getSamplesPerSecond() const { return mSamplesPerSecond; }
|
||||
|
||||
/// The bits of data per channel.
|
||||
U8 getBitsPerChannel() const { return mBitsPerSample / mChannels; }
|
||||
/// The bits of data per channel.
|
||||
U8 getBitsPerChannel() const { return mBitsPerSample / mChannels; }
|
||||
|
||||
/// The number of bytes of data per channel.
|
||||
U8 getBytesPerChannel() const { return getBitsPerChannel() / 8; }
|
||||
/// The number of bytes of data per channel.
|
||||
U8 getBytesPerChannel() const { return getBitsPerChannel() / 8; }
|
||||
|
||||
/// The number of bits per sound sample.
|
||||
U8 getBitsPerSample() const { return mBitsPerSample; }
|
||||
/// The number of bits per sound sample.
|
||||
U8 getBitsPerSample() const { return mBitsPerSample; }
|
||||
|
||||
/// The number of bytes of data per sample.
|
||||
/// @note Be aware that this comprises all channels.
|
||||
U8 getBytesPerSample() const { return mBitsPerSample / 8; }
|
||||
SFXSampleType getSampleType() const { return mSampleType; }
|
||||
|
||||
/// Returns the duration from the sample count.
|
||||
U32 getDuration( U32 samples ) const
|
||||
{
|
||||
// Use 64bit types to avoid overflow during division.
|
||||
return ( (U64)samples * (U64)1000 ) / (U64)mSamplesPerSecond;
|
||||
}
|
||||
/// The number of bytes of data per sample.
|
||||
/// @note Be aware that this comprises all channels.
|
||||
U8 getBytesPerSample() const { return mBitsPerSample / 8; }
|
||||
|
||||
///
|
||||
U32 getSampleCount( U32 ms ) const
|
||||
{
|
||||
return U64( mSamplesPerSecond ) * U64( ms ) / U64( 1000 );
|
||||
}
|
||||
/// Returns the duration from the sample count.
|
||||
U32 getDuration(U32 samples) const
|
||||
{
|
||||
// Use 64bit types to avoid overflow during division.
|
||||
return ((U64)samples * (U64)1000) / (U64)mSamplesPerSecond;
|
||||
}
|
||||
|
||||
/// Returns the data length in bytes.
|
||||
U32 getDataLength( U32 ms ) const
|
||||
{
|
||||
U32 bytes = ( ( (U64)ms * (U64)mSamplesPerSecond ) * (U64)getBytesPerSample() ) / (U64)1000;
|
||||
return bytes;
|
||||
}
|
||||
///
|
||||
U32 getSampleCount(U32 ms) const
|
||||
{
|
||||
return U64(mSamplesPerSecond) * U64(ms) / U64(1000);
|
||||
}
|
||||
|
||||
/// Returns the data length in bytes.
|
||||
U32 getDataLength(U32 ms) const
|
||||
{
|
||||
U32 bytes = (((U64)ms * (U64)mSamplesPerSecond) * (U64)getBytesPerSample()) / (U64)1000;
|
||||
return bytes;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -363,8 +403,8 @@ public:
|
|||
flGain = 0.0f;
|
||||
flGainHF = 0.0f;
|
||||
flGainLF = 0.0000f;
|
||||
flDecayTime = 0.0f;
|
||||
flDecayHFRatio = 0.0f;
|
||||
flDecayTime = 0.1f;
|
||||
flDecayHFRatio = 0.1f;
|
||||
flDecayLFRatio = 0.0f;
|
||||
flReflectionsGain = 0.0f;
|
||||
flReflectionsDelay = 0.0f;
|
||||
|
|
@ -372,15 +412,17 @@ public:
|
|||
flLateReverbGain = 0.0f;
|
||||
flLateReverbDelay = 0.0f;
|
||||
dMemset(flLateReverbPan, 0, sizeof(flLateReverbPan));
|
||||
flEchoTime = 0.0f;
|
||||
flEchoTime = 0.075f;
|
||||
flEchoDepth = 0.0f;
|
||||
flModulationTime = 0.0f;
|
||||
flModulationTime = 0.04f;
|
||||
flModulationDepth = 0.0f;
|
||||
flAirAbsorptionGainHF = 0.0f;
|
||||
flAirAbsorptionGainHF = 0.892f;
|
||||
flHFReference = 0.0f;
|
||||
flLFReference = 0.0f;
|
||||
flRoomRolloffFactor = 0.0f;
|
||||
iDecayHFLimit = 0;
|
||||
|
||||
validate();
|
||||
}
|
||||
|
||||
void validate()
|
||||
|
|
@ -528,31 +570,33 @@ public:
|
|||
///
|
||||
class SFXListenerProperties
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void Parent;
|
||||
|
||||
/// Position and orientation of the listener.
|
||||
MatrixF mTransform;
|
||||
|
||||
///
|
||||
Point3F mVelocity;
|
||||
public:
|
||||
|
||||
SFXListenerProperties()
|
||||
: mTransform( true ),
|
||||
mVelocity( 0.0f, 0.0f, 0.0f ) {}
|
||||
|
||||
SFXListenerProperties( const MatrixF& transform, const Point3F& velocity )
|
||||
: mTransform( transform ),
|
||||
mVelocity( velocity ) {}
|
||||
|
||||
///
|
||||
const MatrixF& getTransform() const { return mTransform; }
|
||||
MatrixF& getTransform() { return mTransform; }
|
||||
|
||||
///
|
||||
const Point3F& getVelocity() const { return mVelocity; }
|
||||
Point3F& getVelocity() { return mVelocity; }
|
||||
typedef void Parent;
|
||||
|
||||
/// Position and orientation of the listener.
|
||||
MatrixF mTransform;
|
||||
|
||||
///
|
||||
Point3F mVelocity;
|
||||
|
||||
SFXListenerProperties()
|
||||
: mTransform(true),
|
||||
mVelocity(0.0f, 0.0f, 0.0f) {
|
||||
}
|
||||
|
||||
SFXListenerProperties(const MatrixF& transform, const Point3F& velocity)
|
||||
: mTransform(transform),
|
||||
mVelocity(velocity) {
|
||||
}
|
||||
|
||||
///
|
||||
const MatrixF& getTransform() const { return mTransform; }
|
||||
MatrixF& getTransform() { return mTransform; }
|
||||
|
||||
///
|
||||
const Point3F& getVelocity() const { return mVelocity; }
|
||||
Point3F& getVelocity() { return mVelocity; }
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -564,29 +608,30 @@ class SFXListenerProperties
|
|||
///
|
||||
class SFXMaterialProperties
|
||||
{
|
||||
public:
|
||||
|
||||
typedef void Parent;
|
||||
|
||||
///
|
||||
bool mDoubleSided;
|
||||
|
||||
///
|
||||
F32 mDirectOcclusion;
|
||||
|
||||
///
|
||||
F32 mReverbOcclusion;
|
||||
|
||||
SFXMaterialProperties()
|
||||
: mDoubleSided( false ),
|
||||
mDirectOcclusion( 0.5f ),
|
||||
mReverbOcclusion( 0.5f ) {}
|
||||
|
||||
void validate()
|
||||
{
|
||||
mDirectOcclusion = mClampF( mDirectOcclusion, 0.0f, 1.0f );
|
||||
mReverbOcclusion = mClampF( mReverbOcclusion, 0.0f, 1.0f );
|
||||
}
|
||||
public:
|
||||
|
||||
typedef void Parent;
|
||||
|
||||
///
|
||||
bool mDoubleSided;
|
||||
|
||||
///
|
||||
F32 mDirectOcclusion;
|
||||
|
||||
///
|
||||
F32 mReverbOcclusion;
|
||||
|
||||
SFXMaterialProperties()
|
||||
: mDoubleSided(false),
|
||||
mDirectOcclusion(0.5f),
|
||||
mReverbOcclusion(0.5f) {
|
||||
}
|
||||
|
||||
void validate()
|
||||
{
|
||||
mDirectOcclusion = mClampF(mDirectOcclusion, 0.0f, 1.0f);
|
||||
mReverbOcclusion = mClampF(mReverbOcclusion, 0.0f, 1.0f);
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
@ -600,28 +645,28 @@ template< S32 NUM_VALUES >
|
|||
struct SFXVariantFloat
|
||||
{
|
||||
/// Base value.
|
||||
F32 mValue[ NUM_VALUES ];
|
||||
|
||||
F32 mValue[NUM_VALUES];
|
||||
|
||||
/// Variance of value. Final value will be
|
||||
///
|
||||
/// mClampF( randF( mValue + mVariance[ 0 ], mValue + mVariance[ 1 ] ), min, max )
|
||||
///
|
||||
/// with min and max being dependent on the context of the value.
|
||||
F32 mVariance[ NUM_VALUES ][ 2 ];
|
||||
|
||||
F32 getValue( U32 index = 0, F32 min = TypeTraits< F32 >::MIN, F32 max = TypeTraits< F32 >::MAX ) const
|
||||
F32 mVariance[NUM_VALUES][2];
|
||||
|
||||
F32 getValue(U32 index = 0, F32 min = TypeTraits< F32 >::MIN, F32 max = TypeTraits< F32 >::MAX) const
|
||||
{
|
||||
AssertFatal( index < NUM_VALUES, "SFXVariantFloat::getValue() - index out of range!" );
|
||||
|
||||
return mClampF( gRandGen.randF( mValue[ index ] + mVariance[ index ][ 0 ],
|
||||
mValue[ index ] + mVariance[ index ][ 1 ] ),
|
||||
min, max );
|
||||
AssertFatal(index < NUM_VALUES, "SFXVariantFloat::getValue() - index out of range!");
|
||||
|
||||
return mClampF(gRandGen.randF(mValue[index] + mVariance[index][0],
|
||||
mValue[index] + mVariance[index][1]),
|
||||
min, max);
|
||||
}
|
||||
|
||||
|
||||
void validate()
|
||||
{
|
||||
for( U32 i = 0; i < NUM_VALUES; ++ i )
|
||||
mVariance[ i ][ 0 ] = getMin( mVariance[ i ][ 0 ], mVariance[ i ][ 1 ] );
|
||||
for (U32 i = 0; i < NUM_VALUES; ++i)
|
||||
mVariance[i][0] = getMin(mVariance[i][0], mVariance[i][1]);
|
||||
}
|
||||
};
|
||||
|
||||
|
|
|
|||
|
|
@ -29,20 +29,36 @@
|
|||
#include "console/consoleTypes.h"
|
||||
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
S32 SFXDevice::smUpdateInterval = SFXInternal::DEFAULT_UPDATE_INTERVAL;
|
||||
S32 SFXDevice::smDeviceFrequency = 44100;
|
||||
S8 SFXDevice::smDeviceBitrate = 16;
|
||||
bool SFXDevice::smDeviceHRTF = false;
|
||||
|
||||
SFXDevice::SFXDevice( const String& name, SFXProvider* provider, bool useHardware, S32 maxBuffers )
|
||||
: mName( name ),
|
||||
mProvider( provider ),
|
||||
mUseHardware( useHardware ),
|
||||
mMaxBuffers( maxBuffers ),
|
||||
mCaps( 0 ),
|
||||
mStatNumBuffers( 0 ),
|
||||
void SFXDevice::initConsole()
|
||||
{
|
||||
// Add global preferences for sfx devices.
|
||||
Con::addVariable("$pref::SFX::bitrate", TypeS8, &smDeviceBitrate,
|
||||
"The devices bitrate.\n"
|
||||
"@ingroup SFX\n");
|
||||
|
||||
Con::addVariable("$pref::SFX::frequency", TypeS32, &smDeviceFrequency,
|
||||
"The devices frequency.\n"
|
||||
"@ingroup SFX\n");
|
||||
|
||||
Con::addVariable("$pref::SFX::useHRTF", TypeBool, &smDeviceHRTF,
|
||||
"The device uses hrtf.\n"
|
||||
"@ingroup SFX\n");
|
||||
|
||||
Con::addVariable("$pref::SFX::updateInterval", TypeS32, &smUpdateInterval,
|
||||
"The update interval.\n"
|
||||
"@ingroup SFX\n");
|
||||
}
|
||||
|
||||
SFXDevice::SFXDevice()
|
||||
: mStatNumBuffers( 0 ),
|
||||
mStatNumVoices( 0 ),
|
||||
mStatNumBufferBytes( 0 )
|
||||
{
|
||||
AssertFatal( provider, "We must have a provider pointer on device creation!" );
|
||||
|
||||
VECTOR_SET_ASSOCIATION( mBuffers );
|
||||
VECTOR_SET_ASSOCIATION( mVoices );
|
||||
|
||||
|
|
@ -54,8 +70,6 @@ SFXDevice::SFXDevice( const String& name, SFXProvider* provider, bool useHardwar
|
|||
Con::addVariable( "SFX::Device::numBufferBytes", TypeS32, &mStatNumBufferBytes );
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
SFXDevice::~SFXDevice()
|
||||
{
|
||||
Con::removeVariable( "SFX::Device::numBuffers" );
|
||||
|
|
@ -78,13 +92,13 @@ void SFXDevice::_releaseAllResources()
|
|||
ThreadSafeRef< SFXUpdateThread > sfxThread = UPDATE_THREAD();
|
||||
if( sfxThread != NULL )
|
||||
{
|
||||
gUpdateThread = NULL; // Kill the global reference.
|
||||
|
||||
sfxThread->stop();
|
||||
sfxThread->triggerUpdate();
|
||||
sfxThread->join();
|
||||
|
||||
sfxThread = NULL;
|
||||
gUpdateThread = NULL; // Kill the global reference.
|
||||
|
||||
}
|
||||
|
||||
// Clean up voices. Do this before cleaning up buffers so that
|
||||
|
|
@ -92,9 +106,11 @@ void SFXDevice::_releaseAllResources()
|
|||
// get released properly.
|
||||
|
||||
SFXVoice::smVoiceDestroyedSignal.remove( this, &SFXDevice::_removeVoice );
|
||||
for( VoiceIterator voice = mVoices.begin();
|
||||
voice != mVoices.end(); voice++ )
|
||||
( *voice )->destroySelf();
|
||||
for (VoiceIterator voice = mVoices.begin(); voice != mVoices.end(); voice++)
|
||||
{
|
||||
(*voice)->stop();
|
||||
(*voice)->destroySelf();
|
||||
}
|
||||
mVoices.clear();
|
||||
|
||||
// Clean up buffers.
|
||||
|
|
|
|||
|
|
@ -23,21 +23,19 @@
|
|||
#ifndef _SFXDEVICE_H_
|
||||
#define _SFXDEVICE_H_
|
||||
|
||||
#ifndef _SFXPROVIDER_H_
|
||||
#include "sfx/sfxProvider.h"
|
||||
#endif
|
||||
#ifndef _PLATFORM_H_
|
||||
#include "platform/platform.h"
|
||||
#endif
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
#ifndef _SFXCOMMON_H_
|
||||
#include "sfx/sfxCommon.h"
|
||||
#endif
|
||||
#ifndef _THREADSAFEREF_H_
|
||||
#include "platform/threads/threadSafeRefCount.h"
|
||||
#endif
|
||||
|
||||
|
||||
class SFXProvider;
|
||||
class SFXListener;
|
||||
class SFXBuffer;
|
||||
class SFXVoice;
|
||||
|
|
@ -46,8 +44,6 @@ class SFXDevice;
|
|||
class SFXStream;
|
||||
class SFXDescription;
|
||||
|
||||
|
||||
|
||||
/// Abstract base class for back-end sound API implementations.
|
||||
class SFXDevice
|
||||
{
|
||||
|
|
@ -58,13 +54,26 @@ class SFXDevice
|
|||
/// Device capability flags.
|
||||
enum ECaps
|
||||
{
|
||||
CAPS_Reverb = BIT( 0 ), ///< Device supports reverb environments.
|
||||
CAPS_VoiceManagement = BIT( 1 ), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
|
||||
CAPS_Occlusion = BIT( 2 ), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
|
||||
CAPS_DSPEffects = BIT( 3 ), ///< Device implements DSP effects (SFXDSPManager).
|
||||
CAPS_MultiListener = BIT( 4 ), ///< Device supports multiple listeners.
|
||||
CAPS_Reverb = BIT(0), ///< Device supports reverb environments.
|
||||
CAPS_VoiceManagement = BIT(1), ///< Device manages voices on its own; deactivates virtualization code in SFX system.
|
||||
CAPS_Occlusion = BIT(2), ///< Device has its own sound occlusion handling (SFXOcclusionManager).
|
||||
CAPS_DSPEffects = BIT(3), ///< Device implements DSP effects (SFXDSPManager).
|
||||
CAPS_MultiListener = BIT(4), ///< Device supports multiple listeners.
|
||||
CAPS_HRTF = BIT(5), ///< Device supports HRTF (3D audio positioning).
|
||||
CAPS_Float32 = BIT(6), ///< Device supports 32-bit float playback.
|
||||
CAPS_MonoStereo = BIT(7), ///< Device supports mono/stereo output modes.
|
||||
};
|
||||
|
||||
static void initConsole();
|
||||
|
||||
static S32 smUpdateInterval;
|
||||
/// The device frequency, used when reading in buffers for the device.
|
||||
static S32 smDeviceFrequency;
|
||||
/// The device bitrate.
|
||||
static S8 smDeviceBitrate;
|
||||
/// Does the device use hrtf
|
||||
static bool smDeviceHRTF;
|
||||
|
||||
protected:
|
||||
|
||||
typedef Vector< SFXBuffer* > BufferVector;
|
||||
|
|
@ -73,13 +82,11 @@ class SFXDevice
|
|||
typedef BufferVector::iterator BufferIterator;
|
||||
typedef VoiceVector::iterator VoiceIterator;
|
||||
|
||||
SFXDevice( const String& name, SFXProvider* provider, bool useHardware, S32 maxBuffers );
|
||||
|
||||
/// The name of this device.
|
||||
String mName;
|
||||
|
||||
/// The provider which created this device.
|
||||
SFXProvider* mProvider;
|
||||
SFXProvider mProvider;
|
||||
|
||||
/// Should the device try to use hardware processing.
|
||||
bool mUseHardware;
|
||||
|
|
@ -125,11 +132,12 @@ class SFXDevice
|
|||
void _releaseAllResources();
|
||||
|
||||
public:
|
||||
|
||||
SFXDevice();
|
||||
virtual ~SFXDevice();
|
||||
|
||||
/// Returns the provider which created this device.
|
||||
SFXProvider* getProvider() const { return mProvider; }
|
||||
virtual const SFXProvider& getProvider() { return mProvider; }
|
||||
virtual void setProvider(const SFXProvider& provider) { mProvider = provider; }
|
||||
|
||||
/// Is the device set to use hardware processing.
|
||||
bool getUseHardware() const { return mUseHardware; }
|
||||
|
|
@ -174,6 +182,9 @@ public:
|
|||
|
||||
/// Set the scale factor to use for doppler effects on 3D sounds.
|
||||
virtual void setDopplerFactor( F32 factor ) {}
|
||||
|
||||
/// Set the speed of sound for the device.
|
||||
virtual void setSpeedOfSound(F32 speedOfSound) {}
|
||||
|
||||
/// Set the rolloff scale factor for distance attenuation of 3D sounds.
|
||||
virtual void setRolloffFactor( F32 factor ) {}
|
||||
|
|
|
|||
|
|
@ -1,95 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "core/strings/stringFunctions.h"
|
||||
#include "sfx/sfxProvider.h"
|
||||
|
||||
SFXProvider* SFXProvider::smProviders = NULL;
|
||||
Vector<SFXProvider*> SFXProvider::sAllProviders( __FILE__, __LINE__ );
|
||||
|
||||
SFXProvider* SFXProvider::findProvider( String providerName )
|
||||
{
|
||||
if( providerName.isEmpty() )
|
||||
return NULL;
|
||||
|
||||
SFXProvider* curr = smProviders;
|
||||
for ( ; curr != NULL; curr = curr->mNextProvider )
|
||||
{
|
||||
if( curr->getName().equal( providerName, String::NoCase ) )
|
||||
return curr;
|
||||
}
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void SFXProvider::regProvider( SFXProvider* provider )
|
||||
{
|
||||
AssertFatal( provider, "Got null provider!" );
|
||||
AssertFatal( findProvider( provider->getName() ) == NULL, "Can't register provider twice!" );
|
||||
AssertFatal( provider->mNextProvider == NULL, "Can't register provider twice!" );
|
||||
|
||||
SFXProvider* oldHead = smProviders;
|
||||
smProviders = provider;
|
||||
provider->mNextProvider = oldHead;
|
||||
}
|
||||
|
||||
SFXProvider::SFXProvider( const String& name )
|
||||
: mNextProvider( NULL ),
|
||||
mName( name )
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mDeviceInfo );
|
||||
|
||||
sAllProviders.push_back( this );
|
||||
}
|
||||
|
||||
void SFXProvider::initializeAllProviders()
|
||||
{
|
||||
|
||||
for (U32 i = 0; i < sAllProviders.size(); i++)
|
||||
sAllProviders[i]->init();
|
||||
|
||||
}
|
||||
|
||||
SFXProvider::~SFXProvider()
|
||||
{
|
||||
SFXDeviceInfoVector::iterator iter = mDeviceInfo.begin();
|
||||
for ( ; iter != mDeviceInfo.end(); iter++ )
|
||||
delete *iter;
|
||||
}
|
||||
|
||||
SFXDeviceInfo* SFXProvider::_findDeviceInfo( const String& deviceName )
|
||||
{
|
||||
SFXDeviceInfoVector::iterator iter = mDeviceInfo.begin();
|
||||
for ( ; iter != mDeviceInfo.end(); iter++ )
|
||||
{
|
||||
if( deviceName.equal( ( *iter )->name, String::NoCase ) )
|
||||
return *iter;
|
||||
}
|
||||
|
||||
// If not found and deviceName is empty,
|
||||
// return first (default) device.
|
||||
|
||||
if( deviceName.isEmpty() && mDeviceInfo.size() > 0 )
|
||||
return mDeviceInfo[ 0 ];
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -23,102 +23,44 @@
|
|||
#ifndef _SFXPROVIDER_H_
|
||||
#define _SFXPROVIDER_H_
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#ifndef _SFXCOMMON_H_
|
||||
#include "sfx/sfxCommon.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
#ifndef _UTIL_DELEGATE_H_
|
||||
#include "core/util/delegate.h"
|
||||
#endif
|
||||
|
||||
class SFXDevice;
|
||||
|
||||
|
||||
|
||||
struct SFXDeviceInfo
|
||||
struct SFXProvider
|
||||
{
|
||||
String driver;
|
||||
String internalName;
|
||||
String name;
|
||||
bool hasHardware = false;
|
||||
S32 maxBuffers =0;
|
||||
public:
|
||||
typedef Delegate<SFXDevice* (U32 providerIndex)> CreateProviderInstanceDelegate;
|
||||
|
||||
virtual ~SFXDeviceInfo() {}
|
||||
};
|
||||
String mName;
|
||||
bool mHasHardware;
|
||||
SFXProviderType mType;
|
||||
SFXDeviceType mDeviceType;
|
||||
U32 mIndex;
|
||||
bool mDefault;
|
||||
CreateProviderInstanceDelegate mCreateDeviceInstanceDelegate;
|
||||
|
||||
typedef Vector<SFXDeviceInfo*> SFXDeviceInfoVector;
|
||||
|
||||
class SFXProvider
|
||||
{
|
||||
friend class SFXSystem;
|
||||
|
||||
private:
|
||||
|
||||
/// The head of the linked list of avalible providers.
|
||||
static SFXProvider* smProviders;
|
||||
|
||||
/// The next provider in the linked list of available providers.
|
||||
SFXProvider* mNextProvider;
|
||||
|
||||
/// The provider name which is passed by the concrete provider
|
||||
/// class to the SFXProvider constructor.
|
||||
String mName;
|
||||
|
||||
static Vector<SFXProvider*> sAllProviders;
|
||||
|
||||
protected:
|
||||
|
||||
/// The array of avaIlable devices from this provider. The
|
||||
/// concrete provider class will fill this on construction.
|
||||
SFXDeviceInfoVector mDeviceInfo;
|
||||
|
||||
/// This registers the provider to the available provider list. It should be called
|
||||
/// for providers that are properly initialized and available for device enumeration and creation.
|
||||
/// the add and registration process is 2 steps to avoid issues when TGEA is used as a shared library (specifically on Windows)
|
||||
static void regProvider( SFXProvider* provider );
|
||||
|
||||
virtual void init() = 0;
|
||||
|
||||
SFXProvider( const String& name );
|
||||
~SFXProvider();
|
||||
|
||||
/// Look up the SFXDeviceInfo for the given device in mDeviceInfo.
|
||||
/// Return default device (first in list) if no other device matches (or null if device list is empty).
|
||||
SFXDeviceInfo* _findDeviceInfo( const String& deviceName );
|
||||
|
||||
/// This is called from SFXSystem to create a new device. Must be implemented
|
||||
/// by all contrete provider classes.
|
||||
///
|
||||
/// @param deviceName The case sensitive name of the device or NULL to create the
|
||||
// default device.
|
||||
/// @param useHardware Toggles the use of hardware processing when available.
|
||||
/// @param maxBuffers The maximum buffers for this device to use or -1
|
||||
/// for the device to pick a reasonable default for that device.
|
||||
///
|
||||
/// @return Returns the created device or NULL for failure.
|
||||
///
|
||||
virtual SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers ) = 0;
|
||||
|
||||
public:
|
||||
|
||||
/// Returns a specific provider by searching the provider list
|
||||
/// for the first provider with the case sensitive name.
|
||||
static SFXProvider* findProvider( String providerName );
|
||||
|
||||
/// Returns the first provider in the provider list. Use
|
||||
/// getNextProvider() to iterate over list.
|
||||
static SFXProvider* getFirstProvider() { return smProviders; }
|
||||
|
||||
/// Returns the next provider in the provider list or NULL
|
||||
/// when the end of the list is reached.
|
||||
SFXProvider* getNextProvider() const { return mNextProvider; }
|
||||
|
||||
/// The case sensitive name of this provider.
|
||||
const String& getName() const { return mName; }
|
||||
|
||||
/// Returns a read only vector with device information for
|
||||
/// all creatable devices available from this provider.
|
||||
const SFXDeviceInfoVector& getDeviceInfo() const { return mDeviceInfo; }
|
||||
|
||||
static void initializeAllProviders();
|
||||
const char* getName() const { return mName; }
|
||||
|
||||
SFXProvider()
|
||||
{
|
||||
mName = String::EmptyString;
|
||||
mHasHardware = false;
|
||||
mType = NullProvider;
|
||||
mIndex = 0;
|
||||
mDefault = false;
|
||||
mDeviceType = Output;
|
||||
}
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -131,14 +131,30 @@ void SFXSoundscapeManager::update()
|
|||
SFXAmbience* ambience = mStack[ reverbIndex ]->getAmbience();
|
||||
AssertFatal( ambience->getEnvironment(), "SFXSoundscapeManager::update - Reverb lookup return ambience without reverb!" );
|
||||
|
||||
SFX->setRolloffFactor( ambience->getRolloffFactor() );
|
||||
SFX->setDopplerFactor( ambience->getDopplerFactor() );
|
||||
SFX->setReverb( ambience->getEnvironment()->getReverb() );
|
||||
SFX->setRolloffFactor(ambience->getRolloffFactor());
|
||||
SFX->setDopplerFactor(ambience->getDopplerFactor());
|
||||
SFX->setSpeedOfSound(ambience->getSpeedOfSound());
|
||||
if (ambience->getEnvironment())
|
||||
SFX->setReverb(ambience->getEnvironment()->getReverb());
|
||||
}
|
||||
|
||||
mCurrentReverbIndex = reverbIndex;
|
||||
}
|
||||
|
||||
|
||||
if (mStack[mStack.size() - 1]->mDirtyBits.test(SFXSoundscape::AmbienceDirty))
|
||||
{
|
||||
SFXAmbience* ambience = mStack[mStack.size() - 1]->getAmbience();
|
||||
SFX->setRolloffFactor(ambience->getRolloffFactor());
|
||||
SFX->setDopplerFactor(ambience->getDopplerFactor());
|
||||
SFX->setSpeedOfSound(ambience->getSpeedOfSound());
|
||||
if (ambience->getEnvironment())
|
||||
SFX->setReverb(ambience->getEnvironment()->getReverb());
|
||||
|
||||
mCurrentReverbIndex = mStack.size() - 1;
|
||||
|
||||
mStack[mStack.size() - 1]->mDirtyBits.clear(SFXSoundscape::AmbienceDirty);
|
||||
}
|
||||
|
||||
// Update the active soundscapes.
|
||||
|
||||
for( U32 i = 0; i < mStack.size(); ++ i )
|
||||
|
|
|
|||
|
|
@ -42,8 +42,11 @@
|
|||
#include "platform/platformTimer.h"
|
||||
#include "core/util/autoPtr.h"
|
||||
#include "core/module.h"
|
||||
#include "T3D/sfx/sfx3DWorld.h"
|
||||
|
||||
|
||||
Vector<SFXProvider*> SFXSystem::smProviders(__FILE__, __LINE__);
|
||||
SFXSystem::RegisterProviderSignal* SFXSystem::smRegisterProviderSignal;
|
||||
|
||||
|
||||
MODULE_BEGIN( SFX )
|
||||
|
|
@ -54,6 +57,8 @@ MODULE_BEGIN( SFX )
|
|||
MODULE_INIT
|
||||
{
|
||||
SFXSystem::init();
|
||||
if (engineAPI::gUseConsoleInterop)
|
||||
SFXDevice::initConsole();
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
|
|
@ -69,6 +74,25 @@ SFXSystem* SFXSystem::smSingleton = NULL;
|
|||
/// Default SFXAmbience used to reset the global soundscape.
|
||||
SFXAmbience *sDefaultAmbience;
|
||||
|
||||
// Provider type
|
||||
ImplementEnumType(SFXProviderType,
|
||||
"The sfx provider.\n"
|
||||
"@ingroup SFX")
|
||||
{ SFXProviderType::OpenAL, "OpenAL", "OpenAL Provider." },
|
||||
{ SFXProviderType::DirectSound, "DirectSound", "DirectSound Provider." },
|
||||
{ SFXProviderType::XAudio, "XAudio", "XAudio Provider." },
|
||||
{ SFXProviderType::NullProvider, "NullProvider","NullProvider Provider." }
|
||||
EndImplementEnumType;
|
||||
|
||||
// Device type
|
||||
ImplementEnumType(SFXDeviceType,
|
||||
"The sfx device type input/output.\n"
|
||||
"@ingroup SFX")
|
||||
{ SFXDeviceType::Input, "InputDevice", "Input/Capture device" },
|
||||
{ SFXDeviceType::Output, "OutputDevice", "Output Device." },
|
||||
EndImplementEnumType;
|
||||
|
||||
|
||||
// Excludes Null and Blocked as these are not passed out to the control layer.
|
||||
ImplementEnumType( SFXStatus,
|
||||
"Playback status of sound source.\n"
|
||||
|
|
@ -185,6 +209,125 @@ static const U32 sDeviceInfoMaxBuffers = 3;
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
SFXSystem::RegisterProviderSignal& SFXSystem::getRegisterProviderSignal()
|
||||
{
|
||||
if (smRegisterProviderSignal)
|
||||
return *smRegisterProviderSignal;
|
||||
smRegisterProviderSignal = new RegisterProviderSignal();
|
||||
return *smRegisterProviderSignal;
|
||||
}
|
||||
|
||||
S32 SFXSystem::getProviderCount()
|
||||
{
|
||||
return smProviders.size();
|
||||
}
|
||||
|
||||
inline static void _SFXInitReportProviders(Vector<SFXProvider*>& providers)
|
||||
{
|
||||
for (U32 i = 0; i < providers.size(); i++)
|
||||
{
|
||||
switch (providers[i]->mType)
|
||||
{
|
||||
case OpenAL:
|
||||
Con::printf(" OpenAL Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
|
||||
break;
|
||||
case NullProvider:
|
||||
Con::printf(" Null device found");
|
||||
break;
|
||||
case XAudio:
|
||||
Con::printf(" XAudio Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
|
||||
break;
|
||||
case DirectSound:
|
||||
Con::printf(" DirectSound Device Found: %s Device %s %s", providers[i]->mDeviceType == Input ? "Input" : "Output", providers[i]->getName(), providers[i]->mDefault ? "(Default)" : "");
|
||||
break;
|
||||
default:
|
||||
Con::printf(" Unknown device found");
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SFXSystem::getProviders(Vector<SFXProvider*>* providers)
|
||||
{
|
||||
providers->clear();
|
||||
for (U32 k = 0; k < smProviders.size(); k++)
|
||||
providers->push_back(smProviders[k]);
|
||||
}
|
||||
|
||||
const char* SFXSystem::getProviderNameFromType(SFXProviderType type)
|
||||
{
|
||||
static const char* _names[] = { "OpenAL", "DirectSound", "XAudio", "NullProvider" };
|
||||
if (type < 0 || type >= SFXProviderType_Count)
|
||||
return _names[OpenAL];
|
||||
|
||||
return _names[type];
|
||||
}
|
||||
|
||||
SFXProvider* SFXSystem::getBestProviderChoice()
|
||||
{
|
||||
const String provider = Con::getVariable("$pref::SFX::provider");
|
||||
const String device = Con::getVariable("$pref::SFX::device");
|
||||
|
||||
SFXProviderType providerType = OpenAL;
|
||||
|
||||
if (provider.isEmpty() || device.isEmpty())
|
||||
{
|
||||
for (U32 i = 0; i < smProviders.size(); i++)
|
||||
{
|
||||
if (smProviders[i]->mType == OpenAL)
|
||||
{
|
||||
if (smProviders[i]->mDefault)
|
||||
return smProviders[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
S32 ret = -1;
|
||||
for (U32 i = 0; i < SFXProviderType_Count; i++)
|
||||
{
|
||||
if (!dStrcmp(getProviderNameFromType((SFXProviderType)i), provider))
|
||||
{
|
||||
ret = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if (ret == -1)
|
||||
providerType = OpenAL;
|
||||
}
|
||||
|
||||
U32 i = 0;
|
||||
for (i = 0; i < smProviders.size(); i++)
|
||||
{
|
||||
if (smProviders[i]->mType == providerType)
|
||||
{
|
||||
if (String::compare(smProviders[i]->getName(), device.c_str()) == 0)
|
||||
{
|
||||
return smProviders[i];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < smProviders.size(); i++)
|
||||
{
|
||||
if (smProviders[i]->mType == providerType)
|
||||
{
|
||||
if (smProviders[i]->mDefault)
|
||||
return smProviders[i];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
SFXProvider* SFXSystem::getProvider(U32 index)
|
||||
{
|
||||
return smProviders[index];
|
||||
}
|
||||
|
||||
SFXSystem::SFXSystem()
|
||||
: mDevice( NULL ),
|
||||
mLastSourceUpdateTime( 0 ),
|
||||
|
|
@ -200,6 +343,7 @@ SFXSystem::SFXSystem()
|
|||
mDistanceModel( SFXDistanceModelLinear ),
|
||||
mStatAmbientUpdateTime( 0 ),
|
||||
mDopplerFactor( 0.5 ),
|
||||
mSpeedOfSound(343.3f),
|
||||
mRolloffFactor( 1.0 ),
|
||||
mSoundscapeMgr( NULL )
|
||||
{
|
||||
|
|
@ -340,15 +484,36 @@ SFXSystem::~SFXSystem()
|
|||
deleteDevice();
|
||||
}
|
||||
|
||||
void SFXSystem::enumerateProviders()
|
||||
{
|
||||
if (smProviders.size())
|
||||
{
|
||||
return;
|
||||
}
|
||||
|
||||
getRegisterProviderSignal().trigger(SFXSystem::smProviders);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SFXSystem::init()
|
||||
{
|
||||
AssertWarn( smSingleton == NULL, "SFX has already been initialized!" );
|
||||
|
||||
SFXProvider::initializeAllProviders();
|
||||
|
||||
// Create the stream thread pool.
|
||||
// SFXProvider::initializeAllProviders();
|
||||
Con::printf("SFX Init:");
|
||||
|
||||
// find our providers
|
||||
Vector<SFXProvider*> providers( __FILE__, __LINE__ );
|
||||
SFXSystem::enumerateProviders();
|
||||
SFXSystem::getProviders(&providers);
|
||||
|
||||
if (!providers.size())
|
||||
Con::errorf("Could not find a sound provider");
|
||||
|
||||
//loop through and tell the user what kind of provider we found
|
||||
_SFXInitReportProviders(providers);
|
||||
Con::printf("");
|
||||
|
||||
SFXInternal::SFXThreadPool::createSingleton();
|
||||
|
||||
|
|
@ -366,6 +531,13 @@ void SFXSystem::destroy()
|
|||
{
|
||||
AssertWarn( smSingleton != NULL, "SFX has not been initialized!" );
|
||||
|
||||
while (smProviders.size())
|
||||
{
|
||||
SFXProvider* provider = smProviders.last();
|
||||
smProviders.decrement();
|
||||
delete provider;
|
||||
}
|
||||
|
||||
delete smSingleton;
|
||||
smSingleton = NULL;
|
||||
|
||||
|
|
@ -373,6 +545,9 @@ void SFXSystem::destroy()
|
|||
|
||||
SFXInternal::SFXThreadPool::deleteSingleton();
|
||||
delete(sDefaultAmbience);
|
||||
|
||||
if (smRegisterProviderSignal)
|
||||
SAFE_DELETE(smRegisterProviderSignal);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
@ -399,59 +574,46 @@ void SFXSystem::removePlugin( SFXSystemPlugin* plugin )
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
bool SFXSystem::createDevice( const String& providerName, const String& deviceName, bool useHardware, S32 maxBuffers, bool changeDevice )
|
||||
bool SFXSystem::createDevice(SFXProvider* provider)
|
||||
{
|
||||
// Make sure we don't have a device already.
|
||||
|
||||
if( mDevice && !changeDevice )
|
||||
return false;
|
||||
|
||||
// Lookup the provider.
|
||||
|
||||
SFXProvider* provider = SFXProvider::findProvider( providerName );
|
||||
if( !provider )
|
||||
return false;
|
||||
|
||||
// If we have already created this device and are using it then no need to do anything.
|
||||
|
||||
if( mDevice
|
||||
&& providerName.equal( mDevice->getProvider()->getName(), String::NoCase )
|
||||
&& deviceName.equal( mDevice->getName(), String::NoCase )
|
||||
&& useHardware == mDevice->getUseHardware() )
|
||||
return true;
|
||||
|
||||
// If we have an existing device remove it.
|
||||
|
||||
if( mDevice )
|
||||
// this should probably just happen tbh.
|
||||
if (mDevice)
|
||||
deleteDevice();
|
||||
|
||||
// Create the new device..
|
||||
|
||||
mDevice = provider->createDevice( deviceName, useHardware, maxBuffers );
|
||||
mDevice = provider->mCreateDeviceInstanceDelegate(provider->mIndex);
|
||||
if( !mDevice )
|
||||
{
|
||||
Con::errorf( "SFXSystem::createDevice - failed creating %s device '%s'", providerName.c_str(), deviceName.c_str() );
|
||||
Con::errorf( "SFXSystem::createDevice - failed creating device '%s'", provider->getName());
|
||||
return false;
|
||||
}
|
||||
|
||||
// Print capabilities.
|
||||
mDevice->setProvider(*provider);
|
||||
|
||||
Con::printf( "SFXSystem::createDevice - created %s device '%s'", providerName.c_str(), deviceName.c_str() );
|
||||
if( mDevice->getCaps() & SFXDevice::CAPS_Reverb )
|
||||
Con::printf( " CAPS_Reverb" );
|
||||
if( mDevice->getCaps() & SFXDevice::CAPS_VoiceManagement )
|
||||
Con::printf( " CAPS_VoiceManagement" );
|
||||
if( mDevice->getCaps() & SFXDevice::CAPS_Occlusion )
|
||||
Con::printf( "\tCAPS_Occlusion" );
|
||||
if( mDevice->getCaps() & SFXDevice::CAPS_MultiListener )
|
||||
Con::printf( "\tCAPS_MultiListener" );
|
||||
// Print capabilities.
|
||||
Con::printf( "\nSFXSystem::createDevice - created device '%s'", provider->getName());
|
||||
Con::printf("| Device Update Interval: %d ms", SFXDevice::smUpdateInterval);
|
||||
Con::printf("| Device Sample rate: %d Hz", SFXDevice::smDeviceFrequency);
|
||||
Con::printf("| Device Bitrate: %d", SFXDevice::smDeviceBitrate);
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_Reverb)
|
||||
Con::printf("| CAPS_Reverb");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_VoiceManagement)
|
||||
Con::printf("| CAPS_VoiceManagement");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_Occlusion)
|
||||
Con::printf("| CAPS_Occlusion");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_MultiListener)
|
||||
Con::printf("| CAPS_MultiListener");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_HRTF)
|
||||
Con::printf("| CAPS_HRTF");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_Float32)
|
||||
Con::printf("| CAPS_Float32");
|
||||
if (mDevice->getCaps() & SFXDevice::CAPS_MonoStereo)
|
||||
Con::printf("| CAPS_MonoStereo");
|
||||
|
||||
// Set defaults.
|
||||
|
||||
mDevice->setNumListeners( getNumListeners() );
|
||||
mDevice->setDistanceModel( mDistanceModel );
|
||||
mDevice->setDopplerFactor( mDopplerFactor );
|
||||
mDevice->setRolloffFactor( mRolloffFactor );
|
||||
mDevice->setSpeedOfSound(mSpeedOfSound);
|
||||
//OpenAL requires slots for effects, this creates an empty function
|
||||
//that will run when a sfxdevice is created.
|
||||
mDevice->openSlots();
|
||||
|
|
@ -464,17 +626,15 @@ bool SFXSystem::createDevice( const String& providerName, const String& deviceNa
|
|||
return true;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
String SFXSystem::getDeviceInfoString()
|
||||
{
|
||||
// Make sure we have a valid device.
|
||||
if( !mDevice )
|
||||
return String();
|
||||
|
||||
return String::ToString( "%s\t%s\t%s\t%d\t%d",
|
||||
mDevice->getProvider()->getName().c_str(),
|
||||
mDevice->getName().c_str(),
|
||||
return String::ToString( "%s\t%s\t%s\t%d\t%d",
|
||||
getProviderNameFromType(mDevice->getProvider().mType),
|
||||
mDevice->getProvider().getName(),
|
||||
mDevice->getUseHardware() ? "1" : "0",
|
||||
mDevice->getMaxBuffers(),
|
||||
mDevice->getCaps() );
|
||||
|
|
@ -1020,6 +1180,18 @@ void SFXSystem::setDopplerFactor( F32 factor )
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
|
||||
void SFXSystem::setSpeedOfSound(F32 speedOfSound)
|
||||
{
|
||||
const bool changed = (speedOfSound != mSpeedOfSound);
|
||||
|
||||
mSpeedOfSound = speedOfSound;
|
||||
if (mDevice && changed)
|
||||
mDevice->setSpeedOfSound(speedOfSound);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void SFXSystem::setRolloffFactor( F32 factor )
|
||||
{
|
||||
const bool changed = ( factor != mRolloffFactor );
|
||||
|
|
@ -1210,6 +1382,43 @@ void SFXSystem::dumpSources( StringBuilder* toString, bool excludeGroups )
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineFunction(sfxGetProviderCount, S32, (), ,
|
||||
"Returns the number of sound providers available\n\n"
|
||||
"@ingroup SFX")
|
||||
{
|
||||
return SFXSystem::getProviderCount();
|
||||
}
|
||||
|
||||
DefineEngineFunction(sfxGetProviderType, SFXProviderType, (S32 index), ,
|
||||
"Returns the type (OpenAL, XAudio, DirectSound, Null) of a sound provider.\n"
|
||||
"@param index The index of the adapter.")
|
||||
{
|
||||
Vector<SFXProvider*> providers(__FILE__, __LINE__);
|
||||
SFXSystem::getProviders(&providers);
|
||||
|
||||
if (index >= 0 && index < providers.size())
|
||||
return providers[index]->mType;
|
||||
|
||||
Con::errorf("SFXSystem::sfxGetProviderType - Out of range provider index.");
|
||||
return SFXProviderType_Count;
|
||||
}
|
||||
|
||||
DefineEngineFunction(sfxGetProviderDevice, const char*, (S32 index), ,
|
||||
"Returns the device name of the sound provider.\n"
|
||||
"@param index The index of the adapter.")
|
||||
{
|
||||
Vector<SFXProvider*> providers(__FILE__, __LINE__);
|
||||
SFXSystem::getProviders(&providers);
|
||||
|
||||
if (index >= 0 && index < providers.size())
|
||||
return providers[index]->getName();
|
||||
|
||||
Con::errorf("SFXSystem::sfxGetProviderDevice - Out of range provider index.");
|
||||
return "";
|
||||
}
|
||||
|
||||
|
||||
|
||||
DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
|
||||
"Get a list of all available sound devices.\n"
|
||||
"The return value will be a newline-separated list of entries where each line describes one available sound "
|
||||
|
|
@ -1240,27 +1449,14 @@ DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
|
|||
char *ptr = deviceList;
|
||||
*ptr = 0;
|
||||
|
||||
SFXProvider* provider = SFXProvider::getFirstProvider();
|
||||
while ( provider )
|
||||
Vector<SFXProvider*> providers(__FILE__, __LINE__);
|
||||
SFXSystem::getProviders(&providers);
|
||||
|
||||
for (U32 i = 0; i < providers.size(); i++)
|
||||
{
|
||||
// List the devices in this provider.
|
||||
const SFXDeviceInfoVector& deviceInfo = provider->getDeviceInfo();
|
||||
for ( S32 d=0; d < deviceInfo.size(); d++ )
|
||||
{
|
||||
const SFXDeviceInfo* info = deviceInfo[d];
|
||||
const char *providerName = provider->getName().c_str();
|
||||
char *infoName = (char*)info->name.c_str();
|
||||
|
||||
dSprintf(ptr, len, "%s\t%s\t%s\t%i\n", providerName, infoName, info->hasHardware ? "1" : "0", info->maxBuffers);
|
||||
|
||||
ptr += dStrlen(ptr);
|
||||
len = bufferSize - (ptr - deviceList);
|
||||
|
||||
if (len <= 0)
|
||||
return deviceList;
|
||||
}
|
||||
|
||||
provider = provider->getNextProvider();
|
||||
dSprintf(ptr, len, "%s\t", providers[i]->getName());
|
||||
ptr += dStrlen(ptr);
|
||||
len = bufferSize - (ptr - deviceList);
|
||||
}
|
||||
|
||||
return deviceList;
|
||||
|
|
@ -1268,7 +1464,7 @@ DefineEngineFunction( sfxGetAvailableDevices, const char*, (),,
|
|||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char* device, bool useHardware, S32 maxBuffers ),,
|
||||
DefineEngineFunction( sfxCreateDevice, bool, (),,
|
||||
"Try to create a new sound device using the given properties.\n"
|
||||
"If a sound device is currently initialized, it will be uninitialized first. However, be aware that in this case, "
|
||||
"if this function fails, it will not restore the previously active device but rather leave the sound system in an "
|
||||
|
|
@ -1276,10 +1472,6 @@ DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char*
|
|||
"Sounds that are already playing while the new device is created will be temporarily transitioned to virtualized "
|
||||
"playback and then resume normal playback once the device has been created.\n\n"
|
||||
"In the core scripts, sound is automatically set up during startup in the sfxStartup() function.\n\n"
|
||||
"@param provider The name of the device provider as returned by sfxGetAvailableDevices().\n"
|
||||
"@param device The name of the device as returned by sfxGetAvailableDevices().\n"
|
||||
"@param useHardware Whether to enabled hardware mixing on the device or not. Only relevant if supported by the given device.\n"
|
||||
"@param maxBuffers The maximum number of concurrent voices for this device to use or -1 for the device to pick its own reasonable default."
|
||||
"@return True if the initialization was successful, false if not.\n"
|
||||
"@note This function must be called before any of the sound playback functions can be used.\n"
|
||||
"@see sfxGetAvailableDevices\n"
|
||||
|
|
@ -1288,7 +1480,14 @@ DefineEngineFunction( sfxCreateDevice, bool, ( const char* provider, const char*
|
|||
"@ref SFX_devices\n"
|
||||
"@ingroup SFX" )
|
||||
{
|
||||
return SFX->createDevice( provider, device, useHardware, maxBuffers, true );
|
||||
// return SFX->createDevice( provider, device, useHardware, maxBuffers, true );
|
||||
SFXProvider* p = SFXSystem::getBestProviderChoice();
|
||||
if (p)
|
||||
{
|
||||
SFX->createDevice(p);
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
|
|
|
|||
|
|
@ -23,9 +23,10 @@
|
|||
#ifndef _SFXSYSTEM_H_
|
||||
#define _SFXSYSTEM_H_
|
||||
|
||||
#ifndef _SFXCOMMON_H_
|
||||
#include "sfx/sfxCommon.h"
|
||||
#endif
|
||||
#ifndef _SFXPROVIDER_H_
|
||||
#include "sfx/sfxProvider.h"
|
||||
#endif // !_SFXPROVIDER_H_
|
||||
|
||||
#ifndef _TSIGNAL_H_
|
||||
#include "core/util/tSignal.h"
|
||||
#endif
|
||||
|
|
@ -98,343 +99,358 @@ class SFXSystemPlugin
|
|||
///
|
||||
class SFXSystem
|
||||
{
|
||||
friend class SFXSound; // _assignVoices
|
||||
friend class SFXSource; // _onAddSource, _onRemoveSource.
|
||||
friend class SFXProfile; // _createBuffer.
|
||||
friend class SFXSound; // _assignVoices
|
||||
friend class SFXSource; // _onAddSource, _onRemoveSource.
|
||||
friend class SFXProfile; // _createBuffer.
|
||||
|
||||
public:
|
||||
/// Allows device to register themselves as available
|
||||
typedef Signal<void(Vector<SFXProvider*>&)> RegisterProviderSignal;
|
||||
static RegisterProviderSignal& getRegisterProviderSignal();
|
||||
/// Get the number of available providers.
|
||||
static S32 getProviderCount();
|
||||
/// Enumerate all the sound providers on the system
|
||||
static void enumerateProviders();
|
||||
static void getProviders(Vector<SFXProvider*>* providers);
|
||||
static const char* getProviderNameFromType(SFXProviderType type);
|
||||
static SFXProvider* getBestProviderChoice();
|
||||
static SFXProvider* getProvider(U32 index);
|
||||
|
||||
typedef Signal< void( SFXSystemEventType event ) > EventSignalType;
|
||||
typedef Vector< SFXSource* > SFXSourceVector;
|
||||
typedef Vector< SFXSound* > SFXSoundVector;
|
||||
private:
|
||||
/// List of known adapters.
|
||||
static Vector<SFXProvider*> smProviders;
|
||||
static RegisterProviderSignal* smRegisterProviderSignal;
|
||||
|
||||
protected:
|
||||
|
||||
/// The one and only instance of the SFXSystem.
|
||||
static SFXSystem* smSingleton;
|
||||
|
||||
/// The protected constructor.
|
||||
///
|
||||
/// @see SFXSystem::init()
|
||||
///
|
||||
SFXSystem();
|
||||
|
||||
/// The non-virtual destructor. You shouldn't
|
||||
/// ever need to overload this class.
|
||||
~SFXSystem();
|
||||
|
||||
public:
|
||||
|
||||
typedef Signal< void( SFXSystemEventType event ) > EventSignalType;
|
||||
typedef Vector< SFXSource* > SFXSourceVector;
|
||||
typedef Vector< SFXSound* > SFXSoundVector;
|
||||
/// The current output sound device initialized
|
||||
/// and ready to play back.
|
||||
SFXDevice* mDevice;
|
||||
|
||||
protected:
|
||||
///
|
||||
SFXSoundVector mSounds;
|
||||
|
||||
/// The one and only instance of the SFXSystem.
|
||||
static SFXSystem* smSingleton;
|
||||
|
||||
/// The protected constructor.
|
||||
///
|
||||
/// @see SFXSystem::init()
|
||||
///
|
||||
SFXSystem();
|
||||
|
||||
/// The non-virtual destructor. You shouldn't
|
||||
/// ever need to overload this class.
|
||||
~SFXSystem();
|
||||
|
||||
/// The current output sound device initialized
|
||||
/// and ready to play back.
|
||||
SFXDevice* mDevice;
|
||||
|
||||
///
|
||||
SFXSoundVector mSounds;
|
||||
|
||||
/// This is used to keep track of play once sources
|
||||
/// that must be released when they stop playing.
|
||||
SFXSourceVector mPlayOnceSources;
|
||||
/// This is used to keep track of play once sources
|
||||
/// that must be released when they stop playing.
|
||||
SFXSourceVector mPlayOnceSources;
|
||||
|
||||
/// The last time the sources got an update.
|
||||
U32 mLastSourceUpdateTime;
|
||||
/// The last time the sources got an update.
|
||||
U32 mLastSourceUpdateTime;
|
||||
|
||||
///
|
||||
U32 mLastAmbientUpdateTime;
|
||||
///
|
||||
U32 mLastAmbientUpdateTime;
|
||||
|
||||
///
|
||||
U32 mLastParameterUpdateTime;
|
||||
///
|
||||
U32 mLastParameterUpdateTime;
|
||||
|
||||
/// The distance model used for rolloff curve computation on 3D sounds.
|
||||
SFXDistanceModel mDistanceModel;
|
||||
/// The distance model used for rolloff curve computation on 3D sounds.
|
||||
SFXDistanceModel mDistanceModel;
|
||||
|
||||
/// The current doppler scale factor.
|
||||
F32 mDopplerFactor;
|
||||
/// The current doppler scale factor.
|
||||
F32 mDopplerFactor;
|
||||
|
||||
/// The current speed of sound.
|
||||
F32 mSpeedOfSound;
|
||||
|
||||
/// The current curve rolloff factor.
|
||||
F32 mRolloffFactor;
|
||||
/// The current curve rolloff factor.
|
||||
F32 mRolloffFactor;
|
||||
|
||||
/// The current position and orientation of all listeners.
|
||||
Vector< SFXListenerProperties > mListeners;
|
||||
/// The current position and orientation of all listeners.
|
||||
Vector< SFXListenerProperties > mListeners;
|
||||
|
||||
/// Current global reverb properties.
|
||||
SFXReverbProperties mReverb;
|
||||
/// Current global reverb properties.
|
||||
SFXReverbProperties mReverb;
|
||||
|
||||
/// SFX system event signal.
|
||||
EventSignalType mEventSignal;
|
||||
/// SFX system event signal.
|
||||
EventSignalType mEventSignal;
|
||||
|
||||
/// Ambient soundscape manager.
|
||||
SFXSoundscapeManager* mSoundscapeMgr;
|
||||
/// Ambient soundscape manager.
|
||||
SFXSoundscapeManager* mSoundscapeMgr;
|
||||
|
||||
/// List of plugins currently linked to the SFX system.
|
||||
Vector< SFXSystemPlugin* > mPlugins;
|
||||
/// List of plugins currently linked to the SFX system.
|
||||
Vector< SFXSystemPlugin* > mPlugins;
|
||||
|
||||
/// @name Stats
|
||||
///
|
||||
/// Stats reported back to the console for tracking performance.
|
||||
///
|
||||
/// @{
|
||||
/// @name Stats
|
||||
///
|
||||
/// Stats reported back to the console for tracking performance.
|
||||
///
|
||||
/// @{
|
||||
|
||||
S32 mStatNumSources;
|
||||
S32 mStatNumSounds;
|
||||
S32 mStatNumPlaying;
|
||||
S32 mStatNumCulled;
|
||||
S32 mStatNumVoices;
|
||||
S32 mStatSourceUpdateTime;
|
||||
S32 mStatParameterUpdateTime;
|
||||
S32 mStatAmbientUpdateTime;
|
||||
S32 mStatNumSources;
|
||||
S32 mStatNumSounds;
|
||||
S32 mStatNumPlaying;
|
||||
S32 mStatNumCulled;
|
||||
S32 mStatNumVoices;
|
||||
S32 mStatSourceUpdateTime;
|
||||
S32 mStatParameterUpdateTime;
|
||||
S32 mStatAmbientUpdateTime;
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// Called to reprioritize and reassign buffers as
|
||||
/// sources change state, volumes are adjusted, and
|
||||
/// the listener moves around.
|
||||
///
|
||||
/// @see SFXSource::_update()
|
||||
///
|
||||
void _updateSources();
|
||||
/// Called to reprioritize and reassign buffers as
|
||||
/// sources change state, volumes are adjusted, and
|
||||
/// the listener moves around.
|
||||
///
|
||||
/// @see SFXSource::_update()
|
||||
///
|
||||
void _updateSources();
|
||||
|
||||
/// This called to reprioritize and reassign
|
||||
/// voices to sources.
|
||||
void _assignVoices();
|
||||
/// This called to reprioritize and reassign
|
||||
/// voices to sources.
|
||||
void _assignVoices();
|
||||
|
||||
///
|
||||
void _assignVoice( SFXSound* sound );
|
||||
///
|
||||
void _assignVoice( SFXSound* sound );
|
||||
|
||||
///
|
||||
void _sortSounds( const SFXListenerProperties& listener );
|
||||
///
|
||||
void _sortSounds( const SFXListenerProperties& listener );
|
||||
|
||||
/// Called from SFXSource::onAdd to register the source.
|
||||
void _onAddSource( SFXSource* source );
|
||||
/// Called from SFXSource::onAdd to register the source.
|
||||
void _onAddSource( SFXSource* source );
|
||||
|
||||
/// Called from SFXSource::onRemove to unregister the source.
|
||||
void _onRemoveSource( SFXSource* source );
|
||||
/// Called from SFXSource::onRemove to unregister the source.
|
||||
void _onRemoveSource( SFXSource* source );
|
||||
|
||||
/// Called from SFXProfile to create a device specific
|
||||
/// sound buffer used in conjunction with a voice in playback.
|
||||
SFXBuffer* _createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
/// Called from SFXProfile to create a device specific
|
||||
/// sound buffer used in conjunction with a voice in playback.
|
||||
SFXBuffer* _createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
|
||||
/// Load file directly through SFXDevice. Depends on
|
||||
/// availability with selected SFXDevice.
|
||||
///
|
||||
/// @return Return new buffer or NULL.
|
||||
SFXBuffer* _createBuffer( const String& filename, SFXDescription* description );
|
||||
/// Load file directly through SFXDevice. Depends on
|
||||
/// availability with selected SFXDevice.
|
||||
///
|
||||
/// @return Return new buffer or NULL.
|
||||
SFXBuffer* _createBuffer( const String& filename, SFXDescription* description );
|
||||
|
||||
///
|
||||
SFXDevice* _getDevice() const { return mDevice; }
|
||||
///
|
||||
SFXDevice* _getDevice() const { return mDevice; }
|
||||
|
||||
public:
|
||||
public:
|
||||
|
||||
/// Returns the one an only instance of the SFXSystem
|
||||
/// unless it hasn't been initialized or its been disabled
|
||||
/// in your build.
|
||||
///
|
||||
/// For convienence you can use the SFX-> macro as well.
|
||||
///
|
||||
/// @see SFXSystem::init()
|
||||
/// @see SFX
|
||||
static SFXSystem* getSingleton() { return smSingleton; }
|
||||
/// Returns the one an only instance of the SFXSystem
|
||||
/// unless it hasn't been initialized or its been disabled
|
||||
/// in your build.
|
||||
///
|
||||
/// For convienence you can use the SFX-> macro as well.
|
||||
///
|
||||
/// @see SFXSystem::init()
|
||||
/// @see SFX
|
||||
static SFXSystem* getSingleton() { return smSingleton; }
|
||||
|
||||
/// This is called from initialization to prepare the
|
||||
/// sound system singleton. This also includes registering
|
||||
/// common resource types and initializing available sound
|
||||
/// providers.
|
||||
static void init();
|
||||
/// This is called from initialization to prepare the
|
||||
/// sound system singleton. This also includes registering
|
||||
/// common resource types and initializing available sound
|
||||
/// providers.
|
||||
static void init();
|
||||
|
||||
/// This is called after Sim::shutdown() in shutdownLibraries()
|
||||
/// to free the sound system singlton. After this the SFX
|
||||
/// singleton is null and any call to it will crash.
|
||||
static void destroy();
|
||||
/// This is called after Sim::shutdown() in shutdownLibraries()
|
||||
/// to free the sound system singlton. After this the SFX
|
||||
/// singleton is null and any call to it will crash.
|
||||
static void destroy();
|
||||
|
||||
/// This is only public so that it can be called by
|
||||
/// the game update loop. It updates the current
|
||||
/// device and all sources.
|
||||
void _update();
|
||||
/// This is only public so that it can be called by
|
||||
/// the game update loop. It updates the current
|
||||
/// device and all sources.
|
||||
void _update();
|
||||
|
||||
/// Register the given plugin with the system.
|
||||
void addPlugin( SFXSystemPlugin* plugin );
|
||||
/// Register the given plugin with the system.
|
||||
void addPlugin( SFXSystemPlugin* plugin );
|
||||
|
||||
/// Unregister the given plugin with the system.
|
||||
void removePlugin( SFXSystemPlugin* plugin );
|
||||
/// Unregister the given plugin with the system.
|
||||
void removePlugin( SFXSystemPlugin* plugin );
|
||||
|
||||
/// @name Device Management
|
||||
/// @{
|
||||
/// @name Device Management
|
||||
/// @{
|
||||
|
||||
/// This initializes a new device.
|
||||
///
|
||||
/// @param providerName The name of the provider.
|
||||
/// @param deviceName The name of the provider device.
|
||||
/// @param useHardware Toggles the use of hardware processing when available.
|
||||
/// @param maxBuffers The maximum buffers for this device to use or -1
|
||||
/// for the device to pick its own reasonable default.
|
||||
/// @param changeDevice Allows this to change the current device to a new one
|
||||
/// @return Returns true if the device was created.
|
||||
bool createDevice( const String& providerName,
|
||||
const String& deviceName,
|
||||
bool useHardware,
|
||||
S32 maxBuffers,
|
||||
bool changeDevice = false);
|
||||
/// This initializes a new device.
|
||||
///
|
||||
/// @return Returns true if the device was created.
|
||||
bool createDevice( SFXProvider* provider);
|
||||
|
||||
/// Returns the current device information or NULL if no
|
||||
/// device is present. The information string is in the
|
||||
/// following format:
|
||||
///
|
||||
/// Provider Name\tDevice Name\tUse Hardware\tMax Buffers
|
||||
String getDeviceInfoString();
|
||||
/// Returns the current device information or NULL if no
|
||||
/// device is present. The information string is in the
|
||||
/// following format:
|
||||
///
|
||||
/// Provider Name\tDevice Name\tUse Hardware\tMax Buffers
|
||||
String getDeviceInfoString();
|
||||
|
||||
/// This destroys the current device. All sources loose their
|
||||
/// playback buffers, but otherwise continue to function.
|
||||
void deleteDevice();
|
||||
/// This destroys the current device. All sources loose their
|
||||
/// playback buffers, but otherwise continue to function.
|
||||
void deleteDevice();
|
||||
|
||||
/// Returns true if a device is allocated.
|
||||
bool hasDevice() const { return mDevice != NULL; }
|
||||
/// Returns true if a device is allocated.
|
||||
bool hasDevice() const { return mDevice != NULL; }
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// @name Source Creation
|
||||
/// @{
|
||||
/// @name Source Creation
|
||||
/// @{
|
||||
|
||||
/// Used to create new sound sources from a sound profile. The
|
||||
/// returned source is in a stopped state and ready for playback.
|
||||
/// Use the SFX_DELETE macro to free the source when your done.
|
||||
///
|
||||
/// @note The track must have at least the same lifetime as the
|
||||
/// source. If the description disappears while the source is still
|
||||
/// there, the source will go with it.
|
||||
///
|
||||
/// @param profile The sound profile for the created source.
|
||||
/// @param transform The optional transform if creating a 3D source.
|
||||
/// @param velocity The optional doppler velocity if creating a 3D source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSource* createSource( SFXTrack* track,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL );
|
||||
/// Used to create new sound sources from a sound profile. The
|
||||
/// returned source is in a stopped state and ready for playback.
|
||||
/// Use the SFX_DELETE macro to free the source when your done.
|
||||
///
|
||||
/// @note The track must have at least the same lifetime as the
|
||||
/// source. If the description disappears while the source is still
|
||||
/// there, the source will go with it.
|
||||
///
|
||||
/// @param profile The sound profile for the created source.
|
||||
/// @param transform The optional transform if creating a 3D source.
|
||||
/// @param velocity The optional doppler velocity if creating a 3D source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSource* createSource( SFXTrack* track,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL );
|
||||
|
||||
/// Used to create a streaming sound source from a user supplied
|
||||
/// stream object.
|
||||
///
|
||||
/// It is only intended for memory based streams. For sound file
|
||||
/// streaming use createSource() with a streaming SFXProfile.
|
||||
///
|
||||
/// Use the SFX_DELETE macro to free the source when your done.
|
||||
///
|
||||
/// @note The description must have at least the same lifetime as the
|
||||
/// sound. If the description disappears while the source is still
|
||||
/// there, the sound will go with it.
|
||||
///
|
||||
/// @param stream The stream used to create the sound buffer. It
|
||||
/// must exist for the lifetime of the source and will
|
||||
/// have its reference count decremented when the source
|
||||
/// is destroyed.
|
||||
///
|
||||
/// @param description The sound description to apply to the source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSound* createSourceFromStream( const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description );
|
||||
/// Used to create a streaming sound source from a user supplied
|
||||
/// stream object.
|
||||
///
|
||||
/// It is only intended for memory based streams. For sound file
|
||||
/// streaming use createSource() with a streaming SFXProfile.
|
||||
///
|
||||
/// Use the SFX_DELETE macro to free the source when your done.
|
||||
///
|
||||
/// @note The description must have at least the same lifetime as the
|
||||
/// sound. If the description disappears while the source is still
|
||||
/// there, the sound will go with it.
|
||||
///
|
||||
/// @param stream The stream used to create the sound buffer. It
|
||||
/// must exist for the lifetime of the source and will
|
||||
/// have its reference count decremented when the source
|
||||
/// is destroyed.
|
||||
///
|
||||
/// @param description The sound description to apply to the source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSound* createSourceFromStream( const ThreadSafeRef< SFXStream >& stream,
|
||||
SFXDescription* description );
|
||||
|
||||
/// Creates a source which when it finishes playing will auto delete
|
||||
/// itself. Be aware that the returned SFXSource pointer should only
|
||||
/// be used for error checking or immediate setting changes. It may
|
||||
/// be deleted as soon as the next system tick.
|
||||
///
|
||||
/// @param profile The sound profile for the created source.
|
||||
/// @param transform The optional transform if creating a 3D source.
|
||||
/// @param velocity The optional doppler velocity if creating a 3D source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSource* playOnce( SFXTrack* track,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL,
|
||||
F32 fadeInTime = -1.f );
|
||||
SFXSource* playOnce( SFXProfile* profile,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL,
|
||||
F32 fadeInTime = -1.f )
|
||||
{ // Avoids having to require inclusion of sfxProfile.h
|
||||
return playOnce( ( SFXTrack* ) profile, transform, velocity, fadeInTime );
|
||||
}
|
||||
/// Creates a source which when it finishes playing will auto delete
|
||||
/// itself. Be aware that the returned SFXSource pointer should only
|
||||
/// be used for error checking or immediate setting changes. It may
|
||||
/// be deleted as soon as the next system tick.
|
||||
///
|
||||
/// @param profile The sound profile for the created source.
|
||||
/// @param transform The optional transform if creating a 3D source.
|
||||
/// @param velocity The optional doppler velocity if creating a 3D source.
|
||||
///
|
||||
/// @return The sound source or NULL if an error occured.
|
||||
SFXSource* playOnce( SFXTrack* track,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL,
|
||||
F32 fadeInTime = -1.f );
|
||||
SFXSource* playOnce( SFXProfile* profile,
|
||||
const MatrixF* transform = NULL,
|
||||
const VectorF* velocity = NULL,
|
||||
F32 fadeInTime = -1.f )
|
||||
{ // Avoids having to require inclusion of sfxProfile.h
|
||||
return playOnce( ( SFXTrack* ) profile, transform, velocity, fadeInTime );
|
||||
}
|
||||
|
||||
/// Stop the source and delete it. This method will take care of
|
||||
/// the fade-out time that the source may need before it will actually
|
||||
/// stop and may be deleted.
|
||||
void stopAndDeleteSource( SFXSource* source );
|
||||
/// Stop the source and delete it. This method will take care of
|
||||
/// the fade-out time that the source may need before it will actually
|
||||
/// stop and may be deleted.
|
||||
void stopAndDeleteSource( SFXSource* source );
|
||||
|
||||
/// Mark source for deletion when it is moving into stopped state.
|
||||
/// This method is useful to basically make a source a play-once source
|
||||
/// after the fact.
|
||||
void deleteWhenStopped( SFXSource* source );
|
||||
/// Mark source for deletion when it is moving into stopped state.
|
||||
/// This method is useful to basically make a source a play-once source
|
||||
/// after the fact.
|
||||
void deleteWhenStopped( SFXSource* source );
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// @name Listeners
|
||||
/// @{
|
||||
/// @name Listeners
|
||||
/// @{
|
||||
|
||||
/// Return the number of listeners currently configured.
|
||||
U32 getNumListeners() const { return mListeners.size(); }
|
||||
/// Return the number of listeners currently configured.
|
||||
U32 getNumListeners() const { return mListeners.size(); }
|
||||
|
||||
/// Set the number of concurrent listeners.
|
||||
/// @note It depends on the selected device if more than one listener is actually supported.
|
||||
void setNumListeners( U32 num );
|
||||
/// Set the number of concurrent listeners.
|
||||
/// @note It depends on the selected device if more than one listener is actually supported.
|
||||
void setNumListeners( U32 num );
|
||||
|
||||
/// Set the property of the given listener.
|
||||
const SFXListenerProperties& getListener( U32 index = 0 ) const { return mListeners[ index ]; }
|
||||
/// Set the property of the given listener.
|
||||
const SFXListenerProperties& getListener( U32 index = 0 ) const { return mListeners[ index ]; }
|
||||
|
||||
/// Set the 3D attributes of the given listener.
|
||||
void setListener( U32 index, const MatrixF& transform, const Point3F& velocity );
|
||||
void setListener( U32 index, const SFXListenerProperties& properties )
|
||||
{
|
||||
setListener( index, properties.getTransform(), properties.getVelocity() );
|
||||
}
|
||||
/// Set the 3D attributes of the given listener.
|
||||
void setListener( U32 index, const MatrixF& transform, const Point3F& velocity );
|
||||
void setListener( U32 index, const SFXListenerProperties& properties )
|
||||
{
|
||||
setListener( index, properties.getTransform(), properties.getVelocity() );
|
||||
}
|
||||
|
||||
/// @}
|
||||
/// @}
|
||||
|
||||
/// @name 3D Sound Configuration
|
||||
/// {
|
||||
/// @name 3D Sound Configuration
|
||||
/// {
|
||||
|
||||
/// Return the curve model currently used distance attenuation of positional sounds.
|
||||
SFXDistanceModel getDistanceModel() const { return mDistanceModel; }
|
||||
/// Return the curve model currently used distance attenuation of positional sounds.
|
||||
SFXDistanceModel getDistanceModel() const { return mDistanceModel; }
|
||||
|
||||
///
|
||||
void setDistanceModel( SFXDistanceModel model );
|
||||
///
|
||||
void setDistanceModel( SFXDistanceModel model );
|
||||
|
||||
///
|
||||
F32 getDopplerFactor() const { return mDopplerFactor; }
|
||||
///
|
||||
F32 getDopplerFactor() const { return mDopplerFactor; }
|
||||
|
||||
///
|
||||
void setDopplerFactor( F32 factor );
|
||||
///
|
||||
void setDopplerFactor( F32 factor );
|
||||
|
||||
///
|
||||
F32 getRolloffFactor() const { return mRolloffFactor; }
|
||||
///
|
||||
F32 getRolloffFactor() const { return mRolloffFactor; }
|
||||
|
||||
/// <summary>
|
||||
/// Change the devices speed of sound.
|
||||
/// </summary>
|
||||
/// <param name="speedOfSound">F32 for speed of sound.</param>
|
||||
void setSpeedOfSound(F32 speedOfSound);
|
||||
|
||||
///
|
||||
void setRolloffFactor( F32 factor );
|
||||
|
||||
///
|
||||
void setRolloffFactor( F32 factor );
|
||||
///
|
||||
const SFXReverbProperties& getReverb() const { return mReverb; }
|
||||
|
||||
///
|
||||
const SFXReverbProperties& getReverb() const { return mReverb; }
|
||||
///
|
||||
void setReverb( const SFXReverbProperties& reverb );
|
||||
|
||||
///
|
||||
void setReverb( const SFXReverbProperties& reverb );
|
||||
/// @}
|
||||
|
||||
/// @}
|
||||
///
|
||||
SFXSoundscapeManager* getSoundscapeManager() const { return mSoundscapeMgr; }
|
||||
|
||||
///
|
||||
SFXSoundscapeManager* getSoundscapeManager() const { return mSoundscapeMgr; }
|
||||
/// Dump information about all current SFXSources to the console or
|
||||
/// to the given StringBuilder.
|
||||
void dumpSources( StringBuilder* toString = NULL, bool excludeGroups = true );
|
||||
|
||||
/// Dump information about all current SFXSources to the console or
|
||||
/// to the given StringBuilder.
|
||||
void dumpSources( StringBuilder* toString = NULL, bool excludeGroups = true );
|
||||
/// Return the SFX system event signal.
|
||||
EventSignalType& getEventSignal() { return mEventSignal; }
|
||||
|
||||
/// Return the SFX system event signal.
|
||||
EventSignalType& getEventSignal() { return mEventSignal; }
|
||||
/// Notify the SFX system that the given description has changed.
|
||||
/// All sources currently using the description will be updated.
|
||||
void notifyDescriptionChanged( SFXDescription* description);
|
||||
|
||||
/// Notify the SFX system that the given description has changed.
|
||||
/// All sources currently using the description will be updated.
|
||||
void notifyDescriptionChanged( SFXDescription* description);
|
||||
|
||||
///
|
||||
void notifyTrackChanged( SFXTrack* track );
|
||||
///
|
||||
void notifyTrackChanged( SFXTrack* track );
|
||||
};
|
||||
|
||||
|
||||
|
|
|
|||
|
|
@ -387,7 +387,7 @@ void SFXWorld< NUM_DIMENSIONS, Object >::_onScopeOut( Object object )
|
|||
// Remove its soundscape.
|
||||
|
||||
Scope& scope = mScopeStack[ index ];
|
||||
if( scope.mSoundscape )
|
||||
if( scope.mSoundscape && SFX )
|
||||
SFX->getSoundscapeManager()->removeSoundscape( scope.mSoundscape );
|
||||
|
||||
mScopeStack.erase( index );
|
||||
|
|
|
|||
|
|
@ -1,125 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/xaudio/sfxXAudioBuffer.h"
|
||||
#include "sfx/xaudio/sfxXAudioVoice.h"
|
||||
|
||||
|
||||
//#define DEBUG_SPEW
|
||||
|
||||
|
||||
SFXXAudioBuffer* SFXXAudioBuffer::create( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
|
||||
{
|
||||
SFXXAudioBuffer *buffer = new SFXXAudioBuffer( stream, description );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
SFXXAudioBuffer::SFXXAudioBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
|
||||
: Parent( stream, description )
|
||||
{
|
||||
VECTOR_SET_ASSOCIATION( mBufferQueue );
|
||||
}
|
||||
|
||||
SFXXAudioBuffer::~SFXXAudioBuffer()
|
||||
{
|
||||
_flush();
|
||||
}
|
||||
|
||||
void SFXXAudioBuffer::write( SFXInternal::SFXStreamPacket* const* packets, U32 num )
|
||||
{
|
||||
AssertFatal( SFXInternal::isSFXThread(), "SFXXAudioBuffer::write() - not on SFX thread" );
|
||||
|
||||
using namespace SFXInternal;
|
||||
|
||||
// Unqueue processed packets.
|
||||
|
||||
if( isStreaming() )
|
||||
{
|
||||
EnterCriticalSection( &_getUniqueVoice()->mLock );
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
_getUniqueVoice()->mXAudioVoice->GetState( &state );
|
||||
|
||||
U32 numProcessed = mBufferQueue.size() - state.BuffersQueued;
|
||||
for( U32 i = 0; i < numProcessed; ++ i )
|
||||
{
|
||||
destructSingle< SFXStreamPacket* >( mBufferQueue.first().mPacket );
|
||||
mBufferQueue.pop_front();
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioBuffer] Unqueued packet" );
|
||||
#endif
|
||||
}
|
||||
|
||||
LeaveCriticalSection( &_getUniqueVoice()->mLock );
|
||||
}
|
||||
|
||||
// Queue new packets.
|
||||
|
||||
for( U32 i = 0; i < num; ++ i )
|
||||
{
|
||||
SFXStreamPacket* packet = packets[ i ];
|
||||
Buffer buffer;
|
||||
|
||||
if( packet->mIsLast )
|
||||
buffer.mData.Flags = XAUDIO2_END_OF_STREAM;
|
||||
|
||||
buffer.mPacket = packet;
|
||||
buffer.mData.AudioBytes = packet->mSizeActual;
|
||||
buffer.mData.pAudioData = packet->data;
|
||||
|
||||
mBufferQueue.push_back( buffer );
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioBuffer] Queued packet" );
|
||||
#endif
|
||||
|
||||
// If this is a streaming buffer, submit the packet to the
|
||||
// voice queue right away.
|
||||
|
||||
if( isStreaming() )
|
||||
{
|
||||
EnterCriticalSection( &_getUniqueVoice()->mLock );
|
||||
|
||||
IXAudio2SourceVoice* voice = _getUniqueVoice()->mXAudioVoice;
|
||||
voice->SubmitSourceBuffer( &buffer.mData );
|
||||
|
||||
LeaveCriticalSection( &_getUniqueVoice()->mLock );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SFXXAudioBuffer::_flush()
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioBuffer] Flushing buffer" );
|
||||
#endif
|
||||
|
||||
if( _getUniqueVoice() )
|
||||
_getUniqueVoice()->_stop();
|
||||
|
||||
while( !mBufferQueue.empty() )
|
||||
{
|
||||
destructSingle( mBufferQueue.last().mPacket );
|
||||
mBufferQueue.pop_back();
|
||||
}
|
||||
}
|
||||
|
|
@ -1,83 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXXAUDIOBUFFER_H_
|
||||
#define _SFXXAUDIOBUFFER_H_
|
||||
|
||||
#include <xaudio2.h>
|
||||
|
||||
#ifndef _SFXINTERNAL_H_
|
||||
#include "sfx/sfxInternal.h"
|
||||
#endif
|
||||
|
||||
#ifndef _TVECTOR_H_
|
||||
#include "core/util/tVector.h"
|
||||
#endif
|
||||
|
||||
|
||||
/// Audio data buffer for the XAudio device layer.
|
||||
class SFXXAudioBuffer : public SFXBuffer
|
||||
{
|
||||
public:
|
||||
|
||||
typedef SFXBuffer Parent;
|
||||
|
||||
friend class SFXXAudioDevice;
|
||||
friend class SFXXAudioVoice;
|
||||
|
||||
protected:
|
||||
|
||||
struct Buffer
|
||||
{
|
||||
XAUDIO2_BUFFER mData;
|
||||
SFXInternal::SFXStreamPacket* mPacket;
|
||||
|
||||
Buffer()
|
||||
: mPacket( 0 )
|
||||
{
|
||||
dMemset( &mData, 0, sizeof( mData ) );
|
||||
}
|
||||
};
|
||||
|
||||
typedef Vector< Buffer > QueueType;
|
||||
|
||||
QueueType mBufferQueue;
|
||||
|
||||
/// If this is a streaming buffer, return the unique voice associated
|
||||
/// with the buffer.
|
||||
SFXXAudioVoice* _getUniqueVoice() { return ( SFXXAudioVoice* ) mUniqueVoice.getPointer(); }
|
||||
|
||||
///
|
||||
SFXXAudioBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
virtual ~SFXXAudioBuffer();
|
||||
|
||||
// SFXBuffer.
|
||||
virtual void write( SFXInternal::SFXStreamPacket* const* packets, U32 num );
|
||||
void _flush();
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
static SFXXAudioBuffer* create( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
};
|
||||
|
||||
#endif // _SFXXAUDIOBUFFER_H_
|
||||
|
|
@ -1,245 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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/xaudio/sfxXAudioDevice.h"
|
||||
#include "platform/async/asyncUpdate.h"
|
||||
#include "core/stringTable.h"
|
||||
#include "console/console.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
#include "core/tAlgorithm.h"
|
||||
#include "platform/profiler.h"
|
||||
|
||||
|
||||
SFXXAudioDevice::SFXXAudioDevice( SFXProvider* provider,
|
||||
const String& name,
|
||||
IXAudio2 *xaudio,
|
||||
U32 deviceIndex,
|
||||
U32 speakerChannelMask,
|
||||
U32 maxBuffers )
|
||||
: Parent( name, provider, false, maxBuffers ),
|
||||
mXAudio( xaudio ),
|
||||
mMasterVoice( NULL )
|
||||
{
|
||||
dMemset( &mListener, 0, sizeof( mListener ) );
|
||||
|
||||
// If mMaxBuffers is negative then use some default value.
|
||||
// to decide on a good maximum value... or set 8.
|
||||
//
|
||||
// TODO: We should change the terminology to voices!
|
||||
if ( mMaxBuffers < 0 )
|
||||
mMaxBuffers = 64;
|
||||
|
||||
// Create the mastering voice.
|
||||
HRESULT hr = mXAudio->CreateMasteringVoice( &mMasterVoice,
|
||||
XAUDIO2_DEFAULT_CHANNELS,
|
||||
XAUDIO2_DEFAULT_SAMPLERATE,
|
||||
0,
|
||||
deviceIndex,
|
||||
NULL );
|
||||
if ( FAILED( hr ) || !mMasterVoice )
|
||||
{
|
||||
Con::errorf( "SFXXAudioDevice - Failed creating master voice!" );
|
||||
return;
|
||||
}
|
||||
|
||||
mMasterVoice->GetVoiceDetails( &mMasterVoiceDetails );
|
||||
|
||||
// Init X3DAudio.
|
||||
X3DAudioInitialize( speakerChannelMask,
|
||||
X3DAUDIO_SPEED_OF_SOUND,
|
||||
mX3DAudio );
|
||||
|
||||
// Start the update thread.
|
||||
|
||||
if( !Con::getBoolVariable( "$_forceAllMainThread" ) )
|
||||
{
|
||||
SFXInternal::gUpdateThread = new AsyncUpdateThread
|
||||
( "XAudio Update Thread", SFXInternal::gBufferUpdateList );
|
||||
SFXInternal::gUpdateThread->start();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
SFXXAudioDevice::~SFXXAudioDevice()
|
||||
{
|
||||
_releaseAllResources();
|
||||
|
||||
if ( mMasterVoice )
|
||||
{
|
||||
mMasterVoice->DestroyVoice();
|
||||
mMasterVoice = NULL;
|
||||
}
|
||||
|
||||
// Kill the engine.
|
||||
SAFE_RELEASE( mXAudio );
|
||||
}
|
||||
|
||||
|
||||
SFXBuffer* SFXXAudioDevice::createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description )
|
||||
{
|
||||
SFXXAudioBuffer* buffer = SFXXAudioBuffer::create( stream, description );
|
||||
if ( !buffer )
|
||||
return NULL;
|
||||
|
||||
_addBuffer( buffer );
|
||||
return buffer;
|
||||
}
|
||||
|
||||
SFXVoice* SFXXAudioDevice::createVoice( bool is3D, SFXBuffer *buffer )
|
||||
{
|
||||
// Don't bother going any further if we've
|
||||
// exceeded the maximum voices.
|
||||
if ( mVoices.size() >= mMaxBuffers )
|
||||
return NULL;
|
||||
|
||||
AssertFatal( buffer, "SFXXAudioDevice::createVoice() - Got null buffer!" );
|
||||
|
||||
SFXXAudioBuffer* xaBuffer = dynamic_cast<SFXXAudioBuffer*>( buffer );
|
||||
AssertFatal( xaBuffer, "SFXXAudioDevice::createVoice() - Got bad buffer!" );
|
||||
|
||||
SFXXAudioVoice* voice = SFXXAudioVoice::create( mXAudio, is3D, xaBuffer );
|
||||
if ( !voice )
|
||||
return NULL;
|
||||
|
||||
voice->mXAudioDevice = this;
|
||||
|
||||
_addVoice( voice );
|
||||
return voice;
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::_setOutputMatrix( SFXXAudioVoice *voice )
|
||||
{
|
||||
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
|
||||
FLOAT32 matrix[12] = { 0 };
|
||||
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
|
||||
dspSettings.pMatrixCoefficients = matrix;
|
||||
|
||||
const X3DAUDIO_EMITTER &emitter = voice->getEmitter();
|
||||
dspSettings.SrcChannelCount = emitter.ChannelCount;
|
||||
|
||||
// Calculate the output volumes and doppler.
|
||||
X3DAudioCalculate( mX3DAudio,
|
||||
&mListener,
|
||||
&emitter,
|
||||
X3DAUDIO_CALCULATE_MATRIX |
|
||||
X3DAUDIO_CALCULATE_DOPPLER,
|
||||
&dspSettings );
|
||||
|
||||
voice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
|
||||
dspSettings.SrcChannelCount,
|
||||
dspSettings.DstChannelCount,
|
||||
dspSettings.pMatrixCoefficients,
|
||||
4321 );
|
||||
|
||||
voice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * voice->mPitch,
|
||||
4321 );
|
||||
|
||||
// Commit the changes.
|
||||
mXAudio->CommitChanges( 4321 );
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::update()
|
||||
{
|
||||
PROFILE_SCOPE( SFXXAudioDevice_Update );
|
||||
|
||||
Parent::update();
|
||||
|
||||
X3DAUDIO_DSP_SETTINGS dspSettings = {0};
|
||||
FLOAT32 matrix[12] = { 0 };
|
||||
dspSettings.DstChannelCount = mMasterVoiceDetails.InputChannels;
|
||||
dspSettings.pMatrixCoefficients = matrix;
|
||||
|
||||
dspSettings.DopplerFactor = mDopplerFactor;
|
||||
|
||||
// Now update the volume and frequency of
|
||||
// all the active 3D voices.
|
||||
VoiceVector::iterator voice = mVoices.begin();
|
||||
for ( ; voice != mVoices.end(); voice++ )
|
||||
{
|
||||
SFXXAudioVoice* xaVoice = ( SFXXAudioVoice* ) *voice;
|
||||
|
||||
// Skip 2D or stopped voices.
|
||||
if ( !xaVoice->is3D() ||
|
||||
xaVoice->getStatus() != SFXStatusPlaying )
|
||||
continue;
|
||||
|
||||
const X3DAUDIO_EMITTER &emitter = xaVoice->getEmitter();
|
||||
dspSettings.SrcChannelCount = emitter.ChannelCount;
|
||||
|
||||
// Calculate the output volumes and doppler.
|
||||
X3DAudioCalculate( mX3DAudio,
|
||||
&mListener,
|
||||
&emitter,
|
||||
X3DAUDIO_CALCULATE_MATRIX |
|
||||
X3DAUDIO_CALCULATE_DOPPLER,
|
||||
&dspSettings );
|
||||
|
||||
xaVoice->mXAudioVoice->SetOutputMatrix( mMasterVoice,
|
||||
dspSettings.SrcChannelCount,
|
||||
dspSettings.DstChannelCount,
|
||||
dspSettings.pMatrixCoefficients,
|
||||
4321 ) ;
|
||||
|
||||
xaVoice->mXAudioVoice->SetFrequencyRatio( dspSettings.DopplerFactor * xaVoice->mPitch,
|
||||
4321 );
|
||||
}
|
||||
|
||||
// Commit the changes.
|
||||
mXAudio->CommitChanges( 4321 );
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::setListener( U32 index, const SFXListenerProperties& listener )
|
||||
{
|
||||
// Get the transform from the listener.
|
||||
const MatrixF& transform = listener.getTransform();
|
||||
transform.getColumn( 3, (Point3F*)&mListener.Position );
|
||||
transform.getColumn( 1, (Point3F*)&mListener.OrientFront );
|
||||
transform.getColumn( 2, (Point3F*)&mListener.OrientTop );
|
||||
|
||||
// And the velocity...
|
||||
const VectorF& velocity = listener.getVelocity();
|
||||
mListener.Velocity.x = velocity.x;
|
||||
mListener.Velocity.y = velocity.y;
|
||||
mListener.Velocity.z = velocity.z;
|
||||
|
||||
// XAudio and Torque use opposite handedness, so
|
||||
// flip the z coord to account for that.
|
||||
mListener.Position.z *= -1.0f;
|
||||
mListener.OrientFront.z *= -1.0f;
|
||||
mListener.OrientTop.z *= -1.0f;
|
||||
mListener.Velocity.z *= -1.0f;
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::setDistanceModel( SFXDistanceModel model )
|
||||
{
|
||||
mDistanceModel = model;
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::setDopplerFactor( F32 factor )
|
||||
{
|
||||
mDopplerFactor = factor;
|
||||
}
|
||||
|
||||
void SFXXAudioDevice::setRolloffFactor( F32 factor )
|
||||
{
|
||||
mRolloffFactor = factor;
|
||||
}
|
||||
|
|
@ -1,101 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXXAUDIODEVICE_H_
|
||||
#define _SFXXAUDIODEVICE_H_
|
||||
|
||||
class SFXProvider;
|
||||
|
||||
#ifndef _SFXDEVICE_H_
|
||||
#include "sfx/sfxDevice.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SFXPROVIDER_H_
|
||||
#include "sfx/sfxProvider.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SFXXAUDIOVOICE_H_
|
||||
#include "sfx/xaudio/sfxXAudioVoice.h"
|
||||
#endif
|
||||
|
||||
#ifndef _SFXXAUDIOBUFFER_H_
|
||||
#include "sfx/xaudio/sfxXAudioBuffer.h"
|
||||
#endif
|
||||
|
||||
#include <xaudio2.h>
|
||||
#include <x3daudio.h>
|
||||
|
||||
|
||||
class SFXXAudioDevice : public SFXDevice
|
||||
{
|
||||
public:
|
||||
|
||||
typedef SFXDevice Parent;
|
||||
friend class SFXXAudioVoice; // mXAudio
|
||||
|
||||
protected:
|
||||
|
||||
/// The XAudio engine interface passed
|
||||
/// on creation from the provider.
|
||||
IXAudio2 *mXAudio;
|
||||
|
||||
/// The X3DAudio instance.
|
||||
X3DAUDIO_HANDLE mX3DAudio;
|
||||
|
||||
/// The one and only mastering voice.
|
||||
IXAudio2MasteringVoice* mMasterVoice;
|
||||
|
||||
/// The details of the master voice.
|
||||
XAUDIO2_VOICE_DETAILS mMasterVoiceDetails;
|
||||
|
||||
/// The one listener.
|
||||
X3DAUDIO_LISTENER mListener;
|
||||
|
||||
SFXDistanceModel mDistanceModel;
|
||||
F32 mRolloffFactor;
|
||||
F32 mDopplerFactor;
|
||||
|
||||
public:
|
||||
|
||||
SFXXAudioDevice( SFXProvider* provider,
|
||||
const String& name,
|
||||
IXAudio2 *xaudio,
|
||||
U32 deviceIndex,
|
||||
U32 speakerChannelMask,
|
||||
U32 maxBuffers );
|
||||
|
||||
virtual ~SFXXAudioDevice();
|
||||
|
||||
// SFXDevice
|
||||
virtual SFXBuffer* createBuffer( const ThreadSafeRef< SFXStream >& stream, SFXDescription* description );
|
||||
virtual SFXVoice* createVoice( bool is3D, SFXBuffer *buffer );
|
||||
virtual void update();
|
||||
virtual void setListener( U32 index, const SFXListenerProperties& listener );
|
||||
virtual void setDistanceModel( SFXDistanceModel model );
|
||||
virtual void setRolloffFactor( F32 factor );
|
||||
virtual void setDopplerFactor( F32 factor );
|
||||
|
||||
/// Called from the voice when its about to start playback.
|
||||
void _setOutputMatrix( SFXXAudioVoice *voice );
|
||||
};
|
||||
|
||||
#endif // _SFXXAUDIODEVICE_H_
|
||||
|
|
@ -1,188 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Note: This must be defined before platform.h so that
|
||||
// CoInitializeEx is properly included.
|
||||
#define _WIN32_DCOM
|
||||
#include <xaudio2.h>
|
||||
|
||||
#include "sfx/xaudio/sfxXAudioDevice.h"
|
||||
#include "sfx/sfxProvider.h"
|
||||
#include "core/util/safeRelease.h"
|
||||
#include "core/strings/unicode.h"
|
||||
#include "core/strings/stringFunctions.h"
|
||||
#include "console/console.h"
|
||||
#include "core/module.h"
|
||||
|
||||
|
||||
class SFXXAudioProvider : public SFXProvider
|
||||
{
|
||||
public:
|
||||
|
||||
SFXXAudioProvider()
|
||||
: SFXProvider( "XAudio" ) {}
|
||||
virtual ~SFXXAudioProvider();
|
||||
|
||||
protected:
|
||||
|
||||
/// Extended SFXDeviceInfo to also store some
|
||||
/// extra XAudio specific data.
|
||||
struct XADeviceInfo : SFXDeviceInfo
|
||||
{
|
||||
UINT32 deviceIndex;
|
||||
|
||||
XAUDIO2_DEVICE_ROLE role;
|
||||
|
||||
WAVEFORMATEXTENSIBLE format;
|
||||
};
|
||||
|
||||
/// Helper for creating the XAudio engine.
|
||||
static bool _createXAudio( IXAudio2 **xaudio );
|
||||
|
||||
public:
|
||||
|
||||
// SFXProvider
|
||||
void init();
|
||||
SFXDevice* createDevice( const String& deviceName, bool useHardware, S32 maxBuffers );
|
||||
|
||||
};
|
||||
|
||||
MODULE_BEGIN( XAudio )
|
||||
|
||||
MODULE_INIT_BEFORE( SFX )
|
||||
MODULE_SHUTDOWN_AFTER( SFX )
|
||||
|
||||
SFXXAudioProvider* mProvider;
|
||||
|
||||
MODULE_INIT
|
||||
{
|
||||
mProvider = new SFXXAudioProvider;
|
||||
}
|
||||
|
||||
MODULE_SHUTDOWN
|
||||
{
|
||||
delete mProvider;
|
||||
}
|
||||
|
||||
MODULE_END;
|
||||
|
||||
SFXXAudioProvider::~SFXXAudioProvider()
|
||||
{
|
||||
}
|
||||
|
||||
void SFXXAudioProvider::init()
|
||||
{
|
||||
// Create a temp XAudio object for device enumeration.
|
||||
IXAudio2 *xAudio = NULL;
|
||||
if ( !_createXAudio( &xAudio ) )
|
||||
{
|
||||
Con::errorf( "SFXXAudioProvider::init() - XAudio2 failed to load!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// Add the devices to the info list.
|
||||
UINT32 count = 0;
|
||||
xAudio->GetDeviceCount( &count );
|
||||
for ( UINT32 i = 0; i < count; i++ )
|
||||
{
|
||||
XAUDIO2_DEVICE_DETAILS details;
|
||||
HRESULT hr = xAudio->GetDeviceDetails( i, &details );
|
||||
if ( FAILED( hr ) )
|
||||
continue;
|
||||
|
||||
// Add a device to the info list.
|
||||
XADeviceInfo* info = new XADeviceInfo;
|
||||
info->deviceIndex = i;
|
||||
info->driver = String( "XAudio" );
|
||||
info->name = String( details.DisplayName );
|
||||
info->hasHardware = false;
|
||||
info->maxBuffers = 64;
|
||||
info->role = details.Role;
|
||||
info->format = details.OutputFormat;
|
||||
mDeviceInfo.push_back( info );
|
||||
}
|
||||
|
||||
// We're done with XAudio for now.
|
||||
SAFE_RELEASE( xAudio );
|
||||
|
||||
// If we have no devices... we're done.
|
||||
if ( mDeviceInfo.empty() )
|
||||
{
|
||||
Con::errorf( "SFXXAudioProvider::init() - No valid XAudio2 devices found!" );
|
||||
return;
|
||||
}
|
||||
|
||||
// If we got this far then we should be able to
|
||||
// safely create a device for XAudio.
|
||||
regProvider( this );
|
||||
}
|
||||
|
||||
bool SFXXAudioProvider::_createXAudio( IXAudio2 **xaudio )
|
||||
{
|
||||
// In debug builds enable the debug version
|
||||
// of the XAudio engine.
|
||||
#ifdef TORQUE_DEBUG
|
||||
#define XAUDIO_FLAGS XAUDIO2_DEBUG_ENGINE
|
||||
#else
|
||||
#define XAUDIO_FLAGS 0
|
||||
#endif
|
||||
|
||||
// This must be called first... it doesn't hurt to
|
||||
// call it more than once.
|
||||
CoInitialize( NULL );
|
||||
|
||||
// Try creating the xaudio engine.
|
||||
HRESULT hr = XAudio2Create( xaudio, XAUDIO_FLAGS, XAUDIO2_DEFAULT_PROCESSOR );
|
||||
|
||||
return SUCCEEDED( hr ) && (*xaudio);
|
||||
}
|
||||
|
||||
SFXDevice* SFXXAudioProvider::createDevice( const String& deviceName, bool useHardware, S32 maxBuffers )
|
||||
{
|
||||
String devName;
|
||||
|
||||
devName = deviceName;
|
||||
|
||||
XADeviceInfo* info = dynamic_cast< XADeviceInfo* >( _findDeviceInfo( devName ) );
|
||||
|
||||
// Do we find one to create?
|
||||
if ( info )
|
||||
{
|
||||
// Create the XAudio object to pass to the device.
|
||||
IXAudio2 *xAudio = NULL;
|
||||
if ( !_createXAudio( &xAudio ) )
|
||||
{
|
||||
Con::errorf( "SFXXAudioProvider::createDevice() - XAudio2 failed to load!" );
|
||||
return NULL;
|
||||
}
|
||||
|
||||
return new SFXXAudioDevice( this,
|
||||
devName,
|
||||
xAudio,
|
||||
info->deviceIndex,
|
||||
info->format.dwChannelMask,
|
||||
maxBuffers );
|
||||
}
|
||||
|
||||
// We didn't find a matching valid device.
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -1,445 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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 "platform/platform.h"
|
||||
#include "sfx/xaudio/sfxXAudioVoice.h"
|
||||
#include "sfx/xaudio/sfxXAudioDevice.h"
|
||||
#include "sfx/xaudio/sfxXAudioBuffer.h"
|
||||
#include "core/util/safeDelete.h"
|
||||
#include "math/mMathFn.h"
|
||||
|
||||
|
||||
//#define DEBUG_SPEW
|
||||
|
||||
|
||||
static void sfxFormatToWAVEFORMATEX( const SFXFormat& format, WAVEFORMATEX *wfx )
|
||||
{
|
||||
dMemset( wfx, 0, sizeof( WAVEFORMATEX ) );
|
||||
wfx->wFormatTag = WAVE_FORMAT_PCM;
|
||||
wfx->nChannels = format.getChannels();
|
||||
wfx->nSamplesPerSec = format.getSamplesPerSecond();
|
||||
wfx->wBitsPerSample = format.getBitsPerChannel();
|
||||
wfx->nBlockAlign = wfx->nChannels * wfx->wBitsPerSample / 8;
|
||||
wfx->nAvgBytesPerSec = wfx->nSamplesPerSec * wfx->nBlockAlign;
|
||||
}
|
||||
|
||||
|
||||
SFXXAudioVoice* SFXXAudioVoice::create( IXAudio2 *xaudio,
|
||||
bool is3D,
|
||||
SFXXAudioBuffer *buffer,
|
||||
SFXXAudioVoice* inVoice )
|
||||
{
|
||||
AssertFatal( xaudio, "SFXXAudioVoice::create() - Got null XAudio!" );
|
||||
AssertFatal( buffer, "SFXXAudioVoice::create() - Got null buffer!" );
|
||||
|
||||
// Create the voice object first as it also the callback object.
|
||||
SFXXAudioVoice* voice = inVoice;
|
||||
if( !voice )
|
||||
voice = new SFXXAudioVoice( buffer );
|
||||
|
||||
// Get the buffer format.
|
||||
WAVEFORMATEX wfx;
|
||||
sfxFormatToWAVEFORMATEX( buffer->getFormat(), &wfx );
|
||||
|
||||
// We don't support multi-channel 3d sounds!
|
||||
if ( is3D && wfx.nChannels > 1 )
|
||||
return NULL;
|
||||
|
||||
// Create the voice.
|
||||
IXAudio2SourceVoice *xaVoice;
|
||||
HRESULT hr = xaudio->CreateSourceVoice( &xaVoice,
|
||||
(WAVEFORMATEX*)&wfx,
|
||||
0,
|
||||
XAUDIO2_DEFAULT_FREQ_RATIO,
|
||||
voice,
|
||||
NULL,
|
||||
NULL );
|
||||
|
||||
if( FAILED( hr ) || !voice )
|
||||
{
|
||||
if( !inVoice )
|
||||
delete voice;
|
||||
return NULL;
|
||||
}
|
||||
|
||||
voice->mIs3D = is3D;
|
||||
voice->mEmitter.ChannelCount = wfx.nChannels;
|
||||
voice->mXAudioVoice = xaVoice;
|
||||
|
||||
return voice;
|
||||
}
|
||||
|
||||
SFXXAudioVoice::SFXXAudioVoice( SFXXAudioBuffer* buffer )
|
||||
: Parent( buffer ),
|
||||
mXAudioDevice( NULL ),
|
||||
mXAudioVoice( NULL ),
|
||||
mIs3D( false ),
|
||||
mPitch( 1.0f ),
|
||||
mHasStopped( false ),
|
||||
mHasStarted( false ),
|
||||
mIsLooping( false ),
|
||||
mIsPlaying( false ),
|
||||
mNonStreamSampleStartPos( 0 ),
|
||||
mNonStreamBufferLoaded( false ),
|
||||
mSamplesPlayedOffset( 0 )
|
||||
{
|
||||
dMemset( &mEmitter, 0, sizeof( mEmitter ) );
|
||||
mEmitter.DopplerScaler = 1.0f;
|
||||
|
||||
InitializeCriticalSection( &mLock );
|
||||
}
|
||||
|
||||
SFXXAudioVoice::~SFXXAudioVoice()
|
||||
{
|
||||
if ( mEmitter.pVolumeCurve )
|
||||
{
|
||||
SAFE_DELETE_ARRAY( mEmitter.pVolumeCurve->pPoints );
|
||||
SAFE_DELETE( mEmitter.pVolumeCurve );
|
||||
}
|
||||
|
||||
SAFE_DELETE( mEmitter.pCone );
|
||||
|
||||
if ( mXAudioVoice )
|
||||
mXAudioVoice->DestroyVoice();
|
||||
|
||||
DeleteCriticalSection( &mLock );
|
||||
}
|
||||
|
||||
SFXStatus SFXXAudioVoice::_status() const
|
||||
{
|
||||
if( mHasStopped )
|
||||
return SFXStatusStopped;
|
||||
else if( mHasStarted )
|
||||
{
|
||||
if( !mIsPlaying )
|
||||
return SFXStatusPaused;
|
||||
else
|
||||
return SFXStatusPlaying;
|
||||
}
|
||||
else
|
||||
return SFXStatusStopped;
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_flush()
|
||||
{
|
||||
AssertFatal( mXAudioVoice != NULL,
|
||||
"SFXXAudioVoice::_flush() - invalid voice" );
|
||||
|
||||
EnterCriticalSection( &mLock );
|
||||
|
||||
mXAudioVoice->Stop( 0 );
|
||||
mXAudioVoice->FlushSourceBuffers();
|
||||
mNonStreamBufferLoaded = false;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Flushed state" );
|
||||
#endif
|
||||
|
||||
mIsPlaying = false;
|
||||
mHasStarted = false;
|
||||
mHasStopped = true;
|
||||
|
||||
//WORKAROUND: According to the docs, SamplesPlayed reported by the
|
||||
// voice should get reset as soon as we submit a new buffer to the voice.
|
||||
// Alas it won't. So, save the current value here and offset our future
|
||||
// play cursors.
|
||||
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
mXAudioVoice->GetState( &state );
|
||||
mSamplesPlayedOffset = - S32( state.SamplesPlayed );
|
||||
|
||||
LeaveCriticalSection( &mLock );
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_play()
|
||||
{
|
||||
AssertFatal( mXAudioVoice != NULL,
|
||||
"SFXXAudioVoice::_play() - invalid voice" );
|
||||
|
||||
// For non-streaming voices queue the data if we haven't yet.
|
||||
|
||||
if( !mBuffer->isStreaming() && !mNonStreamBufferLoaded )
|
||||
_loadNonStreamed();
|
||||
|
||||
// Start playback.
|
||||
|
||||
mXAudioVoice->Start( 0, 0 );
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Started playback" );
|
||||
#endif
|
||||
|
||||
mIsPlaying = true;
|
||||
mHasStarted = true;
|
||||
mHasStopped = false;
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_pause()
|
||||
{
|
||||
AssertFatal( mXAudioVoice != NULL,
|
||||
"SFXXAudioVoice::_pause() - invalid voice" );
|
||||
|
||||
mXAudioVoice->Stop( 0 );
|
||||
mIsPlaying = false;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Paused playback" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_stop()
|
||||
{
|
||||
AssertFatal( mXAudioVoice != NULL,
|
||||
"SFXXAudioVoice::_stop() - invalid voice" );
|
||||
|
||||
_flush();
|
||||
|
||||
mIsPlaying = false;
|
||||
mHasStarted = false;
|
||||
mHasStopped = true;
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Stopped playback" );
|
||||
#endif
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_seek( U32 sample )
|
||||
{
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Seeking to %i", sample );
|
||||
#endif
|
||||
|
||||
mNonStreamSampleStartPos = sample;
|
||||
|
||||
bool wasPlaying = mIsPlaying;
|
||||
|
||||
_stop();
|
||||
if( wasPlaying )
|
||||
_play();
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::_loadNonStreamed()
|
||||
{
|
||||
AssertFatal( !mBuffer->isStreaming(), "SFXXAudioVoice::_loadNonStreamed - must not be called on streaming voices" );
|
||||
AssertFatal( mXAudioVoice != NULL, "SFXXAudioVoice::_loadNonStreamed - invalid voice" );
|
||||
AssertWarn( !mNonStreamBufferLoaded, "SFXXAudioVoice::_nonStreamNonstreamed - Data already loaded" );
|
||||
|
||||
#ifdef DEBUG_SPEW
|
||||
Platform::outputDebugString( "[SFXXAudioVoice] Loading non-stream buffer at %i", mNonStreamSampleStartPos );
|
||||
#endif
|
||||
|
||||
EnterCriticalSection( &mLock );
|
||||
|
||||
const XAUDIO2_BUFFER& orgBuffer = _getBuffer()->mBufferQueue.front().mData;
|
||||
|
||||
mNonStreamBuffer = orgBuffer;
|
||||
|
||||
if( mNonStreamSampleStartPos )
|
||||
{
|
||||
mNonStreamBuffer.PlayBegin = mNonStreamSampleStartPos;
|
||||
mNonStreamBuffer.PlayLength = _getBuffer()->getNumSamples() - mNonStreamSampleStartPos;
|
||||
mSamplesPlayedOffset += mNonStreamSampleStartPos; // Add samples that we are skipping.
|
||||
mNonStreamSampleStartPos = 0;
|
||||
}
|
||||
|
||||
if( mIsLooping )
|
||||
{
|
||||
mNonStreamBuffer.LoopCount = XAUDIO2_LOOP_INFINITE;
|
||||
mNonStreamBuffer.LoopLength = _getBuffer()->getNumSamples();
|
||||
}
|
||||
|
||||
// Submit buffer.
|
||||
|
||||
mXAudioVoice->SubmitSourceBuffer( &mNonStreamBuffer );
|
||||
mNonStreamBufferLoaded = true;
|
||||
|
||||
LeaveCriticalSection( &mLock );
|
||||
}
|
||||
|
||||
U32 SFXXAudioVoice::_tell() const
|
||||
{
|
||||
XAUDIO2_VOICE_STATE state;
|
||||
mXAudioVoice->GetState( &state );
|
||||
|
||||
// Workaround SamplesPlayed not getting reset.
|
||||
return ( state.SamplesPlayed + mSamplesPlayedOffset );
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setMinMaxDistance( F32 min, F32 max )
|
||||
{
|
||||
// Set the overall volume curve scale.
|
||||
mEmitter.CurveDistanceScaler = max;
|
||||
|
||||
// The curve uses normalized distances, so
|
||||
// figure out the normalized min distance.
|
||||
F32 normMin = 0.0f;
|
||||
if ( min > 0.0f )
|
||||
normMin = min / max;
|
||||
|
||||
// See what type of curve we are supposed to generate.
|
||||
const bool linear = ( mXAudioDevice->mDistanceModel == SFXDistanceModelLinear );
|
||||
|
||||
// Have we setup the curve yet?
|
||||
if( !mEmitter.pVolumeCurve
|
||||
|| ( linear && mEmitter.pVolumeCurve->PointCount != 2 )
|
||||
|| ( !linear && mEmitter.pVolumeCurve->PointCount != 6 ) )
|
||||
{
|
||||
if( !mEmitter.pVolumeCurve )
|
||||
mEmitter.pVolumeCurve = new X3DAUDIO_DISTANCE_CURVE;
|
||||
else
|
||||
SAFE_DELETE_ARRAY( mEmitter.pVolumeCurve->pPoints );
|
||||
|
||||
// We use 6 points for logarithmic volume curves and 2 for linear volume curves.
|
||||
if( linear )
|
||||
{
|
||||
mEmitter.pVolumeCurve->pPoints = new X3DAUDIO_DISTANCE_CURVE_POINT[ 2 ];
|
||||
mEmitter.pVolumeCurve->PointCount = 2;
|
||||
}
|
||||
else
|
||||
{
|
||||
mEmitter.pVolumeCurve->pPoints = new X3DAUDIO_DISTANCE_CURVE_POINT[ 6 ];
|
||||
mEmitter.pVolumeCurve->PointCount = 6;
|
||||
}
|
||||
|
||||
// The first and last points are known
|
||||
// and will not change.
|
||||
mEmitter.pVolumeCurve->pPoints[ 0 ].Distance = 0.0f;
|
||||
mEmitter.pVolumeCurve->pPoints[ 0 ].DSPSetting = 1.0f;
|
||||
mEmitter.pVolumeCurve->pPoints[ linear ? 1 : 5 ].Distance = 1.0f;
|
||||
mEmitter.pVolumeCurve->pPoints[ linear ? 1 : 5 ].DSPSetting = 0.0f;
|
||||
}
|
||||
|
||||
if( !linear )
|
||||
{
|
||||
// Set the second point of the curve.
|
||||
mEmitter.pVolumeCurve->pPoints[1].Distance = normMin;
|
||||
mEmitter.pVolumeCurve->pPoints[1].DSPSetting = 1.0f;
|
||||
|
||||
// The next three points are calculated to
|
||||
// give the sound a rough logarithmic falloff.
|
||||
F32 distStep = ( 1.0f - normMin ) / 4.0f;
|
||||
for ( U32 i=0; i < 3; i++ )
|
||||
{
|
||||
U32 index = 2 + i;
|
||||
F32 dist = normMin + ( distStep * (F32)( i + 1 ) );
|
||||
|
||||
mEmitter.pVolumeCurve->pPoints[index].Distance = dist;
|
||||
mEmitter.pVolumeCurve->pPoints[index].DSPSetting = 1.0f - log10( dist * 10.0f );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::OnBufferEnd( void* bufferContext )
|
||||
{
|
||||
if( mBuffer->isStreaming() )
|
||||
SFXInternal::TriggerUpdate();
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::OnStreamEnd()
|
||||
{
|
||||
// Warning: This is being called within the XAudio
|
||||
// thread, so be sure you're thread safe!
|
||||
|
||||
mHasStopped = true;
|
||||
|
||||
if( mBuffer->isStreaming() )
|
||||
SFXInternal::TriggerUpdate();
|
||||
else
|
||||
_stop();
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::play( bool looping )
|
||||
{
|
||||
// Give the device a chance to calculate our positional
|
||||
// audio settings before we start playback... this is
|
||||
// important else we get glitches.
|
||||
if( mIs3D )
|
||||
mXAudioDevice->_setOutputMatrix( this );
|
||||
|
||||
mIsLooping = looping;
|
||||
Parent::play( looping );
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setVelocity( const VectorF& velocity )
|
||||
{
|
||||
mEmitter.Velocity.x = velocity.x;
|
||||
mEmitter.Velocity.y = velocity.y;
|
||||
|
||||
// XAudio and Torque use opposite handedness, so
|
||||
// flip the z coord to account for that.
|
||||
mEmitter.Velocity.z = -velocity.z;
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setTransform( const MatrixF& transform )
|
||||
{
|
||||
transform.getColumn( 3, (Point3F*)&mEmitter.Position );
|
||||
transform.getColumn( 1, (Point3F*)&mEmitter.OrientFront );
|
||||
transform.getColumn( 2, (Point3F*)&mEmitter.OrientTop );
|
||||
|
||||
// XAudio and Torque use opposite handedness, so
|
||||
// flip the z coord to account for that.
|
||||
mEmitter.Position.z *= -1.0f;
|
||||
mEmitter.OrientFront.z *= -1.0f;
|
||||
mEmitter.OrientTop.z *= -1.0f;
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setVolume( F32 volume )
|
||||
{
|
||||
mXAudioVoice->SetVolume( volume );
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setPitch( F32 pitch )
|
||||
{
|
||||
mPitch = mClampF( pitch, XAUDIO2_MIN_FREQ_RATIO, XAUDIO2_DEFAULT_FREQ_RATIO );
|
||||
mXAudioVoice->SetFrequencyRatio( mPitch );
|
||||
}
|
||||
|
||||
void SFXXAudioVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume )
|
||||
{
|
||||
// If the cone is set to 360 then the
|
||||
// cone is null and doesn't need to be
|
||||
// set on the voice.
|
||||
if ( mIsEqual( innerAngle, 360 ) )
|
||||
{
|
||||
SAFE_DELETE( mEmitter.pCone );
|
||||
return;
|
||||
}
|
||||
|
||||
if ( !mEmitter.pCone )
|
||||
{
|
||||
mEmitter.pCone = new X3DAUDIO_CONE;
|
||||
|
||||
// The inner volume is always 1... the overall
|
||||
// volume is what scales it.
|
||||
mEmitter.pCone->InnerVolume = 1.0f;
|
||||
|
||||
// We don't use these yet.
|
||||
mEmitter.pCone->InnerLPF = 0.0f;
|
||||
mEmitter.pCone->OuterLPF = 0.0f;
|
||||
mEmitter.pCone->InnerReverb = 0.0f;
|
||||
mEmitter.pCone->OuterReverb = 0.0f;
|
||||
}
|
||||
|
||||
mEmitter.pCone->InnerAngle = mDegToRad( innerAngle );
|
||||
mEmitter.pCone->OuterAngle = mDegToRad( outerAngle );
|
||||
mEmitter.pCone->OuterVolume = outerVolume;
|
||||
}
|
||||
|
|
@ -1,154 +0,0 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
#ifndef _SFXXAUDIOVOICE_H_
|
||||
#define _SFXXAUDIOVOICE_H_
|
||||
|
||||
#include <xaudio2.h>
|
||||
#include <x3daudio.h>
|
||||
|
||||
#include "sfx/sfxVoice.h"
|
||||
|
||||
|
||||
class SFXXAudioBuffer;
|
||||
|
||||
|
||||
class SFXXAudioVoice : public SFXVoice,
|
||||
public IXAudio2VoiceCallback
|
||||
{
|
||||
public:
|
||||
|
||||
typedef SFXVoice Parent;
|
||||
|
||||
friend class SFXXAudioDevice;
|
||||
friend class SFXXAudioBuffer;
|
||||
|
||||
protected:
|
||||
|
||||
/// This constructor does not create a valid voice.
|
||||
/// @see SFXXAudioVoice::create
|
||||
SFXXAudioVoice( SFXXAudioBuffer* buffer );
|
||||
|
||||
/// The device that created us.
|
||||
SFXXAudioDevice *mXAudioDevice;
|
||||
|
||||
/// The XAudio voice.
|
||||
IXAudio2SourceVoice *mXAudioVoice;
|
||||
|
||||
///
|
||||
CRITICAL_SECTION mLock;
|
||||
|
||||
/// Used to know what sounds need positional updates.
|
||||
bool mIs3D;
|
||||
|
||||
/// Whether the voice has stopped playing.
|
||||
mutable bool mHasStopped;
|
||||
|
||||
/// Whether we have started playback.
|
||||
bool mHasStarted;
|
||||
|
||||
/// Whether playback is currently running.
|
||||
bool mIsPlaying;
|
||||
|
||||
/// Whether playback is looping.
|
||||
bool mIsLooping;
|
||||
|
||||
/// Since 3D sounds are pitch shifted for doppler
|
||||
/// effect we need to track the users base pitch.
|
||||
F32 mPitch;
|
||||
|
||||
/// The cached X3DAudio emitter data.
|
||||
X3DAUDIO_EMITTER mEmitter;
|
||||
|
||||
/// XAudio does not reset the SamplesPlayed count as is stated in the docs. To work around
|
||||
/// that, we offset the values reported by XAudio through this field.
|
||||
S32 mSamplesPlayedOffset;
|
||||
|
||||
/// @name Data for Non-Streaming Voices
|
||||
/// @{
|
||||
|
||||
/// Whether we have loaded our non-streaming data. We use an explicit
|
||||
/// flag here as we really can't rely on XAUDIO2_VOICE_STATE.
|
||||
bool mNonStreamBufferLoaded;
|
||||
|
||||
/// Audio buffer for non-streaming voice.
|
||||
XAUDIO2_BUFFER mNonStreamBuffer;
|
||||
|
||||
/// Sample to start playing at when seting up #mNonStreamBuffer.
|
||||
U32 mNonStreamSampleStartPos;
|
||||
|
||||
/// @}
|
||||
|
||||
// IXAudio2VoiceCallback
|
||||
void STDMETHODCALLTYPE OnStreamEnd();
|
||||
void STDMETHODCALLTYPE OnVoiceProcessingPassStart( UINT32 BytesRequired ) {}
|
||||
void STDMETHODCALLTYPE OnVoiceProcessingPassEnd() {}
|
||||
void STDMETHODCALLTYPE OnBufferEnd( void *bufferContext );
|
||||
void STDMETHODCALLTYPE OnBufferStart( void *bufferContext ) {}
|
||||
void STDMETHODCALLTYPE OnLoopEnd( void *bufferContext ) {}
|
||||
void STDMETHODCALLTYPE OnVoiceError( void * bufferContext, HRESULT error ) {}
|
||||
|
||||
/// @deprecated This is only here for compatibility with
|
||||
/// the March 2008 SDK version of IXAudio2VoiceCallback.
|
||||
void STDMETHODCALLTYPE OnVoiceProcessingPassStart() {}
|
||||
|
||||
void _flush();
|
||||
void _loadNonStreamed();
|
||||
|
||||
// SFXVoice.
|
||||
virtual SFXStatus _status() const;
|
||||
virtual void _play();
|
||||
virtual void _pause();
|
||||
virtual void _stop();
|
||||
virtual void _seek( U32 sample );
|
||||
virtual U32 _tell() const;
|
||||
|
||||
SFXXAudioBuffer* _getBuffer() const { return ( SFXXAudioBuffer* ) mBuffer.getPointer(); }
|
||||
|
||||
public:
|
||||
|
||||
///
|
||||
static SFXXAudioVoice* create( IXAudio2 *xaudio,
|
||||
bool is3D,
|
||||
SFXXAudioBuffer *buffer,
|
||||
SFXXAudioVoice* inVoice = NULL );
|
||||
|
||||
///
|
||||
virtual ~SFXXAudioVoice();
|
||||
|
||||
// SFXVoice
|
||||
void setMinMaxDistance( F32 min, F32 max );
|
||||
void play( bool looping );
|
||||
void setVelocity( const VectorF& velocity );
|
||||
void setTransform( const MatrixF& transform );
|
||||
void setVolume( F32 volume );
|
||||
void setPitch( F32 pitch );
|
||||
void setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume );
|
||||
|
||||
/// Is this a 3D positional voice.
|
||||
bool is3D() const { return mIs3D; }
|
||||
|
||||
///
|
||||
const X3DAUDIO_EMITTER& getEmitter() const { return mEmitter; }
|
||||
};
|
||||
|
||||
#endif // _SFXXAUDIOVOICE_H_
|
||||
|
|
@ -70,9 +70,7 @@ function CoreModule::onCreate(%this)
|
|||
|
||||
// Init the physics plugin.
|
||||
physicsInit();
|
||||
|
||||
sfxStartup();
|
||||
|
||||
|
||||
// Set up networking.
|
||||
setNetPort(0);
|
||||
|
||||
|
|
|
|||
|
|
@ -3,10 +3,10 @@ function Core_SFX::onCreate(%this)
|
|||
{
|
||||
exec("./scripts/audio." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioData." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioStates." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioEnvironments." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioAmbience." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioDescriptions." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioEnvironments." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioStates." @ $TorqueScriptFileExtension);
|
||||
exec("./scripts/audioOptions." @ $TorqueScriptFileExtension);
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -145,10 +145,6 @@ function sfxStartup()
|
|||
function sfxInit()
|
||||
{
|
||||
// If already initialized, shut down the current device first.
|
||||
|
||||
if( sfxGetDeviceInfo() !$= "" )
|
||||
sfxShutdown();
|
||||
|
||||
if ($isDedicated)
|
||||
{
|
||||
sfxCreateDevice("Null","Null Device", false, 8);
|
||||
|
|
@ -156,12 +152,16 @@ function sfxInit()
|
|||
}
|
||||
|
||||
// Start it up!
|
||||
%maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers;
|
||||
if ( !sfxCreateDevice( $pref::SFX::provider, $pref::SFX::device, $pref::SFX::useHardware, %maxBuffers ) )
|
||||
return false;
|
||||
%info = sfxGetDeviceInfo();
|
||||
if(%info $= "" )
|
||||
{
|
||||
%maxBuffers = $pref::SFX::useHardware ? -1 : $pref::SFX::maxSoftwareBuffers;
|
||||
if ( !sfxCreateDevice() )
|
||||
return false;
|
||||
}
|
||||
|
||||
// This returns a tab seperated string with
|
||||
// the initialized system info.
|
||||
// the initialized system info
|
||||
%info = sfxGetDeviceInfo();
|
||||
$pref::SFX::provider = getField( %info, 0 );
|
||||
$pref::SFX::device = getField( %info, 1 );
|
||||
|
|
|
|||
|
|
@ -23,22 +23,27 @@
|
|||
singleton SFXAmbience( AudioAmbienceDefault )
|
||||
{
|
||||
environment = AudioEnvOff;
|
||||
dopplerFactor = "1";
|
||||
};
|
||||
|
||||
singleton SFXAmbience( AudioAmbienceOutside )
|
||||
{
|
||||
environment = AudioEnvPlain;
|
||||
states[ 0 ] = AudioLocationOutside;
|
||||
dopplerFactor = "1";
|
||||
};
|
||||
|
||||
singleton SFXAmbience( AudioAmbienceInside )
|
||||
{
|
||||
environment = AudioEnvRoom;
|
||||
states[ 0 ] = AudioLocationInside;
|
||||
dopplerFactor = "1";
|
||||
};
|
||||
|
||||
singleton SFXAmbience( AudioAmbienceUnderwater )
|
||||
{
|
||||
environment = AudioEnvUnderwater;
|
||||
states[ 0 ] = AudioLocationUnderwater;
|
||||
dopplerFactor = "0.5";
|
||||
speedOfSound = "1500.0";
|
||||
};
|
||||
|
|
|
|||
|
|
@ -6,8 +6,8 @@ new SimGroup(AudioSettingsGroup)
|
|||
new SimGroup()
|
||||
{
|
||||
class = "SubOptionsGroup";
|
||||
displayName = "Audio Devices";
|
||||
|
||||
displayName = "Audio Settings";
|
||||
|
||||
new SimGroup(AudioSettingsProviderGroup)
|
||||
{
|
||||
class = "AudioOptionsSettings";
|
||||
|
|
@ -15,7 +15,7 @@ new SimGroup(AudioSettingsGroup)
|
|||
OptionName = "Audio Provider";
|
||||
Description = "";
|
||||
};
|
||||
|
||||
|
||||
new SimGroup(AudioSettingsDeviceGroup)
|
||||
{
|
||||
class = "AudioOptionsSettings";
|
||||
|
|
@ -31,43 +31,40 @@ function AudioSettingsGroup::populateSettings(%this)
|
|||
AudioSettingsProviderGroup.clear();
|
||||
AudioSettingsDeviceGroup.clear();
|
||||
|
||||
%buffer = sfxGetAvailableDevices();
|
||||
%count = getRecordCount( %buffer );
|
||||
|
||||
for(%i = 0; %i < %count; %i++)
|
||||
%pCount = sfxGetProviderCount();
|
||||
for(%i = 0; %i < %pCount; %i++)
|
||||
{
|
||||
%record = getRecord(%buffer, %i);
|
||||
%provider = getField(%record, 0);
|
||||
%device = getField(%record, 1);
|
||||
|
||||
//When the client is actually running, we don't care about null audo devices
|
||||
if(%provider $= "null")
|
||||
continue;
|
||||
|
||||
//We can't have duplicate providers, so double check for uniqueness
|
||||
%foundProvider = false;
|
||||
foreach(%registeredProviders in AudioSettingsProviderGroup)
|
||||
%provider = sfxGetProviderType(%i);
|
||||
if(%provider !$= "NullProvider")
|
||||
{
|
||||
if(%registeredProviders.displayName $= %provider)
|
||||
//We can't have duplicate providers, so double check for uniqueness
|
||||
%foundProvider = false;
|
||||
foreach(%registeredProviders in AudioSettingsProviderGroup)
|
||||
{
|
||||
%foundProvider = true;
|
||||
break;
|
||||
if(%registeredProviders.displayName $= %provider)
|
||||
{
|
||||
%foundProvider = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
if(!%foundProvider)
|
||||
{
|
||||
//Provider entry
|
||||
%providerEntry = new ArrayObject()
|
||||
{
|
||||
class = "OptionsQualityLevel";
|
||||
displayName = %provider;
|
||||
key["$pref::SFX::provider"] = %provider;
|
||||
};
|
||||
AudioSettingsProviderGroup.add(%providerEntry);
|
||||
}
|
||||
}
|
||||
|
||||
if(!%foundProvider)
|
||||
{
|
||||
//Provider entry
|
||||
%providerEntry = new ArrayObject()
|
||||
{
|
||||
class = "OptionsQualityLevel";
|
||||
displayName = %provider;
|
||||
key["$pref::SFX::provider"] = %provider;
|
||||
};
|
||||
|
||||
AudioSettingsProviderGroup.add(%providerEntry);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
for(%i = 0; %i < %pCount; %i++)
|
||||
{
|
||||
%device = sfxGetProviderDevice(%i);
|
||||
//Device Entry
|
||||
%deviceEntry = new ArrayObject()
|
||||
{
|
||||
|
|
@ -93,10 +90,7 @@ function AudioSettingsDeviceGroup::onApply(%this)
|
|||
|
||||
function updateAudioOptionsSettings()
|
||||
{
|
||||
if ( !sfxCreateDevice( $pref::SFX::provider,
|
||||
$pref::SFX::device,
|
||||
$pref::SFX::useHardware,
|
||||
-1 ) )
|
||||
if ( !sfxCreateDevice() )
|
||||
error( "Unable to create SFX device: " @ $pref::SFX::provider
|
||||
SPC $pref::SFX::device
|
||||
SPC $pref::SFX::useHardware );
|
||||
|
|
|
|||
|
|
@ -223,7 +223,6 @@ function OptionsMenu::openOptionsCategory(%this, %categoryName)
|
|||
else if(%categoryName $= "Audio")
|
||||
{
|
||||
$MenuList = AudioSettingsList;
|
||||
|
||||
%this.currentCatgeoryIdx = 1;
|
||||
}
|
||||
else if(%categoryName $= "KBM")
|
||||
|
|
|
|||
|
|
@ -1,8 +0,0 @@
|
|||
# OpenAL module
|
||||
option(TORQUE_SFX_DIRECTX "Use DirectSound SFX" OFF)
|
||||
|
||||
if(TORQUE_SFX_DIRECTX AND WIN32)
|
||||
message("Enabling DirectSound Module")
|
||||
|
||||
torqueAddSourceDirectories("${CMAKE_SOURCE_DIR}/Engine/source/sfx/dsound" "${CMAKE_SOURCE_DIR}/Engine/source/sfx/xaudio")
|
||||
endif(TORQUE_SFX_DIRECTX AND WIN32)
|
||||
Loading…
Add table
Add a link
Reference in a new issue