source_dsound.cpp

Go to the documentation of this file.
00001 
00005 /* Copyright, 2001 Nevrax Ltd.
00006  *
00007  * This file is part of NEVRAX NEL.
00008  * NEVRAX NEL is free software; you can redistribute it and/or modify
00009  * it under the terms of the GNU General Public License as published by
00010  * the Free Software Foundation; either version 2, or (at your option)
00011  * any later version.
00012 
00013  * NEVRAX NEL is distributed in the hope that it will be useful, but
00014  * WITHOUT ANY WARRANTY; without even the implied warranty of
00015  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00016  * General Public License for more details.
00017 
00018  * You should have received a copy of the GNU General Public License
00019  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00020  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00021  * MA 02111-1307, USA.
00022  */
00023 
00024 
00025 #include "stddsound.h"
00026 #include "nel/misc/hierarchical_timer.h"
00027 #include "source_dsound.h"
00028 #include "sound_driver_dsound.h"
00029 #include "buffer_dsound.h"
00030 #include "listener_dsound.h"
00031 #include "../sound_driver.h"
00032 
00033 #include <algorithm>
00034 
00035 
00036 using namespace NLMISC;
00037 using namespace std;
00038 
00039 
00040 namespace NLSOUND {
00041 
00042 
00043 #if NLSOUND_PROFILE
00044 
00045     #define INITTIME(_var)   TTicks _var = CTime::getPerformanceTime()
00046 
00047     #define DEBUG_POSITIONS  1
00048 
00049     #if DEBUG_POSITIONS
00050     #define DBGPOS(_a) nldebug ## _a
00051     #else
00052     #define DBGPOS(_a)
00053     #endif
00054 
00055 #else
00056     #define INITTIME(_var)
00057     #define DBGPOS(_a)
00058 #endif
00059 
00060 
00061 
00062 const uint32 CSourceDSound::_SecondaryBufferSize = 0x10000;
00063 const uint32 CSourceDSound::_SizeMask = 0xffff;
00064 const uint32 CSourceDSound::_SwapCopySize = 0x8000;
00065 const uint32 CSourceDSound::_UpdateCopySize = 0x4000;
00066 const uint32 CSourceDSound::_XFadeSize = 64;
00067 const uint CSourceDSound::_DefaultChannels = 1;
00068 const uint CSourceDSound::_DefaultSampleRate = 22050;
00069 const uint CSourceDSound::_DefaultSampleSize = 16;
00070 
00071 
00072 
00073 #define NLSOUND_MIN(_a,_b)    (((_a) < (_b)) ? (_a) : (_b))
00074 #define NLSOUND_DISTANCE(_from, _to, _period)   (((_to) > (_from)) ? (_to) - (_from) : (_period) + (_to) - (_from))
00075 
00076 
00077 #if NLSOUND_PROFILE
00078 
00079 // Static variables used for profiling
00080 double CSourceDSound::_LastSwapTime = 0.0;
00081 double CSourceDSound::_TotalSwapTime = 0.0;
00082 double CSourceDSound::_MaxSwapTime = 0.0;
00083 double CSourceDSound::_MinSwapTime = 1000000.0;
00084 uint32 CSourceDSound::_SwapCount = 0;
00085 double CSourceDSound::_PosTime = 0.0;
00086 double CSourceDSound::_LockTime = 0.0;
00087 double CSourceDSound::_CopyTime = 0.0;
00088 double CSourceDSound::_UnlockTime = 0.0;
00089 uint32 CSourceDSound::_CopyCount = 0;
00090 double CSourceDSound::_TotalUpdateTime = 0.0;
00091 double CSourceDSound::_MaxUpdateTime = 0.0;
00092 double CSourceDSound::_MinUpdateTime = 1000000.0;
00093 uint32 CSourceDSound::_UpdateCount = 0;
00094 uint32 CSourceDSound::_TotalUpdateSize = 0;
00095 #endif
00096 
00097 
00098 uint32 getWritePosAndSpace(uint32 &nextWritePos, uint32 playPos, uint32 writePos, uint32 bufferSize);
00099 
00100 
00101 // ******************************************************************
00102 
00103 CSourceDSound::CSourceDSound( uint sourcename )
00104 :   ISource(),
00105     _SourceName(sourcename)
00106 {
00107 #if EAX_AVAILABLE == 1
00108     _EAXSource = 0;
00109 #endif
00110     _Sample = 0;
00111     _SampleSize = 0;
00112     _SampleOffset = 0;
00113     _Format = Mono8;
00114     _SampleFreq = _DefaultSampleRate;
00115     _FillOffset = 0;
00116     _State = source_stoped;
00117     _PlayOffset = 0;
00118     _LastPlayPos = 0;
00119     _PosRelative= false;
00120 
00121 //  _BufferSize = 0;
00122 //  _SwapBuffer = 0;
00123     _SecondaryBuffer = 0;
00124 //  _SecondaryBufferState = NL_DSOUND_SILENCED;
00125     _3DBuffer = 0;
00126 //  _NextWritePos = 0;
00127 //  _BytesWritten = 0;
00128 //  _SilenceWritten = 0;
00129     _Loop = false;
00130 //  _EndPosition = 0;
00131 //  _EndState = NL_DSOUND_TAIL1;
00132 //  _UserState = NL_DSOUND_STOPPED;
00133     _Freq = 1.0f;
00134     _SampleRate = _DefaultSampleRate;
00135 //  _IsUsed = false;
00136     _Gain = 1.0f;
00137     _Volume = 0;
00138     _Alpha = 0.0;
00139     InitializeCriticalSection(&_CriticalSection);
00140 }
00141 
00142 
00143 // ******************************************************************
00144 
00145 CSourceDSound::~CSourceDSound()
00146 {
00147     nldebug("Destroying DirectSound source");
00148 
00149     CSoundDriverDSound::instance()->removeSource(this);
00150 
00151     EnterCriticalSection(&_CriticalSection);
00152 
00153     // Release the DirectSound buffer within the critical zone
00154     // to avoid a call to update during deconstruction
00155     release();
00156 
00157     LeaveCriticalSection(&_CriticalSection);
00158     DeleteCriticalSection(&_CriticalSection);
00159 }
00160 
00161 
00162 // ******************************************************************
00163 
00164 void CSourceDSound::release()
00165 {
00166 //  _Buffer = 0;
00167 
00168 #if EAX_AVAILABLE == 1
00169     if (_EAXSource != 0)
00170     {
00171         _EAXSource->Release();
00172         _EAXSource = 0;
00173     }
00174 #endif
00175 
00176     if (_SecondaryBuffer != 0)
00177     {
00178         _SecondaryBuffer->Stop();
00179     }
00180 
00181     if (_3DBuffer != 0)
00182     {
00183         _3DBuffer->Release();
00184         _3DBuffer = 0;
00185     }
00186 
00187     if (_SecondaryBuffer != 0)
00188     {
00189         _SecondaryBuffer->Release();
00190         _SecondaryBuffer = 0;
00191     }
00192 
00193 }
00194 
00195 
00196 uint32  CSourceDSound::getTime()
00197 {
00198     if (_Sample == 0)
00199         return 0;
00200 
00201     TSampleFormat format;
00202     uint freq;
00203 
00204     _Sample->getFormat(format, freq);
00205 
00206     return uint32(1000.0f * (_PlayOffset+1) / (float)freq);
00207 }
00208 
00209 // ******************************************************************
00210 
00211 void CSourceDSound::init(LPDIRECTSOUND directSound, bool useEax)
00212 {
00213 
00214     // Initialize the buffer format
00215     WAVEFORMATEX format;
00216 
00217     format.cbSize = sizeof(WAVEFORMATEX);
00218     format.nChannels = _DefaultChannels;
00219     format.wBitsPerSample = _DefaultSampleSize;
00220     format.nSamplesPerSec = _DefaultSampleRate;
00221     format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
00222     format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
00223     format.wFormatTag = WAVE_FORMAT_PCM;
00224 
00225 
00226     // Initialize the buffer description
00227 
00228     DSBUFFERDESC desc;
00229 
00230     CSoundDriverDSound* driver = CSoundDriverDSound::instance();
00231 
00232 
00233     ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00234     desc.dwSize = sizeof(DSBUFFERDESC);
00235     desc.lpwfxFormat = &format;
00236     desc.dwBufferBytes = _SecondaryBufferSize;
00237     desc.dwReserved = 0;
00238 
00239     if (driver->countHw3DBuffers() > 0)
00240     {
00241         //nldebug("Source: Allocating 3D buffer in hardware");
00242         desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2
00243                         | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
00244     }
00245     else
00246     {
00247         nldebug("Failed to create a 3D Hardware DirectX secondary buffer. Try 3D software one");
00248 
00249         if (useEax)
00250         {
00251             throw ESoundDriver("No 3d hardware sound buffer, but EAX support requested");
00252         }
00253         //nldebug("Source: Allocating 3D buffer in software");
00254         desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2
00255                         | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_MUTE3DATMAXDISTANCE;
00256         desc.guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
00257         //desc.guid3DAlgorithm = DS3DALG_HRTF_FULL;
00258     }
00259 
00260 
00261     // Allocate the secondary buffer
00262 
00263     if (FAILED(directSound->CreateSoundBuffer(&desc, &_SecondaryBuffer, NULL)))
00264     {
00265         if (useEax)
00266         {
00267             throw ESoundDriver("Failed to create a 3d hardware sound buffer, but EAX support requested");
00268         }
00269         nlwarning("Source: Failed to create a buffer with 3D capabilities.");
00270 
00271         ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00272         desc.dwSize = sizeof(DSBUFFERDESC);
00273         desc.lpwfxFormat = &format;
00274         desc.dwBufferBytes = _SecondaryBufferSize;
00275         desc.dwReserved = 0;
00276 
00277         if (driver->countHw2DBuffers() > 0)
00278         {
00279             //nldebug("Source: Allocating 2D buffer in hardware");
00280             desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCHARDWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
00281         }
00282         else
00283         {
00284             //nldebug("Source: Allocating 2D buffer in software");
00285             desc.dwFlags = DSBCAPS_GLOBALFOCUS | DSBCAPS_LOCSOFTWARE | DSBCAPS_GETCURRENTPOSITION2 | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY;
00286         }
00287 
00288         if (FAILED(directSound->CreateSoundBuffer(&desc, &_SecondaryBuffer, NULL)))
00289         {
00290             throw ESoundDriver("Failed to allocate the DirectSound secondary buffer");
00291         }
00292     }
00293 
00294 
00295     nldebug("Created DirectX secondary buffer @ %p", _SecondaryBuffer);
00296 
00297     // Fill the buffer with silence
00298     LPVOID ptr;
00299     DWORD bytes;
00300 
00301     if (FAILED(_SecondaryBuffer->Lock(0, 0, &ptr, &bytes, NULL, NULL, DSBLOCK_ENTIREBUFFER)))
00302     {
00303         throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
00304     }
00305 
00306     memset(ptr, 0, bytes);
00307 
00308     _SecondaryBuffer->Unlock(ptr, bytes, 0, 0);
00309 
00310     // Allocate the 3D interface, if necessary
00311 
00312     if (FAILED(_SecondaryBuffer->QueryInterface(IID_IDirectSound3DBuffer, (LPVOID *) &_3DBuffer)))
00313     {
00314        throw ESoundDriver("Failed to allocate the DirectSound 3D buffer");
00315     }
00316 
00317 
00318     if (FAILED(_SecondaryBuffer->Play(0, 0, DSBPLAY_LOOPING)))
00319     {
00320         throw ESoundDriver("Play failed");
00321     }
00322 
00323 }
00324 
00325 // ******************************************************************
00326 
00327 void CSourceDSound::reset()
00328 {
00329     setPitch(1.0f);
00330     setLooping(false);
00331     setGain(1.0f);
00332 }
00333 
00335 void CSourceDSound::setStreaming(bool streaming)
00336 {
00337     if (streaming) throw ESoundDriverNoBufferStreaming();
00338 }
00339 
00340 // ******************************************************************
00341 
00342 void CSourceDSound::setStaticBuffer( IBuffer *buffer )
00343 {
00344     EnterCriticalSection(&_CriticalSection);
00345 
00346     if (_State == source_playing)
00347     {
00348         _State = source_swap_pending;
00349         _Sample = 0;
00350         _NextSample = buffer;
00351         _SampleOffset = 0;
00352         _PlayOffset = 0;
00353     }
00354     else
00355     {
00356         _Sample = buffer;
00357         _NextSample = 0;
00358         _SampleOffset = 0;
00359         _PlayOffset = 0;
00360         _ADPCMState.PreviousSample = 0;
00361         _ADPCMState.StepIndex = 0;
00362         if (buffer)
00363         {
00364 //          _SampleSize = buffer->getSize();
00365             buffer->getFormat(_Format, _SampleFreq);
00366             switch(_Format)
00367             {
00368             case Mono8:
00369                 _SampleSize = buffer->getSize();
00370                 break;
00371             case Mono16:
00372                 _SampleSize = buffer->getSize() / 2;
00373                 break;
00374             case Mono16ADPCM:
00375                 _SampleSize = buffer->getSize() * 2;
00376                 break;
00377             case Stereo8:
00378                 _SampleSize = buffer->getSize() / 2;
00379                 break;
00380             case Stereo16:
00381                 _SampleSize = buffer->getSize() / 4;
00382                 break;
00383             }
00384         }
00385     }
00386 
00387 /*
00388     // If the user calls setStaticBuffer with a null buffer,
00389     // stop the currently playing buffer and set it to null.
00390     // Otherwise, store the buffer in the swap buffer variable.
00391     // A crossfade between the current buffer and the swap buffer
00392     // will be done when the user calls play.
00393     if (buffer == 0)
00394     {
00395         stop();
00396         _Buffer = 0;
00397         _BufferSize = 0;
00398         _BytesWritten = 0;
00399     }
00400 
00401     _SwapBuffer = _Buffer = buffer;
00402 
00403     _ADPCMState.PreviousSample = 0;
00404     _ADPCMState.StepIndex = 0;
00405 */
00406     LeaveCriticalSection(&_CriticalSection);
00407 }
00408 
00409 IBuffer *CSourceDSound::getStaticBuffer()
00410 {
00411     if (_State == source_swap_pending)
00412         return _NextSample;
00413     else
00414         return _Sample;
00415 
00416 }
00417 
00420 void CSourceDSound::submitStreamingBuffer(IBuffer * /* buffer */)
00421 {
00422     throw ESoundDriverNoBufferStreaming();
00423 }
00424 
00426 uint CSourceDSound::countStreamingBuffers() const
00427 {
00428     throw ESoundDriverNoBufferStreaming();
00429 }
00430 
00431 void CSourceDSound::getCursors(TCursors &cursors)
00432 {
00433     _SecondaryBuffer->GetCurrentPosition((DWORD*)&cursors.PlayCursor, (DWORD*)&cursors.WriteCursor);
00434     // add a security margin to the write cursor
00435 /*  cursors.WriteCursor += _UpdateCopySize;
00436     if (cursors.WriteCursor > _SecondaryBufferSize)
00437         cursors.WriteCursor -= _SecondaryBufferSize;
00438 */
00439     // compute the available write size
00440 //  cursors.WriteSize = std::min(_UpdateCopySize, cursors.PlayCursor + _SecondaryBufferSize - cursors.WriteCursor);
00441     cursors.WriteSize = std::min(_UpdateCopySize, (cursors.PlayCursor - cursors.WriteCursor) & _SizeMask);
00442 }
00443 
00444 void CSourceDSound::fillData(sint16 *dst, uint nbSample)
00445 {
00446     nlassert((nbSample & 0xfffffffe) == nbSample);
00447     if (_Sample != 0)
00448     {
00449         const void *data = ((CBufferDSound*) _Sample)->getData();
00450         const sint8 *data8;
00451         const uint8 *dataAdpcm;
00452         const sint16 *data16;
00453         uint    i;
00454 
00455 //nldebug("Filling from %p to %p (%p sample, %p bytes)", dst, dst+nbSample, nbSample, nbSample*2);
00456 
00457 
00458         switch(_Format)
00459         {
00460         case Mono8:
00461             data8 = (sint8*) data;
00462             data8 += _SampleOffset;
00463 //  nldebug(" with data (Mono8) from %p to %p (sample : base = %p, size = %p)", data8, data8+nbSample, data, _SampleSize);
00464             for (i=0; i<nbSample; ++i)
00465             {
00466                 dst[i] = sint16(data8[i])*256;
00467             }
00468             _SampleOffset += nbSample;
00469             break;
00470         case Mono16ADPCM:
00471             dataAdpcm = (uint8*) data;
00472             dataAdpcm += _SampleOffset/2;
00473 //nldebug("Filling ADPCM : %p => %p with %p to %p", dst, dst+nbSample, dataAdpcm - (uint8*)data, dataAdpcm + (nbSample/2)-(uint8*)data);
00474 //nldebug(" with data (Mono16ADPCM) from %p to %p (sample : base = %p, size = %p)", dataAdpcm, dataAdpcm+(nbSample/2), data, _SampleSize*2);
00475             IBuffer::decodeADPCM(dataAdpcm, dst, nbSample, _ADPCMState);
00476             _SampleOffset += nbSample;
00477             break;
00478         case Mono16:
00479             data16 = (sint16*)data;
00480             data16 += _SampleOffset;
00481 //nldebug("Filling Mono16 : %p => %p with %p to %p", dst, dst+nbSample, data16 - (sint16*)data, data16 + (nbSample)-(sint16*)data);
00482 //  nldebug(" with data (Mono16) from %p to %p (sample : base = %p, size = %p)", data16, data16+nbSample, data, _SampleSize/2);
00483             CFastMem::memcpy(dst, data16, nbSample*2);
00484             _SampleOffset += nbSample;
00485             break;
00486         case Stereo8:
00487             data8 = (sint8*) data;
00488             data8 += _SampleOffset*2;
00489             for (i=0; i<nbSample; ++i)
00490             {
00491                 dst[i] = (sint16(data8[i*2])*128) + (sint16(data8[i*2+1])*128);
00492             }
00493             _SampleOffset += nbSample*2;
00494             break;
00495         case Stereo16:
00496             data16 = (sint16*) data;
00497             data16 += _SampleOffset*2;
00498             for (i=0; i<nbSample; ++i)
00499             {
00500                 dst[i] = (data16[i*2]>>1) + (data16[i*2+1]>>1);
00501             }
00502             _SampleOffset += nbSample*2;
00503             break;
00504         }
00505 
00506 /*      if (_SampleOffset == _SampleSize)
00507         {
00508             _SampleOffset = 0;
00509             _ADPCMState.PreviousSample = 0;
00510             _ADPCMState.StepIndex = 0;
00511         }
00512 */
00513 
00514         nlassert(_SampleOffset <= _SampleSize);
00515     }
00516     else
00517     {
00518     nldebug("Filling : NO DATA from %p to %p (%p sample, %p bytes)", dst, dst+nbSample, nbSample, nbSample*2);
00519 
00520         // write silence in the dst.
00521         while (nbSample)
00522         {
00523             *dst++ = 0;
00524             --nbSample;
00525         }
00526     }
00527 }
00528 
00529 void CSourceDSound::fillData(const TLockedBufferInfo &lbi, int nbSample)
00530 {
00531     nlassert((nbSample & 0x1) == 0);
00532 /*  nlassert(lbi.Size1 != 0);
00533     nlassert(lbi.Ptr1 != NULL);
00534 */  uint size = std::min(uint32(nbSample), lbi.Size1>>1);
00535     fillData(lbi.Ptr1, size);
00536     nbSample -= size;
00537 
00538     if (nbSample)
00539     {
00540 /*      nlassert(lbi.Size2 != 0);
00541         nlassert(lbi.Ptr2 != NULL);
00542 */      size = min(uint32(nbSample), lbi.Size2>>1);
00543         fillData(lbi.Ptr2, size);
00544         nbSample -= size;
00545     }
00546     nlassert(nbSample == 0);
00547 }
00548 
00549 void CSourceDSound::fillSilence(const TLockedBufferInfo &lbi, int nbSample)
00550 {
00551     uint size = min(uint32(nbSample), lbi.Size1>>1);
00552     uint tmp = size;
00553     sint16  *ptr = lbi.Ptr1;
00554 //  nldebug("Silencing from %p to %p (%p sample, %p bytes)", ptr, ptr+size, size, size*2);
00555 
00556     for (; size != 0; --size)
00557         *ptr++ = 0;
00558     nbSample -= tmp;
00559 
00560     if (nbSample)
00561     {
00562         size = std::min(uint32(nbSample), lbi.Size2>>1);
00563         tmp = size;
00564         ptr = lbi.Ptr2;
00565 //  nldebug("Silencing from %p to %p (%p sample, %p bytes)", ptr, ptr+size, size, size*2);
00566         for (; size != 0; --size)
00567             *ptr++ = 0;
00568         nbSample -= tmp;
00569     }
00570     nlassert(nbSample == 0);
00571 
00572 }
00573 
00574 void CSourceDSound::xfade(const TLockedBufferInfo &lbi, sint16 *src)
00575 {
00576     // do the XFade in integer fixed point arithmetic
00577 
00578     nlassert((_XFadeSize & 0x1) == 0);
00579     uint    fade = _XFadeSize;
00580     sint16  *ptr = lbi.Ptr1;
00581     uint    count = lbi.Size1 /2;
00582     sint    alpha, invAlpha;
00583 
00584     while (fade && count)
00585     {
00586         alpha = (fade<<16) / _XFadeSize;
00587         invAlpha = 0x10000 - alpha;
00588         *ptr = (sint(*ptr)*alpha + sint(*src) * invAlpha) >> 16;
00589         ++src;
00590         ++ptr;
00591         --count;
00592         --fade;
00593     }
00594 
00595     ptr = lbi.Ptr2;
00596     count = lbi.Size2 /2;
00597 
00598     while (fade && count)
00599     {
00600         alpha = (fade<<16) / _XFadeSize;
00601         invAlpha = 0x10000 - alpha;
00602         *ptr = (sint(*ptr)*alpha + sint(*src) * invAlpha) >> 16;
00603         ++src;
00604         ++ptr;
00605         --count;
00606         --fade;
00607     }
00608 }
00609 
00610 void CSourceDSound::fadeOut(const TLockedBufferInfo &lbi)
00611 {
00612     nlassert((_XFadeSize & 0x1) == 0);
00613     uint    fade = _XFadeSize;
00614     sint16  *ptr = lbi.Ptr1;
00615     uint    count = lbi.Size1/2;
00616     sint    alpha;
00617 
00618     while (fade && count)
00619     {
00620         alpha = (fade<<16) / _XFadeSize;
00621         *ptr = (*ptr*alpha) >> 16;
00622         ++ptr;
00623         --count;
00624         --fade;
00625     }
00626 
00627     ptr = lbi.Ptr2;
00628     count = lbi.Size2/2;
00629 
00630     while (fade && count)
00631     {
00632         alpha = (fade<<16) / _XFadeSize;
00633         *ptr = (*ptr*alpha) >> 16;
00634         ++ptr;
00635         --count;
00636         --fade;
00637     }
00638 }
00639 void CSourceDSound::fadeIn(const TLockedBufferInfo &lbi)
00640 {
00641     // do the XFade in integer fixed point arithmetic
00642 
00643     nlassert((_XFadeSize & 0x1) == 0);
00644     uint    fade = _XFadeSize;
00645     sint16  *ptr = lbi.Ptr1;
00646     uint    count = lbi.Size1 /2;
00647     sint    alpha, invAlpha;
00648 
00649     while (fade && count)
00650     {
00651         alpha = (fade<<16) / _XFadeSize;
00652         invAlpha = 0x10000 - alpha;
00653         *ptr = (*ptr*invAlpha) >> 16;
00654         ++ptr;
00655         --count;
00656         --fade;
00657     }
00658 
00659     ptr = lbi.Ptr2;
00660     count = lbi.Size2 /2;
00661 
00662     while (fade && count)
00663     {
00664         alpha = (fade<<16) / _XFadeSize;
00665         invAlpha = 0x10000 - alpha;
00666         *ptr = (*ptr*invAlpha) >> 16;
00667         ++ptr;
00668         --count;
00669         --fade;
00670     }
00671 }
00672 
00673 
00674 void CSourceDSound::advanceFill(TLockedBufferInfo &lbi, uint nbSample)
00675 {
00676     uint32 size = nbSample * 2;
00677     if (lbi.Size1 < size)
00678     {
00679         size -= lbi.Size1;
00680         lbi.Size1 = lbi.Size2;
00681         lbi.Size2 = 0;
00682         lbi.Ptr1 = lbi.Ptr2;
00683         lbi.Ptr2 = 0;
00684     }
00685 
00686     nlassert(lbi.Size1 >= size);
00687     lbi.Size1 -= size;
00688     lbi.Ptr1 += size/2;
00689 
00690     _FillOffset += nbSample*2;
00691     nlassert(_FillOffset == (_FillOffset & 0xfffffffC));
00692     _FillOffset &= _SizeMask;
00693 //  if (_FillOffset >= _SecondaryBufferSize)
00694 //      _FillOffset -= _SecondaryBufferSize;
00695     nlassert(_FillOffset < _SecondaryBufferSize);
00696 }
00697 
00698 
00699 
00700 bool CSourceDSound::play()
00701 {
00702 //  nldebug("Play");
00703     EnterCriticalSection(&_CriticalSection);
00704 
00705     _SilenceWriten = 0;
00706 
00707 //  uint32 writeSize = checkFillCursor();
00708     TCursors cursors;
00709     getCursors(cursors);
00710 
00711     // set a new filling point
00712     _FillOffset = cursors.WriteCursor;
00713     _FillOffset = (_FillOffset+3) & 0xfffffffC;
00714     cursors.WriteCursor = _FillOffset;
00715 
00716     TLockedBufferInfo lbi;
00717     if (lock(_FillOffset, cursors.WriteSize, lbi))
00718     {
00719         TLockedBufferInfo unlockInfo(lbi);
00720         // ok, the buffer is locked, write data
00721         if (_State == source_swap_pending)
00722         {
00723             // we swap the buffer.
00724             _Sample = _NextSample;
00725             _NextSample = 0;
00726             if (_Sample != 0)
00727             {
00728                 _Sample->getFormat(_Format, _SampleFreq);
00729                 switch(_Format)
00730                 {
00731                 case Mono8:
00732                     _SampleSize = _Sample->getSize();
00733                     break;
00734                 case Mono16:
00735                     _SampleSize = _Sample->getSize() / 2;
00736                     break;
00737                 case Mono16ADPCM:
00738                     _SampleSize = _Sample->getSize() * 2;
00739                     break;
00740                 case Stereo8:
00741                     _SampleSize = _Sample->getSize() / 2;
00742                     break;
00743                 case Stereo16:
00744                     _SampleSize = _Sample->getSize() / 4;
00745                     break;
00746                 }
00747                 _State = source_playing;
00748             }
00749             else
00750             {
00751                 _SampleSize = 0;
00752                 _State = source_silencing;
00753             }
00754         }
00755         _LastPlayPos = cursors.PlayCursor;
00756         _SampleOffset = 0;
00757         _PlayOffset = 0;
00758         _ADPCMState.PreviousSample = 0;
00759         _ADPCMState.StepIndex = 0;
00760         // Compute the size of data to write.
00761         uint dataToFill = std::min(uint(cursors.WriteSize / 2), _SampleSize - _SampleOffset);
00762         dataToFill &= 0xfffffffe;
00763         // ok, the buffer is locked, write data
00764         if (_State == source_playing || _State == source_silencing)
00765         {
00766             // we need a little XFade
00767             sint16  fadeBuffer[_XFadeSize];
00768             fillData(fadeBuffer, _XFadeSize);
00769             xfade(lbi, fadeBuffer);
00770             advanceFill(lbi, _XFadeSize);
00771             cursors.WriteSize -= _XFadeSize*2;
00772             dataToFill -= _XFadeSize;
00773         }
00774         else
00775         {
00776             // we need a little FadeIn
00777             fillData(lbi, _XFadeSize);
00778             fadeIn(lbi);
00779             advanceFill(lbi, _XFadeSize);
00780             cursors.WriteSize -= _XFadeSize*2;
00781             dataToFill -= _XFadeSize;
00782         }
00783         fillData(lbi, dataToFill);
00784         cursors.WriteSize -= dataToFill * 2;
00785         advanceFill(lbi, dataToFill);
00786         _State = source_playing;
00787         if (_Loop)
00788         {
00789             while (cursors.WriteSize >= 4)
00790             {
00791                 if (_SampleOffset == _SampleSize)
00792                 {
00793                     // rewind the sample
00794                     _SampleOffset = 0;
00795                     _ADPCMState.PreviousSample = 0;
00796                     _ADPCMState.StepIndex = 0;
00797                 }
00798         nlassert(_SampleOffset < _SampleSize);
00799                 dataToFill = std::min(uint(cursors.WriteSize / 2), _SampleSize - _SampleOffset);
00800                 dataToFill &= 0xfffffffe;
00801                 fillData(lbi, dataToFill);
00802                 advanceFill(lbi, dataToFill);
00803                 cursors.WriteSize -= dataToFill*2;
00804             }
00805         }
00806         else
00807         {
00808             if (_SampleOffset == _SampleSize)
00809             {
00810                 // begin to write silence, but stil in play state until all sample are played
00811 //              _State = source_silencing;
00812                 fillSilence(lbi, cursors.WriteSize/2);
00813                 advanceFill(lbi, cursors.WriteSize/2);
00814                 _SilenceWriten = cursors.WriteSize;
00815                 cursors.WriteSize = 0;
00816             }
00817 //          else
00818 //              _State = source_playing;
00819         }
00820 
00821 
00822         unlock(unlockInfo);
00823     }
00824     else
00825     {
00826         nlwarning("Couldn't lock the sound buffer for %u bytes", cursors.WriteSize);
00827     }
00828 
00829     // set the volume NOW
00830     CListenerDSound* listener = CListenerDSound::instance();
00831 
00832     updateVolume(listener->getPos());
00833 
00834     LeaveCriticalSection(&_CriticalSection);
00835 
00836     return true;
00837 }
00838 
00839 void CSourceDSound::stop()
00840 {
00841 //  nldebug("Stop");
00842     EnterCriticalSection(&_CriticalSection);
00843 
00844     if (_State != source_stoped && _State != source_silencing)
00845     {
00846         // retreive the cursors;
00847         TCursors    cursors;
00848         getCursors(cursors);
00849 
00850         _FillOffset = cursors.WriteCursor;
00851         _FillOffset = (_FillOffset+3) & 0xfffffffC;
00852 
00853         TLockedBufferInfo lbi;
00854         if (lock(_FillOffset, cursors.WriteSize, lbi))
00855         {
00856             TLockedBufferInfo unlockInfo(lbi);
00857 
00858             fadeOut(lbi);
00859             advanceFill(lbi, _XFadeSize);
00860             cursors.WriteSize -= _XFadeSize*2;
00861             fillSilence(lbi, cursors.WriteSize/2);
00862             advanceFill(lbi, cursors.WriteSize/2);
00863             _SilenceWriten = cursors.WriteSize;
00864 
00865             _State = source_silencing;
00866 
00867             unlock(unlockInfo);
00868         }
00869     }
00870 
00871     LeaveCriticalSection(&_CriticalSection);
00872 }
00873 
00874 
00875 
00876 // ******************************************************************
00877 
00878 void CSourceDSound::setLooping( bool l )
00879 {
00880     _Loop = l;
00881 }
00882 
00883 
00884 // ******************************************************************
00885 
00886 bool CSourceDSound::getLooping() const
00887 {
00888     return _Loop;
00889 }
00890 
00891 
00892 // ******************************************************************
00893 /*
00894 void CSourceDSound::swap()
00895 {
00896     _Buffer = _SwapBuffer;
00897     _BufferSize = _Buffer->getSize();
00898     _BytesWritten = 0;
00899     _SwapBuffer = 0;
00900 }
00901 */
00902 // ******************************************************************
00903 /*
00904 bool CSourceDSound::play()
00905 {
00906     EnterCriticalSection(&_CriticalSection);
00907 
00908     if (_Buffer == 0 || ((CBufferDSound*) _Buffer)->getData() == 0)
00909     {
00910         // the sample has been unloaded, can't play!
00911 
00912         LeaveCriticalSection(&_CriticalSection);
00913         return false;
00914     }
00915 
00916 
00917     DBGPOS(("[%p] PLAY: Enter, buffer state = %u", this, _SecondaryBufferState));
00918     switch (_SecondaryBufferState)
00919     {
00920     case NL_DSOUND_FILLING:
00921         if (_SwapBuffer != 0)
00922         {
00923             // crossfade to the new sound
00924             DBGPOS(("[%p] PLAY: XFading 1", this));
00925             crossFade();
00926         }
00927         break;
00928 
00929     case NL_DSOUND_SILENCING:
00930         if (_SwapBuffer != 0)
00931         {
00932             if ((_Buffer != 0) && (_UserState == NL_DSOUND_PLAYING))
00933             {
00934                 // crossfade to the new sound
00935                 DBGPOS(("[%p] PLAY: XFading 2", this));
00936                 crossFade();
00937             }
00938             else
00939             {
00940                 DBGPOS(("[%p] PLAY: Swap & fadein 1", this));
00941                 swap();
00942                 fadeIn();
00943             }
00944         }
00945         else
00946         {
00947             DBGPOS(("[%p] PLAY: Fadein", this));
00948             _BytesWritten = 0;
00949             // start the old sound again
00950             fadeIn();
00951         }
00952 
00953         break;
00954 
00955 
00956     case NL_DSOUND_SILENCED:
00957         if (_SwapBuffer != 0)
00958         {
00959             // fade in to the new sound
00960                 DBGPOS(("[%p] PLAY: Swap & fadein 2", this));
00961             swap();
00962             fadeIn();
00963         }
00964         else
00965         {
00966             DBGPOS(("[%p] PLAY: Fadein", this));
00967             _BytesWritten = 0;
00968             // start the old sound again
00969             fadeIn();
00970         }
00971     }
00972 
00973     _UserState = NL_DSOUND_PLAYING;
00974     DBGPOS(("[%p] PLAY: PLAYING", this));
00975 
00976     //nldebug ("NLSOUND: %p play", this);
00977 
00978     LeaveCriticalSection(&_CriticalSection);
00979 
00980     return true;
00981 }
00982 */
00983 
00984 // ******************************************************************
00985 /*
00986 void CSourceDSound::stop()
00987 {
00988     EnterCriticalSection(&_CriticalSection);
00989 
00990     TSourceDSoundUserState old = _UserState;
00991 
00992     _UserState = NL_DSOUND_STOPPED;
00993     DBGPOS(("[%p] STOP: STOPPED", this));
00994 
00995     //nldebug ("NLSOUND: %p stop", this);
00996 
00997     if (old == NL_DSOUND_PLAYING)
00998     {
00999         fadeOut();
01000     }
01001 
01002     _BytesWritten = 0;
01003 
01004     LeaveCriticalSection(&_CriticalSection);
01005 }
01006 */
01007 // ******************************************************************
01008 
01009 void CSourceDSound::pause()
01010 {
01011     // TODO : recode this !
01012     nlassert(false);
01013 /*  EnterCriticalSection(&_CriticalSection);
01014 
01015     TSourceDSoundUserState old = _UserState;
01016 
01017     _UserState = NL_DSOUND_PAUSED;
01018     DBGPOS(("[%p] PAUZ: PAUSED", this));
01019 
01020     //nldebug ("NLOUND: pause %p", this);
01021 
01022     if (old == NL_DSOUND_PLAYING)
01023     {
01024         fadeOut();
01025     }
01026 
01027     LeaveCriticalSection(&_CriticalSection);
01028 */
01029 }
01030 
01031 // ******************************************************************
01032 
01033 bool CSourceDSound::isPlaying() const
01034 {
01035 //  return (_UserState == NL_DSOUND_PLAYING);
01036     return _State == source_playing || _State == source_swap_pending;
01037 }
01038 
01039 
01040 // ******************************************************************
01041 
01042 bool CSourceDSound::isPaused() const
01043 {
01044     // TODO
01045     nlassert(false);
01046     return false;
01047 //  return (_UserState == NL_DSOUND_PAUSED);
01048 }
01049 
01050 
01051 // ******************************************************************
01052 
01053 bool CSourceDSound::isStopped() const
01054 {
01055     return _State == source_silencing || _State == source_stoped;
01056 //  return (_UserState == NL_DSOUND_STOPPED);
01057 }
01058 
01059 
01060 // ******************************************************************
01061 
01062 bool CSourceDSound::needsUpdate()
01063 {
01064     return _State == source_silencing || _State == source_playing || _State == source_swap_pending;
01065 }
01066 
01067 
01068 
01069 // ******************************************************************
01070 
01071 bool CSourceDSound::update()
01072 {
01073     H_AUTO(NLSOUND_SourceDSoundUpdate)
01074     bool updateDone = false;
01075 
01076     EnterCriticalSection(&_CriticalSection);
01077 
01078     // fill some data into the buffer
01079     TCursors cursors;
01080     getCursors(cursors);
01081     uint32  writeSize;
01082 
01083     // The total size available for fill (between fillOffset and play cusors)
01084     uint32 fillSize = (cursors.PlayCursor - _FillOffset) & _SizeMask;
01085     // The play margin (between play and write cursor)
01086     uint32 margin = (cursors.WriteCursor - cursors.PlayCursor) & _SizeMask;
01087     // The number of sample played since previous update
01088     uint32 samplePlayed = ((cursors.PlayCursor - _LastPlayPos) & _SizeMask) / 2;
01089     _LastPlayPos = cursors.PlayCursor;
01090 
01091 
01092 //  if (_FillOffset < cursors.WriteCursor && _FillOffset >cursors.PlayCursor)
01093     if (fillSize + margin > _SecondaryBufferSize)
01094     {
01095         // arg !
01096         nlwarning("FillOffset is between play and write cursor (P = %p F = %p W = %p!", cursors.PlayCursor, _FillOffset, cursors.WriteCursor);
01097         _FillOffset = cursors.WriteCursor;
01098         _FillOffset = (_FillOffset+3) & 0xfffffffC;
01099         _SilenceWriten = 0;
01100     nlassert(_FillOffset < _SecondaryBufferSize);
01101     }
01102 
01103     // advance of the fill offset over the write cursor
01104     uint32 advance = (_FillOffset - cursors.WriteCursor) & _SizeMask;
01105 
01106 /*  nldebug("Play = %p, Write = %p, Fill = %p, FillSize = %p, Margin = %p, Advance = %p",
01107         cursors.PlayCursor, cursors.WriteCursor, _FillOffset, fillSize, margin, advance);
01108 */
01109     if (advance > _UpdateCopySize)
01110     {
01111         // enougth data wrote, wait until next update
01112         cursors.WriteSize = 0;
01113     }
01114 /*  if (cursors.WriteSize)
01115     {
01116         if (_FillOffset < cursors.WriteCursor)
01117         {
01118             if (_FillOffset > cursors.WriteCursor + _UpdateCopySize - _SecondaryBufferSize )
01119             {
01120 //              nlwarning("Enougth data wrote");
01121                 // already fill enough data
01122                 cursors.WriteSize = 0;
01123             }
01124         }
01125         else
01126         {
01127             if (_FillOffset > cursors.WriteCursor + _UpdateCopySize)
01128             {
01129 //              nlwarning("Enougth data wrote");
01130                 // already fill enough data
01131                 cursors.WriteSize = 0;
01132             }
01133         }
01134     }
01135 */
01136 //  nldebug("Cursors : Play = %p, Write = %p, Fill = %p", cursors.PlayCursor, cursors.WriteCursor, _FillOffset);
01137 
01138     cursors.WriteCursor = _FillOffset;
01139     writeSize = cursors.WriteSize;  // compute the real played sample offset
01140 
01141     // update the real number of played sample
01142     if (_State == source_playing)
01143         _PlayOffset += samplePlayed;
01144 
01145     if (writeSize >= _UpdateCopySize)
01146     {
01147 //      nldebug("Update %p bytes", _UpdateCopySize);
01148         writeSize = _UpdateCopySize;
01149         updateDone = true;
01150         TLockedBufferInfo lbi;
01151         if (lock(_FillOffset, writeSize, lbi))
01152         {
01153             TLockedBufferInfo unlockInfo(lbi);
01154             if (_State == source_playing)
01155             {
01156         nlassert(_SampleOffset <= _SampleSize);
01157                 uint32  updateSize = min(_SampleSize - _SampleOffset, uint(writeSize/2));
01158                 updateSize &= 0xfffffffe;
01159                 fillData(lbi, updateSize);
01160                 advanceFill(lbi, updateSize);
01161                 writeSize -= updateSize*2;
01162 
01163                 if (_Loop)
01164                 {
01165                     while (_PlayOffset >= _SampleSize)
01166                         _PlayOffset -= _SampleSize;
01167 
01168                     // repeat until we have at least 2 sample to write
01169                     while (writeSize >= 4)
01170                     {
01171                         if (_SampleOffset == _SampleSize)
01172                         {
01173                             // rewind the sample
01174                             _SampleOffset = 0;
01175                             _ADPCMState.PreviousSample = 0;
01176                             _ADPCMState.StepIndex = 0;
01177                         }
01178 
01179                         updateSize = min(_SampleSize - _SampleOffset, uint(writeSize/2));
01180                         updateSize &= 0xfffffffe;
01181                         fillData(lbi, updateSize);
01182                         advanceFill(lbi, updateSize);
01183                         writeSize -= updateSize*2;
01184                     }
01185                 }
01186                 else
01187                 {
01188                     if (_SampleOffset == _SampleSize)
01189                     {
01190                         fillSilence(lbi, writeSize/2);
01191                         advanceFill(lbi, writeSize/2);
01192                         _SilenceWriten += writeSize;
01193                     }
01194                     if (_PlayOffset >= _SampleSize)
01195                     {
01196                         // all the sample is played, no we are in silencing state !
01197                         _PlayOffset = _SampleSize;
01198                         _State = source_silencing;
01199                     }
01200                 }
01201 
01202             }
01203             else if (_State == source_swap_pending)
01204             {
01205                 // the sample has been changed but not replayed yet ? so we 'stop' the old buffer
01206 
01207                 fadeOut(lbi);
01208                 advanceFill(lbi, _XFadeSize);
01209                 writeSize -= _XFadeSize*2;
01210                 fillSilence(lbi, writeSize/2);
01211                 advanceFill(lbi, writeSize/2);
01212                 _SilenceWriten = writeSize;
01213                 _State = source_silencing;
01214             }
01215             else if (_State == source_silencing)
01216             {
01217                 // write silence into the buffer.
01218                 uint32 updateSize = min(writeSize, _SecondaryBufferSize - _SilenceWriten);
01219                 updateSize &= 0xfffffffC;
01220                 fillSilence(lbi, updateSize/2);
01221                 advanceFill(lbi, updateSize/2);
01222                 _SilenceWriten += updateSize;
01223 
01224                 if (_SilenceWriten == _SecondaryBufferSize)
01225                     _State = source_stoped;
01226             }
01227             else
01228             {
01229                 nlwarning("Update not needed !");
01230             }
01231 
01232             unlock(unlockInfo);
01233         }
01234     }
01235 
01236     LeaveCriticalSection(&_CriticalSection);
01237 
01238     return updateDone;
01239 }
01240 
01241 // ******************************************************************
01242 /*
01243 bool CSourceDSound::update2()
01244 {
01245     bool res = false;
01246 
01247 
01248 
01249     INITTIME(start);
01250 
01251     //
01252     // Enter critical region
01253     //
01254     EnterCriticalSection(&_CriticalSection);
01255 
01256 
01257     switch (_SecondaryBufferState)
01258     {
01259 
01260 
01261     case NL_DSOUND_SILENCED:
01262         {
01263             // Just pretend were writing silence by advancing the next
01264             // write position.
01265             DWORD playPos, writePos;
01266             uint32 space;
01267 
01268             _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
01269 
01270             if (playPos == _NextWritePos)
01271             {
01272                 LeaveCriticalSection(&_CriticalSection);
01273                 return false;
01274             }
01275 
01276             space = getWritePosAndSpace(_NextWritePos, playPos, writePos, _SecondaryBufferSize);
01277 
01278             // not enougth space available
01279             if (space < _UpdateCopySize)
01280                 break;
01281 
01282             _NextWritePos += _UpdateCopySize;
01283 
01284             if (_NextWritePos >= _SecondaryBufferSize)
01285             {
01286                 _NextWritePos  -= _SecondaryBufferSize;
01287             }
01288         }
01289         break;
01290 
01291 
01292     case NL_DSOUND_FILLING:
01293         res = fill();
01294         break;
01295 
01296 
01297     case NL_DSOUND_SILENCING:
01298         res = silence();
01299         break;
01300 
01301     }
01302 
01303 
01304     //
01305     // Leave critical region
01306     //
01307     LeaveCriticalSection(&_CriticalSection);
01308 
01309 
01310 #if NLSOUND_PROFILE
01311     double dt = CTime::ticksToSecond(CTime::getPerformanceTime() - start);;
01312     _TotalUpdateTime += dt;
01313     _MaxUpdateTime = (dt > _MaxUpdateTime) ? dt : _MaxUpdateTime;
01314     _MinUpdateTime = (dt < _MinUpdateTime) ? dt : _MinUpdateTime;
01315     _UpdateCount++;
01316 #endif
01317 
01318     return res;
01319 }
01320 */
01321 
01322 
01323 // ******************************************************************
01324 
01325 void CSourceDSound::setPos( const NLMISC::CVector& pos, bool deferred )
01326 {
01327     _Pos = pos;
01328     // Coordinate system: conversion from NeL to OpenAL/GL:
01329     if (_3DBuffer != NULL)
01330     {
01331         if (_3DBuffer->SetPosition(pos.x, pos.z, pos.y, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
01332         {
01333             nlwarning ("SetPosition failed");
01334         }
01335         else
01336         {
01337             //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);
01338         }
01339     }
01340 }
01341 
01342 
01343 // ******************************************************************
01344 
01345 const NLMISC::CVector &CSourceDSound::getPos() const
01346 {
01347     return _Pos;
01348 }
01349 
01350 
01351 // ******************************************************************
01352 
01353 void CSourceDSound::setVelocity( const NLMISC::CVector& vel, bool deferred )
01354 {
01355     if (_3DBuffer != NULL)
01356     {
01357         if (_3DBuffer->SetVelocity(vel.x, vel.z, vel.y, deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
01358         {
01359             nlwarning ("SetVelocity failed");
01360         }
01361     }
01362 }
01363 
01364 
01365 // ******************************************************************
01366 
01367 void CSourceDSound::getVelocity( NLMISC::CVector& vel ) const
01368 {
01369     if (_3DBuffer != NULL)
01370     {
01371         D3DVECTOR v;
01372 
01373         if (_3DBuffer->GetVelocity(&v) != DS_OK)
01374         {
01375             nlwarning ("GetVelocity failed");
01376             vel.set(0, 0, 0);
01377         }
01378         else
01379         {
01380             vel.set(v.x, v.z, v.y);
01381         }
01382     }
01383     else
01384     {
01385         vel.set(0, 0, 0);
01386     }
01387 }
01388 
01389 
01390 // ******************************************************************
01391 
01392 void CSourceDSound::setDirection( const NLMISC::CVector& dir )
01393 {
01394     if (_3DBuffer != 0)
01395     {
01396         if (_3DBuffer->SetConeOrientation(dir.x, dir.z, dir.y, DS3D_DEFERRED) != DS_OK)
01397         {
01398             nlwarning ("SetConeOrientation failed (x=%.2f, y=%.2f, z=%.2f)", dir.x, dir.y, dir.z);
01399         }
01400         else
01401         {
01402             //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);
01403         }
01404     }
01405 }
01406 
01407 
01408 // ******************************************************************
01409 
01410 void CSourceDSound::getDirection( NLMISC::CVector& dir ) const
01411 {
01412     if (_3DBuffer != NULL)
01413     {
01414         D3DVECTOR v;
01415 
01416         if (_3DBuffer->GetConeOrientation(&v) != DS_OK)
01417         {
01418             nlwarning("GetConeOrientation failed");
01419             dir.set(0, 0, 1);
01420         }
01421         else
01422         {
01423             dir.set(v.x, v.z, v.y);
01424         }
01425     }
01426     else
01427     {
01428         dir.set(0, 0, 1);
01429     }
01430 }
01431 
01432 
01433 // ******************************************************************
01434 
01435 void CSourceDSound::setGain( float gain )
01436 {
01437     clamp(gain, 0.00001f, 1.0f);
01438     _Gain = gain;
01439 
01440     /* convert from linear amplitude to hundredths of decibels */
01441     _Volume = (uint32)(100.0 * 20.0 * log10(gain));
01442     clamp(_Volume, DSBVOLUME_MIN, DSBVOLUME_MAX);
01443 
01444     //nlwarning ("set gain %f vol %d", gain, _Volume);
01445 
01446     /*
01447     if ((_SecondaryBuffer != 0) && (_SecondaryBuffer->SetVolume(_Volume) != DS_OK))
01448     {
01449         nlwarning("SetVolume failed");
01450     }
01451     */
01452 }
01453 
01454 
01455 /*
01456  * Get the gain
01457  */
01458 float CSourceDSound::getGain() const
01459 {
01460     return _Gain;
01461 }
01462 
01463 
01464 // ******************************************************************
01465 
01466 void CSourceDSound::setPitch( float coeff )
01467 {
01468 //  _Freq = coeff;
01469 
01470     if ((_Sample != 0) && (_SecondaryBuffer != 0))
01471     {
01472         TSampleFormat format;
01473         uint freq;
01474 
01475         _Sample->getFormat(format, freq);
01476 
01477         _SampleRate = (uint32) (coeff * (float) freq);
01478 
01479         //nlwarning("Freq=%d", newfreq);
01480 
01481         if (_SecondaryBuffer->SetFrequency(_SampleRate) != DS_OK)
01482         {
01483 //          nlwarning("SetFrequency failed (buffer freq=%d, NeL freq=%.5f, DSound freq=%d)", freq, coeff, newfreq);
01484             nlwarning("SetFrequency");
01485         }
01486     }
01487 }
01488 
01489 
01490 // ******************************************************************
01491 
01492 float CSourceDSound::getPitch() const
01493 {
01494     if ((_Sample != 0) && (_SecondaryBuffer != 0))
01495     {
01496         TSampleFormat format;
01497         uint freq0;
01498         DWORD freq;
01499 
01500         _Sample->getFormat(format, freq0);
01501 
01502         if (_SecondaryBuffer->GetFrequency(&freq) != DS_OK)
01503         {
01504             nlwarning("GetFrequency failed");
01505             return 1.0;
01506         }
01507 
01508         return ((float) freq / (float) freq0);
01509     }
01510 
01511     return 1.0;
01512 }
01513 
01514 
01515 // ******************************************************************
01516 
01517 void CSourceDSound::setSourceRelativeMode( bool mode )
01518 {
01519     if (_3DBuffer != 0)
01520     {
01521         HRESULT hr;
01522 
01523         if (mode)
01524         {
01525             hr = _3DBuffer->SetMode(DS3DMODE_HEADRELATIVE, DS3D_IMMEDIATE);
01526         }
01527         else
01528         {
01529             hr = _3DBuffer->SetMode(DS3DMODE_NORMAL, DS3D_IMMEDIATE);
01530         }
01531 
01532         // cache
01533         if (hr == DS_OK)
01534             _PosRelative= mode;
01535         else
01536             nlwarning("SetMode failed");
01537     }
01538     else
01539     {
01540         nlwarning("Requested setSourceRelativeMode on a non-3D source");
01541     }
01542 }
01543 
01544 
01545 // ******************************************************************
01546 
01547 bool CSourceDSound::getSourceRelativeMode() const
01548 {
01549     return _PosRelative;
01550 }
01551 
01552 
01553 // ******************************************************************
01554 void CSourceDSound::setMinMaxDistances( float mindist, float maxdist, bool deferred )
01555 {
01556     if (_3DBuffer != 0)
01557     {
01558         if (_3DBuffer->SetMinDistance(std::max(DS3D_DEFAULTMINDISTANCE, mindist), deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
01559         {
01560             nlwarning("SetMinDistance (%f) failed", mindist);
01561         }
01562         if (_3DBuffer->SetMaxDistance(std::min(DS3D_DEFAULTMAXDISTANCE, maxdist), deferred ? DS3D_DEFERRED : DS3D_IMMEDIATE) != DS_OK)
01563         {
01564             nlwarning("SetMaxDistance (%f) failed", maxdist);
01565         }
01566     }
01567     else
01568     {
01569         nlwarning("Requested setMinMaxDistances on a non-3D source");
01570     }
01571 }
01572 
01573 
01574 // ******************************************************************
01575 
01576 void CSourceDSound::getMinMaxDistances( float& mindist, float& maxdist ) const
01577 {
01578     if (_3DBuffer != 0)
01579     {
01580         D3DVALUE min, max;
01581 
01582         if ((_3DBuffer->GetMinDistance(&min) != DS_OK)
01583             || (_3DBuffer->GetMaxDistance(&max) != DS_OK))
01584         {
01585             mindist = 0.0f;
01586             maxdist = 0.0f;
01587             nlwarning("GetMinDistance or GetMaxDistance failed");
01588         }
01589         else
01590         {
01591             mindist = min;
01592             maxdist = max;
01593         }
01594     }
01595     else
01596     {
01597         mindist = 0.0f;
01598         maxdist = 0.0f;
01599         nlwarning("Requested getMinMaxDistances on a non-3D source");
01600     }
01601 }
01602 
01603 // ******************************************************************
01604 void CSourceDSound::updateVolume( const NLMISC::CVector& listener )
01605 {
01606     if (!CSoundDriverDSound::instance()->getOption(ISoundDriver::OptionManualRolloff))
01607     {
01608         // API controlled rolloff => return (just set the volume)
01609         _SecondaryBuffer->SetVolume(_Volume);
01610     }
01611     else // manual rolloff
01612     {
01613         CVector pos = getPos();
01614         // make relative to listener (if not already!)
01615         if(!_PosRelative)
01616             pos -= listener;
01617         float sqrdist = pos.sqrnorm();
01618 
01619         float mindist, maxdist;
01620         getMinMaxDistances(mindist, maxdist);
01621 
01622         // attenuate the volume according to distance and alpha
01623         sint32 volumeDB = ISource::computeManualRollOff(_Volume, DSBVOLUME_MIN, DSBVOLUME_MAX, _Alpha, sqrdist, mindist, maxdist);
01624 
01625         // set attenuated volume
01626         _SecondaryBuffer->SetVolume(volumeDB);
01627     }
01628 }
01629 
01630 // ******************************************************************
01631 
01632 void CSourceDSound::setCone( float innerAngle, float outerAngle, float outerGain )
01633 {
01634     if (_3DBuffer != 0)
01635     {
01636         // Set the cone angles
01637 
01638         // Convert from radians to degrees
01639         DWORD inner = (DWORD)(180.0 * innerAngle / Pi);
01640         DWORD outer = (DWORD)(180.0 * outerAngle / Pi);
01641 
01642 
01643         // Sanity check: wrap the angles in the [0,360] interval
01644         if (outer < inner)
01645         {
01646             outer = inner;
01647         }
01648 
01649         while (inner < DS3D_MINCONEANGLE)
01650         {
01651             inner += 360;
01652         }
01653 
01654         while (inner > DS3D_MAXCONEANGLE)
01655         {
01656             inner -= 360;
01657         }
01658 
01659         while (outer < DS3D_MINCONEANGLE)
01660         {
01661             outer += 360;
01662         }
01663 
01664         while (outer > DS3D_MAXCONEANGLE)
01665         {
01666             outer -= 360;
01667         }
01668 
01669         if (_3DBuffer->SetConeAngles(inner, outer, DS3D_DEFERRED) != DS_OK)
01670         {
01671             nlwarning("SetConeAngles failed");
01672         }
01673 
01674         // Set the outside volume
01675         if (outerGain < 0.00001f)
01676         {
01677             outerGain = 0.00001f;
01678         }
01679 
01680         // convert from linear amplitude to hundredths of decibels
01681         LONG volume = (LONG)(100.0 * 20.0 * log10(outerGain));
01682 
01683         if (volume < DSBVOLUME_MIN)
01684         {
01685             volume = DSBVOLUME_MIN;
01686         }
01687         else if (volume > DSBVOLUME_MAX)
01688         {
01689             volume = DSBVOLUME_MAX;
01690         }
01691 
01692         if (_3DBuffer->SetConeOutsideVolume(volume, DS3D_DEFERRED) != DS_OK)
01693         {
01694             nlwarning("SetConeOutsideVolume failed");
01695         }
01696 
01697     }
01698     else
01699     {
01700         nlwarning("Requested setCone on a non-3D source");
01701     }
01702 }
01703 
01704 // ******************************************************************
01705 
01706 void CSourceDSound::getCone( float& innerAngle, float& outerAngle, float& outerGain ) const
01707 {
01708     if (_3DBuffer != 0)
01709     {
01710         DWORD inner, outer;
01711         LONG volume;
01712 
01713         if (_3DBuffer->GetConeAngles(&inner, &outer) != DS_OK)
01714         {
01715             nlwarning("GetConeAngles failed");
01716             innerAngle = outerAngle = (float)(2.0 * Pi);
01717         }
01718         else
01719         {
01720             innerAngle = (float)(Pi * inner / 180.0);
01721             outerAngle = (float)(Pi * outer / 180.0);
01722         }
01723 
01724         if (_3DBuffer->GetConeOutsideVolume(&volume) != DS_OK)
01725         {
01726             nlwarning("GetConeOutsideVolume failed");
01727             outerGain = 0.0f;
01728         }
01729         else
01730         {
01731             outerGain = (float) pow((double)10, (double) volume / 20.0 / 100.0);
01732         }
01733     }
01734     else
01735     {
01736         nlwarning("Requested getCone on a non-3D source");
01737     }
01738 }
01739 
01740 // ******************************************************************
01741 
01742 //void CSourceDSound::setEAXProperty( uint prop, void *value, uint valuesize )
01743 //{
01744 //#if EAX_AVAILABLE == 1
01745 //  if (_EAXSource == 0)
01746 //  {
01747 //      _EAXSource = CSoundDriverDSound::instance()->createPropertySet(this);
01748 //  }
01749 //  if ( _EAXSource != NULL )
01750 //  {
01751 //      H_AUTO(NLSOUND_EAXPropertySet_Set)
01752 //      HRESULT res = _EAXSource->Set( DSPROPSETID_EAX_BufferProperties, prop, NULL, 0, value, valuesize );
01753 //      if (res != S_OK)
01754 //      {
01756 //      }
01757 //  }
01758 //#endif
01759 //}
01760 
01774 void CSourceDSound::setAlpha(double a)
01775 {
01776     _Alpha = a;
01777 }
01778 
01780 void CSourceDSound::setDirect(bool /* enable */)
01781 {
01782     
01783 }
01784 
01786 bool CSourceDSound::getDirect() const
01787 {
01788     return true;
01789 }
01790 
01792 void CSourceDSound::setDirectGain(float /* gain */)
01793 {
01794     
01795 }
01796 
01798 float CSourceDSound::getDirectGain() const
01799 {
01800     return NLSOUND_DEFAULT_DIRECT_GAIN;
01801 }
01802 
01804 void CSourceDSound::enableDirectFilter(bool /* enable */)
01805 {
01806     
01807 }
01808 
01810 bool CSourceDSound::isDirectFilterEnabled() const
01811 {
01812     return false;
01813 }
01814 
01816 void CSourceDSound::setDirectFilter(TFilter /*filterType*/, float /*lowFrequency*/, float /*highFrequency*/, float /*passGain*/)
01817 {
01818     
01819 }
01820 
01822 void CSourceDSound::getDirectFilter(TFilter &filterType, float &lowFrequency, float &highFrequency, float &passGain) const
01823 {
01824     filterType = FilterLowPass;
01825     lowFrequency = NLSOUND_DEFAULT_FILTER_PASS_LF; 
01826     highFrequency = NLSOUND_DEFAULT_FILTER_PASS_HF; 
01827     passGain = NLSOUND_DEFAULT_FILTER_PASS_GAIN;
01828 }
01829 
01831 void CSourceDSound::setDirectFilterPassGain(float /*passGain*/)
01832 {
01833     
01834 }
01835 
01837 float CSourceDSound::getDirectFilterPassGain() const
01838 {
01839     return 0.0f;
01840 }
01841 
01843 void CSourceDSound::setEffect(IReverbEffect * /* reverbEffect */)
01844 {
01845     
01846 }
01847 
01849 IEffect *CSourceDSound::getEffect() const
01850 {
01851     return NULL;
01852 }
01853 
01855 void CSourceDSound::setEffectGain(float /* gain */)
01856 {
01857     
01858 }
01859 
01861 float CSourceDSound::getEffectGain() const
01862 {
01863     return NLSOUND_DEFAULT_EFFECT_GAIN;
01864 }
01865 
01867 void CSourceDSound::enableEffectFilter(bool /* enable */)
01868 {
01869     
01870 }
01871 
01873 bool CSourceDSound::isEffectFilterEnabled() const
01874 {
01875     return false;
01876 }
01877 
01879 void CSourceDSound::setEffectFilter(TFilter /*filterType*/, float /*lowFrequency*/, float /*highFrequency*/, float /*passGain*/)
01880 {
01881     
01882 }
01883 
01885 void CSourceDSound::getEffectFilter(TFilter &filterType, float &lowFrequency, float &highFrequency, float &passGain) const
01886 {
01887     filterType = FilterLowPass;
01888     lowFrequency = NLSOUND_DEFAULT_FILTER_PASS_LF; 
01889     highFrequency = NLSOUND_DEFAULT_FILTER_PASS_HF; 
01890     passGain = NLSOUND_DEFAULT_FILTER_PASS_GAIN;
01891 }
01892 
01894 void CSourceDSound::setEffectFilterPassGain(float /*passGain*/)
01895 {
01896     
01897 }
01898 
01900 float CSourceDSound::getEffectFilterPassGain() const
01901 {
01902     return 0.0f;
01903 }
01904 
01905 // ******************************************************************
01906 
01907 IBuffer *CSourceDSound::getBuffer()
01908 {
01909     return _Sample;
01910 }
01911 
01912 
01913 // ******************************************************************
01914 
01915 bool CSourceDSound::lock(uint32 offset, uint32 size, TLockedBufferInfo &lbi)
01916 {
01917     HRESULT hr = _SecondaryBuffer->Lock(offset, size, (LPVOID*) &lbi.Ptr1, (DWORD*) &lbi.Size1, (LPVOID*) &lbi.Ptr2, (DWORD*) &lbi.Size2, 0);
01918 
01919     if (hr == DSERR_BUFFERLOST)
01920     {
01921         // If the buffer got lost somehow, try to restore it.
01922         if (FAILED(_SecondaryBuffer->Restore()))
01923         {
01924             nlwarning("Lock failed (1)");
01925             return false;
01926         }
01927         if (FAILED(_SecondaryBuffer->Lock(offset, size, (LPVOID*) &lbi.Ptr1, (DWORD*)&lbi.Size1, (LPVOID*) &lbi.Ptr2, (DWORD*)&lbi.Size2, 0)))
01928         {
01929             nlwarning("Lock failed (2)");
01930             return false;
01931         }
01932     }
01933     else if (hr != DS_OK)
01934     {
01935         nlwarning("Lock failed (3)");
01936         return false;
01937     }
01938 
01939     return true;
01940 }
01941 /*
01942 
01943 bool CSourceDSound::lock(uint32 writePos, uint32 size, uint8* &ptr1, DWORD &bytes1, uint8* &ptr2, DWORD &bytes2)
01944 {
01945     HRESULT hr = _SecondaryBuffer->Lock(writePos, size, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0);
01946 
01947     if (hr == DSERR_BUFFERLOST)
01948     {
01949         // If the buffer got lost somehow, try to restore it.
01950         if (FAILED(_SecondaryBuffer->Restore()))
01951         {
01952             nlwarning("Lock failed (1)");
01953             return false;
01954         }
01955         if (FAILED(_SecondaryBuffer->Lock(_NextWritePos, _UpdateCopySize, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
01956         {
01957             nlwarning("Lock failed (2)");
01958             return false;
01959         }
01960     }
01961     else if (hr != DS_OK)
01962     {
01963         nlwarning("Lock failed (3)");
01964         return false;
01965     }
01966 
01967     return true;
01968 }
01969 */
01970 // ******************************************************************
01971 
01972 bool CSourceDSound::unlock(const TLockedBufferInfo &lbi)
01973 {
01974     _SecondaryBuffer->Unlock(lbi.Ptr1, lbi.Size1, lbi.Ptr2, lbi.Size2);
01975     return true;
01976 }
01977 
01978 
01979 /*
01980 bool CSourceDSound::unlock(uint8* ptr1, DWORD bytes1, uint8* ptr2, DWORD bytes2)
01981 {
01982     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
01983     return true;
01984 }
01985 */
01986 /*
01987 void CSourceDSound::copySampleTo16BitsTrack(void *dst, void *src, uint nbSample, TSampleFormat sourceFormat)
01988 {
01989     if (sourceFormat == Mono8 || sourceFormat == Stereo8)
01990     {
01991         nlassert("8 bit mixing is not supported now !");
01992         return;
01993         // convert sample from 8 to 16 inside the dst buffer
01994         sint8 *psrc = (sint8*)src;
01995         sint16 *pdst = (sint16*)dst;
01996         sint8 *endSrc = psrc + nbSample;
01997 
01998         for (; psrc != endSrc; psrc += 2)
01999         {
02000             // write the high word
02001             *pdst++ = sint16(*psrc++) * 256;
02002         }
02003     }
02004     if (sourceFormat == Mono16ADPCM)
02005     {
02006         // unpack ADPCM data
02007         nldebug("Mixing %u samples in ADPCM", nbSample);
02008         IBuffer::decodeADPCM((uint8*)src, (sint16*)dst, nbSample, _ADPCMState);
02009     }
02010     else
02011     {
02012         // use the fastmem copy buffer
02013         CFastMem::memcpy(dst, src, nbSample*2);
02014     }
02015 }
02016 */
02017 /***************************************************************************
02018 
02019 
02020   Buffer operations
02021 
02022   There are five buffer operation: fill, silence, fadeOut, crossFade
02023   and fadeIn. fill and silence are called by the update function. The
02024   others are called by the user state functions (play, stop, pause).
02025 
02026 
02027             NW     P   W
02028    +--------+------+---+-----------------------+
02029    |........|      |xxx|.......................|
02030    +--------+------+---+-----------------------+
02031 
02032   The source maintains the next write position (_NextWritePos, NW in figure
02033   above). That is the position at which new samples or silemce is written.
02034   DirectSound maintaines a play cursor and a write cursor (P and W in figure).
02035   The data between P and W is scheduled for playing and cannot be touched.
02036   The data between W and NW are unplayed sample data that the source copied
02037   into the DirectSound buffer.
02038 
02039   The update functions (fill, silence) refresh the buffer with new samples
02040   or silence. That insert the sample data at the next write position NW. This
02041   write position is maintained as closely behind the DirectSound play cursor
02042   as possible to keep the buffer filled with data.
02043 
02044   The user functions (the fades) modify the sample data that is right after
02045   the write cursor W maintained by DirectSound. The data has to be written
02046   after W to hear the changes as soon as possible. When a fade is done, the
02047   data already written in the buffer has to be overwritten. The function
02048   getFadeOutSize() helps to found out how many samples are writen between
02049   W and NW and to what section of the original audio data they correspond.
02050 
02051   All the buffer functions below have the same pattern:
02052 
02053     - get current play and write cursors (P and W)
02054     - lock the buffer
02055     - copy samples
02056     - unlock buffer
02057     - update state variables
02058 
02059   The differences between the functions are due to different operation
02060   (fades), position and size of the buffer to lock, handling of silence
02061   and looping.
02062 
02063   Enjoy!
02064 
02065   PH
02066 
02067 
02068 ************************************************************************/
02069 /*
02070 uint32 getWritePosAndSpace(uint32 &nextWritePos, uint32 playPos, uint32 writePos, uint32 bufferSize)
02071 {
02072     uint32 space;
02073     if (playPos < writePos) //_NextWritePos)
02074     {
02075         // the 'forbiden' interval is continuous
02076         if (nextWritePos > playPos && nextWritePos < writePos)
02077         {
02078             // We have a problem here because our write pointer is in the forbiden zone
02079             // This is mainly due to cpu overload.
02080             nextWritePos = writePos;
02081         }
02082 //      space = playPos - _NextWritePos;
02083     }
02084     else
02085     {
02086         // The forbiden interval is wrapping
02087         if (nextWritePos > playPos || nextWritePos < writePos)
02088         {
02089             // We have a problem here because our write pointer is in the forbiden zone
02090             // This is mainly due to cpu overload.
02091             nextWritePos = writePos;
02092         }
02093 //      space = _SecondaryBufferSize + playPos - _NextWritePos;
02094     }
02095 
02096     // compute the available space to write to
02097     if (nextWritePos > playPos)
02098     {
02099         space = bufferSize + playPos - nextWritePos;
02100     }
02101     else
02102     {
02103         space = playPos - nextWritePos;
02104     }
02105 
02106     return space;
02107 }
02108 */
02109 /*
02110 bool CSourceDSound::fill()
02111 {
02112     bool res = false;
02113     uint8 *ptr1, *ptr2;
02114     DWORD bytes1, bytes2;
02115     DWORD playPos, writePos;
02116     uint32 space;
02117 
02118 
02119     if (_Buffer == NULL)
02120     {
02121         _SecondaryBufferState = NL_DSOUND_SILENCING;
02122         _UserState = NL_DSOUND_STOPPED;
02123         return false;
02124     }
02125 
02126     if (_SecondaryBuffer == 0)
02127     {
02128         return false;
02129     }
02130 
02131     TSampleFormat   sampleFormat;
02132     uint            freq;
02133     _Buffer->getFormat(sampleFormat, freq);
02134 
02135 
02136     INITTIME(startPos);
02137 
02138 
02139     _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
02140 
02141     if (playPos == _NextWritePos)
02142     {
02143         return false;
02144     }
02145 
02146     uint32 nextWritePos = _NextWritePos;
02147     space = getWritePosAndSpace(nextWritePos, playPos, writePos, _SecondaryBufferSize);
02148 
02149     // Don't bother if the number of samples that can be written is too small.
02150     if (space < _UpdateCopySize)
02151     {
02152         return false;
02153     }
02154 
02155     _NextWritePos = nextWritePos;
02156 
02157     uint8* data = ((CBufferDSound*) _Buffer)->getData();
02158     uint32 available = (_BytesWritten < _BufferSize) ? _BufferSize - _BytesWritten : 0;
02159 
02160 
02161     // The number of samples bytes that will be copied. If bytes is 0
02162     // than write silence to the buffer.
02163     uint32 bytes = std::min(_UpdateCopySize, available);
02164 //  uint32 clear = _UpdateCopySize - available;
02165 
02166 
02167     // Lock the buffer
02168 
02169     INITTIME(startLock);
02170 
02171 
02172     if (!lock(_NextWritePos, _UpdateCopySize, ptr1, bytes1, ptr2, bytes2))
02173     {
02174         return false;
02175     }
02176 
02177 
02178     INITTIME(startCopy);
02179 
02180     // Start copying the samples
02181 
02182 
02183     if (bytes1 <= bytes) {
02184 
02185 //      CFastMem::memcpy(ptr1, data + _BytesWritten, bytes1);
02186         copySampleTo16BitsTrack(ptr1, data + _BytesWritten, bytes1/2, sampleFormat);
02187         _BytesWritten += bytes1;
02188         bytes -= bytes1;
02189 
02190         if (ptr2)
02191         {
02192             if (bytes > 0)
02193             {
02194 //              CFastMem::memcpy(ptr2, data + _BytesWritten, bytes);
02195                 copySampleTo16BitsTrack(ptr2, data + _BytesWritten, bytes/2, sampleFormat);
02196                 _BytesWritten += bytes;
02197             }
02198 
02199             if (bytes < bytes2)
02200             {
02201                 if (_Loop)
02202                 {
02203                     DBGPOS(("[%p] FILL: LOOP", this));
02204 
02205                     //CFastMem::memcpy(ptr2 + bytes, data, bytes2 - bytes);
02206                     copySampleTo16BitsTrack(ptr2 + bytes, data, (bytes2 - bytes)/2, sampleFormat);
02207                     _BytesWritten = bytes2 - bytes;
02208                 }
02209                 else
02210                 {
02211                     memset(ptr2 + bytes, 0, bytes2 - bytes);
02212                     _SilenceWritten = bytes2 - bytes;
02213                 }
02214             }
02215         }
02216     }
02217     else
02218     {
02219         if (bytes > 0)
02220         {
02221 //          CFastMem::memcpy(ptr1, data + _BytesWritten, bytes);
02222             copySampleTo16BitsTrack(ptr1, data + _BytesWritten, bytes/2, sampleFormat);
02223             _BytesWritten += bytes;
02224         }
02225 
02226         if (_Loop)
02227         {
02228             DBGPOS(("[%p] FILL: LOOP", this));
02229 
02230 //          CFastMem::memcpy(ptr1 + bytes, data, bytes1 - bytes);
02231             copySampleTo16BitsTrack(ptr1 + bytes, data, (bytes1 - bytes)/2, sampleFormat);
02232             _BytesWritten = bytes1 - bytes;
02233 
02234             if (ptr2)
02235             {
02236 //              CFastMem::memcpy(ptr2, data + _BytesWritten, bytes2);
02237                 copySampleTo16BitsTrack(ptr2, data + _BytesWritten, bytes2 / 2, sampleFormat);
02238                 _BytesWritten += bytes2;
02239             }
02240 
02241         }
02242         else
02243         {
02244             memset(ptr1 + bytes, 0, bytes1 - bytes);
02245             _SilenceWritten = bytes1 - bytes;
02246 
02247             if (ptr2)
02248             {
02249                 memset(ptr2, 0, bytes2);
02250                 _SilenceWritten += bytes2;
02251             }
02252         }
02253 
02254     }
02255 
02256 
02257 
02258 
02259     INITTIME(startUnlock);
02260 
02261     // Unlock the buffer
02262     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02263 
02264 
02265     // Update the state variables
02266 
02267     // Check if we've reached the end of the file
02268     if (_BytesWritten == _BufferSize)
02269     {
02270         if (_Loop)
02271         {
02272             // If we're looping, start all over again
02273             DBGPOS(("[%p] FILL: LOOP", this));
02274             _BytesWritten = 0;
02275         }
02276         else
02277         {
02278             _SecondaryBufferState = NL_DSOUND_SILENCING;
02279 
02280             // Keep track of where tha last sample was written and the position
02281             // of the play cursor relative to the end position. if the _EndState
02282             // is 0, the play cursor is after the end position, 1 otherwise.
02283             _EndPosition = writePos + bytes;
02284             if (_EndPosition >= _SecondaryBufferSize)
02285             {
02286                 _EndPosition -= _SecondaryBufferSize;
02287             }
02288 
02289             _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
02290 
02291             DBGPOS(("[%p] FILL: SILENCING", this));
02292             DBGPOS(("[%p] FILL: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
02293         }
02294     }
02295 
02296 
02297     // Update the write pointer
02298     _NextWritePos += bytes1 + bytes2;
02299     if (_NextWritePos >= _SecondaryBufferSize)
02300     {
02301         _NextWritePos  -= _SecondaryBufferSize;
02302     }
02303 
02304     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));
02305 
02306 
02307 #if NLSOUND_PROFILE
02308     _TotalUpdateSize += bytes1 + bytes2;
02309     _PosTime += CTime::ticksToSecond(startLock - startPos);
02310     _LockTime += CTime::ticksToSecond(startCopy - startLock);
02311     _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
02312     _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
02313     _CopyCount++;
02314 #endif
02315 
02316 
02317     return true;
02318 }
02319 */
02320 
02321 
02322 
02323 // ******************************************************************
02324 /*
02325 bool CSourceDSound::silence()
02326 {
02327     uint8 *ptr1, *ptr2;
02328     DWORD bytes1, bytes2;
02329     DWORD playPos, writePos;
02330     uint32 space;
02331 
02332     if (_SecondaryBuffer == 0)
02333     {
02334         return false;
02335     }
02336 
02337     INITTIME(startPos);
02338 
02339     _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
02340 
02341     if (playPos == _NextWritePos)
02342     {
02343         return false;
02344     }
02345 
02346     space = getWritePosAndSpace(_NextWritePos, playPos, writePos, _SecondaryBufferSize);
02347 */
02348 /*  else if (playPos > _NextWritePos)
02349     {
02350         space = playPos - _NextWritePos;
02351     }
02352     else
02353     {
02354         space = _SecondaryBufferSize + playPos - _NextWritePos;
02355     }
02356 */
02357 /*  // Don't bother if the number of samples that can be written is too small.
02358     if (space < _UpdateCopySize)
02359     {
02360         return false;
02361     }
02362 
02363         // Lock the buffer
02364 
02365     INITTIME(startLock);
02366 
02367     if (!lock(_NextWritePos, _UpdateCopySize, ptr1, bytes1, ptr2, bytes2))
02368     {
02369         return false;
02370     }
02371 
02372 
02373     INITTIME(startCopy);
02374 
02375     // Silence the buffer
02376     memset(ptr1, 0, bytes1);
02377     memset(ptr2, 0, bytes2);
02378 
02379         // Unlock the buffer
02380 
02381     INITTIME(startUnlock);
02382 
02383     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02384 
02385 
02386     // Update the next write position
02387     _NextWritePos += bytes1 + bytes2;
02388     if (_NextWritePos >= _SecondaryBufferSize)
02389     {
02390         _NextWritePos  -= _SecondaryBufferSize;
02391     }
02392 
02393 
02394     // Check if all the samples in the buffer are played
02395     if ((playPos > _EndPosition) && (_EndState == NL_DSOUND_TAIL2))
02396     {
02397         // The buffer played passed the last sample. Flag the source as stopped.
02398         _EndState = NL_DSOUND_ENDED;
02399         DBGPOS(("[%p] SLNC: ENDED", this));
02400 
02401         // If the buffer was playing, mark it as stopped
02402         if (_UserState == NL_DSOUND_PLAYING)
02403         {
02404             _UserState = NL_DSOUND_STOPPED;
02405             DBGPOS(("[%p] SLNC: STOPPED", this));
02406         }
02407     }
02408     else if ((playPos < _EndPosition) && (_EndState == NL_DSOUND_TAIL1))
02409     {
02410         // The play cursor wrapped around the buffer and is now before the end position
02411         _EndState = NL_DSOUND_TAIL2;
02412         DBGPOS(("[%p] FILL: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
02413     }
02414 
02415 
02416     // Update the amount of silence written
02417     _SilenceWritten += bytes1 + bytes2;
02418     if (_SilenceWritten >= _SecondaryBufferSize)
02419     {
02420         // The buffer is now completely filled with silence
02421         _SecondaryBufferState = NL_DSOUND_SILENCED;
02422         DBGPOS(("[%p] SLNC: SILENCED", this));
02423 
02424         // If the buffer was playing, mark it as stopped
02425         if (_UserState == NL_DSOUND_PLAYING)
02426         {
02427             _UserState = NL_DSOUND_STOPPED;
02428             DBGPOS(("[%p] SLNC: STOPPED*", this));
02429         }
02430     }
02431 
02432     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));
02433 
02434 
02435 #if NLSOUND_PROFILE
02436     _TotalUpdateSize += bytes1 + bytes2;
02437     _PosTime += CTime::ticksToSecond(startLock - startPos);
02438     _LockTime += CTime::ticksToSecond(startCopy - startLock);
02439     _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
02440     _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
02441     _CopyCount++;
02442 #endif
02443 
02444     return true;
02445 }
02446 */
02447 
02448 // ******************************************************************
02449 
02457 /*
02458 void CSourceDSound::getFadeOutSize(uint32 writePos, uint32 &xfadeSize, sint16* &in1, uint32 &writtenTooMuch)
02459 {
02460     // The number of samples over which we will do the crossfade
02461     xfadeSize = _XFadeSize;
02462 
02463 
02464     // The tricky part of this method is to figger out how many samples of the old
02465     // buffer were written after the write cursor and figger our with what position
02466     // in the old buffer the write cursor corresponds. We have to consider the following
02467     // cases:
02468     //
02469     // - the old buffer just looped,
02470     // - the old buffer is finished, but stil has samples in the DirectSound buffer
02471     // - the default case, i.e. the old buffer is playing somewhere in the middle.
02472     //
02473 
02474     // How many bytes did we write after the write position?
02475 
02476     writtenTooMuch = NLSOUND_DISTANCE(writePos, _NextWritePos, _SecondaryBufferSize);
02477 
02478     DBGPOS(("[%p] FADE: TOO=%d", this, writtenTooMuch));
02479 
02480 
02481     uint8* data = ((CBufferDSound*) _Buffer)->getData();
02482 
02483     // If the sound is finished and all the samples are written in the
02484     // buffer, it's possible that there are still samples after the write
02485     // position. If this is the case, we have to do a fade out. If there is
02486     // only silence, we only need to copy without fade.
02487 
02488     if (_SilenceWritten > 0)
02489     {
02490 
02491         if (writtenTooMuch > _SilenceWritten)
02492         {
02493             writtenTooMuch -= _SilenceWritten;
02494             in1 = (sint16*) (data + _BufferSize - writtenTooMuch) ;
02495 
02496             if (writtenTooMuch < 2 * xfadeSize)
02497             {
02498                 xfadeSize = writtenTooMuch / 2;
02499             }
02500         }
02501         else
02502         {
02503             xfadeSize = 0;
02504         }
02505 
02506         DBGPOS(("[%p] FADE: END, TOO=%d, S=%d, F=%d", this, writtenTooMuch, _SilenceWritten, xfadeSize));
02507     }
02508 
02509     // If the sound looped, it's possible that the number of samples
02510     // written is small. In that case, the write cursor is still inside
02511     // the previous loop. All we have to do is fade out the last part
02512     // of the previous loop.
02513 
02514     else if (writtenTooMuch >= _BytesWritten)
02515     {
02516 
02517         writtenTooMuch -= _BytesWritten;
02518 
02519         in1 = (sint16*) (data + _BufferSize - writtenTooMuch) ;
02520 
02521         if (writtenTooMuch < 2 * xfadeSize)
02522         {
02523             xfadeSize = writtenTooMuch / 2;
02524         }
02525 
02526         DBGPOS(("[%p] FADE: LOOPED, TOO=%d, F=%d", this, writtenTooMuch, xfadeSize));
02527 
02528     }
02529 
02530     // This is the default case. Simply fade from the previous to the next buffer.
02531     // The variable writtenTooMuch tells us how much of the previous sound has
02532     // been written after the current write cursor. We just have to check there
02533     // are enough samples available for the fade.
02534 
02535     else
02536     {
02537         in1 = (sint16*) (data + (sint32) _BytesWritten - writtenTooMuch);
02538 
02539         if (xfadeSize > _BufferSize - _BytesWritten)
02540         {
02541             xfadeSize = _BufferSize - _BytesWritten;
02542         }
02543 
02544         DBGPOS(("[%p] FADE: STD, TOO=%d, F=%d", this, writtenTooMuch, xfadeSize));
02545     }
02546 }
02547 */
02548 
02549 
02550 // ******************************************************************
02551 /*
02552 void CSourceDSound::crossFade()
02553 {
02554     uint8 *ptr1, *ptr2;
02555     DWORD bytes1, bytes2;
02556     DWORD playPos, writePos;
02557     uint32 i;
02558 
02559 
02560 
02561     if (_Buffer == NULL)
02562     {
02563         return;
02564     }
02565 
02566     if (_SecondaryBuffer == 0)
02567     {
02568         return;
02569     }
02570 
02571 
02572     INITTIME(start);
02573 
02574 
02575     EnterCriticalSection(&_CriticalSection);
02576 
02577     TSampleFormat   sampleFormat;
02578     uint            freq;
02579     _Buffer->getFormat(sampleFormat, freq);
02580 
02581 
02582     // The source is currently playing an other buffer. We will do a hot
02583     // swap between the old and the new buffer. DirectSound maintains two
02584     // cursors into the buffer: the play cursor and the write cursor.
02585     // The write cursor indicates where we can start writing the new samples.
02586     // To avoid clicks, we have to do a cross fade between the old buffer and
02587     // the new buffer.
02588 
02589     _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
02590 
02591 
02592     // The number of bytes we will write to the DirectSound buffer
02593     uint32 bytes = _SwapCopySize;
02594     if (bytes > _SwapBuffer->getSize())
02595     {
02596         bytes = _SwapBuffer->getSize();
02597     }
02598 
02599 
02600     // Lock the DirectSound buffer
02601 
02602     if (FAILED(_SecondaryBuffer->Lock(writePos, bytes, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
02603     {
02604         LeaveCriticalSection(&_CriticalSection);
02605         throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
02606     }
02607 
02608 
02609     sint16* in1;
02610     uint8* data1 = ((CBufferDSound*) _Buffer)->getData();
02611     uint8* data2 = ((CBufferDSound*) _SwapBuffer)->getData();
02612     sint16* in2 = (sint16*) data2;
02613     sint16* out = (sint16*) ptr1;
02614 
02615     // The number of samples over which we will do the crossfade
02616     uint32 xfadeSize;
02617     uint32 xfadeByteSize;
02618     uint32 writtenTooMuch;
02619 
02620     getFadeOutSize(writePos, xfadeSize, in1, writtenTooMuch);
02621     xfadeByteSize = 2 * xfadeSize;
02622 
02623 #define MIX 1
02624 
02625 
02626 #if MIX
02627     float incr, amp1, amp2;
02628 
02629     if (xfadeSize == 0)
02630     {
02631         amp1 = 0.0f;
02632         amp2 = 1.0f;
02633         incr = 0.0f;
02634     }
02635     else
02636     {
02637         amp1 = 1.0f;
02638         amp2 = 0.0f;
02639         incr = 1.0f / xfadeSize;
02640     }
02641 
02642 #else
02643     float incr, amp1;
02644 
02645     if (xfadeSize == 0)
02646     {
02647         amp1 = 0.0f;
02648         incr = 0.0f;
02649     }
02650     else
02651     {
02652         amp1 = 1.0f;
02653         incr = 1.0f / xfadeSize;
02654     }
02655 
02656 #endif
02657 
02658 
02659     // Start copying the samples
02660 
02661 
02662     // In the first case, the cross fade is completely contained in the first buffer
02663     // pointed to by ptr1.
02664     if (xfadeByteSize < bytes1)
02665     {
02666 
02667         // Do cross fade
02668 
02669         for (i = 0; i < xfadeSize; i++)
02670         {
02671 #if MIX
02672             out[i] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
02673             amp1 -= incr;
02674             amp2 += incr;
02675 #else
02676             out[i] = (sint16) (amp1 * in1[i]);
02677             amp1 -= incr;
02678 #endif
02679         }
02680 
02681         // Copy remaining samples
02682 
02683 #if MIX
02684 //      CFastMem::memcpy(ptr1 + xfadeByteSize, data2 + xfadeByteSize, bytes1 - xfadeByteSize);
02685         copySampleTo16BitsTrack(ptr1 + xfadeByteSize, data2 + xfadeByteSize, (bytes1 - xfadeByteSize)/2, sampleFormat);
02686 
02687         _BytesWritten = bytes1;
02688 #else
02689 //      CFastMem::memcpy(ptr1 + xfadeByteSize, data2, bytes1 - xfadeByteSize);
02690         copySampleTo16BitsTrack(ptr1 + xfadeByteSize, data2, (bytes1 - xfadeByteSize)/2, sampleFormat);
02691         _BytesWritten = bytes1 - xfadeByteSize;
02692 #endif
02693 
02694         if (ptr2)
02695         {
02696             //CFastMem::memcpy(ptr2, data2 + _BytesWritten, bytes2);
02697             copySampleTo16BitsTrack(ptr2, data2 + _BytesWritten, bytes2/2, sampleFormat);
02698             _BytesWritten += bytes2;
02699         }
02700 
02701     }
02702 
02703     // In the second case, the cross fade stretches over the first and the second buffers.
02704     else
02705     {
02706 
02707         uint32 fade1 = bytes1 / 2;
02708         uint32 fade2 = xfadeSize - fade1;
02709 
02710         // Do cross fade
02711 
02712         // Part 1, start at ptr1
02713         for (i = 0; i < fade1; i++)
02714         {
02715 #if MIX
02716             out[i] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
02717             amp1 -= incr;
02718             amp2 += incr;
02719 #else
02720             out[i] = (sint16) (amp1 * in1[i]);
02721             amp1 -= incr;
02722 #endif
02723         }
02724 #if MIX
02725         _BytesWritten = bytes1;
02726 #else
02727         _BytesWritten = 0;
02728 #endif
02729 
02730 
02731         if (ptr2)
02732         {
02733             out = (sint16*) ptr2;
02734 
02735             // Part 2, ontinue at ptr2
02736             for (uint32 k = 0; i < xfadeSize; i++, k++)
02737             {
02738 #if MIX
02739                 out[k] = (sint16) (amp1 * in1[i] + amp2 * in2[i]);
02740                 amp1 -= incr;
02741                 amp2 += incr;
02742 #else
02743                 out[k] = (sint16) (amp1 * in1[i]);
02744                 amp1 -= incr;
02745 #endif
02746             }
02747 
02748             // Copy remaining samples
02749 #if MIX
02750 //          CFastMem::memcpy(ptr2 + 2 * k, data2 + _BytesWritten + 2 * k, bytes2 - 2 * k);
02751             copySampleTo16BitsTrack(ptr2 + 2 * k, data2 + _BytesWritten + 2 * k, (bytes2 - 2 * k)/2, sampleFormat);
02752             _BytesWritten += bytes2;
02753 #else
02754             //CFastMem::memcpy(ptr2 + 2 * k, data2, bytes2 - 2 * k);
02755             copySampleTo16BitsTrack(ptr2 + 2 * k, data2, (bytes2 - 2 * k)/2, sampleFormat);
02756             _BytesWritten = bytes2 - 2 * k;
02757 #endif
02758         }
02759     }
02760 
02761 
02762     // Unlock the DirectSound buffer
02763     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02764 
02765 
02766     // Update the state variables
02767 
02768     _SilenceWritten = 0;
02769 
02770     _NextWritePos = (writePos + bytes1 + bytes2);
02771     if (_NextWritePos >= _SecondaryBufferSize)
02772     {
02773         _NextWritePos -= _SecondaryBufferSize;
02774     }
02775 
02776 
02777 
02778     _SecondaryBufferState = NL_DSOUND_FILLING;
02779 
02780 
02781     // Swap the two buffers
02782     _BufferSize = _SwapBuffer->getSize();
02783     _Buffer = _SwapBuffer;
02784     _SwapBuffer = 0;
02785 
02786     setPitch(_Freq);
02787 
02788     // Check if we've reached the end of the file
02789     if (_BytesWritten == _BufferSize)
02790     {
02791         if (_Loop)
02792         {
02793             _BytesWritten = 0;
02794         }
02795         else
02796         {
02797             _SecondaryBufferState = NL_DSOUND_SILENCING;
02798         }
02799     }
02800 
02801 
02802     DBGPOS(("[%p] XFADE", this));
02803     DBGPOS(("[%p] P=%d, W=%d, NW=%d, SZ=%d, BW=%d, B=%d", this, playPos, writePos, _NextWritePos, _BufferSize, _BytesWritten, bytes1 + bytes2));
02804 
02805 
02806 
02807     LeaveCriticalSection(&_CriticalSection);
02808 
02809 
02810 #if NLSOUND_PROFILE
02811     _LastSwapTime = CTime::ticksToSecond(CTime::getPerformanceTime() - start);
02812     _TotalSwapTime += _LastSwapTime;
02813     _MaxSwapTime = (_LastSwapTime > _MaxSwapTime) ? _LastSwapTime : _MaxSwapTime;
02814     _MinSwapTime = (_LastSwapTime < _MinSwapTime) ? _LastSwapTime : _MinSwapTime;
02815     _SwapCount++;
02816 #endif
02817 
02818 }
02819 */
02820 
02821 
02822 // ******************************************************************
02823 /*
02824 void CSourceDSound::fadeOut()
02825 {
02826     uint8 *ptr1, *ptr2;
02827     DWORD bytes1, bytes2;
02828     DWORD playPos, writePos;
02829     uint32 i;
02830 
02831 
02832     if (_Buffer == NULL)
02833     {
02834         _SecondaryBufferState = NL_DSOUND_SILENCING;
02835         _UserState = NL_DSOUND_STOPPED;
02836         return;
02837     }
02838 
02839     if (_SecondaryBuffer == 0)
02840     {
02841         return;
02842     }
02843 
02844     INITTIME(start);
02845 
02846 
02847     _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
02848 
02849 
02850     // Lock the DirectSound buffer
02851 
02852     if (FAILED(_SecondaryBuffer->Lock(writePos, _SwapCopySize, (LPVOID*) &ptr1, &bytes1, (LPVOID*) &ptr2, &bytes2, 0)))
02853     {
02854         throw ESoundDriver("Failed to lock the DirectSound secondary buffer");
02855     }
02856 
02857 
02858 
02859     // in1 points to the position in the old buffer where the fade out starts
02860     sint16* in1;
02861     sint16* out = (sint16*) ptr1;
02862 
02863     // The number of samples over which we will do the crossfade
02864     uint32 xfadeSize;
02865     uint32 xfadeByteSize;
02866     uint32 writtenTooMuch;
02867 
02868     getFadeOutSize(writePos, xfadeSize, in1, writtenTooMuch);
02869     xfadeByteSize = 2 * xfadeSize;
02870 
02871     float amp1, incr;
02872 
02873     if (xfadeSize == 0)
02874     {
02875         amp1 = 0.0f;
02876         incr = 0.0f;
02877     }
02878     else
02879     {
02880         amp1 = 1.0f;
02881         incr = 1.0f / xfadeSize;
02882     }
02883 
02884 
02885     if (writtenTooMuch > _BytesWritten)
02886     {
02887         // The buffer looped. Count backwards from the end of the file.
02888         _BytesWritten = _BufferSize - writtenTooMuch;
02889     }
02890     else
02891     {
02892         _BytesWritten -= writtenTooMuch;
02893     }
02894 
02895 
02896     // Start copying the samples
02897 
02898 
02899     // In the first case, the fade out is completely contained in the first buffer
02900     // pointed to by ptr1.
02901     if (xfadeByteSize < bytes1)
02902     {
02903 
02904         // Do cross fade
02905 
02906         for (i = 0; i < xfadeSize; i++)
02907         {
02908             out[i] = (sint16) (amp1 * in1[i]);
02909             amp1 -= incr;
02910         }
02911 
02912         // Copy remaining samples
02913 
02914         memset(ptr1 + xfadeByteSize, 0, bytes1 - xfadeByteSize);
02915         _SilenceWritten = bytes1 - xfadeByteSize;
02916 
02917         if (ptr2)
02918         {
02919             memset(ptr2, 0, bytes2);
02920             _SilenceWritten += bytes2;
02921         }
02922 
02923     }
02924 
02925     // In the second case, the fade out stretches over the first and the second buffers.
02926     else
02927     {
02928 
02929         uint32 fade1 = bytes1 / 2;
02930         uint32 fade2 = xfadeSize - fade1;
02931 
02932         // Do cross fade
02933 
02934         // Part 1, start at ptr1
02935         for (i = 0; i < fade1; i++)
02936         {
02937             out[i] = (sint16) (amp1 * in1[i]);
02938             amp1 -= incr;
02939         }
02940 
02941 
02942         if (ptr2)
02943         {
02944             out = (sint16*) ptr2;
02945 
02946             // Part 2, continue at ptr2
02947             for (uint32 k = 0; i < xfadeSize; i++, k++)
02948             {
02949                 out[k] = (sint16) (amp1 * in1[i]);
02950                 amp1 -= incr;
02951             }
02952 
02953             // Clear remaining samples
02954             memset(ptr2 + 2 * k, 0, bytes2 - 2 * k);
02955             _SilenceWritten = bytes2 - 2 * k;
02956         }
02957 
02958     }
02959 
02960 
02961     _BytesWritten += xfadeByteSize;
02962 
02963 
02964     // Unlock the DirectSound buffer
02965     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
02966 
02967 
02968     // Update the next write position
02969     _NextWritePos = (writePos + bytes1 + bytes2);
02970     if (_NextWritePos >= _SecondaryBufferSize)
02971     {
02972         _NextWritePos -= _SecondaryBufferSize;
02973     }
02974 
02975 
02976     _SecondaryBufferState = NL_DSOUND_SILENCING;
02977     DBGPOS(("[%p] FDOU: SILENCING", this));
02978 
02979     // Keep track of where tha last sample was written and the position
02980     // of the play cursor relative to the end position. if the _EndState
02981     // is 0, the play cursor is after the end position, 1 otherwise.
02982     _EndPosition = writePos + xfadeSize;
02983     if (_EndPosition >= _SecondaryBufferSize)
02984     {
02985         _EndPosition -= _SecondaryBufferSize;
02986     }
02987 
02988     _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
02989     DBGPOS(("[%p] FDOU: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
02990 
02991 
02992     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));
02993 
02994 
02995 
02996 #if NLSOUND_PROFILE
02997     _LastSwapTime = CTime::ticksToSecond(CTime::getPerformanceTime() - start);
02998     _TotalSwapTime += _LastSwapTime;
02999     _MaxSwapTime = (_LastSwapTime > _MaxSwapTime) ? _LastSwapTime : _MaxSwapTime;
03000     _MinSwapTime = (_LastSwapTime < _MinSwapTime) ? _LastSwapTime : _MinSwapTime;
03001     _SwapCount++;
03002 #endif
03003 
03004 }
03005 */
03006 // ******************************************************************
03007 /*
03008 void CSourceDSound::fadeIn()
03009 {
03010     bool res = false;
03011     uint8 *ptr1, *ptr2;
03012     DWORD bytes1, bytes2;
03013     DWORD playPos, writePos;
03014 
03015 
03016     if (_Buffer == NULL)
03017     {
03018         _SecondaryBufferState = NL_DSOUND_SILENCING;
03019         _UserState = NL_DSOUND_STOPPED;
03020         return;
03021     }
03022 
03023     if (_SecondaryBuffer == 0)
03024     {
03025         return;
03026     }
03027 
03028     INITTIME(startPos);
03029 
03030     TSampleFormat   sampleFormat;
03031     uint            freq;
03032     _Buffer->getFormat(sampleFormat, freq);
03033 
03034     // Set the correct pitch for this sound
03035 //  setPitch(_Freq);
03036 //  setPitch(_SecondaryBuffer->GetFrequency());
03037 
03038     // Set the correct volume
03039     // FIXME: a bit of a hack
03040     const CVector &pos = CListenerDSound::instance()->getPos();
03041     updateVolume(pos);
03042 
03043 
03044     _SecondaryBuffer->GetCurrentPosition(&playPos, &writePos);
03045 
03046     uint8* data = ((CBufferDSound*) _Buffer)->getData();
03047     uint32 available = (_BytesWritten < _BufferSize) ? _BufferSize - _BytesWritten : 0;
03048     uint32 bytes = NLSOUND_MIN(_SwapCopySize, available);
03049 //  uint32 clear = _SwapCopySize - available;
03050 
03051 
03052     _SilenceWritten = 0;
03053 
03054     // Lock the buffer
03055 
03056     INITTIME(startLock);
03057 
03058 
03059     if (!lock(writePos, _SwapCopySize, ptr1, bytes1, ptr2, bytes2))
03060     {
03061         return;
03062     }
03063 
03064 
03065     INITTIME(startCopy);
03066 
03067     // Start copying the samples
03068 
03069     if (bytes1 <= bytes) {
03070 
03071 //      CFastMem::memcpy(ptr1, data + _BytesWritten, bytes1);
03072         copySampleTo16BitsTrack(ptr1, data + _BytesWritten, bytes1/2, sampleFormat);
03073         _BytesWritten += bytes1;
03074         bytes -= bytes1;
03075 
03076         if (ptr2)
03077         {
03078             if (bytes > 0)
03079             {
03080                 //CFastMem::memcpy(ptr2, data + _BytesWritten, bytes);
03081                 copySampleTo16BitsTrack(ptr2, data + _BytesWritten, bytes/2, sampleFormat);
03082                 _BytesWritten += bytes;
03083             }
03084 
03085             if (bytes < bytes2)
03086             {
03087                 if (_Loop)
03088                 {
03089                     DBGPOS(("[%p] FDIN: LOOP", this));
03090 
03091                     //CFastMem::memcpy(ptr2 + bytes, data, bytes2 - bytes);
03092                     copySampleTo16BitsTrack(ptr2 + bytes, data, (bytes2 - bytes)/2, sampleFormat);
03093                     _BytesWritten = bytes2 - bytes;
03094                 }
03095                 else
03096                 {
03097                     memset(ptr2 + bytes, 0, bytes2 - bytes);
03098                     _SilenceWritten = bytes2 - bytes;
03099                 }
03100             }
03101         }
03102     }
03103     else
03104     {
03105         if (bytes > 0)
03106         {
03107             //CFastMem::memcpy(ptr1, data + _BytesWritten, bytes);
03108             copySampleTo16BitsTrack(ptr1, data + _BytesWritten, bytes/2, sampleFormat);
03109             _BytesWritten += bytes;
03110         }
03111 
03112         if (_Loop)
03113         {
03114             DBGPOS(("[%p] FDIN: LOOP", this));
03115 
03116             //CFastMem::memcpy(ptr1 + bytes, data, bytes1 - bytes);
03117             copySampleTo16BitsTrack(ptr1 + bytes, data, (bytes1 - bytes) / 2, sampleFormat);
03118             _BytesWritten = bytes1 - bytes;
03119 
03120             if (ptr2)
03121             {
03122                 //CFastMem::memcpy(ptr2, data + _BytesWritten, bytes2);
03123                 copySampleTo16BitsTrack(ptr2, data + _BytesWritten, bytes2/2, sampleFormat);
03124                 _BytesWritten += bytes2;
03125             }
03126         }
03127         else
03128         {
03129             memset(ptr1 + bytes, 0, bytes1 - bytes);
03130             _SilenceWritten = bytes1 - bytes;
03131 
03132             if (ptr2)
03133             {
03134                 memset(ptr2, 0, bytes2);
03135                 _SilenceWritten += bytes2;
03136             }
03137         }
03138     }
03139 
03140 
03141     INITTIME(startUnlock);
03142 
03143     // Unlock the buffer
03144     _SecondaryBuffer->Unlock(ptr1, bytes1, ptr2, bytes2);
03145 
03146 
03147     // Update the state variables
03148 
03149     _SecondaryBufferState = NL_DSOUND_FILLING;
03150     DBGPOS(("[%p] FDIN: FILLING", this));
03151 
03152 
03153     // Check if we've reached the end of the file
03154     if (_BytesWritten == _BufferSize)
03155     {
03156         if (_Loop)
03157         {
03158             // If we're looping, start all over again
03159             DBGPOS(("[%p] FDIN: LOOP", this));
03160             _BytesWritten = 0;
03161         }
03162         else
03163         {
03164             _SecondaryBufferState = NL_DSOUND_SILENCING;
03165 
03166             // Keep track of where tha last sample was written and the position
03167             // of the play cursor relative to the end position. if the _EndState
03168             // is NL_DSOUND_TAIL1, the play cursor is after the end position,
03169             // NL_DSOUND_TAIL2 otherwise.
03170             _EndPosition = writePos + bytes;
03171             if (_EndPosition >= _SecondaryBufferSize)
03172             {
03173                 _EndPosition -= _SecondaryBufferSize;
03174             }
03175 
03176             _EndState = (playPos > _EndPosition)? NL_DSOUND_TAIL1 : NL_DSOUND_TAIL2;
03177 
03178             DBGPOS(("[%p] FDIN: SILENCING", this));
03179             DBGPOS(("[%p] FDIN: ENDSTATE=%d, E=%d, P=%d", this, (int) _EndState, _EndPosition, playPos));
03180         }
03181     }
03182 
03183 
03184     // Update the write pointer
03185     _NextWritePos = writePos + bytes1 + bytes2;
03186     if (_NextWritePos >= _SecondaryBufferSize)
03187     {
03188         _NextWritePos  -= _SecondaryBufferSize;
03189     }
03190 
03191     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));
03192 
03193 
03194 #if NLSOUND_PROFILE
03195     _TotalUpdateSize += bytes1 + bytes2;
03196     _PosTime += CTime::ticksToSecond(startLock - startPos);
03197     _LockTime += CTime::ticksToSecond(startCopy - startLock);
03198     _CopyTime += CTime::ticksToSecond(startUnlock - startCopy);
03199     _UnlockTime += CTime::ticksToSecond(CTime::getPerformanceTime() - startUnlock);
03200     _CopyCount++;
03201 #endif
03202 
03203 
03204 }
03205 
03206 */
03207 
03208 } // NLSOUND

Generated on Thu Jan 7 08:26:37 2010 for NeL by  doxygen 1.6.1