sfxDSVoice.cpp
Engine/source/sfx/dsound/sfxDSVoice.cpp
Detailed Description
1 2//----------------------------------------------------------------------------- 3// Copyright (c) 2012 GarageGames, LLC 4// 5// Permission is hereby granted, free of charge, to any person obtaining a copy 6// of this software and associated documentation files (the "Software"), to 7// deal in the Software without restriction, including without limitation the 8// rights to use, copy, modify, merge, publish, distribute, sublicense, and/or 9// sell copies of the Software, and to permit persons to whom the Software is 10// furnished to do so, subject to the following conditions: 11// 12// The above copyright notice and this permission notice shall be included in 13// all copies or substantial portions of the Software. 14// 15// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING 20// FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS 21// IN THE SOFTWARE. 22//----------------------------------------------------------------------------- 23 24#include "sfx/dsound/sfxDSVoice.h" 25#include "sfx/dsound/sfxDSDevice.h" 26#include "core/util/safeRelease.h" 27 28 29SFXDSVoice* SFXDSVoice::create( SFXDSDevice *device, SFXDSBuffer *buffer ) 30{ 31 AssertFatal( buffer, "SFXDSVoice::create() - Got null buffer!" ); 32 33 IDirectSoundBuffer8 *dsBuffer8 = NULL; 34 if ( !buffer->createVoice( &dsBuffer8 ) || !dsBuffer8 ) 35 return NULL; 36 37 // Now try to grab a 3D interface... if we don't 38 // get one its probably because its not a 3d sound. 39 IDirectSound3DBuffer8* dsBuffer3d8 = NULL; 40 dsBuffer8->QueryInterface( IID_IDirectSound3DBuffer8, (LPVOID*)&dsBuffer3d8 ); 41 42 // Create the voice and return! 43 SFXDSVoice* voice = new SFXDSVoice( device, 44 buffer, 45 dsBuffer8, 46 dsBuffer3d8 ); 47 48 // Now set the voice to a default state. 49 // The buffer from which we have duplicated may have been assigned different 50 // properties and we don't want to inherit these. 51 52 voice->setVolume( 1.0 ); 53 voice->setPitch( 1.0 ); 54 55 return voice; 56} 57 58SFXDSVoice::SFXDSVoice( SFXDSDevice *device, 59 SFXDSBuffer *buffer, 60 IDirectSoundBuffer8 *dsBuffer, 61 IDirectSound3DBuffer8 *dsBuffer3d ) 62 : Parent( buffer ), 63 mDevice( device ), 64 mDSBuffer( dsBuffer ), 65 mDSBuffer3D( dsBuffer3d ), 66 mIsLooping( false ) 67{ 68 AssertFatal( mDevice, "SFXDSVoice::SFXDSVoice() - SFXDSDevice is null!" ); 69 AssertFatal( mBuffer, "SFXDSVoice::SFXDSVoice() - SFXDSBuffer is null!" ); 70 AssertFatal( mDSBuffer, "SFXDSVoice::SFXDSVoice() - Dsound buffer is null!" ); 71} 72 73SFXDSVoice::~SFXDSVoice() 74{ 75 SAFE_RELEASE( mDSBuffer3D ); 76 77 SFXDSBuffer* dsBuffer = _getBuffer(); 78 if( dsBuffer ) 79 dsBuffer->releaseVoice( &mDSBuffer ); 80 81 mBuffer = NULL; 82} 83 84SFXStatus SFXDSVoice::_status() const 85{ 86 DWORD status = 0; 87 mDSBuffer->GetStatus( &status ); 88 89 if ( status & DSBSTATUS_PLAYING ) 90 return SFXStatusPlaying; 91 else 92 return SFXStatusStopped; 93} 94 95void SFXDSVoice::_play() 96{ 97 DSAssert( mDSBuffer->Play( 0, 0, mIsLooping ? DSBPLAY_LOOPING : 0 ), 98 "SFXDSVoice::_play() - Playback failed!" ); 99} 100 101void SFXDSVoice::_stop() 102{ 103 DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" ); 104 mDSBuffer->SetCurrentPosition( 0 ); 105} 106 107void SFXDSVoice::_pause() 108{ 109 DSAssert( mDSBuffer->Stop(), "SFXDSVoice::pause - stop failed!" ); 110} 111 112void SFXDSVoice::_seek( U32 sample ) 113{ 114 U32 pos = mBuffer->getFormat().getBytesPerSample() * sample; 115 mDSBuffer->SetCurrentPosition( pos ); 116} 117 118U32 SFXDSVoice::_tell() const 119{ 120 DWORD position = 0; 121 mDSBuffer->GetCurrentPosition( &position, NULL ); 122 U32 samplePos = _getBuffer()->getSamplePos( position ); 123 return samplePos; 124} 125 126void SFXDSVoice::setMinMaxDistance( F32 min, F32 max ) 127{ 128 if ( !mDSBuffer3D ) 129 return; 130 131 mDSBuffer3D->SetMinDistance( min, DS3D_DEFERRED ); 132 mDSBuffer3D->SetMaxDistance( max, DS3D_DEFERRED ); 133} 134 135void SFXDSVoice::play( bool looping ) 136{ 137 // If this is a 3d sound then we need 138 // to commit any deferred settings before 139 // we start playback else we can get some 140 // glitches. 141 142 if ( mDSBuffer3D ) 143 mDevice->_commitDeferred(); 144 145 // If this is a streaming buffer, 146 // force looping. 147 148 const bool isStreaming = mBuffer->isStreaming(); 149 if( isStreaming ) 150 looping = true; 151 mIsLooping = looping; 152 153 Parent::play( looping ); 154} 155 156void SFXDSVoice::setVelocity( const VectorF& velocity ) 157{ 158 if ( !mDSBuffer3D ) 159 return; 160 161 DSAssert( mDSBuffer3D->SetVelocity( velocity.x, velocity.z, velocity.y, DS3D_DEFERRED ), 162 "SFXDSVoice::setVelocity - couldn't update buffer!" ); 163} 164 165void SFXDSVoice::setTransform( const MatrixF& transform ) 166{ 167 if ( !mDSBuffer3D ) 168 return; 169 170 Point3F pos, dir; 171 transform.getColumn( 3, &pos ); 172 transform.getColumn( 1, &dir ); 173 DSAssert( mDSBuffer3D->SetPosition( pos.x, pos.z, pos.y, DS3D_DEFERRED ), 174 "SFXDSVoice::setTransform - couldn't set position of the buffer." ); 175 176 DSAssert( mDSBuffer3D->SetConeOrientation( dir.x, dir.z, dir.y, DS3D_DEFERRED ), 177 "SFXDSVoice::setTransform - couldn't set cone orientation of the buffer." ); 178} 179 180/// Helper for converting floating point linear volume 181/// to a logrithmic integer volume for dsound. 182LONG SFXDSVoice::_linearToLogVolume( F32 linVolume ) 183{ 184 LONG logVolume; 185 186 if ( linVolume <= 0.0f ) 187 logVolume = DSBVOLUME_MIN; 188 else 189 { 190 logVolume = -2000.0 * mLog( 1.0f / linVolume ); 191 logVolume = mClamp( logVolume, DSBVOLUME_MIN, DSBVOLUME_MAX ); 192 } 193 194 return logVolume; 195} 196 197void SFXDSVoice::setVolume( F32 volume ) 198{ 199 LONG logVolume = _linearToLogVolume( volume ); 200 201 HRESULT hr = mDSBuffer->SetVolume( logVolume ); 202 DSAssert( hr, "SFXDSVoice::setVolume - couldn't set volume!" ); 203} 204 205void SFXDSVoice::setPitch( F32 pitch ) 206{ 207 F32 sampleRate = _getBuffer()->getFormat().getSamplesPerSecond(); 208 F32 frequency = mFloor( mClampF( sampleRate * pitch, DSBFREQUENCY_MIN, DSBFREQUENCY_MAX ) ); 209 210 DSAssert( mDSBuffer->SetFrequency( ( U32 )frequency ), 211 "SFXDSVoice::setPitch - couldn't set playback frequency."); 212} 213 214void SFXDSVoice::setCone( F32 innerAngle, F32 outerAngle, F32 outerVolume ) 215{ 216 if ( !mDSBuffer3D ) 217 return; 218 219 DSAssert( mDSBuffer3D->SetConeAngles( innerAngle, 220 outerAngle, 221 DS3D_DEFERRED ), 222 "SFXDSVoice::setCone - couldn't set cone angles!" ); 223 224 225 LONG logVolume = _linearToLogVolume( outerVolume ); 226 227 DSAssert( mDSBuffer3D->SetConeOutsideVolume( logVolume, 228 DS3D_DEFERRED ), 229 "SFXDSVoice::setCone - couldn't set cone outside volume!" ); 230} 231