Source code of Windows XP (NT5)
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

378 lines
10 KiB

  1. /*==========================================================================
  2. *
  3. * Copyright (c) 1995 - 1999 Microsoft Corporation. All Rights Reserved.
  4. *
  5. * File: dsutil.cpp
  6. * Content: Routines for dealing with sounds from resources
  7. *
  8. *
  9. ***************************************************************************/
  10. #define WIN32_LEAN_AND_MEAN
  11. #include <windows.h>
  12. #include <windowsx.h>
  13. #include <mmsystem.h>
  14. #include <dsound.h>
  15. typedef struct
  16. {
  17. BYTE *pbWaveData; // pointer into wave resource (for restore)
  18. DWORD cbWaveSize; // size of wave data (for restore)
  19. int iAlloc; // number of buffers.
  20. int iCurrent; // current buffer
  21. IDirectSoundBuffer* Buffers[1]; // list of buffers
  22. } SNDOBJ, *HSNDOBJ;
  23. #define _HSNDOBJ_DEFINED
  24. #include "dsutil.h"
  25. static const char c_szWAV[] = "WAV";
  26. ///////////////////////////////////////////////////////////////////////////////
  27. //
  28. // DSLoadSoundBuffer
  29. //
  30. ///////////////////////////////////////////////////////////////////////////////
  31. IDirectSoundBuffer *DSLoadSoundBuffer(IDirectSound *pDS, LPCTSTR lpName)
  32. {
  33. IDirectSoundBuffer *pDSB = NULL;
  34. DSBUFFERDESC dsBD = {0};
  35. BYTE *pbWaveData;
  36. if (DSGetWaveResource(NULL, lpName, &dsBD.lpwfxFormat, &pbWaveData, &dsBD.dwBufferBytes))
  37. {
  38. dsBD.dwSize = sizeof(dsBD);
  39. dsBD.dwFlags = DSBCAPS_STATIC | DSBCAPS_CTRLPAN | DSBCAPS_CTRLVOLUME | DSBCAPS_CTRLFREQUENCY | DSBCAPS_GETCURRENTPOSITION2;
  40. if (SUCCEEDED(IDirectSound_CreateSoundBuffer(pDS, &dsBD, &pDSB, NULL)))
  41. {
  42. if (!DSFillSoundBuffer(pDSB, pbWaveData, dsBD.dwBufferBytes))
  43. {
  44. IDirectSoundBuffer_Release(pDSB);
  45. pDSB = NULL;
  46. }
  47. }
  48. else
  49. {
  50. pDSB = NULL;
  51. }
  52. }
  53. return pDSB;
  54. }
  55. ///////////////////////////////////////////////////////////////////////////////
  56. //
  57. // DSReloadSoundBuffer
  58. //
  59. ///////////////////////////////////////////////////////////////////////////////
  60. BOOL DSReloadSoundBuffer(IDirectSoundBuffer *pDSB, LPCTSTR lpName)
  61. {
  62. BOOL result=FALSE;
  63. BYTE *pbWaveData;
  64. DWORD cbWaveSize;
  65. if (DSGetWaveResource(NULL, lpName, NULL, &pbWaveData, &cbWaveSize))
  66. {
  67. if (SUCCEEDED(IDirectSoundBuffer_Restore(pDSB)) &&
  68. DSFillSoundBuffer(pDSB, pbWaveData, cbWaveSize))
  69. {
  70. result = TRUE;
  71. }
  72. }
  73. return result;
  74. }
  75. ///////////////////////////////////////////////////////////////////////////////
  76. //
  77. // DSGetWaveResource
  78. //
  79. ///////////////////////////////////////////////////////////////////////////////
  80. BOOL DSGetWaveResource(HMODULE hModule, LPCTSTR lpName,
  81. WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData, DWORD *pcbWaveSize)
  82. {
  83. HRSRC hResInfo;
  84. HGLOBAL hResData;
  85. void *pvRes;
  86. if (((hResInfo = FindResource(hModule, lpName, c_szWAV)) != NULL) &&
  87. ((hResData = LoadResource(hModule, hResInfo)) != NULL) &&
  88. ((pvRes = LockResource(hResData)) != NULL) &&
  89. DSParseWaveResource(pvRes, ppWaveHeader, ppbWaveData, pcbWaveSize))
  90. {
  91. return TRUE;
  92. }
  93. return FALSE;
  94. }
  95. ///////////////////////////////////////////////////////////////////////////////
  96. // SndObj fns
  97. ///////////////////////////////////////////////////////////////////////////////
  98. SNDOBJ *SndObjCreate(IDirectSound *pDS, LPCTSTR lpName, int iConcurrent)
  99. {
  100. SNDOBJ *pSO = NULL;
  101. LPWAVEFORMATEX pWaveHeader;
  102. BYTE *pbData;
  103. UINT cbData;
  104. if (DSGetWaveResource(NULL, lpName, &pWaveHeader, &pbData, &cbData))
  105. {
  106. if (iConcurrent < 1)
  107. iConcurrent = 1;
  108. if ((pSO = (SNDOBJ *)LocalAlloc(LPTR, sizeof(SNDOBJ) +
  109. (iConcurrent-1) * sizeof(IDirectSoundBuffer *))) != NULL)
  110. {
  111. int i;
  112. pSO->iAlloc = iConcurrent;
  113. pSO->pbWaveData = pbData;
  114. pSO->cbWaveSize = cbData;
  115. pSO->Buffers[0] = DSLoadSoundBuffer(pDS, lpName);
  116. for (i=1; i<pSO->iAlloc; i++)
  117. {
  118. if (FAILED(IDirectSound_DuplicateSoundBuffer(pDS,
  119. pSO->Buffers[0], &pSO->Buffers[i])))
  120. {
  121. pSO->Buffers[i] = DSLoadSoundBuffer(pDS, lpName);
  122. if (!pSO->Buffers[i]) {
  123. SndObjDestroy(pSO);
  124. pSO = NULL;
  125. break;
  126. }
  127. }
  128. }
  129. }
  130. }
  131. return pSO;
  132. }
  133. ///////////////////////////////////////////////////////////////////////////////
  134. ///////////////////////////////////////////////////////////////////////////////
  135. void SndObjDestroy(SNDOBJ *pSO)
  136. {
  137. if (pSO)
  138. {
  139. int i;
  140. for (i=0; i<pSO->iAlloc; i++)
  141. {
  142. if (pSO->Buffers[i])
  143. {
  144. IDirectSoundBuffer_Release(pSO->Buffers[i]);
  145. pSO->Buffers[i] = NULL;
  146. }
  147. }
  148. LocalFree((HANDLE)pSO);
  149. }
  150. }
  151. ///////////////////////////////////////////////////////////////////////////////
  152. ///////////////////////////////////////////////////////////////////////////////
  153. IDirectSoundBuffer *SndObjGetFreeBuffer(SNDOBJ *pSO)
  154. {
  155. IDirectSoundBuffer *pDSB;
  156. if (pSO == NULL)
  157. return NULL;
  158. if (pDSB = pSO->Buffers[pSO->iCurrent])
  159. {
  160. HRESULT hres;
  161. DWORD dwStatus;
  162. hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus);
  163. if (FAILED(hres))
  164. dwStatus = 0;
  165. if ((dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
  166. {
  167. if (pSO->iAlloc > 1)
  168. {
  169. if (++pSO->iCurrent >= pSO->iAlloc)
  170. pSO->iCurrent = 0;
  171. pDSB = pSO->Buffers[pSO->iCurrent];
  172. hres = IDirectSoundBuffer_GetStatus(pDSB, &dwStatus);
  173. if (SUCCEEDED(hres) && (dwStatus & DSBSTATUS_PLAYING) == DSBSTATUS_PLAYING)
  174. {
  175. IDirectSoundBuffer_Stop(pDSB);
  176. IDirectSoundBuffer_SetCurrentPosition(pDSB, 0);
  177. }
  178. }
  179. else
  180. {
  181. pDSB = NULL;
  182. }
  183. }
  184. if (pDSB && (dwStatus & DSBSTATUS_BUFFERLOST))
  185. {
  186. if (FAILED(IDirectSoundBuffer_Restore(pDSB)) ||
  187. !DSFillSoundBuffer(pDSB, pSO->pbWaveData, pSO->cbWaveSize))
  188. {
  189. pDSB = NULL;
  190. }
  191. }
  192. }
  193. return pDSB;
  194. }
  195. ///////////////////////////////////////////////////////////////////////////////
  196. ///////////////////////////////////////////////////////////////////////////////
  197. BOOL SndObjPlay(SNDOBJ *pSO, DWORD dwPlayFlags)
  198. {
  199. BOOL result = FALSE;
  200. if (pSO == NULL)
  201. return FALSE;
  202. if ((!(dwPlayFlags & DSBPLAY_LOOPING) || (pSO->iAlloc == 1)))
  203. {
  204. IDirectSoundBuffer *pDSB = SndObjGetFreeBuffer(pSO);
  205. if (pDSB != NULL) {
  206. result = SUCCEEDED(IDirectSoundBuffer_Play(pDSB, 0, 0, dwPlayFlags));
  207. }
  208. }
  209. return result;
  210. }
  211. ///////////////////////////////////////////////////////////////////////////////
  212. ///////////////////////////////////////////////////////////////////////////////
  213. BOOL SndObjStop(SNDOBJ *pSO)
  214. {
  215. int i;
  216. if (pSO == NULL)
  217. return FALSE;
  218. for (i=0; i<pSO->iAlloc; i++)
  219. {
  220. IDirectSoundBuffer_Stop(pSO->Buffers[i]);
  221. IDirectSoundBuffer_SetCurrentPosition(pSO->Buffers[i], 0);
  222. }
  223. return TRUE;
  224. }
  225. ///////////////////////////////////////////////////////////////////////////////
  226. ///////////////////////////////////////////////////////////////////////////////
  227. BOOL DSFillSoundBuffer(IDirectSoundBuffer *pDSB, BYTE *pbWaveData, DWORD cbWaveSize)
  228. {
  229. if (pDSB && pbWaveData && cbWaveSize)
  230. {
  231. LPVOID pMem1, pMem2;
  232. DWORD dwSize1, dwSize2;
  233. if (SUCCEEDED(IDirectSoundBuffer_Lock(pDSB, 0, cbWaveSize,
  234. &pMem1, &dwSize1, &pMem2, &dwSize2, 0)))
  235. {
  236. CopyMemory(pMem1, pbWaveData, dwSize1);
  237. if ( 0 != dwSize2 )
  238. CopyMemory(pMem2, pbWaveData+dwSize1, dwSize2);
  239. IDirectSoundBuffer_Unlock(pDSB, pMem1, dwSize1, pMem2, dwSize2);
  240. return TRUE;
  241. }
  242. }
  243. return FALSE;
  244. }
  245. ///////////////////////////////////////////////////////////////////////////////
  246. ///////////////////////////////////////////////////////////////////////////////
  247. BOOL DSParseWaveResource(void *pvRes, WAVEFORMATEX **ppWaveHeader, BYTE **ppbWaveData,DWORD *pcbWaveSize)
  248. {
  249. DWORD *pdw;
  250. DWORD *pdwEnd;
  251. DWORD dwRiff;
  252. DWORD dwType;
  253. DWORD dwLength;
  254. if (ppWaveHeader)
  255. *ppWaveHeader = NULL;
  256. if (ppbWaveData)
  257. *ppbWaveData = NULL;
  258. if (pcbWaveSize)
  259. *pcbWaveSize = 0;
  260. pdw = (DWORD *)pvRes;
  261. dwRiff = *pdw++;
  262. dwLength = *pdw++;
  263. dwType = *pdw++;
  264. if (dwRiff != mmioFOURCC('R', 'I', 'F', 'F'))
  265. goto exit; // not even RIFF
  266. if (dwType != mmioFOURCC('W', 'A', 'V', 'E'))
  267. goto exit; // not a WAV
  268. pdwEnd = (DWORD *)((BYTE *)pdw + dwLength-4);
  269. while (pdw < pdwEnd)
  270. {
  271. dwType = *pdw++;
  272. dwLength = *pdw++;
  273. switch (dwType)
  274. {
  275. case mmioFOURCC('f', 'm', 't', ' '):
  276. if (ppWaveHeader && !*ppWaveHeader)
  277. {
  278. if (dwLength < sizeof(WAVEFORMAT))
  279. goto exit; // not a WAV
  280. *ppWaveHeader = (WAVEFORMATEX *)pdw;
  281. if ((!ppbWaveData || *ppbWaveData) &&
  282. (!pcbWaveSize || *pcbWaveSize))
  283. {
  284. return TRUE;
  285. }
  286. }
  287. break;
  288. case mmioFOURCC('d', 'a', 't', 'a'):
  289. if ((ppbWaveData && !*ppbWaveData) ||
  290. (pcbWaveSize && !*pcbWaveSize))
  291. {
  292. if (ppbWaveData)
  293. *ppbWaveData = (LPBYTE)pdw;
  294. if (pcbWaveSize)
  295. *pcbWaveSize = dwLength;
  296. if (!ppWaveHeader || *ppWaveHeader)
  297. return TRUE;
  298. }
  299. break;
  300. }
  301. pdw = (DWORD *)((BYTE *)pdw + ((dwLength+1)&~1));
  302. }
  303. exit:
  304. return FALSE;
  305. }