00001
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
00024 #include "stddsound.h"
00025
00026
00027 #define INITGUID
00028
00029 #ifdef DIRECTSOUND_VERSION
00030 #undef DIRECTSOUND_VERSION
00031 #endif
00032 #define DIRECTSOUND_VERSION 0x0800
00033
00034 #include "../sound_driver.h"
00035
00036 #include <cmath>
00037
00038 #include "nel/misc/hierarchical_timer.h"
00039 #include "nel/misc/dynloadlib.h"
00040 #include "sound_driver_dsound.h"
00041 #include "listener_dsound.h"
00042
00043
00044 using namespace std;
00045 using namespace NLMISC;
00046
00047
00048 namespace NLSOUND {
00049
00050 CSoundDriverDSound* CSoundDriverDSound::_Instance = NULL;
00051 uint32 CSoundDriverDSound::_TimerPeriod = 100;
00052 HWND CSoundDriverWnd = 0;
00053
00055 LRESULT NelIOProc(LPSTR lpmmioinfo, UINT uMsg, LONG lParam1, LONG lParam2);
00056
00057 #ifndef NL_STATIC
00058
00059 HINSTANCE CSoundDriverDllHandle = 0;
00060
00061
00062
00063 BOOL WINAPI DllMain(HANDLE hModule, DWORD , LPVOID )
00064 {
00065 CSoundDriverDllHandle = (HINSTANCE) hModule;
00066 return TRUE;
00067 }
00068
00069 class CSoundDriverDSoundNelLibrary : public NLMISC::INelLibrary {
00070 void onLibraryLoaded(bool ) { }
00071 void onLibraryUnloaded(bool ) { }
00072 };
00073 NLMISC_DECL_PURE_LIB(CSoundDriverDSoundNelLibrary)
00074
00075 #endif
00076
00077
00078
00079
00080
00081 LRESULT CALLBACK CSoundDriverCreateWindowProc(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
00082 {
00083 return DefWindowProc(hWnd, message, wParam, lParam);
00084 }
00085
00086
00087
00088 #ifdef NL_STATIC
00089 ISoundDriver* createISoundDriverInstanceDSound
00090 #else
00091 __declspec(dllexport) ISoundDriver *NLSOUND_createISoundDriverInstance
00092 #endif
00093 (ISoundDriver::IStringMapperProvider *stringMapper)
00094 {
00095 #ifdef NL_STATIC
00096 HINSTANCE CSoundDriverDllHandle = (HINSTANCE)GetModuleHandle(NULL);
00097 #endif
00098
00099 static bool Registered = false;
00100
00101 if (!Registered)
00102 {
00103
00104
00105 WNDCLASS myClass;
00106 myClass.hCursor = LoadCursor( NULL, IDC_ARROW );
00107 myClass.hIcon = NULL;
00108 myClass.lpszMenuName = (LPSTR) NULL;
00109 myClass.lpszClassName = (LPSTR) "CSoundDriver";
00110 myClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
00111 myClass.hInstance = CSoundDriverDllHandle;
00112 myClass.style = CS_GLOBALCLASS;
00113 myClass.lpfnWndProc = CSoundDriverCreateWindowProc;
00114 myClass.cbClsExtra = 0;
00115 myClass.cbWndExtra = 0;
00116
00117 if (!RegisterClass(&myClass))
00118 {
00119 nlwarning("Failed to initialize the sound driver (RegisterClass)");
00120 return 0;
00121 }
00122
00123 Registered = true;
00124 }
00125
00126 CSoundDriverWnd = CreateWindow((LPSTR) "CSoundDriver", (LPSTR) "CSoundDriver", WS_OVERLAPPEDWINDOW,
00127 CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, (HWND) NULL, (HMENU) NULL,
00128 CSoundDriverDllHandle, (LPSTR) NULL);
00129
00130 if (CSoundDriverWnd == NULL)
00131 {
00132 nlwarning("Failed to initialize the sound driver (CreateWindow)");
00133 return 0;
00134 }
00135
00136
00137
00138
00139
00140
00141 return new CSoundDriverDSound(stringMapper);
00142 }
00143
00144
00145
00146 #ifdef NL_STATIC
00147 uint32 interfaceVersionDSound()
00148 #else
00149 __declspec(dllexport) uint32 NLSOUND_interfaceVersion()
00150 #endif
00151 {
00152 return ISoundDriver::InterfaceVersion;
00153 }
00154
00155
00156
00157 #ifdef NL_STATIC
00158 void outputProfileDSound
00159 #else
00160 __declspec(dllexport) void NLSOUND_outputProfile
00161 #endif
00162 (string &out)
00163 {
00164 CSoundDriverDSound::instance()->writeProfile(out);
00165 }
00166
00167
00168
00169 #ifdef NL_STATIC
00170 ISoundDriver::TDriver getDriverTypeDSound()
00171 #else
00172 __declspec(dllexport) ISoundDriver::TDriver NLSOUND_getDriverType()
00173 #endif
00174 {
00175 return ISoundDriver::DriverDSound;
00176 }
00177
00178
00179
00180
00181
00182
00183
00184
00185 CSoundDriverDSound::CSoundDriverDSound(ISoundDriver::IStringMapperProvider *stringMapper)
00186 : _StringMapper(stringMapper)
00187 {
00188 if ( _Instance == NULL )
00189 {
00190 _Instance = this;
00191
00192 _DirectSound = NULL;
00193 _PrimaryBuffer = NULL;
00194 _SourceCount = 0;
00195 _TimerID = NULL;
00196
00197 #if NLSOUND_PROFILE
00198 _TimerIntervalCount = 0;
00199 _TotalTime = 0.0;
00200 _TotalUpdateTime = 0.0;
00201 _UpdateCount = 0;
00202 _UpdateSources = 0;
00203 _UpdateExec = 0;
00204 #endif
00205
00206 }
00207 else
00208 {
00209 nlerror("Sound driver singleton instanciated twice");
00210 }
00211 }
00212
00213
00214 #if EAX_AVAILABLE == 1
00215
00216 LPKSPROPERTYSET CSoundDriverDSound::createPropertySet(CSourceDSound *source)
00217 {
00218 if (_Sources.empty())
00219 return NULL;
00220
00221 LPDIRECTSOUND3DBUFFER8 d3dBuffer;
00222 if (source == NULL)
00223 d3dBuffer = (*_Sources.begin())->_3DBuffer;
00224 else
00225 {
00226 d3dBuffer = source->_3DBuffer;
00227 }
00228 LPKSPROPERTYSET propertySet;
00229 d3dBuffer->QueryInterface(IID_IKsPropertySet, (void**) &propertySet);
00230
00231
00232 {
00233 if (propertySet != 0)
00234 {
00235 char *listenerProperties[] =
00236 {
00237 "DSPROPERTY_EAXLISTENER_NONE",
00238 "DSPROPERTY_EAXLISTENER_ALLPARAMETERS",
00239 "DSPROPERTY_EAXLISTENER_ROOM",
00240 "DSPROPERTY_EAXLISTENER_ROOMHF",
00241 "DSPROPERTY_EAXLISTENER_ROOMROLLOFFFACTOR",
00242 "DSPROPERTY_EAXLISTENER_DECAYTIME",
00243 "DSPROPERTY_EAXLISTENER_DECAYHFRATIO",
00244 "DSPROPERTY_EAXLISTENER_REFLECTIONS",
00245 "DSPROPERTY_EAXLISTENER_REFLECTIONSDELAY",
00246 "DSPROPERTY_EAXLISTENER_REVERB",
00247 "DSPROPERTY_EAXLISTENER_REVERBDELAY",
00248 "DSPROPERTY_EAXLISTENER_ENVIRONMENT",
00249 "DSPROPERTY_EAXLISTENER_ENVIRONMENTSIZE",
00250 "DSPROPERTY_EAXLISTENER_ENVIRONMENTDIFFUSION",
00251 "DSPROPERTY_EAXLISTENER_AIRABSORPTIONHF",
00252 "DSPROPERTY_EAXLISTENER_FLAGS"
00253 };
00254 uint i;
00255 for (i=DSPROPERTY_EAXLISTENER_NONE; i<= DSPROPERTY_EAXLISTENER_FLAGS; ++i)
00256 {
00257 ULONG ulSupport = 0;
00258 propertySet->QuerySupport(DSPROPSETID_EAX_ListenerProperties, i, &ulSupport);
00259 if ( (ulSupport&(KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET) )
00260 {
00261
00262 }
00263 }
00264
00265 char *bufferProperties[] =
00266 {
00267 "DSPROPERTY_EAXBUFFER_NONE",
00268 "DSPROPERTY_EAXBUFFER_ALLPARAMETERS",
00269 "DSPROPERTY_EAXBUFFER_DIRECT",
00270 "DSPROPERTY_EAXBUFFER_DIRECTHF",
00271 "DSPROPERTY_EAXBUFFER_ROOM",
00272 "DSPROPERTY_EAXBUFFER_ROOMHF",
00273 "DSPROPERTY_EAXBUFFER_ROOMROLLOFFFACTOR",
00274 "DSPROPERTY_EAXBUFFER_OBSTRUCTION",
00275 "DSPROPERTY_EAXBUFFER_OBSTRUCTIONLFRATIO",
00276 "DSPROPERTY_EAXBUFFER_OCCLUSION",
00277 "DSPROPERTY_EAXBUFFER_OCCLUSIONLFRATIO",
00278 "DSPROPERTY_EAXBUFFER_OCCLUSIONROOMRATIO",
00279 "DSPROPERTY_EAXBUFFER_OUTSIDEVOLUMEHF",
00280 "DSPROPERTY_EAXBUFFER_AIRABSORPTIONFACTOR",
00281 "DSPROPERTY_EAXBUFFER_FLAGS"
00282 };
00283
00284 for (i=DSPROPERTY_EAXBUFFER_NONE; i<=DSPROPERTY_EAXBUFFER_FLAGS; ++i)
00285 {
00286 ULONG ulSupport = 0;
00287 propertySet->QuerySupport(DSPROPSETID_EAX_BufferProperties, i, &ulSupport);
00288 if ( (ulSupport&(KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET)) != (KSPROPERTY_SUPPORT_GET|KSPROPERTY_SUPPORT_SET) )
00289 {
00290
00291 }
00292 }
00293 }
00294 else
00295 {
00296 nlwarning("CSoundDriverDSound::createPropertySet : propertie set not available !");
00297 }
00298 }
00299
00300 return propertySet;
00301 }
00302
00303 #endif // EAX_AVAILABLE
00304
00305
00306
00307
00308 class CDeviceDescription
00309 {
00310 public:
00311
00312 static CDeviceDescription* _List;
00313
00314 CDeviceDescription(LPGUID guid, const char* descr)
00315 {
00316 _Guid = guid;
00317 _Description = strdup(descr);
00318 _Next = _List;
00319 _List = this;
00320 }
00321
00322 virtual ~CDeviceDescription()
00323 {
00324 if (_Description)
00325 {
00326 free(_Description);
00327 }
00328 if (_Next)
00329 {
00330 delete _Next;
00331 }
00332 }
00333
00334 char* _Description;
00335 CDeviceDescription* _Next;
00336 LPGUID _Guid;
00337 };
00338
00339 CDeviceDescription* CDeviceDescription::_List = 0;
00340
00341
00342 BOOL CALLBACK CSoundDriverDSoundEnumCallback(LPGUID guid, LPCSTR description, PCSTR , LPVOID )
00343 {
00344 new CDeviceDescription(guid, description);
00345 return TRUE;
00346 }
00347
00348
00349
00350 CSoundDriverDSound::~CSoundDriverDSound()
00351 {
00352 nldebug("Destroying DirectSound driver");
00353
00354 if (_TimerID != NULL)
00355 {
00356 timeKillEvent(_TimerID);
00357 timeEndPeriod(_TimerResolution);
00358 }
00359
00360
00361
00362
00363 set<CSourceDSound*>::iterator iter;
00364
00365 for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00366 {
00367 (*iter)->release();
00368 }
00369
00370
00371
00372
00373 if (CListenerDSound::instance() != 0)
00374 {
00375 CListenerDSound::instance()->release();
00376 }
00377
00378
00379 if (_PrimaryBuffer != NULL)
00380 {
00381 _PrimaryBuffer->Release();
00382 _PrimaryBuffer = NULL;
00383 }
00384
00385 if (_DirectSound != NULL)
00386 {
00387 _DirectSound->Release();
00388 _DirectSound = NULL;
00389 }
00390
00391 _Instance = 0;
00392
00393
00394 if (CDeviceDescription::_List)
00395 {
00396 delete CDeviceDescription::_List;
00397 CDeviceDescription::_List = NULL;
00398 }
00399 }
00400
00402
00403
00405 void CSoundDriverDSound::init(std::string device, ISoundDriver::TSoundOptions options)
00406 {
00407
00408
00409 const sint supportedOptions =
00410 OptionAllowADPCM
00411 #if EAX_AVAILABLE
00412 | OptionEnvironmentEffects
00413 #endif
00414 | OptionSoftwareBuffer
00415 | OptionManualRolloff
00416 | OptionLocalBufferCopy;
00417
00418
00419
00420 const sint forcedOptions =
00421 OptionLocalBufferCopy;
00422
00423
00424 _Options = (TSoundOptions)(((sint)options & supportedOptions) | forcedOptions);
00425
00426 if (FAILED(DirectSoundEnumerate(CSoundDriverDSoundEnumCallback, this)))
00427 {
00428 throw ESoundDriver("Failed to enumerate the DirectSound devices");
00429 }
00430
00431
00432 #if EAX_AVAILABLE
00433 if (getOption(OptionEnvironmentEffects))
00434 {
00435 if (EAXDirectSoundCreate8(NULL, &_DirectSound, NULL) != DS_OK)
00436 {
00437 throw ESoundDriver("Failed to create the DirectSound object from EAX proxy funtion");
00438 }
00439 }
00440 else
00441 #endif
00442 {
00443 if (DirectSoundCreate(NULL, &_DirectSound, NULL) != DS_OK)
00444 {
00445 throw ESoundDriver("Failed to create the DirectSound object");
00446 }
00447 }
00448
00449
00450 if (_DirectSound->SetCooperativeLevel(CSoundDriverWnd, DSSCL_PRIORITY) != DS_OK)
00451 {
00452 throw ESoundDriver("Failed to set the cooperative level");
00453 }
00454
00455
00456
00457
00458 _Caps.dwSize = sizeof(_Caps);
00459
00460 if (_DirectSound->GetCaps(&_Caps) != DS_OK)
00461 {
00462 throw ESoundDriver("Failed to query the sound device caps");
00463 }
00464
00465
00466
00467
00468 DSBUFFERDESC desc;
00469
00470 ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00471 desc.dwSize = sizeof(DSBUFFERDESC);
00472
00473
00474
00475
00476
00477
00478
00479 if (countHw3DBuffers() > 10)
00480 {
00481 _UseEAX = getOption(OptionEnvironmentEffects);
00482 }
00483 else
00484 {
00485
00486 _UseEAX = false;
00487 }
00488
00489 if (countHw3DBuffers() > 0)
00490 {
00491 nldebug("Primary buffer: Allocating 3D buffer in hardware");
00492 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
00493 }
00494 else
00495 {
00496 nldebug("Primary buffer: Allocating 3D buffer in software");
00497 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
00498
00499 }
00500
00501
00502
00503 HRESULT res = _DirectSound->CreateSoundBuffer(&desc, &_PrimaryBuffer, NULL);
00504
00505 if (res != DS_OK && res != DS_NO_VIRTUALIZATION)
00506 {
00507
00508 nlwarning("Primary buffer: Failed to create a buffer with 3D capabilities.");
00509
00510 ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00511 desc.dwSize = sizeof(DSBUFFERDESC);
00512
00513 if (countHw2DBuffers() > 0)
00514 {
00515 nldebug("Primary buffer: Allocating 2D buffer in hardware");
00516 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLVOLUME;
00517 }
00518 else
00519 {
00520 nldebug("Primary buffer: Allocating 2D buffer in software");
00521 desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME;
00522 }
00523
00524 if (_DirectSound->CreateSoundBuffer(&desc, &_PrimaryBuffer, NULL) != DS_OK)
00525 {
00526 throw ESoundDriver("Failed to create the primary buffer");
00527 }
00528 }
00529
00530
00531
00532
00533 WAVEFORMATEX format;
00534
00535 format.cbSize = sizeof(WAVEFORMATEX);
00536
00537
00538
00539
00540
00541 if ((_Caps.dwMinSecondarySampleRate > 22050) && (22050 > _Caps.dwMaxSecondarySampleRate)) {
00542 throw ESoundDriver("Unsupported sample rate range");
00543 }
00544
00545 if ((_Caps.dwFlags & DSCAPS_PRIMARY16BIT) == 0) {
00546 throw ESoundDriver("Unsupported sample size [16bits]");
00547 }
00548
00549 format.wBitsPerSample = 16;
00550 format.nChannels = 1;
00551 format.nSamplesPerSec = 22050;
00552 format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
00553 format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
00554 format.wFormatTag = WAVE_FORMAT_PCM;
00555
00556
00557 if (_PrimaryBuffer->SetFormat(&format) != DS_OK)
00558 {
00559 throw ESoundDriver("Failed to create set the format of the primary buffer");
00560 }
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590 uint32 numBuffers = countHw3DBuffers();
00591 if (numBuffers == 0)
00592 {
00593 numBuffers = 31;
00594 }
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625
00626
00627
00628
00629
00630
00631 TIMECAPS tcaps;
00632
00633 timeGetDevCaps(&tcaps, sizeof(TIMECAPS));
00634 _TimerResolution = (tcaps.wPeriodMin > 10)? tcaps.wPeriodMin : 10;
00635 timeBeginPeriod(_TimerResolution);
00636
00637 #if NLSOUND_PROFILE
00638 for (uint i = 0; i < 1024; i++)
00639 {
00640 _TimerInterval[i] = 0;
00641 }
00642
00643 _TimerDate = CTime::getPerformanceTime();
00644 #endif
00645
00646 _TimerID = timeSetEvent(_TimerPeriod, 0, &CSoundDriverDSound::TimerCallback, (DWORD_PTR)this, TIME_CALLBACK_FUNCTION | TIME_PERIODIC);
00647
00648 if (_TimerID == NULL)
00649 {
00650 throw ESoundDriver("Failed to create the timer");
00651 }
00652 }
00653
00655 ISoundDriver::TSoundOptions CSoundDriverDSound::getOptions()
00656 {
00657 return _Options;
00658 }
00659
00661 bool CSoundDriverDSound::getOption(ISoundDriver::TSoundOptions option)
00662 {
00663 return ((uint)_Options & (uint)option) == (uint)option;
00664 }
00665
00666
00667
00668 uint CSoundDriverDSound::countMaxSources()
00669 {
00670
00671 uint n = countHw3DBuffers();
00672 if (n > 0)
00673 {
00674 return n;
00675 }
00676
00677
00678 n = countHw2DBuffers();
00679 if (n > 0)
00680 {
00681 return n;
00682 }
00683
00684
00685 return 32;
00686 }
00687
00688
00689
00690 void CSoundDriverDSound::writeProfile(string& out)
00691 {
00692
00693 CDeviceDescription* list = CDeviceDescription::_List;
00694 while (list) {
00695 out += "\t" + string(list->_Description) + "\n";
00696 list = list->_Next;
00697 }
00698
00699
00700 out += "\tBuffer size: " + toString ((int)CSourceDSound::_SecondaryBufferSize) + "\n";
00701 out += "\tCopy size: " + toString ((int)CSourceDSound::_UpdateCopySize) + "\n";
00702 out += "\tSwap size: " + toString ((int)CSourceDSound::_SwapCopySize) + "\n";
00703
00704
00705 DSCAPS caps;
00706 caps.dwSize = sizeof(caps);
00707 _DirectSound->GetCaps(&caps);
00708
00709 out += "\t3d hw buffers: " + toString ((uint32)caps.dwMaxHw3DAllBuffers) + "\n";
00710 out += "\t2d hw buffers: " + toString ((uint32)caps.dwMaxHwMixingAllBuffers) + "\n";
00711
00712
00713 #if NLSOUND_PROFILE
00714 out += "\tUpdate time total --- " + toString (getAverageUpdateTime()) + "\n";
00715 out += "\tUpdate time source --- " + toString (CSourceDSound::getAverageUpdateTime()) + "\n";
00716 out += "\tUpdate --- t: " + toString (CSourceDSound::getAverageCumulTime());
00717 out += "\t - p: " + toString (CSourceDSound::getAveragePosTime());
00718 out += "\t - l: " + toString (CSourceDSound::getAverageLockTime());
00719 out += "\t - c: " + toString (CSourceDSound::getAverageCopyTime());
00720 out += "\t - u: " + toString (CSourceDSound::getAverageUnlockTime()) + "\n";
00721 out += "\tUpdate percentage: --- " + toString (getUpdatePercentage()) + "\n";
00722 out += "\tUpdate num sources --- " + toString ((int)getAverageUpdateSources()) + "\n";
00723 out += "\tUpdate byte size --- " + toString (CSourceDSound::getAverageUpdateSize()) + "\n";
00724 out += "\tSwap time --- " + toString (CSourceDSound::getTestAverage()) + "\n";
00725 out += "\tSrc --- " + toString (countPlayingSources()) + "\n";
00726 #endif
00727 }
00728
00729
00730 void CALLBACK CSoundDriverDSound::TimerCallback(UINT , UINT , DWORD_PTR dwUser, DWORD_PTR , DWORD_PTR )
00731 {
00732
00733 static NLMISC::TTime lastUpdate = NLMISC::CTime::getLocalTime();
00734 NLMISC::TTime now = NLMISC::CTime::getLocalTime();
00735
00736 if (now - lastUpdate > _TimerPeriod * 2)
00737 {
00738
00739 }
00740 else
00741 {
00742
00743 }
00744
00745 lastUpdate = now;
00746
00747
00748 CSoundDriverDSound* driver = (CSoundDriverDSound*) dwUser;
00749 driver->update();
00750 }
00751
00752
00753
00754 void CSoundDriverDSound::update()
00755 {
00756 H_AUTO(NLSOUND_DSoundUpdate)
00757 #if NLSOUND_PROFILE
00758 TTicks tnow = CTime::getPerformanceTime();
00759 #endif
00760
00761 NLMISC::TTime now = NLMISC::CTime::getLocalTime();
00762
00763 set<CSourceDSound*>::iterator first(_Sources.begin()), last(_Sources.end());
00764 for (;first != last; ++first)
00765 {
00766 if ((*first)->needsUpdate())
00767 {
00768 if ((*first)->update())
00769 {
00770 #if NLSOUND_PROFILE
00771 _UpdateSources++;
00772 #endif
00773 }
00774 }
00775 }
00776
00777
00778
00779
00780
00781
00782
00783
00784
00785
00786
00787
00788
00789
00790
00791
00792
00793
00794
00795
00796
00797
00798
00799 {
00800 NLMISC::TTime last = CTime::getLocalTime() - now;
00801 if (last > _TimerPeriod / 2)
00802 {
00803 nlwarning("CSoundDriverDSound::TimerCallback : update took %u millisec", (uint32)last);
00804 }
00805 }
00806
00807 #if NLSOUND_PROFILE
00808 _TotalUpdateTime += 1000.0 * CTime::ticksToSecond(CTime::getPerformanceTime() - tnow);
00809 _UpdateCount++;
00810 #endif
00811 }
00812
00813
00814
00815 uint CSoundDriverDSound::countHw3DBuffers()
00816 {
00817 DSCAPS caps;
00818 caps.dwSize = sizeof(caps);
00819
00820 if (_DirectSound->GetCaps(&caps) != DS_OK)
00821 {
00822 throw ESoundDriver("Failed to query the sound device caps");
00823 }
00824
00825 return caps.dwFreeHw3DStreamingBuffers;
00826 }
00827
00828
00829
00830 uint CSoundDriverDSound::countHw2DBuffers()
00831 {
00832 DSCAPS caps;
00833 caps.dwSize = sizeof(caps);
00834
00835 if (_DirectSound->GetCaps(&caps) != DS_OK)
00836 {
00837 throw ESoundDriver("Failed to query the sound device caps");
00838 }
00839
00840 return caps.dwFreeHwMixingStreamingBuffers;
00841 }
00842
00843
00844
00845 IListener *CSoundDriverDSound::createListener()
00846 {
00847 LPDIRECTSOUND3DLISTENER dsoundListener;
00848
00849 if (CListenerDSound::instance() != NULL)
00850 {
00851 return CListenerDSound::instance();
00852 }
00853
00854 if (_PrimaryBuffer == 0)
00855 {
00856 throw ESoundDriver("Corrupt driver");
00857 }
00858
00859 if (FAILED(_PrimaryBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID *) &dsoundListener)))
00860 {
00861 nlwarning("The 3D listener interface is not available.");
00862 return new CListenerDSound(NULL);
00863 }
00864
00865 return new CListenerDSound(dsoundListener);
00866 }
00867
00868
00869
00870 IBuffer *CSoundDriverDSound::createBuffer()
00871 {
00872 if (_PrimaryBuffer == 0)
00873 {
00874 throw ESoundDriver("Corrupt driver");
00875 }
00876
00877
00878
00879 return new CBufferDSound();
00880 }
00881
00882
00883
00884 void CSoundDriverDSound::removeBuffer(IBuffer * )
00885 {
00886 }
00887
00889
00890
00891
00892
00893
00894
00895
00896
00897
00898
00899
00900
00901
00902 ISource *CSoundDriverDSound::createSource()
00903 {
00904 if (_PrimaryBuffer == 0)
00905 {
00906 throw ESoundDriver("Corrupt driver");
00907 }
00908
00909
00910 CSourceDSound* src = new CSourceDSound(0);
00911 src->init(_DirectSound, _UseEAX);
00912 _Sources.insert(src);
00913
00914 return src;
00915 }
00916
00917
00918
00919
00920 void CSoundDriverDSound::removeSource(ISource *source)
00921 {
00922 _Sources.erase((CSourceDSound*) source);
00923 }
00924
00925
00926
00927 void CSoundDriverDSound::commit3DChanges()
00928 {
00929 CListenerDSound* listener = CListenerDSound::instance();
00930 listener->commit3DChanges();
00931
00932
00933 const CVector &origin = listener->getPos();
00934
00935 set<CSourceDSound*>::iterator iter;
00936
00937
00938
00939
00940 for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00941 {
00942 if ((*iter)->isPlaying())
00943 {
00944 (*iter)->updateVolume(origin);
00945 }
00946 }
00947 }
00948
00949
00950
00951
00952 uint CSoundDriverDSound::countPlayingSources()
00953 {
00954 uint n = 0;
00955 set<CSourceDSound*>::iterator iter;
00956
00957 for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00958 {
00959 if ((*iter)->isPlaying())
00960 {
00961 n++;
00962 }
00963 }
00964
00965 return n;
00966 }
00967
00968
00969
00970
00971 void CSoundDriverDSound::setGain( float gain )
00972 {
00973 if (_PrimaryBuffer != 0)
00974 {
00975 if (gain < 0.00001f)
00976 {
00977 gain = 0.00001f;
00978 }
00979
00980
00981 LONG volume = (LONG)(100.0 * 20.0 * log10(gain));
00982
00983 if (volume < DSBVOLUME_MIN)
00984 {
00985 volume = DSBVOLUME_MIN;
00986 }
00987 else if (volume > DSBVOLUME_MAX)
00988 {
00989 volume = DSBVOLUME_MAX;
00990 }
00991
00992 HRESULT hr = _PrimaryBuffer->SetVolume(volume);
00993
00994 if (hr != DS_OK)
00995 {
00996 nldebug("Failed to set the volume");
00997 }
00998 }
00999 }
01000
01001
01002
01003 float CSoundDriverDSound::getGain()
01004 {
01005 if (_PrimaryBuffer != 0)
01006 {
01007
01008 LONG volume;
01009 HRESULT hr = _PrimaryBuffer->GetVolume(&volume);
01010
01011 if (hr != DS_OK)
01012 {
01013 nldebug("Failed to get the volume");
01014 return 1.0;
01015 }
01016
01017 return (float) pow((double)10, (double) volume / 20.0 / 100.0);
01018 }
01019
01020 return 1.0;
01021 }
01022
01023
01024
01025 #if NLSOUND_PROFILE
01026
01027
01028
01029 uint CSoundDriverDSound::countTimerIntervals()
01030 {
01031 return 1024;
01032 }
01033
01034
01035
01036 uint CSoundDriverDSound::getTimerIntervals(uint index)
01037 {
01038 return _TimerInterval[index];
01039 }
01040
01041
01042
01043 void CSoundDriverDSound::addTimerInterval(uint32 dt)
01044 {
01045 if (_TimerIntervalCount >= 1024)
01046 {
01047 _TimerIntervalCount = 0;
01048 }
01049
01050 _TimerInterval[_TimerIntervalCount++] = dt;
01051 }
01052
01053
01054
01055 double CSoundDriverDSound::getCPULoad()
01056 {
01057 return (_TotalTime > 0.0)? 100.0 * _TotalUpdateTime / _TotalTime : 0.0;
01058 }
01059
01060
01061
01062 void CSoundDriverDSound::printDriverInfo(FILE* fp)
01063 {
01064 CDeviceDescription* list = CDeviceDescription::_List;
01065
01066 while (list) {
01067 fprintf(fp, "%s\n", list->_Description);
01068 list = list->_Next;
01069 }
01070
01071 fprintf(fp, "\n");
01072
01073 fprintf(fp, "buffer size: %d\n"
01074 "copy size: %d\n"
01075 "swap size: %d\n",
01076 CSourceDSound::_SecondaryBufferSize,
01077 CSourceDSound::_UpdateCopySize,
01078 CSourceDSound::_SwapCopySize);
01079
01080 fprintf(fp, "\n");
01081
01082 DSCAPS caps;
01083 caps.dwSize = sizeof(caps);
01084
01085 if (_DirectSound->GetCaps(&caps) != DS_OK)
01086 {
01087 throw ESoundDriver("Failed to query the sound device caps");
01088 }
01089
01090
01091 fprintf(fp, "3d hw buffers: %d\n" "2d hw buffers: %d\n\n", caps.dwMaxHw3DAllBuffers, caps.dwMaxHwMixingAllBuffers);
01092 }
01093
01094 #endif
01095
01096
01097 void CSoundDriverDSound::startBench()
01098 {
01099 NLMISC::CHTimer::startBench();
01100 }
01101 void CSoundDriverDSound::endBench()
01102 {
01103 NLMISC::CHTimer::endBench();
01104 }
01105 void CSoundDriverDSound::displayBench(CLog *log)
01106 {
01107 NLMISC::CHTimer::displayHierarchicalByExecutionPathSorted(log, CHTimer::TotalTime, true, 48, 2);
01108 NLMISC::CHTimer::displayHierarchical(log, true, 48, 2);
01109 NLMISC::CHTimer::displayByExecutionPath(log, CHTimer::TotalTime);
01110 NLMISC::CHTimer::display(log, CHTimer::TotalTime);
01111 }
01112
01113 }