sfxDSVoice.cpp

Engine/source/sfx/dsound/sfxDSVoice.cpp

More...

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