Torque3D/Engine/source/sfx/dsound/sfxDSDevice.cpp

230 lines
7.4 KiB
C++
Raw Normal View History

2012-09-19 15:15:01 +00:00
//-----------------------------------------------------------------------------
// 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.
}