NLS Engine  v0.1
The Next Logical Step in game engine design.
 All Classes Namespaces Files Functions Variables Enumerations Enumerator Defines
SoundModule.cpp
Go to the documentation of this file.
00001 
00011 #pragma once
00012 
00013 #include "SoundModule.h"
00014 
00015 // System Library Includes
00016 #include <cassert>
00017 #include <set>
00018 #include <string>
00019 
00020 // Application Library Includes
00021 #include <d3d9.h>
00022 #include <boost/foreach.hpp>
00023 
00024 // Local Includes
00025 #include "../sharedbase/MessageRouter.h"
00026 #include "../sharedbase/PropertyMap.h"
00027 #include "../sharedbase/Envelope.h"
00028 
00029 #include "Messages.h"
00030 
00031 // Prototypes
00032 namespace Sound {
00033   void WINAPI XACTNotificationCallback(const XACT_NOTIFICATION*);
00034 }
00035 
00036 // Static data
00037 namespace Sound {
00038   SoundModule* SoundModule::moduleInstance;
00039 }
00040 
00041 // Helpers
00042 namespace Sound {
00043   // Taken from a comment on: http://notfaq.wordpress.com/2006/08/30/c-convert-int-to-string/
00044   template <class T>
00045   inline std::string to_string (const T& t) {
00046     std::stringstream ss;
00047     ss << t;
00048     return ss.str();
00049   }
00050 
00051   template <class T>
00052   inline std::string to_hex (const T& t) {
00053     std::stringstream ss;
00054     ss << std::hex << t;
00055     return ss.str();
00056   }
00057 }
00058 
00059 // Class Methods
00060 namespace Sound {
00061   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00062   SoundModule::SoundModule(PropertyMap* gprops, MessageRouter* msgrouter, EntityList* elist) :
00063     ModuleInterface(gprops, msgrouter, elist),
00064     // Initialize member data
00065     deltaAccumulator(0.0f),
00066     updateDelay(1.0f / 30.0f), // 30 FPS
00067     engine(nullptr),
00068     engineInitialized(false)
00069   {
00070     // Verify status as an instantiable Singleton.
00071     assert(SoundModule::moduleInstance == NULL);
00072     SoundModule::moduleInstance = this;
00073     
00074     /* * * * * * * * * * * * * * * * * * * * * */
00075     // Register the message handlers
00076     /* * * * * * * * * * * * * * * * * * * * * */
00077     this->RegisterMessageHandlers();
00078     
00079     {
00080       HRESULT hr;
00081       DWORD dwCreationFlags = 0;
00082       
00083       CoInitializeEx(NULL, COINIT_MULTITHREADED);
00084       
00085       std::string errStr;
00086       
00087 #ifdef _DEBUG
00088       dwCreationFlags |= XACT_FLAG_API_DEBUG_MODE;
00089 #endif
00090       
00091       {
00092         Threading::WriteLock w_lock(this->engineMutex);
00093         hr = XACT3CreateEngine( dwCreationFlags, &this->engine );
00094       }
00095       if (SUCCEEDED(hr)) {
00096         assert(this->engine != nullptr);
00097       }
00098       else {
00099         errStr = "Audio failed to initialize. Error code: 0x" + to_hex<HRESULT>(hr);
00100         
00101         this->engine = nullptr;
00102       }
00103       
00104       if (errStr.length() > 0) {
00105         LOG(LOG_PRIORITY::ERR, errStr);
00106         MessageBox(NULL, (LPCTSTR)errStr.c_str(), TEXT("Audio Error"), MB_OK); 
00107       }
00108     }
00109     
00110     /* * * * * * * * * * * * * * * * * * * * * */
00111     // Notify loading success
00112     /* * * * * * * * * * * * * * * * * * * * * */
00113     {
00114       EnvelopeSPTR e(new Envelope);
00115       e->msgid = ACK_MODULE_LOADED;
00116       this->msgrouter->SendSP(e);
00117     }
00118   }
00119   
00120   SoundModule::~SoundModule(void) {
00121     this->engineInitialized = false;
00122     
00123     {// Release the sound banks
00124       Threading::WriteLock w_lock(this->soundBanksMutex);
00125       
00126       BOOST_FOREACH(soundbank_pair soundBankPair, this->soundBanks) {
00127         IXACT3SoundBank* bank = soundBankPair.second;
00128         Threading::ReadLock r_lock(this->engineMutex);
00129         bank->Destroy();
00130       }
00131       this->soundBanks.clear();
00132     }
00133     
00134     {// Release the wave banks
00135       Threading::WriteLock w_lock(this->waveBanksMutex);
00136       
00137       BOOST_FOREACH(wavebank_pair waveBankPair, this->waveBanks) {
00138         IXACT3WaveBank* bank = waveBankPair.second;
00139         Threading::ReadLock r_lock(this->engineMutex);
00140         bank->Destroy();
00141       }
00142       this->waveBanks.clear();
00143     }
00144     
00145     // Shut down XACT
00146     if (this->engine != nullptr) {
00147       Threading::WriteLock w_lock(this->engineMutex);
00148       this->engine->ShutDown();
00149       this->engine->Release();
00150       this->engine = nullptr;
00151     }
00152     
00153     CoUninitialize();
00154   }
00155   
00156   /* * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * * */
00157   void SoundModule::Update(double dt) {
00158     this->deltaAccumulator += dt;
00159     
00160     if (this->deltaAccumulator >= this->updateDelay) {
00161       
00162       // It is important to allow XACT to do periodic work by calling engine->DoWork().
00163       // However this must function be call often enough.  If you call it too infrequently,
00164       // streaming will suffer and resources will not be managed promptly.  On the other hand
00165       // if you call it too frequently, it will negatively affect performance. Calling it once
00166       // per frame is usually a good balance.
00167       //-----------------------------------------------------------------------------------------
00168       if (this->engine != nullptr && this->engineInitialized) {
00169         Threading::ReadLock r_lock(this->engineMutex);
00170         this->engine->DoWork();
00171       }
00172       
00173       // Zero the accumulator
00174       this->deltaAccumulator = 0.0;
00175     }
00176   }
00177 }