DSoundManager.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535
  1. #pragma warning(disable:4996)
  2. #include "DSoundManager.h"
  3. #include <io.h>
  4. #include <fcntl.h>
  5. #include "DSoundInstance.h"
  6. #include <math.h>
  7. using namespace Beefy;
  8. static HMODULE gDSoundDLL;
  9. #pragma comment(lib, "dsound.lib")
  10. #define SOUND_FLAGS (DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_STATIC | DSBCAPS_LOCSOFTWARE | DSBCAPS_GLOBALFOCUS | DSBCAPS_CTRLFREQUENCY)
  11. DSoundManager::DSoundManager(HWND theHWnd)
  12. {
  13. mLastReleaseTick = 0;
  14. mPrimaryBuffer = NULL;
  15. int i;
  16. for (i = 0; i < MAX_SOURCE_SOUNDS; i++)
  17. {
  18. mSourceSounds[i] = NULL;
  19. mBaseVolumes[i] = 1;
  20. mBasePans[i] = 0;
  21. }
  22. for (i = 0; i < MAX_CHANNELS; i++)
  23. mPlayingSounds[i] = NULL;
  24. mDirectSound = NULL;
  25. mMasterVolume = 1.0;
  26. //typedef HRESULT (WINAPI *DirectSoundCreateFunc)(LPCGUID lpcGuid, LPDIRECTSOUND * ppDS, LPUNKNOWN pUnkOuter);
  27. //DirectSoundCreateFunc aDirectSoundCreateFunc = (DirectSoundCreateFunc)GetProcAddress(gDSoundDLL,"DirectSoundCreate");
  28. // Seems crazy but this was even suggested in MSDN docs for windowless applications
  29. if (theHWnd == NULL)
  30. theHWnd = ::GetDesktopWindow();
  31. //if (aDirectSoundCreateFunc != NULL && aDirectSoundCreateFunc(NULL, &mDirectSound, NULL) == DS_OK)
  32. if (DirectSoundCreate(NULL, &mDirectSound, NULL) == DS_OK)
  33. {
  34. bool handled = false;
  35. if (theHWnd != NULL)
  36. {
  37. HRESULT aResult = mDirectSound->SetCooperativeLevel(theHWnd, DSSCL_PRIORITY);
  38. if (SUCCEEDED(aResult))
  39. {
  40. // Set primary buffer to 16-bit 44.1Khz
  41. WAVEFORMATEX aWaveFormat;
  42. DSBUFFERDESC aBufferDesc;
  43. // Set up wave format structure.
  44. int aBitCount = 16;
  45. int aChannelCount = 2;
  46. int aSampleRate = 44100;
  47. // Set up wave format structure.
  48. memset(&aWaveFormat, 0, sizeof(WAVEFORMATEX));
  49. aWaveFormat.cbSize = sizeof(WAVEFORMATEX);
  50. aWaveFormat.wFormatTag = WAVE_FORMAT_PCM;
  51. aWaveFormat.nChannels = aChannelCount;
  52. aWaveFormat.nSamplesPerSec = aSampleRate;
  53. aWaveFormat.nBlockAlign = aChannelCount * aBitCount / 8;
  54. aWaveFormat.nAvgBytesPerSec =
  55. aWaveFormat.nSamplesPerSec * aWaveFormat.nBlockAlign;
  56. aWaveFormat.wBitsPerSample = aBitCount;
  57. // Set up DSBUFFERDESC structure.
  58. memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
  59. aBufferDesc.dwSize = sizeof(DSBUFFERDESC1);
  60. aBufferDesc.dwFlags = DSBCAPS_PRIMARYBUFFER;//| DSBCAPS_CTRL3D; // Need default controls (pan, volume, frequency).
  61. aBufferDesc.dwBufferBytes = 0;
  62. aBufferDesc.lpwfxFormat = NULL;//(LPWAVEFORMATEX)&aWaveFormat;
  63. HRESULT aResult = mDirectSound->CreateSoundBuffer(&aBufferDesc, &mPrimaryBuffer, NULL);
  64. if (aResult == DS_OK)
  65. {
  66. aResult = mPrimaryBuffer->SetFormat(&aWaveFormat);
  67. }
  68. handled = true;
  69. }
  70. }
  71. if (!handled)
  72. {
  73. HRESULT aResult = mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
  74. }
  75. }
  76. }
  77. DSoundManager::~DSoundManager()
  78. {
  79. ReleaseChannels();
  80. ReleaseSounds();
  81. if (mPrimaryBuffer)
  82. mPrimaryBuffer->Release();
  83. if (mDirectSound != NULL)
  84. {
  85. mDirectSound->Release();
  86. }
  87. }
  88. int DSoundManager::FindFreeChannel()
  89. {
  90. DWORD aTick = GetTickCount();
  91. if (aTick-mLastReleaseTick > 1000)
  92. {
  93. ReleaseFreeChannels();
  94. mLastReleaseTick = aTick;
  95. }
  96. for (int i = 0; i < MAX_CHANNELS; i++)
  97. {
  98. if (mPlayingSounds[i] == NULL)
  99. return i;
  100. if (mPlayingSounds[i]->IsReleased())
  101. {
  102. delete mPlayingSounds[i];
  103. mPlayingSounds[i] = NULL;
  104. return i;
  105. }
  106. }
  107. return -1;
  108. }
  109. bool DSoundManager::Initialized()
  110. {
  111. /*
  112. if (mDirectSound!=NULL)
  113. {
  114. mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
  115. }
  116. */
  117. return (mDirectSound != NULL);
  118. }
  119. int DSoundManager::VolumeToDB(float theVolume)
  120. {
  121. int aVol = (int) ((log10(1 + theVolume*9) - 1.0) * 2333);
  122. if (aVol < -2000)
  123. aVol = -10000;
  124. return aVol;
  125. }
  126. void DSoundManager::SetVolume(float theVolume)
  127. {
  128. mMasterVolume = theVolume;
  129. for (int i = 0; i < MAX_CHANNELS; i++)
  130. if (mPlayingSounds[i] != NULL)
  131. mPlayingSounds[i]->RehupVolume();
  132. }
  133. bool DSoundManager::LoadWAVSound(unsigned int theSfxID, const StringImpl& theFilename)
  134. {
  135. int aDataSize;
  136. FILE* fp;
  137. fp = fopen(theFilename.c_str(), "rb");
  138. if (fp <= 0)
  139. return false;
  140. char aChunkType[5];
  141. aChunkType[4] = '\0';
  142. uint32 aChunkSize;
  143. fread(aChunkType, 1, 4, fp);
  144. if (!strcmp(aChunkType, "RIFF") == 0)
  145. return false;
  146. fread(&aChunkSize, 4, 1, fp);
  147. fread(aChunkType, 1, 4, fp);
  148. if (!strcmp(aChunkType, "WAVE") == 0)
  149. return false;
  150. uint16 aBitCount = 16;
  151. uint16 aChannelCount = 1;
  152. uint32 aSampleRate = 22050;
  153. uint8 anXor = 0;
  154. while (!feof(fp))
  155. {
  156. fread(aChunkType, 1, 4, fp);
  157. if (fread(&aChunkSize, 4, 1, fp) == 0)
  158. return false;
  159. int aCurPos = ftell(fp);
  160. if (strcmp(aChunkType, "fmt ") == 0)
  161. {
  162. uint16 aFormatTag;
  163. uint32 aBytesPerSec;
  164. uint16 aBlockAlign;
  165. fread(&aFormatTag, 2, 1, fp);
  166. fread(&aChannelCount, 2, 1, fp);
  167. fread(&aSampleRate, 4, 1, fp);
  168. fread(&aBytesPerSec, 4, 1, fp);
  169. fread(&aBlockAlign, 2, 1, fp);
  170. fread(&aBitCount, 2, 1, fp);
  171. if (aFormatTag != 1)
  172. return false;
  173. }
  174. else if (strcmp(aChunkType, "data") == 0)
  175. {
  176. aDataSize = aChunkSize;
  177. mSourceDataSizes[theSfxID] = aChunkSize;
  178. PCMWAVEFORMAT aWaveFormat;
  179. DSBUFFERDESC aBufferDesc;
  180. // Set up wave format structure.
  181. memset(&aWaveFormat, 0, sizeof(PCMWAVEFORMAT));
  182. aWaveFormat.wf.wFormatTag = WAVE_FORMAT_PCM;
  183. aWaveFormat.wf.nChannels = aChannelCount;
  184. aWaveFormat.wf.nSamplesPerSec = aSampleRate;
  185. aWaveFormat.wf.nBlockAlign = aChannelCount*aBitCount/8;
  186. aWaveFormat.wf.nAvgBytesPerSec =
  187. aWaveFormat.wf.nSamplesPerSec * aWaveFormat.wf.nBlockAlign;
  188. aWaveFormat.wBitsPerSample = aBitCount;
  189. // Set up DSBUFFERDESC structure.
  190. memset(&aBufferDesc, 0, sizeof(DSBUFFERDESC)); // Zero it out.
  191. aBufferDesc.dwSize = sizeof(DSBUFFERDESC);
  192. //aBufferDesc.dwFlags = DSBCAPS_CTRL3D;
  193. aBufferDesc.dwFlags = SOUND_FLAGS; //DSBCAPS_CTRLDEFAULT;
  194. //aBufferDesc.dwFlags = 0;
  195. aBufferDesc.dwBufferBytes = aDataSize;
  196. aBufferDesc.lpwfxFormat = (LPWAVEFORMATEX)&aWaveFormat;
  197. if (mDirectSound->CreateSoundBuffer(&aBufferDesc, &mSourceSounds[theSfxID], NULL) != DS_OK)
  198. {
  199. fclose(fp);
  200. return false;
  201. }
  202. void* lpvPtr;
  203. DWORD dwBytes;
  204. if (mSourceSounds[theSfxID]->Lock(0, aDataSize, &lpvPtr, &dwBytes, NULL, NULL, 0) != DS_OK)
  205. {
  206. fclose(fp);
  207. return false;
  208. }
  209. int aReadSize = (int)fread(lpvPtr, 1, aDataSize, fp);
  210. fclose(fp);
  211. for (int i = 0; i < aDataSize; i++)
  212. ((uint8*) lpvPtr)[i] ^= anXor;
  213. if (mSourceSounds[theSfxID]->Unlock(lpvPtr, dwBytes, NULL, NULL) != DS_OK)
  214. return false;
  215. if (aReadSize != aDataSize)
  216. return false;
  217. return true;
  218. }
  219. fseek(fp, aCurPos+aChunkSize, SEEK_SET);
  220. }
  221. return false;
  222. }
  223. bool DSoundManager::LoadSound(unsigned int theSfxID, const StringImpl& theFilename)
  224. {
  225. if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
  226. return false;
  227. ReleaseSound(theSfxID);
  228. if (!mDirectSound)
  229. return true; // sounds just won't play, but this is not treated as a failure condition
  230. mSourceFileNames[theSfxID] = theFilename;
  231. StringImpl aFilename = theFilename;
  232. if (aFilename.EndsWith(".wav", StringImpl::CompareKind_OrdinalIgnoreCase))
  233. {
  234. if (LoadWAVSound(theSfxID, aFilename))
  235. return true;
  236. }
  237. return false;
  238. }
  239. int DSoundManager::LoadSound(const StringImpl& theFilename)
  240. {
  241. int i;
  242. for (i = 0; i < MAX_SOURCE_SOUNDS; i++)
  243. if (mSourceFileNames[i] == theFilename)
  244. return i;
  245. for (i = MAX_SOURCE_SOUNDS-1; i >= 0; i--)
  246. {
  247. if (mSourceSounds[i] == NULL)
  248. {
  249. if (!LoadSound(i, theFilename))
  250. return -1;
  251. else
  252. return i;
  253. }
  254. }
  255. return -1;
  256. }
  257. void DSoundManager::ReleaseSound(unsigned int theSfxID)
  258. {
  259. if (mSourceSounds[theSfxID] != NULL)
  260. {
  261. mSourceSounds[theSfxID]->Release();
  262. mSourceSounds[theSfxID] = NULL;
  263. mSourceFileNames[theSfxID] = "";
  264. }
  265. }
  266. int DSoundManager::GetFreeSoundId()
  267. {
  268. for (int i=0; i<MAX_SOURCE_SOUNDS; i++)
  269. {
  270. if (mSourceSounds[i]==NULL)
  271. return i;
  272. }
  273. return -1;
  274. }
  275. int DSoundManager::GetNumSounds()
  276. {
  277. int aCount = 0;
  278. for (int i=0; i<MAX_SOURCE_SOUNDS; i++)
  279. {
  280. if (mSourceSounds[i]!=NULL)
  281. aCount++;
  282. }
  283. return aCount;
  284. }
  285. bool DSoundManager::SetBaseVolume(unsigned int theSfxID, float theBaseVolume)
  286. {
  287. if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
  288. return false;
  289. mBaseVolumes[theSfxID] = theBaseVolume;
  290. return true;
  291. }
  292. bool DSoundManager::SetBasePan(unsigned int theSfxID, int theBasePan)
  293. {
  294. if ((theSfxID < 0) || (theSfxID >= MAX_SOURCE_SOUNDS))
  295. return false;
  296. mBasePans[theSfxID] = theBasePan;
  297. return true;
  298. }
  299. BFSoundInstance* DSoundManager::GetSoundInstance(unsigned int theSfxID)
  300. {
  301. if (theSfxID > MAX_SOURCE_SOUNDS)
  302. return NULL;
  303. int aFreeChannel = FindFreeChannel();
  304. if (aFreeChannel < 0)
  305. return NULL;
  306. if (mDirectSound==NULL)
  307. {
  308. mPlayingSounds[aFreeChannel] = new DSoundInstance(this, NULL);
  309. }
  310. else
  311. {
  312. if (mSourceSounds[theSfxID] == NULL)
  313. return NULL;
  314. mPlayingSounds[aFreeChannel] = new DSoundInstance(this, mSourceSounds[theSfxID]);
  315. }
  316. mPlayingSounds[aFreeChannel]->SetBasePan(mBasePans[theSfxID]);
  317. mPlayingSounds[aFreeChannel]->SetBaseVolume(mBaseVolumes[theSfxID]);
  318. return mPlayingSounds[aFreeChannel];
  319. }
  320. void DSoundManager::ReleaseSounds()
  321. {
  322. for (int i = 0; i < MAX_SOURCE_SOUNDS; i++)
  323. if (mSourceSounds[i] != NULL)
  324. {
  325. mSourceSounds[i]->Release();
  326. mSourceSounds[i] = NULL;
  327. }
  328. }
  329. void DSoundManager::ReleaseChannels()
  330. {
  331. for (int i = 0; i < MAX_CHANNELS; i++)
  332. if (mPlayingSounds[i] != NULL)
  333. {
  334. delete mPlayingSounds[i];
  335. mPlayingSounds[i] = NULL;
  336. }
  337. }
  338. void DSoundManager::ReleaseFreeChannels()
  339. {
  340. for (int i = 0; i < MAX_CHANNELS; i++)
  341. if (mPlayingSounds[i] != NULL && mPlayingSounds[i]->IsReleased())
  342. {
  343. delete mPlayingSounds[i];
  344. mPlayingSounds[i] = NULL;
  345. }
  346. }
  347. void DSoundManager::StopAllSounds()
  348. {
  349. for (int i = 0; i < MAX_CHANNELS; i++)
  350. if (mPlayingSounds[i] != NULL)
  351. {
  352. bool isAutoRelease = mPlayingSounds[i]->mAutoRelease;
  353. mPlayingSounds[i]->Stop();
  354. mPlayingSounds[i]->mAutoRelease = isAutoRelease;
  355. }
  356. }
  357. float DSoundManager::GetMasterVolume()
  358. {
  359. MIXERCONTROLDETAILS mcd;
  360. MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
  361. MIXERLINECONTROLS mxlc;
  362. MIXERCONTROL mlct;
  363. MIXERLINE mixerLine;
  364. HMIXER hmx;
  365. MIXERCAPS pmxcaps;
  366. mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER);
  367. mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps));
  368. mxlc.cbStruct = sizeof(mxlc);
  369. mxlc.cbmxctrl = sizeof(mlct);
  370. mxlc.pamxctrl = &mlct;
  371. mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  372. mixerLine.cbStruct = sizeof(mixerLine);
  373. mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
  374. mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE);
  375. mxlc.dwLineID = mixerLine.dwLineID;
  376. mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
  377. mcd.cbStruct = sizeof(mcd);
  378. mcd.dwControlID = mlct.dwControlID;
  379. mcd.cChannels = 1;
  380. mcd.cMultipleItems = 0;
  381. mcd.cbDetails = sizeof(mxcd_u);
  382. mcd.paDetails = &mxcd_u;
  383. mixerGetControlDetails((HMIXEROBJ) hmx, &mcd, 0L);
  384. mixerClose(hmx);
  385. return mxcd_u.dwValue / (float) 0xFFFF;
  386. }
  387. void DSoundManager::SetMasterVolume(float theVolume)
  388. {
  389. MIXERCONTROLDETAILS mcd;
  390. MIXERCONTROLDETAILS_UNSIGNED mxcd_u;
  391. MIXERLINECONTROLS mxlc;
  392. MIXERCONTROL mlct;
  393. MIXERLINE mixerLine;
  394. HMIXER hmx;
  395. MIXERCAPS pmxcaps;
  396. mixerOpen((HMIXER*) &hmx, 0, 0, 0, MIXER_OBJECTF_MIXER);
  397. mixerGetDevCaps(0, &pmxcaps, sizeof(pmxcaps));
  398. mxlc.cbStruct = sizeof(mxlc);
  399. mxlc.cbmxctrl = sizeof(mlct);
  400. mxlc.pamxctrl = &mlct;
  401. mxlc.dwControlType = MIXERCONTROL_CONTROLTYPE_VOLUME;
  402. mixerLine.cbStruct = sizeof(mixerLine);
  403. mixerLine.dwComponentType = MIXERLINE_COMPONENTTYPE_SRC_WAVEOUT;
  404. mixerGetLineInfo((HMIXEROBJ) hmx, &mixerLine, MIXER_GETLINEINFOF_COMPONENTTYPE);
  405. mxlc.dwLineID = mixerLine.dwLineID;
  406. mixerGetLineControls((HMIXEROBJ) hmx, &mxlc, MIXER_GETLINECONTROLSF_ONEBYTYPE);
  407. mcd.cbStruct = sizeof(mcd);
  408. mcd.dwControlID = mlct.dwControlID;
  409. mcd.cChannels = 1;
  410. mcd.cMultipleItems = 0;
  411. mcd.cbDetails = sizeof(mxcd_u);
  412. mcd.paDetails = &mxcd_u;
  413. mxcd_u.dwValue = (int) (0xFFFF * theVolume);
  414. mixerSetControlDetails((HMIXEROBJ) hmx, &mcd, 0L);
  415. mixerClose(hmx);
  416. }
  417. void DSoundManager::Flush()
  418. {
  419. }
  420. void DSoundManager::SetCooperativeWindow(HWND theHWnd, bool isWindowed)
  421. {
  422. if (mDirectSound != NULL)
  423. mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
  424. /*
  425. if (isWindowed==true) mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_NORMAL);
  426. else mDirectSound->SetCooperativeLevel(theHWnd,DSSCL_EXCLUSIVE);
  427. */
  428. }
  429. #undef SOUND_FLAGS