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

sound_driver_dsound.cpp

Go to the documentation of this file.
00001 
00007 /* Copyright, 2001 Nevrax Ltd.
00008  *
00009  * This file is part of NEVRAX NEL.
00010  * NEVRAX NEL is free software; you can redistribute it and/or modify
00011  * it under the terms of the GNU General Public License as published by
00012  * the Free Software Foundation; either version 2, or (at your option)
00013  * any later version.
00014 
00015  * NEVRAX NEL is distributed in the hope that it will be useful, but
00016  * WITHOUT ANY WARRANTY; without even the implied warranty of
00017  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
00018  * General Public License for more details.
00019 
00020  * You should have received a copy of the GNU General Public License
00021  * along with NEVRAX NEL; see the file COPYING. If not, write to the
00022  * Free Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
00023  * MA 02111-1307, USA.
00024  */
00025 
00026 
00027 // The one and only INITGUID
00028 #define INITGUID
00029 
00030 #include "stddsound.h"
00031 
00032 
00033 #include "sound_driver_dsound.h"
00034 #include "listener_dsound.h"
00035 #include <math.h>
00036 
00037 
00038 using namespace std;
00039 using namespace NLMISC;
00040 
00041 
00042 namespace NLSOUND {
00043 
00044 CSoundDriverDSound* CSoundDriverDSound::_Instance = NULL;
00045 uint32 CSoundDriverDSound::_TimerPeriod = 100;
00046 HINSTANCE CSoundDriverDllHandle = 0;
00047 HWND CSoundDriverWnd = 0;
00048 
00049 
00050 // ******************************************************************
00051 // The main entry of the DLL. It's used to get a hold of the hModule handle.
00052 
00053 BOOL WINAPI DllMain(HANDLE hModule, DWORD ul_reason_for_call, LPVOID lpReserved)
00054 {
00055   CSoundDriverDllHandle = (HINSTANCE) hModule;
00056   return TRUE;
00057 }
00058 
00059 
00060 // ******************************************************************
00061 // The event handling procedure of the invisible window created below. 
00062 
00063 long FAR PASCAL CSoundDriverCreateWindowProc(HWND hWnd, unsigned message, WPARAM wParam, LPARAM lParam)
00064 {
00065     return DefWindowProc(hWnd, message, wParam, lParam);
00066 }
00067 
00068 // ******************************************************************
00069 
00070 __declspec(dllexport) ISoundDriver *NLSOUND_createISoundDriverInstance()
00071 {
00072         static bool Registered = false;
00073 
00074         if (!Registered)
00075         {
00076                 // Don't ask me why we have to create a window to do sound!
00077                 // echo <your comment> | mail support@microsoft.com -s "F#%@cking window"
00078                 WNDCLASS myClass;
00079                 myClass.hCursor = LoadCursor( NULL, IDC_ARROW );
00080                 myClass.hIcon = NULL; 
00081                 myClass.lpszMenuName = (LPSTR) NULL;
00082                 myClass.lpszClassName = (LPSTR) "CSoundDriver";
00083                 myClass.hbrBackground = (HBRUSH)(COLOR_WINDOW);
00084                 myClass.hInstance = CSoundDriverDllHandle;
00085                 myClass.style = CS_GLOBALCLASS;
00086                 myClass.lpfnWndProc = CSoundDriverCreateWindowProc;
00087                 myClass.cbClsExtra = 0;
00088                 myClass.cbWndExtra = 0;
00089 
00090                 if (!RegisterClass(&myClass)) 
00091                 {
00092                         nlwarning("Failed to initialize the sound driver (RegisterClass)");
00093                         return 0;
00094                 }
00095 
00096                 Registered = true;
00097         }
00098 
00099         CSoundDriverWnd = CreateWindow((LPSTR) "CSoundDriver", (LPSTR) "CSoundDriver", WS_OVERLAPPEDWINDOW,
00100                                                                         CW_USEDEFAULT, CW_USEDEFAULT, 400, 300, (HWND) NULL, (HMENU) NULL, 
00101                                                                         CSoundDriverDllHandle, (LPSTR) NULL);  
00102 
00103         if (CSoundDriverWnd == NULL)
00104         {
00105                 nlwarning("Failed to initialize the sound driver (CreateWindow)");
00106                 return 0;
00107         }
00108         
00109         CSoundDriverDSound *driver = new CSoundDriverDSound();
00110         driver->init(CSoundDriverWnd);
00111 
00112         return driver;
00113 }
00114 
00115 // ******************************************************************
00116 
00117 __declspec(dllexport) uint32 NLSOUND_interfaceVersion()
00118 {
00119         return ISoundDriver::InterfaceVersion;
00120 }
00121 
00122 // ******************************************************************
00123 
00124 __declspec(dllexport) void NLSOUND_outputProfile(ostream &out)
00125 {
00126         CSoundDriverDSound::instance()->writeProfile(out);
00127 }
00128 
00129 
00130 
00131 
00132 
00133 // ******************************************************************
00134 
00135 CSoundDriverDSound::CSoundDriverDSound() : ISoundDriver()
00136 {
00137         if ( _Instance == NULL )
00138         {
00139                 _Instance = this;
00140 
00141         _DirectSound = NULL;
00142         _PrimaryBuffer = NULL;
00143         _SourceCount = 0;
00144         _TimerID = NULL;
00145 
00146 #if NLSOUND_PROFILE
00147         _TimerIntervalCount = 0;
00148         _TotalTime = 0.0;
00149         _TotalUpdateTime = 0.0;
00150                 _UpdateCount = 0;
00151                 _UpdateSources = 0;
00152                 _UpdateExec = 0;
00153 #endif
00154 
00155     }
00156         else
00157         {
00158                 nlerror("Sound driver singleton instanciated twice");
00159         }
00160 }
00161 
00162 // ******************************************************************
00163 
00164 CSoundDriverDSound::~CSoundDriverDSound()
00165 {
00166         nldebug("Destroying DirectSound driver");
00167 
00168     if (_TimerID != NULL)
00169     {
00170         timeKillEvent(_TimerID);
00171         timeEndPeriod(_TimerResolution); 
00172     }
00173 
00174 
00175         // Assure that the remaining sources have released all their DSBuffers 
00176         // before closing down DirectSound
00177         set<CSourceDSound*>::iterator iter;
00178 
00179         for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00180         {
00181                 (*iter)->release();
00182         }
00183 
00184 
00185         // Assure that the listener has released all resources before closing 
00186         // down DirectSound
00187         if (CListenerDSound::instance() != 0)
00188         {
00189                 CListenerDSound::instance()->release();
00190         }
00191 
00192 
00193     if (_PrimaryBuffer != NULL) 
00194     {
00195         _PrimaryBuffer->Release(); 
00196         _PrimaryBuffer = NULL;
00197     }
00198 
00199     if (_DirectSound != NULL) 
00200     {
00201         _DirectSound->Release(); 
00202         _DirectSound = NULL;
00203     }
00204 
00205         _Instance = 0;
00206 }
00207 
00208 // ******************************************************************
00209 
00210 class CDeviceDescription
00211 {
00212 public:
00213 
00214     static CDeviceDescription* _List;
00215 
00216     CDeviceDescription(LPGUID guid, const char* descr) 
00217     {
00218         _Guid = guid;
00219         _Description = strdup(descr);
00220         _Next = _List;
00221         _List = this;
00222     }
00223 
00224     virtual ~CDeviceDescription()
00225     {
00226         if (_Description) 
00227         {
00228             free(_Description);
00229         }
00230         if (_Next)
00231         {
00232             delete _Next;
00233         }
00234     }
00235 
00236     char* _Description;
00237     CDeviceDescription* _Next;
00238     LPGUID _Guid;
00239 };
00240 
00241 CDeviceDescription* CDeviceDescription::_List = 0;
00242 
00243 
00244 BOOL CALLBACK CSoundDriverDSoundEnumCallback(LPGUID guid, LPCSTR description, PCSTR module, LPVOID context)
00245 {
00246     new CDeviceDescription(guid, description);
00247     return TRUE;
00248 }
00249 
00250 // ******************************************************************
00251 
00252 bool CSoundDriverDSound::init(HWND wnd)
00253 {
00254     if (FAILED(DirectSoundEnumerate(CSoundDriverDSoundEnumCallback, this)))
00255     {
00256         throw ESoundDriver("Failed to enumerate the DirectSound devices");
00257     }
00258 
00259     // Create a DirectSound object and set the cooperative level.
00260 
00261     if (DirectSoundCreate(NULL, &_DirectSound, NULL) != DS_OK) 
00262     {
00263         throw ESoundDriver("Failed to create the DirectSound object");
00264     }
00265 
00266 
00267     if (_DirectSound->SetCooperativeLevel(wnd, DSSCL_PRIORITY) != DS_OK) 
00268     {
00269         throw ESoundDriver("Failed to set the cooperative level");
00270     }
00271 
00272 
00273     // Analyse the capabilities of the sound driver/device
00274 
00275     _Caps.dwSize = sizeof(_Caps); 
00276 
00277     if (_DirectSound->GetCaps(&_Caps) != DS_OK)  
00278     {
00279         throw ESoundDriver("Failed to query the sound device caps");
00280     }
00281 
00282 
00283     // Create primary buffer 
00284  
00285     DSBUFFERDESC desc;
00286 
00287     ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00288     desc.dwSize = sizeof(DSBUFFERDESC);
00289 
00290 
00291     // First, try to allocate a 3D hardware buffer.
00292     // If we can't get a 3D hardware buffer, use a 2D hardware buffer.
00293     // As last option, use a 2D software buffer.
00294 
00295     if (countHw3DBuffers() > 0) 
00296     {
00297                 nldebug("Primary buffer: Allocating 3D buffer in hardware");
00298         desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
00299     } 
00300     else
00301     {
00302                 nldebug("Primary buffer: Allocating 3D buffer in software");
00303         desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRL3D | DSBCAPS_CTRLVOLUME;
00304         desc.guid3DAlgorithm = DS3DALG_NO_VIRTUALIZATION;
00305     }
00306 
00307 
00308     if (_DirectSound->CreateSoundBuffer(&desc, &_PrimaryBuffer, NULL) != DS_OK) 
00309     {
00310 
00311                 nlwarning("Primary buffer: Failed to create a buffer with 3D capabilities.");
00312 
00313                 ZeroMemory(&desc, sizeof(DSBUFFERDESC));
00314                 desc.dwSize = sizeof(DSBUFFERDESC);
00315 
00316                 if (countHw2DBuffers() > 0) 
00317                 {
00318                         nldebug("Primary buffer: Allocating 2D buffer in hardware");
00319                         desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCHARDWARE | DSBCAPS_CTRLVOLUME;
00320                 } 
00321                 else
00322                 {
00323                         nldebug("Primary buffer: Allocating 2D buffer in software");
00324                         desc.dwFlags = DSBCAPS_PRIMARYBUFFER | DSBCAPS_LOCSOFTWARE | DSBCAPS_CTRLVOLUME;
00325                 }
00326 
00327                 if (_DirectSound->CreateSoundBuffer(&desc, &_PrimaryBuffer, NULL) != DS_OK) 
00328                 {
00329                         throw ESoundDriver("Failed to create the primary buffer");
00330                 }
00331     }
00332 
00333 
00334     // Set the format of the primary buffer
00335 
00336     WAVEFORMATEX format;
00337 
00338     format.cbSize = sizeof(WAVEFORMATEX);
00339 
00340     // Make sure the sound card accepts the default settings.
00341     // For now, only the default settings are accepted. Fallback
00342     // strategy will be handled later.
00343 
00344     if ((_Caps.dwMinSecondarySampleRate > 22050) && (22050 > _Caps.dwMaxSecondarySampleRate)) {
00345         throw ESoundDriver("Unsupported sample rate range");        
00346     }   
00347 
00348     if ((_Caps.dwFlags & DSCAPS_PRIMARY16BIT) == 0) {
00349         throw ESoundDriver("Unsupported sample size [16bits]");        
00350     }   
00351 
00352     format.wBitsPerSample = 16;
00353     format.nChannels = 1;
00354     format.nSamplesPerSec = 22050;
00355     format.nBlockAlign = format.nChannels * format.wBitsPerSample / 8;
00356     format.nAvgBytesPerSec = format.nSamplesPerSec * format.nBlockAlign;
00357     format.wFormatTag = WAVE_FORMAT_PCM;
00358 
00359 
00360     if (_PrimaryBuffer->SetFormat(&format) != DS_OK) 
00361     {
00362         throw ESoundDriver("Failed to create set the format of the primary buffer");
00363     }
00364 
00365 
00366     uint32 numBuffers = countHw3DBuffers();
00367         if (numBuffers == 0)
00368         {
00369                 numBuffers = 31;
00370         }
00371 
00372         /*
00373     _Sources = new CSourceDSound*[numBuffers];
00374 
00375 
00376         for (uint i = 0; i < numBuffers; i++) 
00377         {
00378                 _Sources[i] = 0;
00379         }
00380 
00381         try
00382         {
00383             for (i = 0; i < numBuffers; i++) 
00384                 {
00385                         _Sources[i] = new CSourceDSound(i);
00386                         _Sources[i]->init(_DirectSound);
00387                         _SourceCount++;
00388                 }
00389         }
00390         catch (ESoundDriver& e)
00391         {
00392                 // Okay, here's the situation: I'm listening to WinAmp while debugging.
00393                 // The caps told me there were 31 buffers available. In reality, there were
00394                 // only 30 available because WinAmp was using one. Somehow DirectSound didn't
00395                 // notice. So when creating buffer 31, an exception was thrown. 
00396                 // If something like this happens, don't bother and go on with the buffers we've 
00397                 // got. If no buffers are created at all, throw the exception again.
00398 
00399                 if (_Sources == 0)
00400                 {
00401                         throw e;
00402                 }
00403         }
00404 
00405 */
00406 
00407 
00408     TIMECAPS tcaps;
00409     
00410     timeGetDevCaps(&tcaps, sizeof(TIMECAPS));
00411     _TimerResolution = (tcaps.wPeriodMin > 10)? tcaps.wPeriodMin : 10;
00412     timeBeginPeriod(_TimerResolution); 
00413 
00414 
00415 
00416 #if NLSOUND_PROFILE
00417     for (uint i = 0; i < 1024; i++)
00418     {
00419         _TimerInterval[i] = 0;
00420     }
00421 
00422     _TimerDate = CTime::getPerformanceTime();
00423 #endif
00424 
00425 
00426 
00427 
00428     _TimerID = timeSetEvent(_TimerPeriod, 0, &CSoundDriverDSound::TimerCallback, (DWORD)this, TIME_CALLBACK_FUNCTION | TIME_PERIODIC);
00429 
00430     if (_TimerID == NULL)
00431     {
00432         throw ESoundDriver("Failed to create the timer");
00433     }
00434 
00435         
00436 
00437 
00438     return true;
00439 }
00440 
00441 // ******************************************************************
00442 
00443 uint CSoundDriverDSound::countMaxSources()
00444 {
00445         // Try the hardware 3d buffers first
00446         uint n = countHw3DBuffers();
00447         if (n > 0) 
00448         {
00449                 return n;
00450         }
00451 
00452         // If not, try the hardware 2d buffers first
00453         n = countHw2DBuffers();
00454         if (n > 0)
00455         {
00456                 return n;
00457         }
00458 
00459         // Okay, we'll use 32 software buffers
00460         return 32;
00461 }
00462 
00463 // ******************************************************************
00464 
00465 void CSoundDriverDSound::writeProfile(ostream& out)
00466 {
00467     // Write the available sound devices
00468     CDeviceDescription* list = CDeviceDescription::_List;
00469     while (list) {
00470                 out << list->_Description << "\n";
00471         list = list->_Next;
00472     }
00473 
00474     out << "\n";
00475 
00476     // Write the buffers sizes
00477     out << "buffer size: " << CSourceDSound::_SecondaryBufferSize << "\n";
00478     out << "copy size: " << CSourceDSound::_UpdateCopySize << "\n";
00479     out << "swap size: " << CSourceDSound::_SwapCopySize << "\n";
00480     out << "\n";
00481 
00482     // Write the number of hardware buffers 
00483     DSCAPS caps;
00484     caps.dwSize = sizeof(caps); 
00485     _DirectSound->GetCaps(&caps);  
00486 
00487     cout << "3d hw buffers: " << caps.dwMaxHw3DAllBuffers << "\n";
00488         cout << "2d hw buffers: " << caps.dwMaxHwMixingAllBuffers << "\n";
00489     out << "\n";
00490 
00491     // Write the number of hardware buffers 
00492 #if NLSOUND_PROFILE
00493     out << "update time total --- " <<  getAverageUpdateTime()<< "\n";
00494         out << "update time source --- " << CSourceDSound::getAverageUpdateTime() << "\n";
00495         out << "update --- t: " << CSourceDSound::getAverageCumulTime();
00496         out << " - p: " << CSourceDSound::getAveragePosTime();
00497         out << " - l: " << CSourceDSound::getAverageLockTime();
00498         out << " - c: " << CSourceDSound::getAverageCopyTime();
00499         out << " - u: " << CSourceDSound::getAverageUnlockTime() << "\n";
00500         out << "update percentage: --- " << getUpdatePercentage() << "\n";
00501         out << "update num sources --- " << getAverageUpdateSources() << "\n";
00502         out << "update byte size --- " << CSourceDSound::getAverageUpdateSize() << "\n";
00503         out << "swap time --- " << CSourceDSound::getTestAverage() << "\n";
00504         out << "src --- " << countPlayingSources() << "\n";
00505 #endif
00506 }
00507 
00508 
00509 void CALLBACK CSoundDriverDSound::TimerCallback(UINT uID, UINT uMsg, DWORD dwUser, DWORD dw1, DWORD dw2)
00510 {
00511     CSoundDriverDSound* driver = (CSoundDriverDSound*) dwUser;
00512     driver->update();
00513 }
00514 
00515 // ******************************************************************
00516 
00517 void CSoundDriverDSound::update()
00518 {
00519 #if NLSOUND_PROFILE
00520     TTicks now = CTime::getPerformanceTime();
00521 #endif
00522 
00523         set<CSourceDSound*>::iterator iter;
00524 
00525         iter = _Sources.begin();
00526 
00527         if ((iter != _Sources.end()) && (*iter)->needsUpdate())
00528         {
00529                 while (iter != _Sources.end())
00530                 {
00531                         if ((*iter)->update2()) {
00532 #if NLSOUND_PROFILE
00533                                 _UpdateSources++;
00534 #endif
00535                         }
00536                         iter++;
00537                 }
00538         }
00539 
00540 
00541 #if NLSOUND_PROFILE
00542     _TotalUpdateTime += 1000.0 * CTime::ticksToSecond(CTime::getPerformanceTime() - now);
00543         _UpdateCount++;
00544 #endif
00545 }
00546 
00547 // ******************************************************************
00548 
00549 uint CSoundDriverDSound::countHw3DBuffers()
00550 {
00551     DSCAPS caps;
00552     caps.dwSize = sizeof(caps); 
00553 
00554     if (_DirectSound->GetCaps(&caps) != DS_OK)  
00555     {
00556         throw ESoundDriver("Failed to query the sound device caps");
00557     }
00558 
00559     return caps.dwFreeHw3DStreamingBuffers;
00560 }
00561 
00562 // ******************************************************************
00563 
00564 uint CSoundDriverDSound::countHw2DBuffers()
00565 {
00566     DSCAPS caps;
00567     caps.dwSize = sizeof(caps); 
00568 
00569     if (_DirectSound->GetCaps(&caps) != DS_OK)  
00570     {
00571         throw ESoundDriver("Failed to query the sound device caps");
00572     }
00573 
00574     return caps.dwFreeHwMixingStreamingBuffers;
00575 }
00576 
00577 // ******************************************************************
00578 
00579 IListener *CSoundDriverDSound::createListener()
00580 {
00581     LPDIRECTSOUND3DLISTENER dsoundListener;
00582 
00583     if (CListenerDSound::instance() != NULL) 
00584     {
00585         return CListenerDSound::instance();
00586     }
00587 
00588     if (_PrimaryBuffer == 0) 
00589     {
00590         throw ESoundDriver("Corrupt driver");
00591     }
00592 
00593     if (FAILED(_PrimaryBuffer->QueryInterface(IID_IDirectSound3DListener, (LPVOID *) &dsoundListener)))
00594     {
00595                 nlwarning("The 3D listener interface is not available.");
00596         return new CListenerDSound(NULL);
00597     }
00598 
00599     return new CListenerDSound(dsoundListener);
00600 }
00601 
00602 // ******************************************************************
00603 
00604 IBuffer *CSoundDriverDSound::createBuffer()
00605 {
00606     if (_PrimaryBuffer == 0) 
00607     {
00608         throw ESoundDriver("Corrupt driver");
00609     }
00610 
00611 
00612     // FIXME: set buffer ID
00613     return new CBufferDSound();   
00614 }
00615 
00616 // ******************************************************************
00617 
00618 void CSoundDriverDSound::removeBuffer(IBuffer *buffer)
00619 {
00620 }
00621 
00622 // ******************************************************************
00623 
00624 bool CSoundDriverDSound::loadWavFile(IBuffer *destbuffer, const char *filename)
00625 {
00626         return ((CBufferDSound*) destbuffer)->loadWavFile(filename);
00627 }
00628 
00629 // ******************************************************************
00630 
00631 ISource *CSoundDriverDSound::createSource()
00632 {
00633     if (_PrimaryBuffer == 0) 
00634     {
00635         throw ESoundDriver("Corrupt driver");
00636     }
00637 
00638 
00639         CSourceDSound* src = new CSourceDSound(0);
00640         src->init(_DirectSound);
00641         _Sources.insert(src);
00642 
00643         return src;
00644 }
00645 
00646 
00647 // ******************************************************************
00648 
00649 void CSoundDriverDSound::removeSource(ISource *source)
00650 {
00651         _Sources.erase((CSourceDSound*) source);
00652 }
00653 
00654 // ******************************************************************
00655 
00656 void CSoundDriverDSound::commit3DChanges()
00657 {
00658         CListenerDSound* listener = CListenerDSound::instance();
00659         listener->commit3DChanges();
00660 
00661 
00662         const CVector &origin = listener->getPos();
00663 
00664         set<CSourceDSound*>::iterator iter;
00665 
00666         // We handle the volume of the source according to the distance
00667         // ourselves. Call updateVolume() to, well..., update the volume
00668         // according to, euh ..., the new distance!
00669         for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00670         {
00671                 if ((*iter)->isPlaying()) 
00672                 {
00673                         (*iter)->updateVolume(origin);
00674                 }
00675         }
00676 }
00677 
00678 
00679 // ******************************************************************
00680 
00681 uint CSoundDriverDSound::countPlayingSources()
00682 {
00683     uint n = 0;
00684         set<CSourceDSound*>::iterator iter;
00685 
00686         for (iter = _Sources.begin(); iter != _Sources.end(); iter++)
00687         {
00688                 if ((*iter)->isPlaying()) 
00689                 {
00690                         n++;
00691                 }
00692         }
00693 
00694     return n;
00695 }
00696 
00697 
00698 // ******************************************************************
00699 
00700 void CSoundDriverDSound::setGain( float gain )
00701 {
00702         if (_PrimaryBuffer != 0)
00703         {
00704                 if (gain < 0.00001f)
00705                 {
00706                         gain = 0.00001f;
00707                 }
00708 
00709                 /* convert from linear amplitude to hundredths of decibels */
00710                 LONG volume = (LONG)(100.0 * 20.0 * log10(gain));
00711 
00712                 if (volume < DSBVOLUME_MIN) 
00713                 {
00714                         volume = DSBVOLUME_MIN;
00715                 }
00716                 else if (volume > DSBVOLUME_MAX) 
00717                 {
00718                         volume = DSBVOLUME_MAX;
00719                 }
00720 
00721                 HRESULT hr = _PrimaryBuffer->SetVolume(volume);
00722 
00723                 if (hr != DS_OK)
00724                 {
00725                         nldebug("Failed to set the volume");
00726                 }
00727         }
00728 }
00729 
00730 // ******************************************************************
00731 
00732 float CSoundDriverDSound::getGain()
00733 {
00734         if (_PrimaryBuffer != 0)
00735         {
00736                 /* convert from hundredths of decibels to linear amplitude */
00737                 LONG volume;
00738                 HRESULT hr = _PrimaryBuffer->GetVolume(&volume);
00739 
00740                 if (hr != DS_OK)
00741                 {
00742                         nldebug("Failed to get the volume");
00743                         return 1.0;
00744                 }
00745 
00746                 return (float) pow(10, (double) volume / 20.0 / 100.0);
00747         }
00748 
00749         return 1.0;
00750 }
00751 
00752 
00753 
00754 #if NLSOUND_PROFILE
00755 
00756 // ******************************************************************
00757 
00758 uint CSoundDriverDSound::countTimerIntervals()
00759 {
00760     return 1024;
00761 }
00762 
00763 // ******************************************************************
00764 
00765 uint CSoundDriverDSound::getTimerIntervals(uint index)
00766 {           
00767     return _TimerInterval[index];
00768 }
00769 
00770 // ******************************************************************
00771 
00772 void CSoundDriverDSound::addTimerInterval(uint32 dt) 
00773 {
00774     if (_TimerIntervalCount >= 1024)
00775     {
00776         _TimerIntervalCount = 0;
00777     }
00778 
00779     _TimerInterval[_TimerIntervalCount++] = dt;
00780 }
00781 
00782 // ******************************************************************
00783 
00784 double CSoundDriverDSound::getCPULoad()
00785 {
00786     return (_TotalTime > 0.0)? 100.0 * _TotalUpdateTime / _TotalTime : 0.0;  
00787 }
00788 
00789 // ******************************************************************
00790 
00791 void CSoundDriverDSound::printDriverInfo(FILE* fp)
00792 {
00793     CDeviceDescription* list = CDeviceDescription::_List;
00794 
00795     while (list) {
00796         fprintf(fp, "%s\n", list->_Description);
00797         list = list->_Next;
00798     }
00799 
00800     fprintf(fp, "\n");
00801 
00802     fprintf(fp, "buffer size: %d\n"
00803                                 "copy size: %d\n"
00804                                 "swap size: %d\n", 
00805                         CSourceDSound::_SecondaryBufferSize,
00806                         CSourceDSound::_UpdateCopySize,
00807                         CSourceDSound::_SwapCopySize);
00808 
00809     fprintf(fp, "\n");
00810 
00811     DSCAPS caps;
00812     caps.dwSize = sizeof(caps); 
00813 
00814     if (_DirectSound->GetCaps(&caps) != DS_OK)  
00815     {
00816         throw ESoundDriver("Failed to query the sound device caps");
00817     }
00818 
00819     
00820     fprintf(fp, "3d hw buffers: %d\n" "2d hw buffers: %d\n\n", caps.dwMaxHw3DAllBuffers, caps.dwMaxHwMixingAllBuffers);
00821 }
00822 
00823 #endif
00824 
00825 
00826 } // NLSOUND