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.

862 lines
23 KiB

  1. //+-------------------------------------------------------------------------
  2. //
  3. // Microsoft Windows
  4. //
  5. // Copyright (C) Microsoft Corporation, 1998 - 1999
  6. //
  7. // File: wave.cpp
  8. //
  9. //--------------------------------------------------------------------------
  10. #include "stdafx.h"
  11. #include "Direct.h"
  12. #include "dSound.h"
  13. #include "dms.h"
  14. #include <mmreg.h>
  15. #include <msacm.h>
  16. // FOURCC codes
  17. #undef FOURCC_RIFF
  18. #define FOURCC_RIFF 'FFIR'
  19. #undef FOURCC_MEM
  20. #define FOURCC_MEM ' MEM'
  21. #undef FOURCC_WAVE
  22. #define FOURCC_WAVE 'EVAW'
  23. #undef FOURCC_FORMAT
  24. #define FOURCC_FORMAT ' tmf'
  25. #undef FOURCC_DATA
  26. #define FOURCC_DATA 'atad'
  27. #define RPF(level,str,err) \
  28. { char outBuf[MAX_PATH]; \
  29. wsprintf(outBuf,str,err); \
  30. OutputDebugString(outBuf); \
  31. }
  32. #define DPFLVL_ERROR 1
  33. /***************************************************************************
  34. *
  35. * FillWfx
  36. *
  37. * Description:
  38. * Fills a WAVEFORMATEX structure, given only the necessary values.
  39. *
  40. * Arguments:
  41. * LPWAVEFORMATEX [out]: structure to fill.
  42. * WORD [in]: number of channels.
  43. * DWORD [in]: samples per second.
  44. * WORD [in]: bits per sample.
  45. *
  46. * Returns:
  47. * (void)
  48. *
  49. ***************************************************************************/
  50. #undef DPF_FNAME
  51. void FillWfx(LPWAVEFORMATEX pwfx, WORD wChannels, DWORD dwSamplesPerSec, WORD wBitsPerSample)
  52. {
  53. pwfx->wFormatTag = WAVE_FORMAT_PCM;
  54. pwfx->nChannels = min(2, max(1, wChannels));
  55. pwfx->nSamplesPerSec = min(DSBFREQUENCY_MAX, max(DSBFREQUENCY_MIN, dwSamplesPerSec));
  56. if(wBitsPerSample < 12)
  57. {
  58. pwfx->wBitsPerSample = 8;
  59. }
  60. else
  61. {
  62. pwfx->wBitsPerSample = 16;
  63. }
  64. pwfx->nBlockAlign = pwfx->nChannels * pwfx->wBitsPerSample / 8;
  65. pwfx->nAvgBytesPerSec = pwfx->nSamplesPerSec * pwfx->nBlockAlign;
  66. pwfx->cbSize = 0;
  67. }
  68. #if 0
  69. HRESULT InternalCreateSoundBuffer(LPDSBUFFERDESC pDsbDesc, byte *pbWaveData,DWORD cbWaveData,LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER *lplpDirectSoundBuffer)
  70. {
  71. HRESULT hr = DS_OK;
  72. HACMSTREAM has = NULL;
  73. BOOL fPrep = FALSE;
  74. ACMSTREAMHEADER ash;
  75. DWORD dwBufferBytes;
  76. LPVOID pvWrite;
  77. DWORD cbWrite;
  78. HMMIO hmm = NULL;
  79. MMRESULT mmr;
  80. MMIOINFO mmioinfo;
  81. MMCKINFO ckiRiff;
  82. MMCKINFO cki;
  83. LPWAVEFORMATEX pwfxSrcFormat = NULL;
  84. LPWAVEFORMATEX pwfxDestFormat = NULL;
  85. BOOL bNULLFORMAT = FALSE;
  86. ZeroMemory(&mmioinfo, sizeof(mmioinfo));
  87. if(SUCCEEDED(hr)){
  88. mmioinfo.fccIOProc = FOURCC_MEM;
  89. mmioinfo.pchBuffer = (HPSTR)pbWaveData;
  90. mmioinfo.cchBuffer = cbWaveData;
  91. hmm = mmioOpen(NULL, &mmioinfo, MMIO_READ);
  92. if(!hmm)
  93. {
  94. DPF1(1, "Unable to open file via MMIO. Error %lu", mmioinfo.wErrorRet);
  95. hr = E_FAIL;
  96. }
  97. }
  98. // Decend into the RIFF chunk
  99. if(SUCCEEDED(hr))
  100. {
  101. ckiRiff.ckid = FOURCC_RIFF;
  102. mmr = mmioDescend(hmm, &ckiRiff, NULL, MMIO_FINDCHUNK);
  103. if(MMSYSERR_NOERROR != mmr)
  104. {
  105. DPF1(1, "Unable to descend into RIFF chunk. Error %lu", mmr);
  106. hr = E_FAIL;
  107. }
  108. }
  109. // Verify that this is a wave file
  110. if(SUCCEEDED(hr) && FOURCC_WAVE != ckiRiff.fccType)
  111. {
  112. DPF1(1, "File is not type WAVE %d",GetLastError());
  113. hr = DSERR_BADFORMAT;
  114. }
  115. // Decend into the format chunk
  116. if(SUCCEEDED(hr))
  117. {
  118. cki.ckid = FOURCC_FORMAT;
  119. mmr = mmioDescend(hmm, &cki, &ckiRiff, MMIO_FINDCHUNK);
  120. if(MMSYSERR_NOERROR != mmr)
  121. {
  122. DPF1(1, "Unable to descend into format chunk. Error %lu", mmr);
  123. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  124. }
  125. if(SUCCEEDED(hr))
  126. {
  127. pwfxSrcFormat = (LPWAVEFORMATEX)(pbWaveData + cki.dwDataOffset);
  128. }
  129. }
  130. // Ascend out of the format chunk
  131. if(SUCCEEDED(hr))
  132. {
  133. mmr = mmioAscend(hmm, &cki, 0);
  134. if(MMSYSERR_NOERROR != mmr)
  135. {
  136. DPF(1, "Unable to ascend out of format chunk. Error %lu", mmr);
  137. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  138. }
  139. }
  140. // Descend into the data chunk
  141. if(SUCCEEDED(hr))
  142. {
  143. cki.ckid = FOURCC_DATA;
  144. mmr = mmioDescend(hmm, &cki, &ckiRiff, MMIO_FINDCHUNK);
  145. if(MMSYSERR_NOERROR != mmr)
  146. {
  147. RPF(DPFLVL_ERROR, "Unable to descend into data chunk. Error %lu", mmr);
  148. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  149. }
  150. }
  151. // Prepare PCM conversion
  152. if(SUCCEEDED(hr))
  153. {
  154. if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
  155. {
  156. // Populate the buffer description
  157. dwBufferBytes = cki.cksize;
  158. pwfxDestFormat = pwfxSrcFormat;
  159. }
  160. else
  161. {
  162. // Open an ACM conversion stream
  163. mmr = acmStreamOpen(&has, NULL, (LPWAVEFORMATEX)pwfxSrcFormat, pwfxDestFormat, NULL, 0, 0, 0);
  164. if(MMSYSERR_NOERROR != mmr)
  165. {
  166. RPF(DPFLVL_ERROR, "Unable to open an ACM stream. Error %lu", mmr);
  167. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  168. }
  169. // Get the size of the PCM data
  170. if(SUCCEEDED(hr))
  171. {
  172. mmr = acmStreamSize(has, cki.cksize, &dwBufferBytes, ACM_STREAMSIZEF_SOURCE);
  173. if(MMSYSERR_NOERROR != mmr)
  174. {
  175. RPF(DPFLVL_ERROR, "Unable to determine converted data size. Error %lu", mmr);
  176. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  177. }
  178. }
  179. // Create the destination format
  180. if(SUCCEEDED(hr))
  181. {
  182. pwfxDestFormat = (WAVEFORMATEX*)malloc(sizeof(WAVEFORMATEX));
  183. if (pwfxDestFormat==NULL) hr=E_OUTOFMEMORY;
  184. }
  185. if(SUCCEEDED(hr))
  186. {
  187. FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
  188. }
  189. }
  190. }
  191. LPDIRECTSOUNDBUFFER lpDirectSoundBuffer=NULL;
  192. if(SUCCEEDED(hr))
  193. {
  194. //hr = InitializeEmpty(pDsbDesc->dwFlags, dwBufferBytes, pwfxDestFormat, NULL);
  195. pDsbDesc->dwBufferBytes=dwBufferBytes;
  196. if (pDsbDesc->lpwfxFormat){
  197. memcpy(pDsbDesc->lpwfxFormat,pwfxDestFormat,sizeof(WAVEFORMATEX));
  198. }
  199. else {
  200. pDsbDesc->lpwfxFormat=pwfxDestFormat;
  201. }
  202. hr=lpDirectSound->CreateSoundBuffer(pDsbDesc,lplpDirectSoundBuffer,NULL);
  203. if (*lplpDirectSoundBuffer==NULL) hr= E_FAIL;
  204. lpDirectSoundBuffer=*lplpDirectSoundBuffer;
  205. }
  206. // Lock the buffer in order to write the PCM data to it
  207. if(SUCCEEDED(hr))
  208. {
  209. hr = lpDirectSoundBuffer->Lock(0, dwBufferBytes, &pvWrite, &cbWrite, NULL, NULL,0);
  210. }
  211. // Convert to PCM
  212. if(SUCCEEDED(hr))
  213. {
  214. if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
  215. {
  216. CopyMemory(pvWrite, pbWaveData + cki.dwDataOffset, cbWrite);
  217. }
  218. else
  219. {
  220. // Prepare the conversion header
  221. ZeroMemory(&ash, sizeof(ash));
  222. ash.cbStruct = sizeof(ash);
  223. ash.pbSrc = pbWaveData + cki.dwDataOffset;
  224. ash.cbSrcLength = cki.cksize;
  225. ash.pbDst = (LPBYTE)pvWrite;
  226. ash.cbDstLength = cbWrite;
  227. mmr = acmStreamPrepareHeader(has, &ash, 0);
  228. if(MMSYSERR_NOERROR != mmr)
  229. {
  230. RPF(DPFLVL_ERROR, "Unable to prepare ACM stream header. Error %lu", mmr);
  231. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  232. }
  233. fPrep = SUCCEEDED(hr);
  234. // Convert the buffer
  235. if(SUCCEEDED(hr))
  236. {
  237. mmr = acmStreamConvert(has, &ash, 0);
  238. if(MMSYSERR_NOERROR != mmr)
  239. {
  240. RPF(DPFLVL_ERROR, "Unable to convert wave data. Error %lu", mmr);
  241. hr = E_FAIL; //MMRESULTtoHRESULT(mmr);
  242. }
  243. }
  244. }
  245. }
  246. // Unlock the buffer
  247. if(SUCCEEDED(hr))
  248. {
  249. hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
  250. }
  251. // Clean up
  252. if(fPrep)
  253. {
  254. acmStreamUnprepareHeader(has, &ash, 0);
  255. }
  256. if(has)
  257. {
  258. acmStreamClose(has, 0);
  259. }
  260. if(hmm)
  261. {
  262. mmioClose(hmm, 0);
  263. }
  264. if(pwfxDestFormat != pwfxSrcFormat)
  265. {
  266. free(pwfxDestFormat);
  267. }
  268. return hr;
  269. }
  270. #endif
  271. ///////////////////////////////////////////////////////////////////////////////////////////
  272. HRESULT InternalCreateSoundBuffer(LPDSBUFFERDESC pDsbDesc, byte *pbWaveData, DWORD cbWaveData,LPDIRECTSOUND lpDirectSound, LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
  273. {
  274. HRESULT hr = DS_OK;
  275. HACMSTREAM has = NULL;
  276. BOOL fPrep = FALSE;
  277. DWORD dwBufferBytes = 0;
  278. LPVOID pvWrite = NULL;
  279. DWORD cbWrite = 0;
  280. LPWAVEFORMATEX pwfxFormat = NULL;
  281. LPWAVEFORMATEX pwfxSrcFormat = NULL;
  282. LPWAVEFORMATEX pwfxDestFormat = NULL;
  283. MMRESULT mmr = 0;
  284. DWORD dwDataLength = 0;
  285. DWORD dwOffset = 0;
  286. char *pChunk = NULL;
  287. LPDIRECTSOUNDBUFFER lpDirectSoundBuffer = NULL;
  288. ACMSTREAMHEADER ash;
  289. BOOL bNULLFORMAT =FALSE;
  290. BOOL bDirty =FALSE;
  291. struct tag_FileHeader
  292. {
  293. DWORD dwRiff;
  294. DWORD dwFileSize;
  295. DWORD dwWave;
  296. DWORD dwFormat;
  297. DWORD dwFormatLength;
  298. } FileHeader;
  299. ZeroMemory(&FileHeader,sizeof(struct tag_FileHeader));
  300. // If our file is big enough to have a header copy it over
  301. // other wise error out
  302. if (cbWaveData>sizeof(struct tag_FileHeader))
  303. {
  304. memcpy(&FileHeader,pbWaveData,sizeof(struct tag_FileHeader));
  305. }
  306. else
  307. {
  308. hr= E_INVALIDARG;
  309. }
  310. // File must be a riff file ( 52 R, 49 I, 46 F, 46 F)
  311. if (FileHeader.dwRiff != 0x46464952)
  312. {
  313. DPF(1, "DXVB: not a RIFF file\n");
  314. return E_INVALIDARG;
  315. }
  316. // must be a WAVE format ( 57 W, 41 A, 56 V, 45 E )
  317. if (FileHeader.dwWave != 0x45564157)
  318. {
  319. DPF(1, "DXVB: not a WAVE file\n");
  320. return E_INVALIDARG;
  321. }
  322. // check for odd stuff
  323. // note 18bytes is a typical WAVEFORMATEX
  324. if (FileHeader.dwFormatLength <= 14) return E_INVALIDARG;
  325. if (FileHeader.dwFormatLength > 1000) return E_INVALIDARG;
  326. //allocate the waveformat
  327. pwfxFormat=(WAVEFORMATEX*)alloca(FileHeader.dwFormatLength);
  328. if (!pwfxFormat) return E_OUTOFMEMORY;
  329. //copy it to our own data structure
  330. pChunk=(char*)(pbWaveData+sizeof (struct tag_FileHeader));
  331. memcpy(pwfxFormat,pChunk,FileHeader.dwFormatLength);
  332. // Now look for the next chunk after the WaveFormat
  333. pChunk=(char*)(pChunk+FileHeader.dwFormatLength);
  334. // Look for option FACT chunk and skip it
  335. // (66 F, 61 A, 63 C, 74 T)
  336. // this chunk is required for compressed wave files
  337. // but is optional for PCM
  338. //
  339. if ( ((DWORD*)pChunk)[0]==0x74636166)
  340. {
  341. dwOffset=((DWORD*)pChunk)[1];
  342. dwBufferBytes=((DWORD*)pChunk)[2]; //number of bytes of PCM data
  343. pChunk =(char*)(pChunk+ dwOffset+8);
  344. }
  345. //Look for required data chunk
  346. // (64 D, 61 A, 74 T, 61 A)
  347. if (((DWORD*)pChunk)[0]!=0x61746164)
  348. {
  349. DPF(1, "DXVB: no DATA chunk in wave file\n");
  350. return E_INVALIDARG;
  351. }
  352. dwDataLength=((DWORD*)pChunk)[1];
  353. pChunk=(char*)(pChunk+8);
  354. //IF we assume PCM
  355. //pcm files are not required to have their fact chunk
  356. //so be ware they may missreport the data length
  357. dwBufferBytes=dwDataLength;
  358. pwfxDestFormat=pwfxSrcFormat=pwfxFormat;
  359. // if we are not PCM then we need to do some things first
  360. if (pwfxFormat->wFormatTag!=WAVE_FORMAT_PCM)
  361. {
  362. // source format is from the file
  363. pwfxSrcFormat=pwfxFormat; //from file
  364. pwfxDestFormat=pDsbDesc->lpwfxFormat ; //from user
  365. //pick the format of the file passed in
  366. FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
  367. // Open an ACM conversion stream
  368. mmr = acmStreamOpen(&has, NULL, (LPWAVEFORMATEX)pwfxSrcFormat, pwfxDestFormat, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME );
  369. if(MMSYSERR_NOERROR != mmr)
  370. {
  371. DPF1(1, "Unable to open an ACM stream. Error %lu\n", mmr);
  372. return E_FAIL;
  373. }
  374. // Get the size of the PCM data
  375. mmr = acmStreamSize(has, dwDataLength, &dwBufferBytes, ACM_STREAMSIZEF_SOURCE);
  376. if(MMSYSERR_NOERROR != mmr)
  377. {
  378. DPF1(1, "Unable to determine converted data size. Error %lu\n", mmr);
  379. return E_FAIL; //MMRESULTtoHRESULT(mmr);
  380. }
  381. // Allocate a DestFormat struct
  382. //pwfxDestFormat = (WAVEFORMATEX*)alloca(sizeof(WAVEFORMATEX));
  383. //if (!pwfxDestFormat) return E_OUTOFMEMORY;
  384. // Fill the format with information from the source but
  385. // FillWfx sets the format to PCM
  386. //FillWfx(pwfxDestFormat, pwfxSrcFormat->nChannels, pwfxSrcFormat->nSamplesPerSec, pwfxSrcFormat->wBitsPerSample);
  387. }
  388. // fill the buffer desc the user passed in with the buffer bytes
  389. // this is the number of PCM bytes
  390. pDsbDesc->dwBufferBytes=dwBufferBytes;
  391. // if they provide us a pointer to a waveformatex
  392. // copy over the format to the input desc and use it
  393. // otherwise have it point to our data format temprarily
  394. if (pDsbDesc->lpwfxFormat){
  395. memcpy(pDsbDesc->lpwfxFormat,pwfxDestFormat,sizeof(WAVEFORMATEX));
  396. }
  397. else {
  398. pDsbDesc->lpwfxFormat=pwfxDestFormat;
  399. //make sure we null out the format before passing it back to the user
  400. //NOTE: consider the problems in a multithreaded enviroment
  401. //where the users data structures are being accesed by multiple
  402. //threads... on the other hand if thats going on..
  403. //then the user would need to syncronize things on his or her own
  404. //for everything else including calling into apis that fill structures..
  405. bNULLFORMAT=TRUE;
  406. }
  407. LPDIRECTSOUNDBUFFER dsbTemp = NULL;
  408. // Create the buffer
  409. if (FAILED(hr=lpDirectSound->CreateSoundBuffer(pDsbDesc,&dsbTemp,NULL) ) )
  410. return hr;
  411. hr = dsbTemp->QueryInterface(IID_IDirectSoundBuffer8, (void**) lplpDirectSoundBuffer);
  412. dsbTemp->Release();
  413. if (FAILED(hr)) return hr;
  414. if (*lplpDirectSoundBuffer==NULL) return E_FAIL; //todo ASSERT this instead..
  415. // for more convenient referencing...
  416. lpDirectSoundBuffer=*lplpDirectSoundBuffer;
  417. // Lock the buffer in order to write the PCM data to it
  418. // cbWrite will contain the number of locked bytes
  419. hr = lpDirectSoundBuffer->Lock(0, dwBufferBytes, &pvWrite, &cbWrite, NULL, NULL,0);
  420. if FAILED(hr) return hr;
  421. // If the sorce format was pcm then copy from the file to the buffer
  422. if(WAVE_FORMAT_PCM == pwfxSrcFormat->wFormatTag)
  423. {
  424. CopyMemory(pvWrite, pChunk, cbWrite);
  425. // Unlock the buffer
  426. hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
  427. if (FAILED(hr))
  428. {
  429. DPF(1, "DXVB: lpDirectSoundBuffer->Unlock failed.. \n");
  430. return hr;
  431. }
  432. }
  433. // if the source format is compressed then convert first then copy
  434. else
  435. {
  436. // Prepare the conversion header
  437. ZeroMemory(&ash, sizeof(ash));
  438. ash.cbStruct = sizeof(ash);
  439. ash.pbSrc = (unsigned char*)pChunk; //start of compressed data
  440. ash.cbSrcLength = dwDataLength; //number of bytes of compressed data
  441. ash.pbDst = (LPBYTE)pvWrite; //where to put the decompressed data
  442. ash.cbDstLength = cbWrite; //how big is that buffer
  443. mmr = acmStreamPrepareHeader(has, &ash, 0);
  444. if(MMSYSERR_NOERROR != mmr)
  445. {
  446. DPF1(1, "DXVB: Unable to prepare ACM stream header. Error %lu \n", mmr);
  447. return E_FAIL;
  448. }
  449. mmr = acmStreamConvert(has, &ash, 0);
  450. if(MMSYSERR_NOERROR != mmr)
  451. {
  452. DPF1(1, "DXVB: Unable to convert wave data. Error %lu \n", mmr);
  453. return hr;
  454. }
  455. // Unlock the buffer
  456. hr = lpDirectSoundBuffer->Unlock(pvWrite, cbWrite, NULL, 0);
  457. if (FAILED(hr))
  458. {
  459. DPF(1, "DXVB: lpDirectSoundBuffer->Unlock failed.. \n");
  460. return hr;
  461. }
  462. acmStreamUnprepareHeader(has, &ash, 0);
  463. acmStreamClose(has, 0);
  464. }
  465. if (bNULLFORMAT){
  466. pDsbDesc->lpwfxFormat=NULL;
  467. }
  468. return hr;
  469. }
  470. HRESULT InternalCreateSoundBufferFromFile(LPDIRECTSOUND8 lpDirectSound,LPDSBUFFERDESC pDesc,WCHAR *file,LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
  471. {
  472. HRESULT hr=S_OK;
  473. HANDLE hFile = NULL;
  474. HANDLE hFileMapping = NULL;
  475. DWORD cbWaveData;
  476. LPBYTE pbWaveData = NULL;
  477. #pragma message("CreateFileW should be used for localization why wont it work")
  478. //hFile = CreateFileW(file, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  479. USES_CONVERSION;
  480. LPSTR pStrA=W2T(file);
  481. hFile = CreateFileA(pStrA, GENERIC_READ, FILE_SHARE_READ, NULL, OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL | FILE_FLAG_SEQUENTIAL_SCAN, NULL);
  482. if(INVALID_HANDLE_VALUE == hFile)
  483. {
  484. hFile = NULL;
  485. }
  486. if(!hFile)
  487. {
  488. RPF(DPFLVL_ERROR, "Unable to open file. Error %lu", GetLastError());
  489. hr=STG_E_FILENOTFOUND;
  490. return hr;
  491. }
  492. if(hFile)
  493. {
  494. cbWaveData = GetFileSize(hFile, NULL);
  495. if(-1 == cbWaveData)
  496. {
  497. RPF(DPFLVL_ERROR, "Unable to get file size. Error %lu", GetLastError());
  498. hr = E_FAIL; //DSERR_FILEREADFAULT;
  499. }
  500. }
  501. if(SUCCEEDED(hr))
  502. {
  503. hFileMapping = CreateFileMapping(hFile, NULL, PAGE_READONLY, 0, cbWaveData, NULL);
  504. if(INVALID_HANDLE_VALUE == hFileMapping)
  505. {
  506. hFileMapping = NULL;
  507. }
  508. if(!hFileMapping)
  509. {
  510. RPF(DPFLVL_ERROR, "Unable to create file mapping. Error %lu", GetLastError());
  511. hr = E_FAIL; //DSERR_FILEREADFAULT;
  512. }
  513. }
  514. if(SUCCEEDED(hr))
  515. {
  516. pbWaveData = (LPBYTE)MapViewOfFile(hFileMapping, FILE_MAP_READ, 0, 0, cbWaveData);
  517. if(!pbWaveData)
  518. {
  519. RPF(DPFLVL_ERROR, "Unable to map view of file. Error %lu", GetLastError());
  520. hr = E_FAIL; //DSERR_FILEREADFAULT;
  521. }
  522. }
  523. if(SUCCEEDED(hr)) {
  524. hr=InternalCreateSoundBuffer(pDesc, pbWaveData, cbWaveData,lpDirectSound, lplpDirectSoundBuffer);
  525. }
  526. if(pbWaveData)
  527. {
  528. UnmapViewOfFile(pbWaveData);
  529. }
  530. if(hFileMapping)
  531. {
  532. CloseHandle(hFileMapping);
  533. }
  534. if(hFile)
  535. {
  536. CloseHandle(hFile);
  537. }
  538. return hr;
  539. }
  540. HRESULT InternalCreateSoundBufferFromResource(LPDIRECTSOUND8 lpDirectSound,LPDSBUFFERDESC pDesc,HANDLE resHandle,WCHAR *resName,LPDIRECTSOUNDBUFFER8 *lplpDirectSoundBuffer)
  541. {
  542. const LPCSTR apszResourceTypeA[] = { "WAVE", "WAV" };
  543. const LPCWSTR apszResourceTypeW[] = { L"WAVE", L"WAV" };
  544. UINT cResourceType = 2;
  545. HRSRC hRsrc = NULL;
  546. DWORD cbWaveData;
  547. LPBYTE pbWaveData = NULL;
  548. HRESULT hr=S_OK;
  549. LPCDSBUFFERDESC pDsbDesc=pDesc;
  550. while(!hRsrc && cResourceType--)
  551. {
  552. hRsrc = FindResourceW((HINSTANCE)resHandle, resName, apszResourceTypeW[cResourceType]);
  553. }
  554. if(!hRsrc)
  555. {
  556. RPF(DPFLVL_ERROR,"Unable to find resource. Error %lu", GetLastError());
  557. hr = STG_E_FILENOTFOUND;
  558. }
  559. if(SUCCEEDED(hr))
  560. {
  561. cbWaveData = SizeofResource((HINSTANCE)resHandle, hRsrc);
  562. if(!cbWaveData)
  563. {
  564. RPF(DPFLVL_ERROR, "Unable to get resource size. Error %lu", GetLastError());
  565. hr = E_FAIL;
  566. }
  567. }
  568. if(SUCCEEDED(hr))
  569. {
  570. pbWaveData = (LPBYTE)LoadResource((HINSTANCE)resHandle, hRsrc);
  571. if(!pbWaveData)
  572. {
  573. RPF(DPFLVL_ERROR, "Unable to load resource. Error %lu", GetLastError());
  574. hr = E_FAIL;
  575. }
  576. }
  577. if(SUCCEEDED(hr)) {
  578. hr=InternalCreateSoundBuffer(pDesc, pbWaveData, cbWaveData,lpDirectSound, lplpDirectSoundBuffer);
  579. }
  580. //loadResource
  581. return hr;
  582. }
  583. HRESULT InternalSaveToFile(IDirectSoundBuffer *pBuff,BSTR file)
  584. {
  585. WAVEFORMATEX waveFormat;
  586. DWORD dwWritten=0;
  587. DWORD dwBytes=0;
  588. LPBYTE lpByte=NULL;
  589. HRESULT hr;
  590. HANDLE hFile=NULL;
  591. if (!pBuff) return E_FAIL;
  592. if (!file) return E_INVALIDARG;
  593. pBuff->GetFormat(&waveFormat,sizeof(WAVEFORMATEX),NULL);
  594. USES_CONVERSION;
  595. LPSTR pStrA=W2T(file);
  596. hFile = CreateFile
  597. (
  598. pStrA,
  599. GENERIC_WRITE,
  600. 0,
  601. NULL,
  602. CREATE_ALWAYS,
  603. FILE_ATTRIBUTE_NORMAL,
  604. NULL
  605. );
  606. if (INVALID_HANDLE_VALUE != hFile)
  607. {
  608. struct tag_FileHeader
  609. {
  610. DWORD dwRiff;
  611. DWORD dwFileSize;
  612. DWORD dwWave;
  613. DWORD dwFormat;
  614. DWORD dwFormatLength;
  615. WORD wFormatTag;
  616. WORD nChannels;
  617. DWORD nSamplesPerSec;
  618. DWORD nAvgBytesPerSec;
  619. WORD nBlockAlign;
  620. WORD wBitsPerSample;
  621. DWORD dwData;
  622. DWORD dwDataLength;
  623. } FileHeader;
  624. hr=pBuff->Lock(0,0,(void**)&lpByte,&dwBytes,NULL,NULL,DSBLOCK_ENTIREBUFFER);
  625. if FAILED(hr) {
  626. CloseHandle(hFile);
  627. return hr;
  628. }
  629. FileHeader.dwRiff = 0x46464952; // RIFF
  630. FileHeader.dwWave = 0x45564157; // WAVE
  631. FileHeader.dwFormat = 0x20746D66; // fmt_chnk
  632. FileHeader.dwFormatLength = 16;
  633. FileHeader.wFormatTag = WAVE_FORMAT_PCM;
  634. FileHeader.nChannels = waveFormat.nChannels ;
  635. FileHeader.nSamplesPerSec = waveFormat.nSamplesPerSec ;
  636. FileHeader.wBitsPerSample = waveFormat.wBitsPerSample ;
  637. FileHeader.nBlockAlign = FileHeader.wBitsPerSample / 8 * FileHeader.nChannels;
  638. FileHeader.nAvgBytesPerSec = FileHeader.nSamplesPerSec * FileHeader.nBlockAlign;
  639. FileHeader.dwData = 0x61746164; // data_chnk
  640. FileHeader.dwDataLength = dwBytes;
  641. FileHeader.dwFileSize = dwBytes + sizeof(FileHeader);
  642. WriteFile(hFile, &FileHeader, sizeof(FileHeader), &dwWritten, NULL);
  643. WriteFile(hFile, lpByte, dwBytes, &dwWritten, NULL);
  644. hr=pBuff->Unlock(lpByte,0,NULL,0);
  645. CloseHandle(hFile);
  646. }
  647. else{
  648. return E_FAIL;
  649. }
  650. return S_OK;
  651. }