mirror of
https://github.com/TorqueGameEngines/Torque3D.git
synced 2026-04-29 00:05:40 +00:00
Engine directory for ticket #1
This commit is contained in:
parent
352279af7a
commit
7dbfe6994d
3795 changed files with 1363358 additions and 0 deletions
27
Engine/source/sfx/dsound/dsFunctions.h
Normal file
27
Engine/source/sfx/dsound/dsFunctions.h
Normal file
|
|
@ -0,0 +1,27 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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) )
|
||||
|
||||
277
Engine/source/sfx/dsound/sfxDSBuffer.cpp
Normal file
277
Engine/source/sfx/dsound/sfxDSBuffer.cpp
Normal file
|
|
@ -0,0 +1,277 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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) );
|
||||
}
|
||||
101
Engine/source/sfx/dsound/sfxDSBuffer.h
Normal file
101
Engine/source/sfx/dsound/sfxDSBuffer.h
Normal file
|
|
@ -0,0 +1,101 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_
|
||||
229
Engine/source/sfx/dsound/sfxDSDevice.cpp
Normal file
229
Engine/source/sfx/dsound/sfxDSDevice.cpp
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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.
|
||||
}
|
||||
142
Engine/source/sfx/dsound/sfxDSDevice.h
Normal file
142
Engine/source/sfx/dsound/sfxDSDevice.h
Normal file
|
|
@ -0,0 +1,142 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_
|
||||
198
Engine/source/sfx/dsound/sfxDSProvider.cpp
Normal file
198
Engine/source/sfx/dsound/sfxDSProvider.cpp
Normal file
|
|
@ -0,0 +1,198 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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;
|
||||
}
|
||||
229
Engine/source/sfx/dsound/sfxDSVoice.cpp
Normal file
229
Engine/source/sfx/dsound/sfxDSVoice.cpp
Normal file
|
|
@ -0,0 +1,229 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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!" );
|
||||
}
|
||||
92
Engine/source/sfx/dsound/sfxDSVoice.h
Normal file
92
Engine/source/sfx/dsound/sfxDSVoice.h
Normal file
|
|
@ -0,0 +1,92 @@
|
|||
//-----------------------------------------------------------------------------
|
||||
// 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_
|
||||
Loading…
Add table
Add a link
Reference in a new issue