# Home    # nevrax.com   
Nevrax
Nevrax.org
#News
#Mailing-list
#Documentation
#CVS
#Bugs
#License
Docs
 
Documentation  
Main Page   Namespace List   Class Hierarchy   Alphabetical List   Compound List   File List   Namespace Members   Compound Members   File Members   Related Pages   Search  

source_dsound.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 #include "stddsound.h"
00028 #include "source_dsound.h"
00029 #include "sound_driver_dsound.h"
00030 #include "buffer_dsound.h"
00031 #include "listener_dsound.h"
00032 
00033 
00034 
00035 using namespace NLMISC;
00036 
00037 
00038 namespace NLSOUND {
00039 
00040 
00041 #if NLSOUND_PROFILE
00042 
00043         #define INITTIME(_var)   TTicks _var = CTime::getPerformanceTime()
00044 
00045         #define DEBUG_POSITIONS  1
00046 
00047         #if DEBUG_POSITIONS
00048         #define DBGPOS(_a) nldebug ## _a
00049         #else
00050         #define DBGPOS(_a) 
00051         #endif
00052 
00053 #else
00054         #define INITTIME(_var)
00055         #define DBGPOS(_a) 
00056 #endif
00057 
00058 
00059 
00060 uint32 CSourceDSound::_SecondaryBufferSize = 65536;
00061 uint32 CSourceDSound::_SwapCopySize = 32768;
00062 uint32 CSourceDSound::_UpdateCopySize = 16384;
00063 uint32 CSourceDSound::_XFadeSize = 64;
00064 uint CSourceDSound::_DefaultChannels = 1;
00065 uint CSourceDSound::_DefaultSampleRate = 22050;
00066 uint CSourceDSound::_DefaultSampleSize = 16;
00067 
00068 
00069 
00070 #define NLSOUND_MIN(_a,_b)        (((_a) < (_b)) ? (_a) : (_b))
00071 #define NLSOUND_DISTANCE(_from, _to, _period)   (((_to) > (_from)) ? (_to) - (_from) : (_period) + (_to) - (_from))
00072 
00073 
00074 #if NLSOUND_PROFILE
00075 
00076 // Static variables used for profiling
00077 double CSourceDSound::_LastSwapTime = 0.0;
00078 double CSourceDSound::_TotalSwapTime = 0.0;
00079 double CSourceDSound::_MaxSwapTime = 0.0;
00080 double CSourceDSound::_MinSwapTime = 1000000.0;
00081 uint32 CSourceDSound::_SwapCount = 0;
00082 double CSourceDSound::_PosTime = 0.0;
00083 double CSourceDSound::_LockTime = 0.0;
00084 double CSourceDSound::_CopyTime = 0.0;
00085 double CSourceDSound::_UnlockTime = 0.0;
00086 uint32 CSourceDSound::_CopyCount = 0;
00087 double CSourceDSound::_TotalUpdateTime = 0.0;
00088 double CSourceDSound::_MaxUpdateTime = 0.0;
00089 double CSourceDSound::_MinUpdateTime = 1000000.0;
00090 uint32 CSourceDSound::_UpdateCount = 0;
00091 uint32 CSourceDSound::_TotalUpdateSize = 0;
00092 #endif
00093 
00094 
00095 
00096 // ******************************************************************
00097 
00098 CSourceDSound::CSourceDSound( uint sourcename ) : ISource(), _SourceName(sourcename)
00099 {
00100         _BufferSize = 0;
00101         _SwapBuffer = 0;
00102         _SecondaryBuffer = 0;
00103         _SecondaryBufferState = NL_DSOUND_SILENCED;
00104         _3DBuffer = 0;
00105         _NextWritePos = 0;
00106         _BytesWritten = 0;
00107         _SilenceWritten = 0;
00108         _Loop = false;
00109         _EndPosition = 0;
00110         _EndState = NL_DSOUND_TAIL1;
00111         _UserState = NL_DSOUND_STOPPED;
00112         _Freq = 1.0f;
00113         _SampleRate = _DefaultSampleRate;
00114         _IsUsed = false;
00115         _Gain = 1.0f;
00116         _Volume = 0;
00117         _Alpha = 0.0;
00118         InitializeCriticalSection(&_CriticalSection);
00119 }
00120 
00121 
00122 // ******************************************************************
00123 
00124 CSourceDSound::~CSourceDSound()
00125 {
00126         nldebug("Destroying DirectSound source");
00127 
00128         CSoundDriverDSound::instance()->removeSource(this);
00129 
00130         EnterCriticalSection(&_CriticalSection); 
00131 
00132         // Release the DirectSound buffer within the critical zone
00133         // to avoid a call to update during deconstruction
00134         release();
00135 
00136         LeaveCriticalSection(&_CriticalSection); 
00137         DeleteCriticalSection(&_CriticalSection);
00138 }
00139 
00140 
00141 // ******************************************************************
00142 
00143 void CSourceDSound::release()
00144 {
00145         _Buffer = 0;
00146 
00147         if (_SecondaryBuffer != 0)
00148         {
00149                 _SecondaryBuffer->Stop();
00150         }
00151 
00152         if (_3DBuffer != 0)
00153         {
00154                 _3DBuffer->Release();
00155                 _3DBuffer = 0;
00156         }
00157 
00158         if (_SecondaryBuffer != 0)
00159         {
00160                 _SecondaryBuffer->Release();
00161                 _SecondaryBuffer = 0;
00162         }
00163 
00164 }
00165 
00166 // ******************************************************************
00167 
00168 void CSourceDSound::init(LPDIRECTSOUND directSound)
00169 {
00170 
00171         // Initialize the buffer format
00172         WAVEFORMATEX format;
00173 
00174         format.cbSize = sizeof(WAVEFORMATEX);
00175         format.nChannels = _DefaultChannels;
00176         format.wBitsPerSample = _DefaultSampleSize;
00177         format.nSamplesPerSec = _DefaultSampleRate;
00178         format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
00179         format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
00180         format.wFormatTag = WAVE_FORMAT_PCM;
00181 
00182 
00183         // Initialize the buffer description 
00184 
00185         DSBUFFERDESC desc;
00186 
00187         CSoundDriverDSound* driver = CSoundDriverDSound::instance();
00188 
00189 
00190         ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00191         desc.dwSize = sizeof(DSBUFFERDESC);
00192         desc.lpwfxFormat = &format;
00193         desc.dwBufferBytes = _SecondaryBufferSize;      
00194         desc.dwReserved = 0; 
00195 
00196         if (driver->countHw3DBuffers() > 0)
00197         {
00198                 //nldebug("Source: Allocating 3D buffer in hardware");
00199                 desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2 
00200                                                 | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
00201         } 
00202         else
00203         {
00204                 //nldebug("Source: Allocating 3D buffer in software");
00205                 desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2 
00206                                                 | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
00207                 desc.guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
00208                 //desc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
00209         }
00210 
00211 
00212         // Allocate the secondary buffer
00213  
00214         if (FAILED(directSound->CreateSoundBuffer(&desc, &_SecondaryBuffer, NULL))) 
00215         {
00216                 nlwarning("Source: Failed to create a buffer with 3D capabilities.");
00217 
00218                 ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00219                 desc.dwSize = sizeof(DSBUFFERDESC);
00220                 desc.lpwfxFormat = &format;
00221                 desc.dwBufferBytes = _SecondaryBufferSize;      
00222                 desc.dwReserved = 0; 
00223 
00224                 if (driver->countHw2DBuffers() > 0)
00225                 {
00226                         //nldebug("Source: Allocating 2D buffer in hardware");
00227                         desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
00228                 } 
00229                 else
00230                 {
00231                         //nldebug("Source: Allocating 2D buffer in software");
00232                         desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
00233                 }
00234 
00235                 if (FAILED(directSound->CreateSoundBuffer(&desc, &_SecondaryBuffer, NULL))) 
00236                 {
00237                         throw ESoundDriver("Failed to allocate the DirectSound secondary buffer");
00238                 }
00239         }
00240 
00241 
00242         // Fill the buffer with silence
00243 
00244         LPVOID ptr;
00245         DWORD bytes;
00246 
00247         if (FAILED(_SecondaryBuffer->Lock(0, 0, &ptr, &bytes, NULL, NULL, DSBLOCK_ENTIREBUFFER)))
00248         {
00249                 throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
00250         }
00251 
00252         memset(ptr, 0, bytes);
00253         
00254         _SecondaryBuffer->Unlock(ptr, bytes, 0, 0);
00255 
00256         // Allocate the 3D interface, if necessary
00257 
00258         if (FAILED(_SecondaryBuffer->QueryInterface(IID_IDirectSound3DBuffer, (LPVOID *) &_3DBuffer)))
00259         {
00260            throw ESoundDriver("Failed to allocate the DirectSound 3D buffer");
00261         }
00262 
00263 
00264         if (FAILED(_SecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING)))
00265         {
00266                 throw ESoundDriver("Play failed");
00267         }
00268 
00269 }
00270 
00271 // ******************************************************************
00272 
00273 void CSourceDSound::reset()
00274 {
00275         setPitch(1.0f);
00276         setLooping(false);
00277         setGain(1.0f);
00278 }
00279 
00280 
00281 // ******************************************************************
00282 
00283 void CSourceDSound::setStaticBuffer( IBuffer *buffer )
00284 {
00285         EnterCriticalSection(&_CriticalSection); 
00286 
00287         // If the user calls setStaticBuffer with a null buffer,
00288         // stop the currently playing buffer and set it to null.
00289         // Otherwise, store the buffer in the swap buffer variable.
00290         // A crossfade between the current buffer and the swap buffer
00291         // will be done when the user calls play.
00292         if (buffer == 0)
00293         {
00294                 stop();
00295                 _Buffer = 0;
00296                 _BufferSize = 0;
00297                 _BytesWritten = 0;
00298         }
00299 
00300         _SwapBuffer = _Buffer = buffer;
00301 
00302         LeaveCriticalSection(&_CriticalSection); 
00303 }
00304 
00305 
00306 
00307 // ******************************************************************
00308 
00309 void CSourceDSound::setLooping( bool l )
00310 {
00311         _Loop = l;
00312 }
00313 
00314 
00315 // ******************************************************************
00316 
00317 bool CSourceDSound::getLooping() const
00318 {
00319         return _Loop;
00320 }
00321 
00322 
00323 // ******************************************************************
00324 
00325 void CSourceDSound::swap()
00326 {
00327         _Buffer = _SwapBuffer;
00328         _BufferSize = _Buffer->getSize();
00329         _BytesWritten = 0;
00330         _SwapBuffer = 0;
00331 }
00332 
00333 // ******************************************************************
00334 
00335 bool CSourceDSound::play()
00336 {
00337         EnterCriticalSection(&_CriticalSection); 
00338 
00339         if (_Buffer == 0 || ((CBufferDSound*) _Buffer)->getData() == 0)
00340         {
00341                 // the sample has been unloaded, can't play!
00342 
00343                 LeaveCriticalSection(&_CriticalSection); 
00344                 return false;
00345         }
00346 
00347 
00348         DBGPOS(("[%p] PLAY: Enter, buffer state = %u", this, _SecondaryBufferState));
00349         switch (_SecondaryBufferState)
00350         {
00351         case NL_DSOUND_FILLING:
00352                 if (_SwapBuffer != 0)
00353                 {
00354                         // crossfade to the new sound 
00355                         DBGPOS(("[%p] PLAY: XFading 1", this));
00356                         crossFade();
00357                 }
00358                 break;
00359 
00360         case NL_DSOUND_SILENCING:
00361                 if (_SwapBuffer != 0)
00362                 {
00363                         if ((_Buffer != 0) && (_UserState == NL_DSOUND_PLAYING))
00364                         {
00365                                 // crossfade to the new sound
00366                                 DBGPOS(("[%p] PLAY: XFading 2", this));
00367                                 crossFade();
00368                         }
00369                         else
00370                         {
00371                                 DBGPOS(("[%p] PLAY: Swap & fadein 1", this));
00372                                 swap();
00373                                 fadeIn();
00374                         }
00375                 }
00376                 else
00377                 {
00378                         DBGPOS(("[%p] PLAY: Fadein", this));
00379                         _BytesWritten = 0;
00380                         // start the old sound again
00381                         fadeIn();
00382                 }
00383 
00384                 break;
00385 
00386 
00387         case NL_DSOUND_SILENCED:
00388                 if (_SwapBuffer != 0)
00389                 {
00390                         // fade in to the new sound
00391                                 DBGPOS(("[%p] PLAY: Swap & fadein 2", this));
00392                         swap();
00393                         fadeIn();
00394                 }
00395                 else
00396                 {
00397                         DBGPOS(("[%p] PLAY: Fadein", this));
00398                         _BytesWritten = 0;
00399                         // start the old sound again
00400                         fadeIn();
00401                 }
00402         }
00403 
00404         _UserState = NL_DSOUND_PLAYING;
00405         DBGPOS(("[%p] PLAY: PLAYING", this));
00406 
00407         //nldebug ("NLSOUND: %p play", this);
00408 
00409         LeaveCriticalSection(&_CriticalSection); 
00410 
00411         return true;
00412 }
00413 
00414 
00415 // ******************************************************************
00416 
00417 void CSourceDSound::stop()
00418 {
00419         EnterCriticalSection(&_CriticalSection); 
00420 
00421         TSourceDSoundUserState old = _UserState;
00422 
00423         _UserState = NL_DSOUND_STOPPED;
00424         DBGPOS(("[%p] STOP: STOPPED", this));
00425 
00426         //nldebug ("NLSOUND: %p stop", this);
00427 
00428         if (old == NL_DSOUND_PLAYING)
00429         {
00430                 fadeOut();
00431         }
00432 
00433         _BytesWritten = 0;
00434 
00435         LeaveCriticalSection(&_CriticalSection); 
00436 }
00437 
00438 // ******************************************************************
00439 
00440 void CSourceDSound::pause()
00441 {
00442         EnterCriticalSection(&_CriticalSection); 
00443 
00444         TSourceDSoundUserState old = _UserState;
00445 
00446         _UserState = NL_DSOUND_PAUSED;
00447         DBGPOS(("[%p] PAUZ: PAUSED", this));
00448 
00449         //nldebug ("NLOUND: pause %p", this);
00450 
00451         if (old == NL_DSOUND_PLAYING)
00452         {
00453                 fadeOut();
00454         }
00455 
00456         LeaveCriticalSection(&_CriticalSection); 
00457 }
00458 
00459 // ******************************************************************
00460 
00461 bool CSourceDSound::isPlaying() const
00462 {
00463         return (_UserState == NL_DSOUND_PLAYING);
00464 }
00465 
00466 
00467 // ******************************************************************
00468 
00469 bool CSourceDSound::isPaused() const
00470 {
00471         return (_UserState == NL_DSOUND_PAUSED);
00472 }
00473 
00474 
00475 // ******************************************************************
00476 
00477 bool CSourceDSound::isStopped() const
00478 {
00479         return (_UserState == NL_DSOUND_STOPPED);
00480 }
00481 
00482 
00483 // ******************************************************************
00484 
00485 bool CSourceDSound::needsUpdate()
00486 {
00487         DWORD playPos, writePos;
00488         uint32 space;
00489         
00490         if (_SecondaryBuffer == 0)
00491         {
00492                 return true;
00493         }
00494 
00495         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
00496 
00497                 
00498         if (playPos == _NextWritePos)
00499         {
00500                 return false;
00501         }
00502         else if (playPos > _NextWritePos) 
00503         {
00504                 space = playPos - _NextWritePos;
00505         }
00506         else
00507         {
00508                 space = _SecondaryBufferSize + playPos - _NextWritePos;
00509         }
00510         
00511         // Don't bother if the number of samples is smaller than the copy size.
00512         return (space > _UpdateCopySize);
00513 }
00514 
00515 
00516 
00517 // ******************************************************************
00518 
00519 void CSourceDSound::update()
00520 {
00521         update2();
00522 }
00523 
00524 // ******************************************************************
00525 
00526 bool CSourceDSound::update2()
00527 {
00528         bool res = false;
00529 
00530 
00531 
00532         INITTIME(start);
00533 
00534         //
00535         // Enter critical region
00536         //
00537         EnterCriticalSection(&_CriticalSection);
00538 
00539 
00540         switch (_SecondaryBufferState)
00541         {
00542 
00543 
00544         case NL_DSOUND_SILENCED:
00545                 {
00546                         // Just pretend were writing silence by advancing the next 
00547                         // write position.
00548                         _NextWritePos += _UpdateCopySize;
00549                         if (_NextWritePos >= _SecondaryBufferSize)
00550                         {
00551                                 _NextWritePos  -= _SecondaryBufferSize;
00552                         }
00553                 }
00554                 break;
00555 
00556 
00557         case NL_DSOUND_FILLING:
00558                 res = fill();   
00559                 break;
00560 
00561 
00562         case NL_DSOUND_SILENCING:
00563                 res = silence();        
00564                 break;
00565 
00566         }
00567 
00568 
00569         //
00570         // Leave critical region
00571         //
00572         LeaveCriticalSection(&_CriticalSection); 
00573 
00574 
00575 #if NLSOUND_PROFILE
00576         double dt = CTime::ticksToSecond(CTime::getPerformanceTime() - start);;
00577         _TotalUpdateTime += dt;
00578         _MaxUpdateTime = (dt > _MaxUpdateTime) ? dt : _MaxUpdateTime;
00579         _MinUpdateTime = (dt < _MinUpdateTime) ? dt : _MinUpdateTime;
00580         _UpdateCount++;
00581 #endif
00582 
00583         return res;
00584 }
00585 
00586 
00587 
00588 // ******************************************************************
00589 
00590 void CSourceDSound::setPos( const NLMISC::CVector& pos, bool deferred )
00591 {
00592         _Pos = pos;
00593         // Coordinate system: conversion from NeL to OpenAL/GL:
00594         if (_3DBuffer != NULL)
00595         {
00596                 if (_3DBuffer->SetPosition(pos.x, pos.z, pos.y, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
00597                 {
00598                         nlwarning ("SetPosition failed");
00599                 }
00600                 else
00601                 {
00602                         //nlwarning ("%p set source NEL(p:%.2f/%.2f/%.2f) DS(p:%.2f/%.2f/%.2f)", this, pos.x, pos.y, pos.z, pos.x, pos.z, pos.y);
00603                 }
00604         }
00605 }
00606 
00607 
00608 // ******************************************************************
00609 
00610 const NLMISC::CVector &CSourceDSound::getPos() const
00611 {
00612         return _Pos;
00613         // Coordinate system: conversion from NeL to OpenAL/GL:
00614 /*      if (_3DBuffer != NULL)
00615         {
00616                 D3DVECTOR v;
00617                 HRESULT hr = _3DBuffer->GetPosition(&v);
00618 
00619                 if (hr != DS_OK)
00620                 {
00621                         nlwarning ("GetPosition failed");
00622                         pos.set(0, 0, 0);       
00623                 }
00624                 else
00625                 {
00626                         pos.set(v.x, v.z, v.y);
00627                 }
00628         }
00629         else
00630         {
00631                 pos.set(0, 0, 0);       
00632         }
00633 */
00634 }
00635 
00636 
00637 // ******************************************************************
00638 
00639 void CSourceDSound::setVelocity( const NLMISC::CVector& vel, bool deferred )
00640 {
00641         if (_3DBuffer != NULL)
00642         {
00643                 if (_3DBuffer->SetVelocity(vel.x, vel.z, vel.y, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
00644                 {
00645                         nlwarning ("SetVelocity failed");
00646                 }
00647         }
00648 }
00649 
00650 
00651 // ******************************************************************
00652 
00653 void CSourceDSound::getVelocity( NLMISC::CVector& vel ) const
00654 {
00655         if (_3DBuffer != NULL)
00656         {
00657                 D3DVECTOR v;
00658 
00659                 if (_3DBuffer->GetVelocity(&v) != DS_OK)
00660                 {
00661                         nlwarning ("GetVelocity failed");
00662                         vel.set(0, 0, 0);       
00663                 }
00664                 else
00665                 {
00666                         vel.set(v.x, v.z, v.y);
00667                 }
00668         }
00669         else
00670         {
00671                 vel.set(0, 0, 0);       
00672         }
00673 }
00674 
00675 
00676 // ******************************************************************
00677 
00678 void CSourceDSound::setDirection( const NLMISC::CVector& dir )
00679 {
00680         if (_3DBuffer != 0)
00681         {
00682                 if (_3DBuffer->SetConeOrientation(dir.x, dir.z, dir.y, DS3D_DEFERRED) != DS_OK)
00683                 {
00684                         nlwarning ("SetConeOrientation failed (x=%.2f, y=%.2f, z=%.2f)", dir.x, dir.y, dir.z);
00685                 }
00686                 else
00687                 {
00688                         //nlwarning ("NLSOUND: %p set source direction NEL(p:%.2f/%.2f/%.2f) DS(p:%.2f/%.2f/%.2f)", this, dir.x, dir.y, dir.z, dir.x, dir.z, dir.y);
00689                 }
00690         }
00691 }
00692 
00693 
00694 // ******************************************************************
00695 
00696 void CSourceDSound::getDirection( NLMISC::CVector& dir ) const
00697 {
00698         if (_3DBuffer != NULL)
00699         {
00700                 D3DVECTOR v;
00701 
00702                 if (_3DBuffer->GetConeOrientation(&v) != DS_OK)
00703                 {
00704                         nlwarning("GetConeOrientation failed");
00705                         dir.set(0, 0, 1);       
00706                 }
00707                 else
00708                 {
00709                         dir.set(v.x, v.z, v.y);
00710                 }
00711         }
00712         else
00713         {
00714                 dir.set(0, 0, 1);       
00715         }
00716 }
00717 
00718 
00719 // ******************************************************************
00720 
00721 void CSourceDSound::setGain( float gain )
00722 {
00723         clamp(gain, 0.00001f, 1.0f);
00724         _Gain = gain;
00725 
00726         /* convert from linear amplitude to hundredths of decibels */
00727         _Volume = (uint32)(100.0 * 20.0 * log10(gain));
00728         clamp(_Volume, DSBVOLUME_MIN, DSBVOLUME_MAX);
00729 
00730         //nlwarning ("set gain %f vol %d", gain, _Volume);
00731 
00732         /*
00733         if ((_SecondaryBuffer != 0) && (_SecondaryBuffer->SetVolume(_Volume) != DS_OK))
00734         {
00735                 nlwarning("SetVolume failed");
00736         }
00737         */
00738 }
00739 
00740 
00741 /*
00742  * Get the gain
00743  */
00744 float CSourceDSound::getGain() const
00745 {
00746         return _Gain;
00747 }
00748 
00749 
00750 // ******************************************************************
00751 
00752 void CSourceDSound::setPitch( float coeff )
00753 {
00754 //      _Freq = coeff;
00755 
00756         if ((_Buffer != 0) && (_SecondaryBuffer != 0))
00757         {
00758                 TSampleFormat format;
00759                 uint freq;
00760 
00761                 _Buffer->getFormat(format, freq);
00762 
00763                 _SampleRate = (uint32) (coeff * (float) freq);
00764 
00765                 //nlwarning("Freq=%d", newfreq);
00766 
00767                 if (_SecondaryBuffer->SetFrequency(_SampleRate) != DS_OK)
00768                 {
00769 //                      nlwarning("SetFrequency failed (buffer freq=%d, NeL freq=%.5f, DSound freq=%d)", freq, coeff, newfreq);
00770                         nlwarning("SetFrequency");
00771                 }
00772         }
00773 }
00774 
00775 
00776 // ******************************************************************
00777 
00778 float CSourceDSound::getPitch() const
00779 {
00780         if ((_Buffer != 0) && (_SecondaryBuffer != 0))
00781         {
00782                 TSampleFormat format;
00783                 uint freq0;
00784                 DWORD freq;
00785 
00786                 _Buffer->getFormat(format, freq0);
00787 
00788                 if (_SecondaryBuffer->GetFrequency(&freq) != DS_OK)
00789                 {
00790                         nlwarning("GetFrequency failed");
00791                         return 1.0;
00792                 }
00793 
00794                 return ((float) freq / (float) freq0);
00795         }
00796 
00797         return 1.0;
00798 }
00799 
00800 
00801 // ******************************************************************
00802 
00803 void CSourceDSound::setSourceRelativeMode( bool mode )
00804 {
00805         if (_3DBuffer != 0)
00806         {
00807                 HRESULT hr;
00808 
00809                 if (mode)
00810                 {
00811                         hr = _3DBuffer->SetMode(DS3DMODE_HEADRELATIVE, DS3D_IMMEDIATE);
00812                 }
00813                 else
00814                 {
00815                         hr = _3DBuffer->SetMode(DS3DMODE_NORMAL, DS3D_IMMEDIATE);
00816                 }
00817 
00818                 if (hr != DS_OK)
00819                 {
00820                         nlwarning("SetMode failed");
00821                 }
00822         }
00823         else
00824         {
00825                 nlwarning("Requested setSourceRelativeMode on a non-3D source");
00826         }
00827 }
00828 
00829 
00830 // ******************************************************************
00831 
00832 bool CSourceDSound::getSourceRelativeMode() const
00833 {
00834         if (_3DBuffer != 0)
00835         {
00836                 DWORD mode;
00837 
00838                 if (_3DBuffer->GetMode(&mode) != DS_OK)
00839                 {
00840                         nlwarning("GetMode failed");
00841                         return false;
00842                 }
00843 
00844                 return (mode == DS3DMODE_HEADRELATIVE);
00845         }
00846         else
00847         {
00848                 nlwarning("Requested setSourceRelativeMode on a non-3D source");
00849                 return false;
00850         }
00851 }
00852 
00853 
00854 // ******************************************************************
00855 
00856 void CSourceDSound::setMinMaxDistances( float mindist, float maxdist, bool deferred )
00857 {
00858         if (_3DBuffer != 0)
00859         {
00860                 if (_3DBuffer->SetMinDistance(mindist, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
00861                 {
00862                         nlwarning("SetMinDistance (%f) failed", mindist);
00863                 }
00864                 if (_3DBuffer->SetMaxDistance(maxdist, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
00865                 {
00866                         nlwarning("SetMaxDistance (%f) failed", maxdist);
00867                 }
00868         }
00869         else
00870         {
00871                 nlwarning("Requested setMinMaxDistances on a non-3D source");
00872         }
00873 }
00874 
00875 
00876 // ******************************************************************
00877 
00878 void CSourceDSound::getMinMaxDistances( float& mindist, float& maxdist ) const
00879 {
00880         if (_3DBuffer != 0)
00881         {
00882                 D3DVALUE min, max;
00883 
00884                 if ((_3DBuffer->GetMinDistance(&min) != DS_OK)
00885                         || (_3DBuffer->GetMaxDistance(&max) != DS_OK))
00886                 {
00887                         mindist = 0.0f;
00888                         maxdist = 0.0f;
00889                         nlwarning("GetMinDistance or GetMaxDistance failed");
00890                 }
00891                 else
00892                 {
00893                         mindist = min;
00894                         maxdist = max;
00895                 }
00896         }
00897         else
00898         {
00899                 mindist = 0.0f;
00900                 maxdist = 0.0f;
00901                 nlwarning("Requested getMinMaxDistances on a non-3D source");
00902         }
00903 }
00904 
00905 // ******************************************************************
00906 
00907 void CSourceDSound::updateVolume( const NLMISC::CVector& listener )
00908 {
00909         CVector pos = getPos();
00910         pos -= listener;
00911 
00912         float sqrdist = pos.sqrnorm();
00913         float min, max;
00914 
00915         getMinMaxDistances(min, max);
00916 
00917         if (sqrdist < min * min) 
00918         {
00919                 _SecondaryBuffer->SetVolume(_Volume);
00920                 //nlwarning("VOLUME = %ddB, rolloff = %0.2f", _Volume/100, CListenerDSound::instance()->getRolloffFactor());
00921         }
00922         else if (sqrdist > max * max)
00923         {
00924                 _SecondaryBuffer->SetVolume(DSBVOLUME_MIN);
00925                 //nlwarning("VOLUME = %ddB, rolloff = %0.2f", DSBVOLUME_MIN/100, CListenerDSound::instance()->getRolloffFactor());
00926         }
00927         else
00928         {
00929                 sint32 db = _Volume;
00930 
00931                 double dist = (double) sqrt(sqrdist);
00932 
00933                 // linearly descending volume on a dB scale
00934                 double db1 = DSBVOLUME_MIN * (dist - min) / (max - min);
00935 
00936                 if (_Alpha == 0.0) {
00937                         db += (sint32) db1;
00938 
00939                 } else if (_Alpha > 0.0) {
00940                         double amp2 = 0.0001 + 0.9999 * (max - dist) / (max - min); // linear amp between 0.00001 and 1.0
00941                         double db2 = 2000.0 * log10(amp2); // covert to 1/100th decibels
00942                         db += (sint32) ((1.0 - _Alpha) * db1 + _Alpha * db2);
00943 
00944                 } else if (_Alpha < 0.0) {
00945                         double amp3 = min / dist; // linear amplitude is 1/distance
00946                         double db3 = 2000.0 * log10(amp3); // covert to 1/100th decibels
00947                         db += (sint32) ((1.0 + _Alpha) * db1 - _Alpha * db3);
00948                 }
00949 
00950                 clamp(db, DSBVOLUME_MIN, DSBVOLUME_MAX);
00951 
00952                 _SecondaryBuffer->SetVolume(db);
00953 
00954 /*              LONG tmp;
00955                 _SecondaryBuffer->GetVolume(&tmp);
00956 */
00957                 
00958                 //nlwarning("VOLUME = %d dB, rolloff = %0.2f", db/100, CListenerDSound::instance()->getRolloffFactor());
00959         }
00960 
00961 }
00962 
00963 // ******************************************************************
00964 
00965 void CSourceDSound::setCone( float innerAngle, float outerAngle, float outerGain )
00966 {
00967         if (_3DBuffer != 0)
00968         {
00969                 // Set the cone angles
00970 
00971                 // Convert from radians to degrees
00972                 DWORD inner = (DWORD)(180.0 * innerAngle / Pi);
00973                 DWORD outer = (DWORD)(180.0 * outerAngle / Pi);
00974 
00975 
00976                 // Sanity check: wrap the angles in the [0,360] interval
00977                 if (outer < inner)
00978                 {
00979                         outer = inner;
00980                 }
00981 
00982                 while (inner < DS3D_MINCONEANGLE) 
00983                 {
00984                         inner += 360;
00985                 }
00986 
00987                 while (inner > DS3D_MAXCONEANGLE)
00988                 {
00989                         inner -= 360;
00990                 }
00991 
00992                 while (outer < DS3D_MINCONEANGLE) 
00993                 {
00994                         outer += 360;
00995                 }
00996 
00997                 while (outer > DS3D_MAXCONEANGLE)
00998                 {
00999                         outer -= 360;
01000                 }
01001 
01002                 if (_3DBuffer->SetConeAngles(inner, outer, DS3D_DEFERRED) != DS_OK)
01003                 {
01004                         nlwarning("SetConeAngles failed");                      
01005                 }
01006 
01007                 // Set the outside volume
01008                 if (outerGain < 0.00001f)
01009                 {
01010                         outerGain = 0.00001f;
01011                 }
01012 
01013                 // convert from linear amplitude to hundredths of decibels 
01014                 LONG volume = (LONG)(100.0 * 20.0 * log10(outerGain));
01015 
01016                 if (volume < DSBVOLUME_MIN) 
01017                 {
01018                         volume = DSBVOLUME_MIN;
01019                 }
01020                 else if (volume > DSBVOLUME_MAX) 
01021                 {
01022                         volume = DSBVOLUME_MAX;
01023                 }
01024 
01025                 if (_3DBuffer->SetConeOutsideVolume(volume, DS3D_DEFERRED) != DS_OK)
01026                 {
01027                         nlwarning("SetConeOutsideVolume failed");               
01028                 }
01029 
01030         }
01031         else
01032         {
01033                 nlwarning("Requested setCone on a non-3D source");
01034         }
01035 }
01036 
01037 // ******************************************************************
01038 
01039 void CSourceDSound::getCone( float& innerAngle, float& outerAngle, float& outerGain ) const
01040 {
01041         if (_3DBuffer != 0)
01042         {
01043                 DWORD inner, outer;
01044                 LONG volume;
01045 
01046                 if (_3DBuffer->GetConeAngles(&inner, &outer) != DS_OK)
01047                 {
01048                         nlwarning("GetConeAngles failed");                      
01049                         innerAngle = outerAngle = (float)(2.0 * Pi);
01050                 }
01051                 else
01052                 {
01053                         innerAngle = (float)(Pi * inner / 180.0);
01054                         outerAngle = (float)(Pi * outer / 180.0);
01055                 }
01056 
01057                 if (_3DBuffer->GetConeOutsideVolume(&volume) != DS_OK)
01058                 {
01059                         nlwarning("GetConeOutsideVolume failed");               
01060                         outerGain = 0.0f;
01061                 }
01062                 else
01063                 {
01064                         outerGain = (float) pow(10, (double) volume / 20.0 / 100.0);
01065                 }
01066         }
01067         else
01068         {
01069                 nlwarning("Requested getCone on a non-3D source");
01070         }
01071 }
01072 
01073 // ******************************************************************
01074 
01075 void CSourceDSound::setEAXProperty( uint prop, void *value, uint valuesize )
01076 {
01077 #ifdef EAX_AVAILABLE
01078         if ( EAXSetProp != NULL )
01079         {
01080                 EAXSetProp( &DSPROPSETID_EAX_SourceProperties, prop, _SourceName, value, valuesize );
01081         }
01082 #endif
01083 }
01084 
01085 
01086 // ******************************************************************
01087 
01088 IBuffer *CSourceDSound::getBuffer()
01089 {       
01090         return _Buffer;
01091 }
01092 
01093 
01094 // ******************************************************************
01095 
01096 bool CSourceDSound::lock(uint32 writePos, uint32 size, uint8* &ptr1, DWORD &bytes1, uint8* &ptr2, DWORD &bytes2)
01097 {
01098         HRESULT hr = _SecondaryBuffer->Lock(writePos, size, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0);
01099 
01100         if (hr == DSERR_BUFFERLOST)
01101         {
01102                 // If the buffer got lost somehow, try to restore it.
01103                 if (FAILED(_SecondaryBuffer->Restore()))
01104                 {
01105                         nlwarning("Lock failed (1)");
01106                         return false;
01107                 }
01108                 if (FAILED(_SecondaryBuffer->Lock(_NextWritePos, _UpdateCopySize, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
01109                 {
01110                         nlwarning("Lock failed (2)");
01111                         return false;
01112                 }
01113         } 
01114         else if (hr != DS_OK)
01115         {
01116                 nlwarning("Lock failed (3)");
01117                 return false;
01118         }
01119 
01120         return true;
01121 }
01122 
01123 // ******************************************************************
01124 
01125 bool CSourceDSound::unlock(uint8* ptr1, DWORD bytes1, uint8* ptr2, DWORD bytes2)
01126 {
01127         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
01128         return true;
01129 }
01130 
01131 
01132 
01133 /***************************************************************************
01134  
01135 
01136   Buffer operations
01137 
01138   There are five buffer operation: fill, silence, fadeOut, crossFade
01139   and fadeIn. fill and silence are called by the update function. The
01140   others are called by the user state functions (play, stop, pause).
01141 
01142 
01143                         NW         P   W
01144    +--------+------+---+-----------------------+
01145    |........|      |xxx|.......................|
01146    +--------+------+---+-----------------------+
01147 
01148   The source maintains the next write position (_NextWritePos, NW in figure
01149   above). That is the position at which new samples or silemce is written.
01150   DirectSound maintaines a play cursor and a write cursor (P and W in figure).
01151   The data between P and W is scheduled for playing and cannot be touched.
01152   The data between W and NW are unplayed sample data that the source copied
01153   into the DirectSound buffer.
01154 
01155   The update functions (fill, silence) refresh the buffer with new samples
01156   or silence. That insert the sample data at the next write position NW. This 
01157   write position is maintained as closely behind the DirectSound play cursor 
01158   as possible to keep the buffer filled with data.
01159 
01160   The user functions (the fades) modify the sample data that is right after
01161   the write cursor W maintained by DirectSound. The data has to be written 
01162   after W to hear the changes as soon as possible. When a fade is done, the
01163   date already written in the buffer has to be overwritten. The function
01164   getFadeOutSize() helps to found out how many samples are writen between
01165   W and NW and to what section of the original audio data they correspond.
01166 
01167   All the buffer functions below have the same pattern:
01168 
01169         - get current play and write cursors (P and W)
01170         - lock the buffer
01171         - copy samples
01172         - unlock buffer
01173         - update state variables
01174 
01175   The differences between the functions are due to different operation
01176   (fades), position and size of the buffer to lock, handling of silence
01177   and looping.
01178 
01179   Enjoy!
01180 
01181   PH
01182 
01183 
01184 ************************************************************************/
01185 
01186 bool CSourceDSound::fill()
01187 {
01188         bool res = false;
01189         uint8 *ptr1, *ptr2;
01190         DWORD bytes1, bytes2;
01191         DWORD playPos, writePos;
01192         uint32 space;
01193 
01194 
01195         if (_Buffer == NULL)
01196         {
01197                 _SecondaryBufferState = NL_DSOUND_SILENCING;
01198                 _UserState = NL_DSOUND_STOPPED;
01199                 return false;
01200         }
01201 
01202         if (_SecondaryBuffer == 0)
01203         {
01204                 return false;
01205         }
01206 
01207 
01208         INITTIME(startPos);
01209 
01210 
01211         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
01212 
01213         if (playPos == _NextWritePos)
01214         {
01215                 return false;
01216         }
01217         else if (playPos > _NextWritePos) 
01218         {
01219                 space = playPos - _NextWritePos;
01220         }
01221         else
01222         {
01223                 space = _SecondaryBufferSize + playPos - _NextWritePos;
01224         }
01225 
01226         // Don't bother if the number of samples that can be written is too small.
01227         if (space < _UpdateCopySize)
01228         {
01229                 return false;
01230         }
01231 
01232 
01233         uint8* data = ((CBufferDSound*) _Buffer)->getData();
01234         uint32 available = (_BytesWritten < _BufferSize) ? _BufferSize - _BytesWritten : 0;
01235 
01236 
01237         // The number of samples bytes that will be copied. If bytes is 0
01238         // than write silence to the buffer.
01239         uint32 bytes = NLSOUND_MIN(_UpdateCopySize, available);
01240         uint32 clear = _UpdateCopySize - available;
01241 
01242 
01243         // Lock the buffer
01244 
01245         INITTIME(startLock);
01246 
01247 
01248         if (!lock(_NextWritePos, _UpdateCopySize, ptr1, bytes1, ptr2, bytes2))
01249         {
01250                 return false;
01251         }
01252 
01253 
01254         INITTIME(startCopy);
01255 
01256         // Start copying the samples
01257 
01258         if (bytes1 <= bytes) {
01259 
01260                 CFastMem::memcpy(ptr1, data + _BytesWritten, bytes1);
01261                 _BytesWritten += bytes1;
01262                 bytes -= bytes1;
01263 
01264                 if (ptr2)
01265                 {
01266                         if (bytes > 0)
01267                         {
01268                                 CFastMem::memcpy(ptr2, data + _BytesWritten, bytes);                                    
01269                                 _BytesWritten += bytes;
01270                         }
01271 
01272                         if (bytes < bytes2)
01273                         {
01274                                 if (_Loop)
01275                                 {
01276                                         DBGPOS(("[%p] FILL: LOOP", this));
01277 
01278                                         CFastMem::memcpy(ptr2 + bytes, data, bytes2 - bytes); 
01279                                         _BytesWritten = bytes2 - bytes;
01280                                 }
01281                                 else
01282                                 {
01283                                         memset(ptr2 + bytes, 0, bytes2 - bytes); 
01284                                         _SilenceWritten = bytes2 - bytes;
01285                                 }
01286                         }
01287                 }
01288         }
01289         else
01290         {
01291                 if (bytes > 0)
01292                 {
01293                         CFastMem::memcpy(ptr1, data + _BytesWritten, bytes);
01294                         _BytesWritten += bytes;
01295                 }
01296 
01297                 if (_Loop)
01298                 {
01299                         DBGPOS(("[%p] FILL: LOOP", this));
01300 
01301                         CFastMem::memcpy(ptr1 + bytes, data, bytes1 - bytes);                                    
01302                         _BytesWritten = bytes1 - bytes;
01303 
01304                         if (ptr2)
01305                         {
01306                                 CFastMem::memcpy(ptr2, data + _BytesWritten, bytes2);                                    
01307                                 _BytesWritten += bytes2;
01308                         }
01309 
01310                 } 
01311                 else
01312                 {
01313                         memset(ptr1 + bytes, 0, bytes1 - bytes);                                        
01314                         _SilenceWritten = bytes1 - bytes;
01315 
01316                         if (ptr2)
01317                         {
01318                                 memset(ptr2, 0, bytes2);                                        
01319                                 _SilenceWritten += bytes2;
01320                         }
01321                 }
01322 
01323         }
01324 
01325 
01326 
01327 
01328         INITTIME(startUnlock);
01329 
01330         // Unlock the buffer
01331         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
01332 
01333 
01334         // Update the state variables
01335 
01336         // Check if we've reached the end of the file
01337         if (_BytesWritten == _BufferSize) 
01338         {
01339                 if (_Loop)
01340                 {
01341                         // If we're looping, start all over again
01342                         DBGPOS(("[%p] FILL: LOOP", this));
01343                         _BytesWritten = 0;
01344                 }
01345                 else
01346                 {
01347                         _SecondaryBufferState = NL_DSOUND_SILENCING;
01348 
01349                         // Keep track of where tha last sample was written and the position
01350                         // of the play cursor relative to the end position. if the _EndState
01351                         // is 0, the play cursor is after the end position, 1 otherwise.
01352                         _EndPosition = writePos + bytes;
01353                         if (_EndPosition >= _SecondaryBufferSize)
01354                         {
01355                                 _EndPosition -= _SecondaryBufferSize;
01356                         }
01357 
01358                         _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
01359 
01360                         DBGPOS(("[%p] FILL: SILENCING", this));
01361                         DBGPOS(("[%p] FILL: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
01362                 }
01363         }
01364 
01365 
01366         // Update the write pointer
01367         _NextWritePos += bytes1 + bytes2;
01368         if (_NextWritePos >= _SecondaryBufferSize)
01369         {
01370                 _NextWritePos  -= _SecondaryBufferSize;
01371         }
01372  
01373         DBGPOS(("[%p] FILL: P=%d, W=%d, NW=%d, SZ=%d, BW=%d, S=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, _SilenceWritten, bytes1 + bytes2));
01374 
01375 
01376 #if NLSOUND_PROFILE
01377         _TotalUpdateSize += bytes1 + bytes2;
01378         _PosTime += CTime::ticksToSecond(startLock - startPos);
01379         _LockTime += CTime::ticksToSecond(startCopy - startLock);
01380         _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
01381         _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
01382         _CopyCount++;
01383 #endif
01384 
01385 
01386         return true;
01387 }
01388 
01389 
01390 
01391 
01392 // ******************************************************************
01393 
01394 bool CSourceDSound::silence()
01395 {
01396         uint8 *ptr1, *ptr2;
01397         DWORD bytes1, bytes2;
01398         DWORD playPos, writePos;
01399         uint32 space;
01400 
01401         if (_SecondaryBuffer == 0)
01402         {
01403                 return false;
01404         }
01405                 
01406         INITTIME(startPos);
01407 
01408         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
01409 
01410         if (playPos == _NextWritePos)
01411         {
01412                 return false;
01413         }
01414         else if (playPos > _NextWritePos) 
01415         {
01416                 space = playPos - _NextWritePos;
01417         }
01418         else
01419         {
01420                 space = _SecondaryBufferSize + playPos - _NextWritePos;
01421         }
01422 
01423         // Don't bother if the number of samples that can be written is too small.
01424         if (space < _UpdateCopySize)
01425         {
01426                 return false;
01427         }
01428 
01429                 // Lock the buffer
01430 
01431         INITTIME(startLock);
01432 
01433         if (!lock(_NextWritePos, _UpdateCopySize, ptr1, bytes1, ptr2, bytes2))
01434         {
01435                 return false;
01436         }
01437 
01438 
01439         INITTIME(startCopy);
01440    
01441         // Silence the buffer
01442         memset(ptr1, 0, bytes1);
01443         memset(ptr2, 0, bytes2);
01444 
01445                 // Unlock the buffer
01446 
01447         INITTIME(startUnlock);
01448 
01449         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
01450 
01451 
01452         // Update the next write position
01453         _NextWritePos += bytes1 + bytes2;
01454         if (_NextWritePos >= _SecondaryBufferSize)
01455         {
01456                 _NextWritePos  -= _SecondaryBufferSize;
01457         }
01458 
01459 
01460         // Check if all the samples in the buffer are played
01461         if ((playPos > _EndPosition) && (_EndState == NL_DSOUND_TAIL2)) 
01462         {
01463                 // The buffer played passed the last sample. Flag the source as stopped.
01464                 _EndState = NL_DSOUND_ENDED;
01465                 DBGPOS(("[%p] SLNC: ENDED", this));
01466 
01467                 // If the buffer was playing, mark it as stopped
01468                 if (_UserState == NL_DSOUND_PLAYING)
01469                 {
01470                         _UserState = NL_DSOUND_STOPPED;
01471                         DBGPOS(("[%p] SLNC: STOPPED", this));
01472                 }
01473         }
01474         else if ((playPos < _EndPosition) && (_EndState == NL_DSOUND_TAIL1))
01475         {
01476                 // The play cursor wrapped around the buffer and is now before the end position
01477                 _EndState = NL_DSOUND_TAIL2;
01478                 DBGPOS(("[%p] FILL: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
01479         }
01480 
01481 
01482         // Update the amount of silence written
01483         _SilenceWritten += bytes1 + bytes2;
01484         if (_SilenceWritten >= _SecondaryBufferSize)
01485         {
01486                 // The buffer is now completely filled with silence
01487                 _SecondaryBufferState = NL_DSOUND_SILENCED;
01488                 DBGPOS(("[%p] SLNC: SILENCED", this));
01489 
01490                 // If the buffer was playing, mark it as stopped
01491                 if (_UserState == NL_DSOUND_PLAYING)
01492                 {
01493                         _UserState = NL_DSOUND_STOPPED;
01494                         DBGPOS(("[%p] SLNC: STOPPED*", this));
01495                 }
01496         }
01497 
01498         DBGPOS(("[%p] SLNC: P=%d, W=%d, NW=%d, SZ=%d, BW=%d, S=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, _SilenceWritten, bytes1 + bytes2));
01499 
01500 
01501 #if NLSOUND_PROFILE
01502         _TotalUpdateSize += bytes1 + bytes2;
01503         _PosTime += CTime::ticksToSecond(startLock - startPos);
01504         _LockTime += CTime::ticksToSecond(startCopy - startLock);
01505         _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
01506         _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
01507         _CopyCount++;
01508 #endif
01509 
01510         return true;
01511 }
01512 
01513 
01514 // ******************************************************************
01515 
01524  void CSourceDSound::getFadeOutSize(uint32 writePos, uint32 &xfadeSize, sint16* &in1, uint32 &writtenTooMuch)
01525 {
01526         // The number of samples over which we will do the crossfade
01527         xfadeSize = _XFadeSize;
01528 
01529 
01530         // The tricky part of this method is to figger out how many samples of the old
01531         // buffer were written after the write cursor and figger our with what position 
01532         // in the old buffer the write cursor corresponds. We have to consider the following
01533         // cases:
01534         //
01535         // - the old buffer just looped, 
01536         // - the old buffer is finished, but stil has samples in the DirectSound buffer
01537         // - the default case, i.e. the old buffer is playing somewhere in the middle.
01538         //
01539 
01540         // How many bytes did we write after the write position?
01541 
01542         writtenTooMuch = NLSOUND_DISTANCE(writePos, _NextWritePos, _SecondaryBufferSize);
01543 
01544         DBGPOS(("[%p] FADE: TOO=%d", this, writtenTooMuch));
01545 
01546 
01547         uint8* data = ((CBufferDSound*) _Buffer)->getData();
01548 
01549         // If the sound is finished and all the samples are written in the
01550         // buffer, it's possible that there are still samples after the write
01551         // position. If this is the case, we have to do a fade out. If there is
01552         // only silence, we only need to copy without fade.
01553 
01554         if (_SilenceWritten > 0)
01555         {
01556                 
01557                 if (writtenTooMuch > _SilenceWritten)
01558                 {
01559                         writtenTooMuch -= _SilenceWritten;
01560                         in1 = (sint16*) (data + _BufferSize - writtenTooMuch) ;
01561 
01562                         if (writtenTooMuch < 2 * xfadeSize)
01563                         {
01564                                 xfadeSize = writtenTooMuch / 2;
01565                         }
01566                 }
01567                 else
01568                 {
01569                         xfadeSize = 0;                                                    
01570                 }
01571 
01572                 DBGPOS(("[%p] FADE: END, TOO=%d, S=%d, F=%d", this, writtenTooMuch, _SilenceWritten, xfadeSize));
01573         }
01574         
01575         // If the sound looped, it's possible that the number of samples
01576         // written is small. In that case, the write cursor is still inside
01577         // the previous loop. All we have to do is fade out the last part
01578         // of the previous loop. 
01579 
01580         else if (writtenTooMuch >= _BytesWritten)
01581         {
01582 
01583                 writtenTooMuch -= _BytesWritten;
01584 
01585                 in1 = (sint16*) (data + _BufferSize - writtenTooMuch) ;
01586 
01587                 if (writtenTooMuch < 2 * xfadeSize)
01588                 {
01589                         xfadeSize = writtenTooMuch / 2;
01590                 }
01591 
01592                 DBGPOS(("[%p] FADE: LOOPED, TOO=%d, F=%d", this, writtenTooMuch, xfadeSize));
01593 
01594         }
01595 
01596         // This is the default case. Simply fade from the previous to the next buffer.
01597         // The variable writtenTooMuch tells us how much of the previous sound has
01598         // been written after the current write cursor. We just have to check there
01599         // are enough samples available for the fade.
01600 
01601         else
01602         {
01603                 in1 = (sint16*) (data + (sint32) _BytesWritten - writtenTooMuch);
01604 
01605                 if (xfadeSize > _BufferSize - _BytesWritten)
01606                 {
01607                         xfadeSize = _BufferSize - _BytesWritten;
01608                 }
01609 
01610                 DBGPOS(("[%p] FADE: STD, TOO=%d, F=%d", this, writtenTooMuch, xfadeSize));
01611         }
01612 }
01613 
01614 
01615 
01616 // ******************************************************************
01617 
01618 void CSourceDSound::crossFade()
01619 {
01620         uint8 *ptr1, *ptr2;
01621         DWORD bytes1, bytes2;
01622         DWORD playPos, writePos;
01623         uint32 i;
01624 
01625 
01626 
01627         if (_Buffer == NULL)
01628         {
01629                 return;
01630         }
01631 
01632         if (_SecondaryBuffer == 0)
01633         {
01634                 return;
01635         }
01636 
01637 
01638         INITTIME(start); 
01639         
01640 
01641         EnterCriticalSection(&_CriticalSection); 
01642 
01643 
01644 
01645         // The source is currently playing an other buffer. We will do a hot
01646         // swap between the old and the new buffer. DirectSound maintains two
01647         // cursors into the buffer: the play cursor and the write cursor.
01648         // The write cursor indicates where we can start writing the new samples.
01649         // To avoid clicks, we have to do a cross fade between the old buffer and
01650         // the new buffer.
01651         
01652         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
01653 
01654 
01655         // The number of bytes we will write to the DirectSound buffer
01656         uint32 bytes = _SwapCopySize;
01657         if (bytes > _SwapBuffer->getSize())
01658         {
01659                 bytes = _SwapBuffer->getSize();
01660         }
01661 
01662 
01663         // Lock the DirectSound buffer
01664 
01665         if (FAILED(_SecondaryBuffer->Lock(writePos, bytes, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
01666         {
01667                 LeaveCriticalSection(&_CriticalSection);
01668                 throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
01669         }
01670 
01671         
01672         sint16* in1;
01673         uint8* data1 = ((CBufferDSound*) _Buffer)->getData();
01674         uint8* data2 = ((CBufferDSound*) _SwapBuffer)->getData();
01675         sint16* in2 = (sint16*) data2;
01676         sint16* out = (sint16*) ptr1;
01677 
01678         // The number of samples over which we will do the crossfade
01679         uint32 xfadeSize;
01680         uint32 xfadeByteSize;
01681         uint32 writtenTooMuch;
01682 
01683         getFadeOutSize(writePos, xfadeSize, in1, writtenTooMuch);
01684         xfadeByteSize = 2 * xfadeSize;
01685 
01686 #define MIX 1
01687 
01688 
01689 #if MIX
01690         float incr, amp1, amp2;
01691 
01692         if (xfadeSize == 0)
01693         {
01694                 amp1 = 0.0f;
01695                 amp2 = 1.0f;
01696                 incr = 0.0f;
01697         }
01698         else
01699         {
01700                 amp1 = 1.0f;
01701                 amp2 = 0.0f;
01702                 incr = 1.0f / xfadeSize;
01703         }
01704 
01705 #else
01706         float incr, amp1;
01707 
01708         if (xfadeSize == 0)
01709         {
01710                 amp1 = 0.0f;
01711                 incr = 0.0f;
01712         }
01713         else
01714         {
01715                 amp1 = 1.0f;
01716                 incr = 1.0f / xfadeSize;
01717         }
01718 
01719 #endif
01720 
01721 
01722         // Start copying the samples
01723         
01724 
01725         // In the first case, the cross fade is completely contained in the first buffer
01726         // pointed to by ptr1.
01727         if (xfadeByteSize < bytes1)
01728         {
01729 
01730                 // Do cross fade
01731 
01732                 for (i = 0; i < xfadeSize; i++) 
01733                 {
01734 #if MIX
01735                         out[i] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
01736                         amp1 -= incr;
01737                         amp2 += incr;
01738 #else
01739                         out[i] = (sint16) (amp1 * in1[i]);
01740                         amp1 -= incr;
01741 #endif
01742                 }
01743 
01744                 // Copy remaining samples
01745 
01746 #if MIX
01747                 CFastMem::memcpy(ptr1 + xfadeByteSize, data2 + xfadeByteSize, bytes1 - xfadeByteSize);
01748                 _BytesWritten = bytes1;
01749 #else
01750                 CFastMem::memcpy(ptr1 + xfadeByteSize, data2, bytes1 - xfadeByteSize);
01751                 _BytesWritten = bytes1 - xfadeByteSize;
01752 #endif
01753 
01754                 if (ptr2)
01755                 {
01756                         CFastMem::memcpy(ptr2, data2 + _BytesWritten, bytes2);
01757                         _BytesWritten += bytes2;
01758                 }
01759 
01760         }
01761 
01762         // In the second case, the cross fade stretches over the first and the second buffers.
01763         else
01764         {
01765 
01766                 uint32 fade1 = bytes1 / 2;
01767                 uint32 fade2 = xfadeSize - fade1;
01768 
01769                 // Do cross fade
01770 
01771                 // Part 1, start at ptr1
01772                 for (i = 0; i < fade1; i++) 
01773                 {
01774 #if MIX
01775                         out[i] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
01776                         amp1 -= incr;
01777                         amp2 += incr;
01778 #else
01779                         out[i] = (sint16) (amp1 * in1[i]);
01780                         amp1 -= incr;
01781 #endif
01782                 }
01783 #if MIX
01784                 _BytesWritten = bytes1;
01785 #else
01786                 _BytesWritten = 0;
01787 #endif
01788 
01789 
01790                 if (ptr2)
01791                 {
01792                         out = (sint16*) ptr2;
01793 
01794                         // Part 2, ontinue at ptr2
01795                         for (uint32 k = 0; i < xfadeSize; i++, k++) 
01796                         {
01797 #if MIX
01798                                 out[k] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
01799                                 amp1 -= incr;
01800                                 amp2 += incr;
01801 #else
01802                                 out[k] = (sint16) (amp1 * in1[i]);
01803                                 amp1 -= incr;
01804 #endif
01805                         }
01806 
01807                         // Copy remaining samples
01808 #if MIX
01809                         CFastMem::memcpy(ptr2 + 2 * k, data2 + _BytesWritten + 2 * k, bytes2 - 2 * k);
01810                         _BytesWritten += bytes2;
01811 #else
01812                         CFastMem::memcpy(ptr2 + 2 * k, data2, bytes2 - 2 * k);
01813                         _BytesWritten = bytes2 - 2 * k;
01814 #endif
01815                 }
01816         }
01817 
01818 
01819         // Unlock the DirectSound buffer
01820         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
01821 
01822         
01823         // Update the state variables
01824 
01825         _SilenceWritten = 0;
01826 
01827         _NextWritePos = (writePos + bytes1 + bytes2);
01828         if (_NextWritePos >= _SecondaryBufferSize)
01829         {
01830                 _NextWritePos -= _SecondaryBufferSize;
01831         }
01832 
01833 
01834 
01835         _SecondaryBufferState = NL_DSOUND_FILLING;
01836 
01837 
01838         // Swap the two buffers
01839         _BufferSize = _SwapBuffer->getSize();
01840         _Buffer = _SwapBuffer;
01841         _SwapBuffer = 0;
01842 
01843         setPitch(_Freq);
01844 
01845         // Check if we've reached the end of the file
01846         if (_BytesWritten == _BufferSize) 
01847         {
01848                 if (_Loop)
01849                 {
01850                         _BytesWritten = 0;
01851                 }
01852                 else
01853                 {
01854                         _SecondaryBufferState = NL_DSOUND_SILENCING;
01855                 }
01856         }
01857 
01858 
01859         DBGPOS(("[%p] XFADE", this));
01860         DBGPOS(("[%p] P=%d, W=%d, NW=%d, SZ=%d, BW=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, bytes1 + bytes2));
01861 
01862         
01863 
01864         LeaveCriticalSection(&_CriticalSection);
01865 
01866 
01867 #if NLSOUND_PROFILE
01868         _LastSwapTime = CTime::ticksToSecond(CTime::getPerformanceTime() - start);
01869         _TotalSwapTime += _LastSwapTime;
01870         _MaxSwapTime = (_LastSwapTime > _MaxSwapTime) ? _LastSwapTime : _MaxSwapTime;
01871         _MinSwapTime = (_LastSwapTime < _MinSwapTime) ? _LastSwapTime : _MinSwapTime;
01872         _SwapCount++;
01873 #endif
01874 
01875 }
01876 
01877 
01878 
01879 // ******************************************************************
01880 
01881 void CSourceDSound::fadeOut()
01882 {
01883         uint8 *ptr1, *ptr2;
01884         DWORD bytes1, bytes2;
01885         DWORD playPos, writePos;
01886         uint32 i;
01887 
01888 
01889         if (_Buffer == NULL)
01890         {
01891                 _SecondaryBufferState = NL_DSOUND_SILENCING;
01892                 _UserState = NL_DSOUND_STOPPED;
01893                 return;
01894         }
01895 
01896         if (_SecondaryBuffer == 0)
01897         {
01898                 return;
01899         }
01900 
01901         INITTIME(start);
01902         
01903 
01904         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
01905 
01906 
01907         // Lock the DirectSound buffer
01908 
01909         if (FAILED(_SecondaryBuffer->Lock(writePos, _SwapCopySize, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
01910         {
01911                 throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
01912         }
01913 
01914         
01915 
01916         // in1 points to the position in the old buffer where the fade out starts
01917         sint16* in1;
01918         sint16* out = (sint16*) ptr1;
01919 
01920         // The number of samples over which we will do the crossfade
01921         uint32 xfadeSize;
01922         uint32 xfadeByteSize;
01923         uint32 writtenTooMuch;
01924 
01925         getFadeOutSize(writePos, xfadeSize, in1, writtenTooMuch);
01926         xfadeByteSize = 2 * xfadeSize;
01927 
01928         float amp1, incr;
01929 
01930         if (xfadeSize == 0)
01931         {
01932                 amp1 = 0.0f;
01933                 incr = 0.0f;
01934         }
01935         else
01936         {
01937                 amp1 = 1.0f;
01938                 incr = 1.0f / xfadeSize;
01939         }
01940 
01941 
01942         if (writtenTooMuch > _BytesWritten)
01943         {
01944                 // The buffer looped. Count backwards from the end of the file.
01945                 _BytesWritten = _BufferSize - writtenTooMuch;
01946         }
01947         else
01948         {
01949                 _BytesWritten -= writtenTooMuch;
01950         }
01951 
01952 
01953         // Start copying the samples
01954         
01955 
01956         // In the first case, the fade out is completely contained in the first buffer
01957         // pointed to by ptr1.
01958         if (xfadeByteSize < bytes1)
01959         {
01960 
01961                 // Do cross fade
01962 
01963                 for (i = 0; i < xfadeSize; i++) 
01964                 {
01965                         out[i] = (sint16) (amp1 * in1[i]);
01966                         amp1 -= incr;
01967                 }
01968 
01969                 // Copy remaining samples
01970 
01971                 memset(ptr1 + xfadeByteSize, 0, bytes1 - xfadeByteSize);
01972                 _SilenceWritten = bytes1 - xfadeByteSize;
01973 
01974                 if (ptr2)
01975                 {
01976                         memset(ptr2, 0, bytes2);
01977                         _SilenceWritten += bytes2;
01978                 }
01979 
01980         }
01981 
01982         // In the second case, the fade out stretches over the first and the second buffers.
01983         else
01984         {
01985 
01986                 uint32 fade1 = bytes1 / 2;
01987                 uint32 fade2 = xfadeSize - fade1;
01988 
01989                 // Do cross fade
01990 
01991                 // Part 1, start at ptr1
01992                 for (i = 0; i < fade1; i++) 
01993                 {
01994                         out[i] = (sint16) (amp1 * in1[i]);
01995                         amp1 -= incr;
01996                 }
01997 
01998 
01999                 if (ptr2)
02000                 {
02001                         out = (sint16*) ptr2;
02002 
02003                         // Part 2, continue at ptr2
02004                         for (uint32 k = 0; i < xfadeSize; i++, k++) 
02005                         {
02006                                 out[k] = (sint16) (amp1 * in1[i]);
02007                                 amp1 -= incr;
02008                         }
02009 
02010                         // Clear remaining samples
02011                         memset(ptr2 + 2 * k, 0, bytes2 - 2 * k);
02012                         _SilenceWritten = bytes2 - 2 * k;
02013                 }
02014 
02015         }
02016 
02017 
02018         _BytesWritten += xfadeByteSize;
02019 
02020 
02021         // Unlock the DirectSound buffer
02022         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02023 
02024         
02025         // Update the next write position
02026         _NextWritePos = (writePos + bytes1 + bytes2);
02027         if (_NextWritePos >= _SecondaryBufferSize)
02028         {
02029                 _NextWritePos -= _SecondaryBufferSize;
02030         }
02031 
02032 
02033         _SecondaryBufferState = NL_DSOUND_SILENCING;
02034         DBGPOS(("[%p] FDOU: SILENCING", this));
02035 
02036         // Keep track of where tha last sample was written and the position
02037         // of the play cursor relative to the end position. if the _EndState
02038         // is 0, the play cursor is after the end position, 1 otherwise.
02039         _EndPosition = writePos + xfadeSize;
02040         if (_EndPosition >= _SecondaryBufferSize)
02041         {
02042                 _EndPosition -= _SecondaryBufferSize;
02043         }
02044 
02045         _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
02046         DBGPOS(("[%p] FDOU: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
02047 
02048 
02049         DBGPOS(("[%p] FDOU: P=%d, W=%d, NW=%d, SZ=%d, BW=%d, S=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, _SilenceWritten, bytes1 + bytes2));
02050 
02051 
02052 
02053 #if NLSOUND_PROFILE
02054         _LastSwapTime = CTime::ticksToSecond(CTime::getPerformanceTime() - start);
02055         _TotalSwapTime += _LastSwapTime;
02056         _MaxSwapTime = (_LastSwapTime > _MaxSwapTime) ? _LastSwapTime : _MaxSwapTime;
02057         _MinSwapTime = (_LastSwapTime < _MinSwapTime) ? _LastSwapTime : _MinSwapTime;
02058         _SwapCount++;
02059 #endif
02060 
02061 }
02062 
02063 // ******************************************************************
02064 
02065 void CSourceDSound::fadeIn()
02066 {
02067         bool res = false;
02068         uint8 *ptr1, *ptr2;
02069         DWORD bytes1, bytes2;
02070         DWORD playPos, writePos;
02071 
02072 
02073         if (_Buffer == NULL)
02074         {
02075                 _SecondaryBufferState = NL_DSOUND_SILENCING;
02076                 _UserState = NL_DSOUND_STOPPED;
02077                 return;
02078         }
02079 
02080         if (_SecondaryBuffer == 0)
02081         {
02082                 return;
02083         }
02084 
02085         INITTIME(startPos);
02086 
02087         // Set the correct pitch for this sound
02088         setPitch(_Freq);
02089 
02090         // Set the correct volume
02091         // FIXME: a bit of a hack
02092         const CVector &pos = CListenerDSound::instance()->getPos();
02093         updateVolume(pos);
02094 
02095 
02096         _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
02097 
02098         uint8* data = ((CBufferDSound*) _Buffer)->getData();
02099         uint32 available = (_BytesWritten < _BufferSize) ? _BufferSize - _BytesWritten : 0;
02100         uint32 bytes = NLSOUND_MIN(_SwapCopySize, available);
02101 //      uint32 clear = _SwapCopySize - available;
02102 
02103 
02104         _SilenceWritten = 0;
02105 
02106         // Lock the buffer
02107 
02108         INITTIME(startLock);
02109 
02110 
02111         if (!lock(writePos, _SwapCopySize, ptr1, bytes1, ptr2, bytes2))
02112         {
02113                 return;
02114         }
02115 
02116 
02117         INITTIME(startCopy);
02118 
02119         // Start copying the samples
02120 
02121         if (bytes1 <= bytes) {
02122 
02123                 CFastMem::memcpy(ptr1, data + _BytesWritten, bytes1);
02124                 _BytesWritten += bytes1;
02125                 bytes -= bytes1;
02126 
02127                 if (ptr2)
02128                 {
02129                         if (bytes > 0)
02130                         {
02131                                 CFastMem::memcpy(ptr2, data + _BytesWritten, bytes);                                    
02132                                 _BytesWritten += bytes;
02133                         }
02134 
02135                         if (bytes < bytes2)
02136                         {
02137                                 if (_Loop)
02138                                 {
02139                                         DBGPOS(("[%p] FDIN: LOOP", this));
02140 
02141                                         CFastMem::memcpy(ptr2 + bytes, data, bytes2 - bytes); 
02142                                         _BytesWritten = bytes2 - bytes;
02143                                 }
02144                                 else
02145                                 {
02146                                         memset(ptr2 + bytes, 0, bytes2 - bytes); 
02147                                         _SilenceWritten = bytes2 - bytes;
02148                                 }
02149                         }
02150                 }
02151         }
02152         else
02153         {
02154                 if (bytes > 0)
02155                 {
02156                         CFastMem::memcpy(ptr1, data + _BytesWritten, bytes);
02157                         _BytesWritten += bytes;
02158                 }
02159 
02160                 if (_Loop)
02161                 {
02162                         DBGPOS(("[%p] FDIN: LOOP", this));
02163 
02164                         CFastMem::memcpy(ptr1 + bytes, data, bytes1 - bytes);                                    
02165                         _BytesWritten = bytes1 - bytes;
02166 
02167                         if (ptr2)
02168                         {
02169                                 CFastMem::memcpy(ptr2, data + _BytesWritten, bytes2);                                    
02170                                 _BytesWritten += bytes2;
02171                         }
02172                 } 
02173                 else
02174                 {
02175                         memset(ptr1 + bytes, 0, bytes1 - bytes);                                        
02176                         _SilenceWritten = bytes1 - bytes;
02177 
02178                         if (ptr2)
02179                         {
02180                                 memset(ptr2, 0, bytes2);                                        
02181                                 _SilenceWritten += bytes2;
02182                         }
02183                 }
02184         }
02185 
02186 
02187         INITTIME(startUnlock);
02188 
02189         // Unlock the buffer
02190         _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02191 
02192 
02193         // Update the state variables
02194 
02195         _SecondaryBufferState = NL_DSOUND_FILLING;
02196         DBGPOS(("[%p] FDIN: FILLING", this));
02197 
02198 
02199         // Check if we've reached the end of the file
02200         if (_BytesWritten == _BufferSize) 
02201         {
02202                 if (_Loop)
02203                 {
02204                         // If we're looping, start all over again
02205                         DBGPOS(("[%p] FDIN: LOOP", this));
02206                         _BytesWritten = 0;
02207                 }
02208                 else
02209                 {
02210                         _SecondaryBufferState = NL_DSOUND_SILENCING;
02211 
02212                         // Keep track of where tha last sample was written and the position
02213                         // of the play cursor relative to the end position. if the _EndState
02214                         // is NL_DSOUND_TAIL1, the play cursor is after the end position, 
02215                         // NL_DSOUND_TAIL2 otherwise.
02216                         _EndPosition = writePos + bytes;
02217                         if (_EndPosition >= _SecondaryBufferSize)
02218                         {
02219                                 _EndPosition -= _SecondaryBufferSize;
02220                         }
02221 
02222                         _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
02223 
02224                         DBGPOS(("[%p] FDIN: SILENCING", this));
02225                         DBGPOS(("[%p] FDIN: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
02226                 }
02227         }
02228 
02229 
02230         // Update the write pointer
02231         _NextWritePos = writePos + bytes1 + bytes2;
02232         if (_NextWritePos >= _SecondaryBufferSize)
02233         {
02234                 _NextWritePos  -= _SecondaryBufferSize;
02235         }
02236  
02237         DBGPOS(("[%p] FDIN: P=%d, W=%d, NW=%d, SZ=%d, BW=%d, S=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, _SilenceWritten, bytes1 + bytes2));
02238 
02239 
02240 #if NLSOUND_PROFILE
02241         _TotalUpdateSize += bytes1 + bytes2;
02242         _PosTime += CTime::ticksToSecond(startLock - startPos);
02243         _LockTime += CTime::ticksToSecond(startCopy - startLock);
02244         _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
02245         _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
02246         _CopyCount++;
02247 #endif
02248 
02249 
02250 }
02251 
02252 
02253 
02254 } // NLSOUND