Leaked source code of windows server 2003
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.

5308 lines
135 KiB

  1. /////////////////////////////////////////////////////////////////////////////////////////
  2. //
  3. // Copyright (c) 1998 Active Voice Corporation. All Rights Reserved.
  4. //
  5. // Active Agent(r) and Unified Communications(tm) are trademarks of Active Voice Corporation.
  6. //
  7. // Other brand and product names used herein are trademarks of their respective owners.
  8. //
  9. // The entire program and user interface including the structure, sequence, selection,
  10. // and arrangement of the dialog, the exclusively "yes" and "no" choices represented
  11. // by "1" and "2," and each dialog message are protected by copyrights registered in
  12. // the United States and by international treaties.
  13. //
  14. // Protected by one or more of the following United States patents: 5,070,526, 5,488,650,
  15. // 5,434,906, 5,581,604, 5,533,102, 5,568,540, 5,625,676, 5,651,054.
  16. //
  17. // Active Voice Corporation
  18. // Seattle, Washington
  19. // USA
  20. //
  21. /////////////////////////////////////////////////////////////////////////////////////////
  22. ////
  23. // wav.c - wave file format functions
  24. ////
  25. #include "winlocal.h"
  26. #include <stdlib.h>
  27. #include "wav.h"
  28. #ifdef MULTITHREAD
  29. #include <objbase.h>
  30. #endif
  31. #include "wavin.h"
  32. #include "wavout.h"
  33. #include "wavmixer.h"
  34. #include "acm.h"
  35. #include "mem.h"
  36. #include "str.h"
  37. #include "trace.h"
  38. #include "mmio.h"
  39. #ifdef AVTSM
  40. #include "avtsm.h"
  41. #define TSMTHUNK
  42. #ifdef TSMTHUNK
  43. #include "tsmthunk.h"
  44. #endif
  45. #define TSM_OUTBUF_SIZE_FACT 4
  46. #endif
  47. // allow telephone output functions if defined
  48. //
  49. #ifdef TELOUT
  50. #include "telout.h"
  51. #endif
  52. // allow telephone input functions if defined
  53. //
  54. #ifdef TELIN
  55. #include "telin.h"
  56. #endif
  57. // use telephone thunk layer if defined
  58. //
  59. #ifdef TELTHUNK
  60. #include "telthunk.h"
  61. #endif
  62. #if defined(TELOUT) || defined(TELIN)
  63. #include "telwav.h"
  64. #include "vox.h"
  65. #endif
  66. ////
  67. // private definitions
  68. ////
  69. #define WAVCLASS TEXT("WavClass")
  70. #define PLAYCHUNKCOUNT_DEFAULT 3
  71. #define PLAYCHUNKCOUNT_MIN 1
  72. #define PLAYCHUNKCOUNT_MAX 16
  73. #define PLAYCHUNKSIZE_DEFAULT 666
  74. #define PLAYCHUNKSIZE_MIN 111
  75. #define PLAYCHUNKSIZE_MAX 9999999
  76. #define RECORDCHUNKCOUNT_DEFAULT 3
  77. #define RECORDCHUNKCOUNT_MIN 1
  78. #define RECORDCHUNKCOUNT_MAX 16
  79. #define RECORDCHUNKSIZE_DEFAULT 666
  80. #define RECORDCHUNKSIZE_MIN 111
  81. #define RECORDCHUNKSIZE_MAX 9999999
  82. // index into format arrays
  83. //
  84. #define FORMATFILE 0
  85. #define FORMATPLAY 1
  86. #define FORMATRECORD 2
  87. // internal state flags
  88. //
  89. #define WAVSTATE_STOPPLAY 0x00000010
  90. #define WAVSTATE_STOPRECORD 0x00000020
  91. #define WAVSTATE_AUTOSTOP 0x00000040
  92. #define WAVSTATE_AUTOCLOSE 0x00000080
  93. // internal array of current handles
  94. //
  95. #define HWAVOUT_MAX 100
  96. #define HWAVIN_MAX 100
  97. #ifdef TELOUT
  98. #define HWAVOUT_MIN -2
  99. #define HWAVOUT_OFFSET 2
  100. #else
  101. #define HWAVOUT_MIN -1
  102. #define HWAVOUT_OFFSET 1
  103. #endif
  104. static HWAV ahWavOutCurr[HWAVOUT_MAX + HWAVOUT_OFFSET] = { 0 };
  105. #ifdef TELIN
  106. #define HWAVIN_MIN -2
  107. #define HWAVIN_OFFSET 2
  108. #else
  109. #define HWAVIN_MIN -1
  110. #define HWAVIN_OFFSET 1
  111. #endif
  112. static HWAV ahWavInCurr[HWAVIN_MAX + HWAVIN_OFFSET] = { 0 };
  113. // internal storage of defaults
  114. //
  115. static int cPlayChunksDefault = PLAYCHUNKCOUNT_DEFAULT;
  116. static long msPlayChunkSizeDefault = PLAYCHUNKSIZE_DEFAULT;
  117. static int cRecordChunksDefault = RECORDCHUNKCOUNT_DEFAULT;
  118. static long msRecordChunkSizeDefault = RECORDCHUNKSIZE_DEFAULT;
  119. // wavinit control struct
  120. //
  121. typedef struct WAVINIT
  122. {
  123. DWORD dwVersion;
  124. HINSTANCE hInst;
  125. HTASK hTask;
  126. DWORD dwFlags;
  127. UINT nLastError;
  128. HACM hAcm;
  129. HACMDRV hAcmDrv;
  130. #ifdef TELTHUNK
  131. HTELTHUNK hTelThunk;
  132. #endif
  133. #ifdef TSMTHUNK
  134. HTSMTHUNK hTsmThunk;
  135. #endif
  136. } WAVINIT, FAR *LPWAVINIT;
  137. // wav control struct
  138. //
  139. typedef struct WAV
  140. {
  141. DWORD dwVersion;
  142. HINSTANCE hInst;
  143. HTASK hTask;
  144. DWORD dwFlags;
  145. LPWAVEFORMATEX lpwfx[3];
  146. LPMMIOPROC lpIOProc;
  147. int cPlayChunks;
  148. long msPlayChunkSize;
  149. int cRecordChunks;
  150. long msRecordChunkSize;
  151. HWND hwndNotify;
  152. #ifdef MULTITHREAD
  153. HANDLE hThreadCallback;
  154. DWORD dwThreadId;
  155. HANDLE hEventThreadCallbackStarted;
  156. HANDLE hEventStopped;
  157. #endif
  158. UINT nLastError;
  159. HMMIO hmmio;
  160. MMCKINFO ckRIFF;
  161. MMCKINFO ckfmt;
  162. MMCKINFO ckdata;
  163. long cbData;
  164. long lDataOffset;
  165. long lDataPos;
  166. long msPositionStop;
  167. HWAVIN hWavIn;
  168. HWAVOUT hWavOut;
  169. HACM hAcm;
  170. DWORD dwState;
  171. HGLOBAL hResource;
  172. long lPosFmt;
  173. DWORD dwFlagsPlay;
  174. DWORD dwFlagsRecord;
  175. int nVolumeLevel;
  176. int dwFlagsVolume;
  177. int nSpeedLevel;
  178. DWORD dwFlagsSpeed;
  179. PLAYSTOPPEDPROC lpfnPlayStopped;
  180. HANDLE hUserPlayStopped;
  181. RECORDSTOPPEDPROC lpfnRecordStopped;
  182. DWORD dwUserRecordStopped;
  183. #ifdef MULTITHREAD
  184. HRESULT hrCoInitialize;
  185. #endif
  186. #ifdef AVTSM
  187. HTSM hTsm;
  188. #endif
  189. LPTSTR lpszFileName;
  190. long msMaxSize;
  191. } WAV, FAR *LPWAV;
  192. // helper functions
  193. //
  194. static int WavStopPlay(HWAV hWav);
  195. static int WavStopRecord(HWAV hWav);
  196. static int WavStopOutputDevice(int idDev, DWORD dwFlags);
  197. static int WavStopInputDevice(int idDev, DWORD dwFlags);
  198. static HWAV WavGetOutputHandle(int idDev);
  199. static HWAV WavGetInputHandle(int idDev);
  200. static int WavPlayNextChunk(HWAV hWav);
  201. static int WavRecordNextChunk(HWAV hWav);
  202. static int WavNotifyCreate(LPWAV lpWav);
  203. static int WavNotifyDestroy(LPWAV lpWav);
  204. #ifdef MULTITHREAD
  205. DWORD WINAPI WavCallbackThread(LPVOID lpvThreadParameter);
  206. #endif
  207. LRESULT DLLEXPORT CALLBACK WavNotify(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam);
  208. static int WavCalcPositionStop(HWAV hWav, long cbPosition);
  209. static int WavSeekTraceBefore(LPWAV lpWav, long lOffset, int nOrigin);
  210. static int WavSeekTraceAfter(LPWAV lpWav, long lPos, long lOffset, int nOrigin);
  211. static LPWAV WavGetPtr(HWAV hWav);
  212. static HWAV WavGetHandle(LPWAV lpWav);
  213. static LPWAVINIT WavInitGetPtr(HWAVINIT hWavInit);
  214. static HWAVINIT WavInitGetHandle(LPWAVINIT lpWavInit);
  215. #ifdef MULTITHREAD
  216. static int SetEventMessageProcessed(LPWAV lpWav, HANDLE hEventMessageProcessed);
  217. #endif
  218. static int WavTempStop(HWAV hWav, LPWORD lpwStatePrev, LPINT lpidDevPrev);
  219. static int WavTempResume(HWAV hWav, WORD wStatePrev, int idDevPrev);
  220. ////
  221. // public functions
  222. ////
  223. // WavInit - initialize wav engine
  224. // <dwVersion> (i) must be WAV_VERSION
  225. // <hInst> (i) instance handle of calling module
  226. // <dwFlags> (i) control flags
  227. // WAV_TELTHUNK initialize telephone thunking layer
  228. // WAV_NOTSMTHUNK do not initialize tsm thunking layer
  229. // WAV_NOACM do not use audio compression manager
  230. // WAV_VOXADPCM load acm driver for Dialogic OKI ADPCM
  231. // return handle (NULL if error)
  232. //
  233. HWAVINIT WINAPI WavInit(DWORD dwVersion, HINSTANCE hInst, DWORD dwFlags)
  234. {
  235. BOOL fSuccess = TRUE;
  236. LPWAVINIT lpWavInit = NULL;
  237. if (dwVersion != WAV_VERSION)
  238. fSuccess = TraceFALSE(NULL);
  239. else if (hInst == NULL)
  240. fSuccess = TraceFALSE(NULL);
  241. else if ((lpWavInit = (LPWAVINIT) MemAlloc(NULL, sizeof(WAVINIT), 0)) == NULL)
  242. fSuccess = TraceFALSE(NULL);
  243. else
  244. {
  245. lpWavInit->dwVersion = dwVersion;
  246. lpWavInit->hInst = hInst;
  247. lpWavInit->hTask = GetCurrentTask();
  248. lpWavInit->dwFlags = dwFlags;
  249. lpWavInit->hAcm = NULL;
  250. lpWavInit->hAcmDrv = NULL;
  251. #ifdef TELTHUNK
  252. lpWavInit->hTelThunk = NULL;
  253. #endif
  254. #ifdef TSMTHUNK
  255. lpWavInit->hTsmThunk = NULL;
  256. #endif
  257. // start the acm engine before any other Wav or Acm functions called
  258. //
  259. if ((lpWavInit->hAcm = AcmInit(ACM_VERSION, lpWavInit->hInst,
  260. (lpWavInit->dwFlags & WAV_NOACM) ? ACM_NOACM : 0)) == NULL)
  261. fSuccess = TraceFALSE(NULL);
  262. // load voxadpcm driver if specified
  263. //
  264. else if ((dwFlags & WAV_VOXADPCM) && (!(dwFlags & WAV_NOACM)) &&
  265. (lpWavInit->hAcmDrv = AcmDriverLoad(lpWavInit->hAcm,
  266. MM_ACTIVEVOICE, MM_ACTIVEVOICE_ACM_VOXADPCM,
  267. #ifdef _WIN32
  268. TEXT("avvox.acm"),
  269. #else
  270. TEXT("voxadpcm.acm"),
  271. #endif
  272. "DriverProc", 0)) == NULL)
  273. {
  274. fSuccess = TraceFALSE(NULL);
  275. }
  276. #ifdef TELTHUNK
  277. // initialize telephone thunking layer if specified
  278. //
  279. else if ((dwFlags & WAV_TELTHUNK) &&
  280. (lpWavInit->hTelThunk = TelThunkInit(TELTHUNK_VERSION,
  281. lpWavInit->hInst)) == NULL)
  282. {
  283. fSuccess = TraceFALSE(NULL);
  284. }
  285. #endif
  286. #ifdef TSMTHUNK
  287. // initialize tsm thunking layer if specified
  288. //
  289. else if (!(dwFlags & WAV_NOTSMTHUNK) &&
  290. (lpWavInit->hTsmThunk = TsmThunkInit(TSMTHUNK_VERSION,
  291. lpWavInit->hInst)) == NULL)
  292. {
  293. fSuccess = TraceTRUE(NULL); // not a fatal error
  294. }
  295. #endif
  296. }
  297. if (!fSuccess)
  298. {
  299. WavTerm(WavInitGetHandle(lpWavInit));
  300. lpWavInit = NULL;
  301. }
  302. return fSuccess ? WavInitGetHandle(lpWavInit) : NULL;
  303. }
  304. // WavTerm - shut down wav engine
  305. // <hWavInit> (i) handle returned from WavInit
  306. // return 0 if success
  307. //
  308. int WINAPI WavTerm(HWAVINIT hWavInit)
  309. {
  310. BOOL fSuccess = TRUE;
  311. LPWAVINIT lpWavInit;
  312. if ((lpWavInit = WavInitGetPtr(hWavInit)) == NULL)
  313. fSuccess = TraceFALSE(NULL);
  314. else if (WavOutTerm(lpWavInit->hInst, lpWavInit->dwFlags) != 0)
  315. fSuccess = TraceFALSE(NULL);
  316. else if (WavInTerm(lpWavInit->hInst, lpWavInit->dwFlags) != 0)
  317. fSuccess = TraceFALSE(NULL);
  318. else
  319. {
  320. #ifdef TELTHUNK
  321. // shut down telephone thunking layer if necessary
  322. //
  323. if (lpWavInit->hTelThunk != NULL &&
  324. TelThunkTerm(lpWavInit->hTelThunk) != 0)
  325. fSuccess = TraceFALSE(NULL);
  326. else
  327. lpWavInit->hTelThunk = NULL;
  328. #endif
  329. #ifdef TSMTHUNK
  330. // shut down tsm thunking layer if necessary
  331. //
  332. if (lpWavInit->hTsmThunk != NULL &&
  333. TsmThunkTerm(lpWavInit->hTsmThunk) != 0)
  334. fSuccess = TraceFALSE(NULL);
  335. else
  336. lpWavInit->hTsmThunk = NULL;
  337. #endif
  338. // unload voxadpcm driver if necessary
  339. //
  340. if (lpWavInit->hAcmDrv != NULL &&
  341. AcmDriverUnload(lpWavInit->hAcm, lpWavInit->hAcmDrv) != 0)
  342. fSuccess = TraceFALSE(NULL);
  343. else
  344. lpWavInit->hAcmDrv = NULL;
  345. // shut down acm engine
  346. //
  347. if (lpWavInit->hAcm != NULL && AcmTerm(lpWavInit->hAcm) != 0)
  348. fSuccess = TraceFALSE(NULL);
  349. else
  350. lpWavInit->hAcm = NULL;
  351. if (fSuccess && (lpWavInit = MemFree(NULL, lpWavInit)) != NULL)
  352. fSuccess = TraceFALSE(NULL);
  353. }
  354. return fSuccess ? 0 : -1;
  355. }
  356. // WavOpen - open or create wav file
  357. // <dwVersion> (i) must be WAV_VERSION
  358. // <hInst> (i) instance handle of calling module
  359. // <lpszFileName> (i) name of file to open or create
  360. // <lpwfx> (i) wave format
  361. // NULL use format from header or default
  362. // <lpIOProc> (i) address of i/o procedure to use
  363. // NULL use default i/o procedure
  364. // <lpadwInfo> (i) data to pass to i/o procedure during open
  365. // NULL no data to pass
  366. // <dwFlags> (i) control flags
  367. // WAV_READ open file for reading (default)
  368. // WAV_WRITE open file for writing
  369. // WAV_READWRITE open file for reading and writing
  370. // WAV_DENYNONE allow other programs read and write access
  371. // WAV_DENYREAD prevent other programs from read access
  372. // WAV_DENYWRITE prevent other programs from write access
  373. // WAV_EXCLUSIVE prevent other programs from read or write
  374. // WAV_CREATE create new file or truncate existing file
  375. // WAV_NORIFF file has no RIFF/WAV header
  376. // WAV_MEMORY <lpszFileName> points to memory block
  377. // WAV_RESOURCE <lpszFileName> points to wave resource
  378. // WAV_NOACM do not use audio compression manager
  379. // WAV_DELETE delete specified file, return TRUE if success
  380. // WAV_EXIST return TRUE if specified file exists
  381. // WAV_GETTEMP create temp file, return TRUE if success
  382. // WAV_TELRFILE telephone will play audio from file on server
  383. #ifdef MULTITHREAD
  384. // WAV_MULTITHREAD support multiple threads (default)
  385. // WAV_SINGLETHREAD do not support multiple threads
  386. // WAV_COINITIALIZE call CoInitialize in all secondary threads
  387. #endif
  388. // return handle (NULL if error)
  389. //
  390. // NOTE: if WAV_CREATE or WAV_NORIFF are used in <dwFlags>, then the
  391. // <lpwfx> parameter must be specified. If <lpwfx> is NULL, the
  392. // current default format is assumed.
  393. // WavSetFormat() can be used to set or override the defaults.
  394. //
  395. // NOTE: if WAV_RESOURCE is specified in <dwFlags>, then <lpszFileName>
  396. // must point to a WAVE resource in the module specified by <hInst>.
  397. // If the first character of the string is a pound sign (#), the remaining
  398. // characters represent a decimal number that specifies the resource id.
  399. //
  400. // NOTE: if WAV_MEMORY is specified in <dwFlags>, then <lpszFileName>
  401. // must be a pointer to a memory block obtained by calling MemAlloc().
  402. //
  403. // NOTE: if <lpIOProc> is not NULL, this i/o procedure will be called
  404. // for opening, closing, reading, writing, and seeking the wav file.
  405. // If <lpadwInfo> is not NULL, this array of three (3) DWORDs will be
  406. // passed to the i/o procedure when the wav file is opened.
  407. // See the Windows mmioOpen() and mmioInstallIOProc() function for details
  408. // on these parameters. Also, the WAV_MEMORY and WAV_RESOURCE flags may
  409. // only be used when <lpIOProc> is NULL.
  410. //
  411. HWAV WINAPI WavOpen(DWORD dwVersion, HINSTANCE hInst,
  412. LPCTSTR lpszFileName, LPWAVEFORMATEX lpwfx,
  413. LPMMIOPROC lpIOProc, DWORD FAR *lpadwInfo, DWORD dwFlags)
  414. {
  415. BOOL fSuccess = TRUE;
  416. LPWAV lpWav = NULL;
  417. #ifdef MULTITHREAD
  418. // assume WAV_MULTITHREAD unless WAV_SINGLETHREAD specified
  419. //
  420. if (!(dwFlags & WAV_SINGLETHREAD))
  421. dwFlags |= WAV_MULTITHREAD;
  422. #endif
  423. if (dwVersion != WAV_VERSION)
  424. fSuccess = TraceFALSE(NULL);
  425. else if (hInst == NULL)
  426. fSuccess = TraceFALSE(NULL);
  427. // special case flags that don't actually open a file
  428. // return TRUE if success, ignore all other flags
  429. //
  430. else if ((dwFlags & WAV_EXIST) ||
  431. (dwFlags & WAV_DELETE) ||
  432. (dwFlags & WAV_GETTEMP))
  433. {
  434. DWORD dwOpenFlags = 0;
  435. HMMIO hmmio;
  436. if (dwFlags & WAV_EXIST)
  437. dwOpenFlags |= MMIO_EXIST;
  438. else if (dwFlags & WAV_DELETE)
  439. dwOpenFlags |= MMIO_DELETE;
  440. else if (dwFlags & WAV_GETTEMP)
  441. dwOpenFlags |= MMIO_GETTEMP;
  442. // use specified i/o procedure
  443. //
  444. if (lpIOProc != NULL)
  445. {
  446. MMIOINFO mmioinfo;
  447. MemSet(&mmioinfo, 0, sizeof(mmioinfo));
  448. mmioinfo.pIOProc = lpIOProc;
  449. // pass data to the i/o procedure
  450. //
  451. if (lpadwInfo != NULL)
  452. MemCpy(mmioinfo.adwInfo, lpadwInfo, sizeof(mmioinfo.adwInfo));
  453. hmmio = mmioOpen((LPTSTR) lpszFileName, &mmioinfo, dwOpenFlags);
  454. }
  455. // default i/o procedure
  456. //
  457. else
  458. {
  459. hmmio = mmioOpen((LPTSTR) lpszFileName, NULL, dwOpenFlags);
  460. }
  461. if ((dwFlags & WAV_EXIST) && hmmio == (HMMIO) FALSE)
  462. fSuccess = FALSE; // no trace
  463. else if ((dwFlags & WAV_DELETE) && hmmio == (HMMIO) FALSE)
  464. fSuccess = TraceFALSE(NULL);
  465. else if ((dwFlags & WAV_GETTEMP) && hmmio == (HMMIO) FALSE)
  466. fSuccess = TraceFALSE(NULL);
  467. return (HWAV)IntToPtr(fSuccess);
  468. }
  469. else if ((lpWav = (LPWAV) MemAlloc(NULL, sizeof(WAV), 0)) == NULL)
  470. fSuccess = TraceFALSE(NULL);
  471. else
  472. {
  473. lpWav->dwVersion = dwVersion;
  474. lpWav->hInst = hInst;
  475. lpWav->hTask = GetCurrentTask();
  476. lpWav->dwFlags = dwFlags;
  477. lpWav->lpwfx[FORMATFILE] = NULL;
  478. lpWav->lpwfx[FORMATPLAY] = NULL;
  479. lpWav->lpwfx[FORMATRECORD] = NULL;
  480. lpWav->lpIOProc = lpIOProc;
  481. lpWav->cPlayChunks = cPlayChunksDefault;
  482. lpWav->msPlayChunkSize = msPlayChunkSizeDefault;
  483. lpWav->cRecordChunks = cRecordChunksDefault;
  484. lpWav->msRecordChunkSize = msRecordChunkSizeDefault;
  485. lpWav->hwndNotify = NULL;
  486. #ifdef MULTITHREAD
  487. lpWav->hThreadCallback = NULL;
  488. lpWav->dwThreadId = 0;
  489. lpWav->hEventThreadCallbackStarted = NULL;
  490. lpWav->hEventStopped = NULL;
  491. #endif
  492. lpWav->nLastError = 0;
  493. lpWav->hmmio = NULL;
  494. lpWav->cbData = 0;
  495. lpWav->lDataOffset = 0;
  496. lpWav->lDataPos = 0;
  497. lpWav->hWavIn = NULL;
  498. lpWav->hWavOut = NULL;
  499. lpWav->hAcm = NULL;
  500. lpWav->msPositionStop = 0L;
  501. lpWav->dwState = 0L;
  502. lpWav->hResource = NULL;
  503. lpWav->lPosFmt = -1;
  504. lpWav->dwFlagsPlay = 0;
  505. lpWav->dwFlagsRecord = 0;
  506. lpWav->nVolumeLevel = 50;
  507. lpWav->dwFlagsVolume = 0;
  508. lpWav->nSpeedLevel = 100;
  509. lpWav->dwFlagsSpeed = 0;
  510. lpWav->lpfnPlayStopped = NULL;
  511. lpWav->hUserPlayStopped = 0;
  512. lpWav->lpfnRecordStopped = NULL;
  513. lpWav->dwUserRecordStopped = 0;
  514. #ifdef MULTITHREAD
  515. lpWav->hrCoInitialize = E_UNEXPECTED;
  516. #endif
  517. #ifdef AVTSM
  518. lpWav->hTsm = NULL;
  519. #endif
  520. lpWav->lpszFileName = NULL;
  521. lpWav->msMaxSize = 0;
  522. // start the acm engine before any other Wav or Acm functions called
  523. //
  524. if ((lpWav->hAcm = AcmInit(ACM_VERSION, lpWav->hInst,
  525. (lpWav->dwFlags & WAV_NOACM) ? ACM_NOACM : 0)) == NULL)
  526. fSuccess = TraceFALSE(NULL);
  527. else
  528. {
  529. // assume default wave format if none specified
  530. //
  531. if (lpwfx == NULL)
  532. {
  533. WAVEFORMATEX wfx;
  534. if (WavSetFormat(WavGetHandle(lpWav),
  535. WavFormatPcm(-1, -1, -1, &wfx), WAV_FORMATALL) != 0)
  536. fSuccess = TraceFALSE(NULL);
  537. }
  538. // set specified wave format
  539. //
  540. else if (WavSetFormat(WavGetHandle(lpWav), lpwfx, WAV_FORMATALL) != 0)
  541. fSuccess = TraceFALSE(NULL);
  542. }
  543. }
  544. // load WAVE resource if specified
  545. //
  546. if (fSuccess && (dwFlags & WAV_RESOURCE))
  547. {
  548. HRSRC hResInfo;
  549. LPVOID lpResource;
  550. if ((hResInfo = FindResource(hInst, lpszFileName, TEXT("WAVE"))) == NULL)
  551. fSuccess = TraceFALSE(NULL);
  552. else if ((lpWav->hResource = LoadResource(hInst, hResInfo)) == NULL)
  553. fSuccess = TraceFALSE(NULL);
  554. else if ((lpResource = LockResource(lpWav->hResource)) == NULL)
  555. fSuccess = TraceFALSE(NULL);
  556. else
  557. {
  558. // <lpszFileName> now points to a memory block
  559. //
  560. lpszFileName = lpResource;
  561. dwFlags |= WAV_MEMORY;
  562. }
  563. }
  564. if (fSuccess && (dwFlags & WAV_MEMORY))
  565. {
  566. // i/o procedure can not be specified with memory block
  567. //
  568. lpIOProc = NULL;
  569. lpadwInfo = NULL;
  570. }
  571. if (fSuccess)
  572. {
  573. DWORD dwOpenFlags = 0;
  574. if (lpWav->dwFlags & WAV_READ)
  575. dwOpenFlags |= MMIO_READ;
  576. if (lpWav->dwFlags & WAV_WRITE)
  577. dwOpenFlags |= MMIO_WRITE;
  578. if (lpWav->dwFlags & WAV_READWRITE)
  579. dwOpenFlags |= MMIO_READWRITE;
  580. if (lpWav->dwFlags & WAV_CREATE)
  581. dwOpenFlags |= MMIO_CREATE;
  582. if (lpWav->dwFlags & WAV_DENYNONE)
  583. dwOpenFlags |= MMIO_DENYNONE;
  584. if (lpWav->dwFlags & WAV_DENYREAD)
  585. dwOpenFlags |= MMIO_DENYREAD;
  586. if (lpWav->dwFlags & WAV_DENYWRITE)
  587. dwOpenFlags |= MMIO_DENYWRITE;
  588. if (lpWav->dwFlags & WAV_EXCLUSIVE)
  589. dwOpenFlags |= MMIO_EXCLUSIVE;
  590. // open/create disk wav file with specified i/o procedure
  591. //
  592. if (lpIOProc != NULL)
  593. {
  594. MMIOINFO mmioinfo;
  595. MemSet(&mmioinfo, 0, sizeof(mmioinfo));
  596. mmioinfo.pIOProc = lpIOProc;
  597. // pass data to the i/o procedure
  598. //
  599. if (lpadwInfo != NULL)
  600. MemCpy(mmioinfo.adwInfo, lpadwInfo, sizeof(mmioinfo.adwInfo));
  601. if ((lpWav->hmmio = mmioOpen((LPTSTR) lpszFileName,
  602. &mmioinfo, dwOpenFlags)) == NULL)
  603. {
  604. fSuccess = TraceFALSE(NULL);
  605. }
  606. }
  607. // open/create a memory wav file if WAV_MEMORY specified
  608. //
  609. else if (lpWav->dwFlags & WAV_MEMORY)
  610. {
  611. MMIOINFO mmioinfo;
  612. MemSet(&mmioinfo, 0, sizeof(mmioinfo));
  613. mmioinfo.fccIOProc = FOURCC_MEM;
  614. mmioinfo.pchBuffer = (HPSTR) lpszFileName;
  615. if (lpszFileName == NULL)
  616. {
  617. // expandable memory file
  618. //
  619. mmioinfo.cchBuffer = 0;
  620. mmioinfo.adwInfo[0] = (DWORD) (16 * 1024);
  621. }
  622. else
  623. {
  624. // expandable memory file
  625. //
  626. mmioinfo.cchBuffer = (long) MemSize(NULL, (LPVOID) lpszFileName);
  627. mmioinfo.adwInfo[0] = (DWORD) 16384;
  628. }
  629. if ((lpWav->hmmio = mmioOpen(NULL,
  630. &mmioinfo, dwOpenFlags)) == NULL)
  631. {
  632. fSuccess = TraceFALSE(NULL);
  633. }
  634. }
  635. // otherwise open/create disk wav file
  636. //
  637. else
  638. {
  639. if ((lpWav->lpszFileName = StrDup(lpszFileName)) == NULL)
  640. fSuccess = TraceFALSE(NULL);
  641. else if ((lpWav->hmmio = mmioOpen((LPTSTR) lpszFileName,
  642. NULL, dwOpenFlags)) == NULL)
  643. {
  644. fSuccess = TraceFALSE(NULL);
  645. }
  646. }
  647. }
  648. // handle reading of RIFF file chunks if necessary
  649. //
  650. if (fSuccess && !(lpWav->dwFlags & WAV_CREATE) &&
  651. !(lpWav->dwFlags & WAV_NORIFF))
  652. {
  653. MMCKINFO ck;
  654. // search for RIFF chunk with form type WAV
  655. //
  656. if ((lpWav->nLastError = mmioDescend(lpWav->hmmio,
  657. &lpWav->ckRIFF, NULL, MMIO_FINDRIFF)) != 0)
  658. {
  659. fSuccess = TraceFALSE(NULL);
  660. TracePrintf_1(NULL, 5,
  661. TEXT("mmioDescend failed (%u)\n"),
  662. (unsigned) lpWav->nLastError);
  663. }
  664. // search for "fmt " subchunk
  665. //
  666. ck.ckid = mmioFOURCC('f', 'm', 't', ' ');
  667. if (fSuccess && (lpWav->nLastError = mmioDescend(lpWav->hmmio,
  668. &ck, &lpWav->ckRIFF, MMIO_FINDCHUNK)) != 0)
  669. {
  670. fSuccess = TraceFALSE(NULL);
  671. TracePrintf_1(NULL, 5,
  672. TEXT("mmioDescend failed (%u)\n"),
  673. (unsigned) lpWav->nLastError);
  674. }
  675. // save position of "fmt " chunk data so we can seek there later
  676. //
  677. else if (fSuccess && (lpWav->lPosFmt = mmioSeek(lpWav->hmmio,
  678. 0, SEEK_CUR)) == -1)
  679. {
  680. fSuccess = TraceFALSE(NULL);
  681. }
  682. // check for file corruption
  683. //
  684. if (fSuccess && (ck.dwDataOffset + ck.cksize) >
  685. (lpWav->ckRIFF.dwDataOffset + lpWav->ckRIFF.cksize))
  686. {
  687. fSuccess = TraceFALSE(NULL);
  688. }
  689. if (fSuccess)
  690. {
  691. LPWAVEFORMATEX lpwfx = NULL;
  692. DWORD cksize;
  693. // save fmt chunk info
  694. //
  695. lpWav->ckfmt = ck;
  696. // fmt chunk must be no smaller than WAVEFORMAT struct
  697. //
  698. if ((cksize = max(ck.cksize, sizeof(WAVEFORMAT)))
  699. < sizeof(WAVEFORMAT))
  700. fSuccess = TraceFALSE(NULL);
  701. // allocate space for WAVEFORMATEX struct
  702. //
  703. else if ((lpwfx = (LPWAVEFORMATEX) MemAlloc(NULL,
  704. max(sizeof(WAVEFORMATEX), cksize), 0)) == NULL)
  705. fSuccess = TraceFALSE(NULL);
  706. // read the fmt chunk
  707. //
  708. else if (mmioRead(lpWav->hmmio,
  709. (HPSTR) lpwfx, (LONG) cksize) != (LONG) cksize)
  710. fSuccess = TraceFALSE(NULL);
  711. // seek to beginning of next chunk if necessary
  712. //
  713. else if (ck.cksize > cksize &&
  714. mmioSeek(lpWav->hmmio, ck.cksize - cksize, SEEK_CUR) == -1)
  715. fSuccess = TraceFALSE(NULL);
  716. // calculate bits per sample if necessary
  717. //
  718. else if (lpwfx->wFormatTag == WAVE_FORMAT_PCM &&
  719. lpwfx->wBitsPerSample == 0)
  720. {
  721. // NOTE: this only works for PCM data with
  722. // sample size that is a multiple of 8 bits
  723. //
  724. lpwfx->wBitsPerSample =
  725. (lpwfx->nBlockAlign * 8) / lpwfx->nChannels;
  726. }
  727. // save format for later
  728. //
  729. if (fSuccess && WavSetFormat(WavGetHandle(lpWav),
  730. lpwfx, WAV_FORMATALL) != 0)
  731. fSuccess = TraceFALSE(NULL);
  732. // clean up
  733. //
  734. if (lpwfx != NULL &&
  735. (lpwfx = MemFree(NULL, lpwfx)) != NULL)
  736. fSuccess = TraceFALSE(NULL);
  737. }
  738. // search for "data" subchunk
  739. //
  740. ck.ckid = mmioFOURCC('d', 'a', 't', 'a');
  741. if (fSuccess && (lpWav->nLastError = mmioDescend(lpWav->hmmio,
  742. &ck, &lpWav->ckRIFF, MMIO_FINDCHUNK)) != 0)
  743. {
  744. fSuccess = TraceFALSE(NULL);
  745. TracePrintf_1(NULL, 5,
  746. TEXT("mmioDescend failed (%u)\n"),
  747. (unsigned) lpWav->nLastError);
  748. }
  749. // check for file corruption
  750. //
  751. if (fSuccess && (ck.dwDataOffset + ck.cksize) >
  752. (lpWav->ckRIFF.dwDataOffset + lpWav->ckRIFF.cksize))
  753. {
  754. fSuccess = TraceFALSE(NULL);
  755. }
  756. if (fSuccess)
  757. {
  758. // save data chunk info
  759. //
  760. lpWav->ckdata = ck;
  761. // save data size and offset for later
  762. //
  763. lpWav->cbData = (long) ck.cksize;
  764. lpWav->lDataOffset = (long) ck.dwDataOffset;
  765. }
  766. }
  767. // handle creation of RIFF file chunks if necessary
  768. //
  769. else if (fSuccess && (lpWav->dwFlags & WAV_CREATE) &&
  770. !(lpWav->dwFlags & WAV_NORIFF))
  771. {
  772. lpWav->ckRIFF.ckid = mmioFOURCC('R', 'I', 'F', 'F');
  773. lpWav->ckRIFF.cksize = 0; // unknown
  774. lpWav->ckRIFF.fccType = mmioFOURCC('W', 'A', 'V', 'E');
  775. lpWav->ckfmt.ckid = mmioFOURCC('f', 'm', 't', ' ');
  776. lpWav->ckfmt.cksize = WavFormatGetSize(lpWav->lpwfx[FORMATFILE]);
  777. lpWav->ckdata.ckid = mmioFOURCC('d', 'a', 't', 'a');
  778. lpWav->ckdata.cksize = 0; // unknown
  779. // create RIFF chunk with form type WAV
  780. //
  781. if ((lpWav->nLastError = mmioCreateChunk(lpWav->hmmio,
  782. &lpWav->ckRIFF, MMIO_CREATERIFF)) != 0)
  783. {
  784. fSuccess = TraceFALSE(NULL);
  785. TracePrintf_1(NULL, 5,
  786. TEXT("mmioCreateChunk failed (%u)\n"),
  787. (unsigned) lpWav->nLastError);
  788. }
  789. // create 'fmt ' chunk
  790. //
  791. else if ((lpWav->nLastError = mmioCreateChunk(lpWav->hmmio,
  792. &lpWav->ckfmt, 0)) != 0)
  793. {
  794. fSuccess = TraceFALSE(NULL);
  795. TracePrintf_1(NULL, 5,
  796. TEXT("mmioCreateChunk failed (%u)\n"),
  797. (unsigned) lpWav->nLastError);
  798. }
  799. // save position of "fmt " chunk data so we can seek there later
  800. //
  801. else if ((lpWav->lPosFmt = mmioSeek(lpWav->hmmio,
  802. 0, SEEK_CUR)) == -1)
  803. {
  804. fSuccess = TraceFALSE(NULL);
  805. }
  806. // write 'fmt ' chunk data
  807. //
  808. else if (mmioWrite(lpWav->hmmio, (HPSTR) lpWav->lpwfx[FORMATFILE],
  809. WavFormatGetSize(lpWav->lpwfx[FORMATFILE])) !=
  810. WavFormatGetSize(lpWav->lpwfx[FORMATFILE]))
  811. {
  812. fSuccess = TraceFALSE(NULL);
  813. }
  814. // ascend out of 'fmt ' chunk
  815. //
  816. else if ((lpWav->nLastError = mmioAscend(lpWav->hmmio,
  817. &lpWav->ckfmt, 0)) != 0)
  818. {
  819. fSuccess = TraceFALSE(NULL);
  820. TracePrintf_1(NULL, 5,
  821. TEXT("mmioAscend failed (%u)\n"),
  822. (unsigned) lpWav->nLastError);
  823. }
  824. // create the 'data' chunk which holds the waveform samples
  825. //
  826. else if ((lpWav->nLastError = mmioCreateChunk(lpWav->hmmio,
  827. &lpWav->ckdata, 0)) != 0)
  828. {
  829. fSuccess = TraceFALSE(NULL);
  830. TracePrintf_1(NULL, 5,
  831. TEXT("mmioCreateChunk failed (%u)\n"),
  832. (unsigned) lpWav->nLastError);
  833. }
  834. // calculate beginning offset of data chunk
  835. //
  836. else if ((lpWav->lDataOffset = mmioSeek(lpWav->hmmio, 0, SEEK_CUR)) == -1)
  837. fSuccess = TraceFALSE(NULL);
  838. }
  839. // calculate size of data chunk (file size) for non-RIFF files
  840. //
  841. else if (fSuccess && !(lpWav->dwFlags & WAV_CREATE) &&
  842. (lpWav->dwFlags & WAV_NORIFF))
  843. {
  844. // RFileIOProc already knows the file size
  845. //
  846. if (lpWav->lpIOProc != NULL &&
  847. (lpWav->dwFlags & WAV_TELRFILE))
  848. {
  849. long lSize;
  850. // retrieve size of remote file from i/o procedure
  851. //
  852. if ((lSize = (long)
  853. WavSendMessage(WavGetHandle(lpWav), MMIOM_GETINFO, 1, 0)) == (long) -1)
  854. fSuccess = TraceFALSE(NULL);
  855. else
  856. lpWav->cbData = (long) lSize;
  857. }
  858. else
  859. {
  860. LONG lPosCurr;
  861. LONG lPosEnd;
  862. // save current position
  863. //
  864. if ((lPosCurr = mmioSeek(lpWav->hmmio, 0, SEEK_CUR)) == -1)
  865. fSuccess = TraceFALSE(NULL);
  866. // seek to end of file
  867. //
  868. else if ((lPosEnd = mmioSeek(lpWav->hmmio, 0, SEEK_END)) == -1)
  869. fSuccess = TraceFALSE(NULL);
  870. // restore current position
  871. //
  872. else if (mmioSeek(lpWav->hmmio, lPosCurr, SEEK_SET) == -1)
  873. fSuccess = TraceFALSE(NULL);
  874. else
  875. lpWav->cbData = (long) lPosEnd; // + 1;
  876. }
  877. }
  878. if (fSuccess)
  879. {
  880. TracePrintf_4(NULL, 6,
  881. TEXT("After WavOpen: lpWav->lDataOffset=%ld, lpWav->lDataPos=%ld, lpWav->cbData=%ld, lpWav->msPositionStop=%ld\n"),
  882. (long) lpWav->lDataOffset,
  883. (long) lpWav->lDataPos,
  884. (long) lpWav->cbData,
  885. (long) lpWav->msPositionStop);
  886. }
  887. if (!fSuccess)
  888. {
  889. WavClose(WavGetHandle(lpWav));
  890. lpWav = NULL;
  891. }
  892. return fSuccess ? WavGetHandle(lpWav) : NULL;
  893. }
  894. // WavClose - close wav file
  895. // <hWav> (i) handle returned from WavOpen
  896. // return 0 if success
  897. //
  898. int WINAPI WavClose(HWAV hWav)
  899. {
  900. BOOL fSuccess = TRUE;
  901. LPWAV lpWav;
  902. #ifdef _WIN32
  903. long lPosTruncate = -1;
  904. #endif
  905. if ((lpWav = WavGetPtr(hWav)) == NULL)
  906. fSuccess = TraceFALSE(NULL);
  907. // stop playback or record if necessary
  908. //
  909. else if (WavStop(hWav) != 0)
  910. fSuccess = TraceFALSE(NULL);
  911. // update the RIFF header chunks if dirty flag set
  912. //
  913. else if (lpWav->hmmio != NULL &&
  914. !(lpWav->dwFlags & WAV_NORIFF) &&
  915. ((lpWav->ckdata.dwFlags & MMIO_DIRTY) ||
  916. (lpWav->ckRIFF.dwFlags & MMIO_DIRTY)))
  917. {
  918. #if 0
  919. // seek to end of file
  920. //
  921. if (mmioSeek(lpWav->hmmio, 0, SEEK_END) == -1)
  922. {
  923. fSuccess = TraceFALSE(NULL);
  924. }
  925. #else
  926. // seek to end of the data
  927. //
  928. if (mmioSeek(lpWav->hmmio, lpWav->lDataOffset + lpWav->cbData, SEEK_SET) == -1)
  929. {
  930. fSuccess = TraceFALSE(NULL);
  931. }
  932. #endif
  933. // ascend out of the 'data' chunk; chunk size will be written
  934. //
  935. else if ((lpWav->nLastError = mmioAscend(lpWav->hmmio,
  936. &lpWav->ckdata, 0)) != 0)
  937. {
  938. fSuccess = TraceFALSE(NULL);
  939. TracePrintf_1(NULL, 5,
  940. TEXT("mmioAscend failed (%u)\n"),
  941. (unsigned) lpWav->nLastError);
  942. }
  943. // ascend out of the 'RIFF' chunk; chunk size will be written
  944. //
  945. else if ((lpWav->nLastError = mmioAscend(lpWav->hmmio,
  946. &lpWav->ckRIFF, 0)) != 0)
  947. {
  948. fSuccess = TraceFALSE(NULL);
  949. TracePrintf_1(NULL, 5,
  950. TEXT("mmioAscend failed (%u)\n"),
  951. (unsigned) lpWav->nLastError);
  952. }
  953. #if 0
  954. // seek to beginning of file
  955. //
  956. else if (mmioSeek(lpWav->hmmio, 0, SEEK_SET) == -1)
  957. {
  958. fSuccess = TraceFALSE(NULL);
  959. }
  960. // search for RIFF chunk with form type WAV
  961. //
  962. else if ((lpWav->nLastError = mmioDescend(lpWav->hmmio,
  963. &lpWav->ckRIFF, NULL, MMIO_FINDRIFF)) != 0)
  964. {
  965. fSuccess = TraceFALSE(NULL);
  966. TracePrintf_1(NULL, 5,
  967. TEXT("mmioDescend failed (%u)\n"),
  968. (unsigned) lpWav->nLastError);
  969. }
  970. // search for 'fmt ' chunk
  971. //
  972. else if ((lpWav->nLastError = mmioDescend(lpWav->hmmio,
  973. &lpWav->ckfmt, &lpWav->ckRIFF, MMIO_FINDCHUNK)) != 0)
  974. {
  975. fSuccess = TraceFALSE(NULL);
  976. TracePrintf_1(NULL, 5,
  977. TEXT("mmioDescend failed (%u)\n"),
  978. (unsigned) lpWav->nLastError);
  979. }
  980. #else
  981. // seek to beginning of "fmt " chunk data
  982. //
  983. else if (mmioSeek(lpWav->hmmio, lpWav->lPosFmt, SEEK_SET) == -1)
  984. {
  985. fSuccess = TraceFALSE(NULL);
  986. }
  987. #endif
  988. // write 'fmt ' chunk data
  989. // $FIXUP - what happens if current file format struct size
  990. // is larger than the original format?
  991. //
  992. else if (mmioWrite(lpWav->hmmio, (HPSTR) lpWav->lpwfx[FORMATFILE],
  993. WavFormatGetSize(lpWav->lpwfx[FORMATFILE])) !=
  994. WavFormatGetSize(lpWav->lpwfx[FORMATFILE]))
  995. {
  996. fSuccess = TraceFALSE(NULL);
  997. }
  998. #ifdef _WIN32
  999. // see if we need to truncate file
  1000. //
  1001. else if (lpWav->lpIOProc == NULL && !(lpWav->dwFlags & WAV_MEMORY) &&
  1002. !(lpWav->dwFlags & WAV_RESOURCE))
  1003. {
  1004. if (mmioSeek(lpWav->hmmio, 0, SEEK_END) >
  1005. lpWav->lDataOffset + lpWav->cbData)
  1006. {
  1007. lPosTruncate = lpWav->lDataOffset + lpWav->cbData;
  1008. }
  1009. }
  1010. #endif
  1011. }
  1012. if (fSuccess)
  1013. {
  1014. // close the file
  1015. //
  1016. if (lpWav->hmmio != NULL && mmioClose(lpWav->hmmio, 0) != 0)
  1017. fSuccess = TraceFALSE(NULL);
  1018. else
  1019. lpWav->hmmio = NULL;
  1020. // close acm engine
  1021. //
  1022. if (lpWav->hAcm != NULL && AcmTerm(lpWav->hAcm) != 0)
  1023. fSuccess = TraceFALSE(NULL);
  1024. else
  1025. lpWav->hAcm = NULL;
  1026. // free wave resource
  1027. //
  1028. if (lpWav->hResource != NULL)
  1029. {
  1030. UnlockResource(lpWav->hResource);
  1031. if (!FreeResource(lpWav->hResource))
  1032. fSuccess = TraceFALSE(NULL);
  1033. else
  1034. lpWav->hResource = NULL;
  1035. }
  1036. #ifdef _WIN32
  1037. // truncate file if necessary
  1038. //
  1039. if (lPosTruncate != -1 && lpWav->lpszFileName != NULL)
  1040. {
  1041. HANDLE hFile = INVALID_HANDLE_VALUE;
  1042. // open file
  1043. //
  1044. if ((hFile = CreateFile(lpWav->lpszFileName,
  1045. GENERIC_READ | GENERIC_WRITE, 0, NULL, OPEN_EXISTING,
  1046. FILE_ATTRIBUTE_NORMAL, NULL)) == INVALID_HANDLE_VALUE)
  1047. {
  1048. fSuccess = TraceFALSE(NULL);
  1049. }
  1050. // seek to truncate position
  1051. //
  1052. else if (SetFilePointer(hFile, lPosTruncate,
  1053. NULL, (DWORD) FILE_BEGIN) == 0xFFFFFFFF)
  1054. {
  1055. fSuccess = TraceFALSE(NULL);
  1056. }
  1057. // truncate file
  1058. //
  1059. else if (!SetEndOfFile(hFile))
  1060. fSuccess = TraceFALSE(NULL);
  1061. // close file
  1062. //
  1063. if (hFile != INVALID_HANDLE_VALUE && !CloseHandle(hFile))
  1064. fSuccess = TraceFALSE(NULL);
  1065. }
  1066. #endif
  1067. // free formats
  1068. //
  1069. if (1)
  1070. {
  1071. int iType;
  1072. for (iType = FORMATFILE; fSuccess && iType <= FORMATRECORD; ++iType)
  1073. {
  1074. if (lpWav->lpwfx[iType] != NULL &&
  1075. WavFormatFree(lpWav->lpwfx[iType]) != 0)
  1076. fSuccess = TraceFALSE(NULL);
  1077. }
  1078. }
  1079. // free file name string
  1080. //
  1081. if (lpWav->lpszFileName != NULL)
  1082. {
  1083. StrDupFree(lpWav->lpszFileName);
  1084. lpWav->lpszFileName = NULL;
  1085. }
  1086. if ((lpWav = MemFree(NULL, lpWav)) != NULL)
  1087. fSuccess = TraceFALSE(NULL);
  1088. }
  1089. return fSuccess ? 0 : -1;
  1090. }
  1091. // WavPlayEx - play data from wav file
  1092. // <hWav> (i) handle returned from WavOpen
  1093. // <idDev> (i) wav output device id
  1094. // -1 use any suitable output device
  1095. // <lpfnPlayStopped> (i) function to call when play is stopped
  1096. // NULL do not notify
  1097. // <hUserPlayStopped> (i) param to pass to lpfnPlayStopped
  1098. // <dwReserved> (i) reserved; must be zero
  1099. // <dwFlags> (i) control flags
  1100. // WAV_PLAYASYNC return when playback starts (default)
  1101. // WAV_PLAYSYNC return after playback completes
  1102. // WAV_NOSTOP if device already playing, don't stop it
  1103. // WAV_AUTOSTOP stop playback when eof reached (default)
  1104. // WAV_NOAUTOSTOP continue playback until WavStop called
  1105. // WAV_AUTOCLOSE close wav file after playback stops
  1106. // WAV_OPENRETRY if output device busy, retry for up to 2 sec
  1107. // return 0 if success
  1108. //
  1109. // NOTE: data from the wav file is sent to the output device in chunks.
  1110. // Chunks are submitted to an output device queue, so that when one
  1111. // chunk is finished playing, another is ready to start playing. By
  1112. // default, each chunk is large enough to hold approximately 666 ms
  1113. // of sound, and 3 chunks are maintained in the output device queue.
  1114. // WavSetChunks() can be used to override the defaults.
  1115. //
  1116. // NOTE: if WAV_NOSTOP is specified in <dwFlags>, and the device specified
  1117. // by <idDev> is already in use, this function returns without playing.
  1118. // Unless this flag is specified, the specified device will be stopped
  1119. // so that the new sound can be played.
  1120. //
  1121. // NOTE: if WAV_AUTOSTOP is specified in <dwFlags>, WavStop() will be
  1122. // called automatically when end of file is reached. This is the
  1123. // default behavior, but can be overridden by using the WAV_NOAUTOSTOP
  1124. // flag. WAV_NOAUTOSTOP is useful if you are playing a file that
  1125. // is growing dynamically as another program writes to it. If this is
  1126. // the case, also use the WAV_DENYNONE flag when calling WavOpen().
  1127. //
  1128. // NOTE: if WAV_AUTOCLOSE is specified in <dwFlags>, WavClose() will
  1129. // be called automatically when playback completes. This will happen
  1130. // when WavStop() is called explicitly, or when WavPlay() reaches end
  1131. // of file and WAV_NOAUTOSTOP was not specified. WAV_AUTOCLOSE is useful
  1132. // when used with WAV_PLAYASYNC, since cleanup occurs automatically.
  1133. // The <hWav> handle is thereafter invalid, and should not be used again.
  1134. //
  1135. int WINAPI WavPlay(HWAV hWav, int idDev, DWORD dwFlags)
  1136. {
  1137. return WavPlayEx(hWav, idDev, NULL, NULL, 0, dwFlags);
  1138. }
  1139. int DLLEXPORT WINAPI WavPlayEx(HWAV hWav, int idDev,
  1140. PLAYSTOPPEDPROC lpfnPlayStopped, HANDLE hUserPlayStopped,
  1141. DWORD dwReserved, DWORD dwFlags)
  1142. {
  1143. BOOL fSuccess = TRUE;
  1144. LPWAV lpWav;
  1145. int i;
  1146. LPWAVEFORMATEX lpwfxWavOutOpen = NULL;
  1147. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1148. fSuccess = TraceFALSE(NULL);
  1149. // make sure output device is not already open for this file
  1150. //
  1151. else if (lpWav->hWavOut != NULL)
  1152. fSuccess = TraceFALSE(NULL);
  1153. #ifdef MULTITHREAD
  1154. // we need to know when we can exit
  1155. //
  1156. else if ((lpWav->dwFlags & WAV_MULTITHREAD) &&
  1157. (dwFlags & WAV_PLAYSYNC) &&
  1158. (lpWav->hEventStopped = CreateEvent(
  1159. NULL, FALSE, FALSE, NULL)) == NULL)
  1160. {
  1161. fSuccess = TraceFALSE(NULL);
  1162. }
  1163. #endif
  1164. // make sure output device is not playing
  1165. //
  1166. else if (WavStopOutputDevice(idDev, dwFlags) != 0)
  1167. fSuccess = TraceFALSE(NULL);
  1168. // set new playback format if device cannot handle the current format
  1169. //
  1170. else if (!WavOutSupportsFormat(NULL, idDev, lpWav->lpwfx[FORMATPLAY]))
  1171. {
  1172. LPWAVEFORMATEX lpwfxPlay = NULL;
  1173. if ((lpwfxPlay = WavOutFormatSuggest(NULL,
  1174. idDev, lpWav->lpwfx[FORMATPLAY],
  1175. (lpWav->dwFlags & WAV_NOACM) ? WAVOUT_NOACM : 0)) != NULL &&
  1176. WavSetFormat(hWav, lpwfxPlay, WAV_FORMATPLAY) != 0)
  1177. {
  1178. fSuccess = TraceFALSE(NULL);
  1179. }
  1180. if (lpwfxPlay != NULL && WavFormatFree(lpwfxPlay) != 0)
  1181. fSuccess = TraceFALSE(NULL);
  1182. else
  1183. lpwfxPlay = NULL;
  1184. }
  1185. if (!fSuccess)
  1186. ;
  1187. // create the notification callback window
  1188. //
  1189. else if (WavNotifyCreate(lpWav) != 0)
  1190. fSuccess = TraceFALSE(NULL);
  1191. // non-standard playback speed must be handled here
  1192. //
  1193. else if (lpWav->nSpeedLevel != 100)
  1194. {
  1195. #ifdef AVTSM
  1196. // use time scale modification engine
  1197. //
  1198. if (!(lpWav->dwFlagsSpeed & WAVSPEED_NOTSM))
  1199. {
  1200. long sizBufPlay;
  1201. // calculate the size of output chunk
  1202. //
  1203. if ((sizBufPlay = WavCalcChunkSize(lpWav->lpwfx[FORMATPLAY],
  1204. lpWav->msPlayChunkSize, TRUE)) <= 0)
  1205. {
  1206. fSuccess = TraceFALSE(NULL);
  1207. }
  1208. // initialize time scale modification engine
  1209. //
  1210. else if ((lpWav->hTsm = TsmInit(TSM_VERSION, lpWav->hInst,
  1211. lpWav->lpwfx[FORMATPLAY],
  1212. 2, sizBufPlay * TSM_OUTBUF_SIZE_FACT, 0)) == NULL)
  1213. {
  1214. fSuccess = TraceFALSE(NULL);
  1215. }
  1216. // set the speed
  1217. //
  1218. else if (TsmSetSpeed(lpWav->hTsm, lpWav->nSpeedLevel, 0) != 0)
  1219. fSuccess = TraceFALSE(NULL);
  1220. }
  1221. else
  1222. #endif
  1223. // device supports playback rate directly
  1224. //
  1225. if (!(lpWav->dwFlagsSpeed & WAVSPEED_NOPLAYBACKRATE))
  1226. {
  1227. // we must wait until device has been opened
  1228. //
  1229. ;
  1230. }
  1231. // device supports adjusted format
  1232. //
  1233. else if (!(lpWav->dwFlagsSpeed & WAVSPEED_NOFORMATADJUST))
  1234. {
  1235. // device supports adjusted format with acm
  1236. //
  1237. if (!(lpWav->dwFlagsSpeed & WAVSPEED_NOACM))
  1238. {
  1239. #if 0
  1240. LPWAVEFORMATEX lpwfxPlay = NULL;
  1241. if ((lpwfxPlay = WavFormatDup(lpWav->lpwfx[FORMATPLAY])) == NULL)
  1242. fSuccess = TraceFALSE(NULL);
  1243. // we must double sample rate so that adjusted format works
  1244. //
  1245. else if (lpWav->nSpeedLevel < 100 &&
  1246. WavFormatSpeedAdjust(lpwfxPlay, 200, 0) != 0)
  1247. {
  1248. fSuccess = TraceFALSE(NULL);
  1249. }
  1250. // we must halve sample rate so that adjusted format works
  1251. //
  1252. else if (lpWav->nSpeedLevel > 100 &&
  1253. WavFormatSpeedAdjust(lpwfxPlay, 50, 0) != 0)
  1254. {
  1255. fSuccess = TraceFALSE(NULL);
  1256. }
  1257. else if (WavSetFormat(hWav, lpwfxPlay, WAV_FORMATPLAY) != 0)
  1258. fSuccess = TraceFALSE(NULL);
  1259. if (lpwfxPlay != NULL && WavFormatFree(lpwfxPlay) != 0)
  1260. fSuccess = TraceFALSE(NULL);
  1261. else
  1262. lpwfxPlay = NULL;
  1263. #endif
  1264. }
  1265. if (fSuccess)
  1266. {
  1267. if ((lpwfxWavOutOpen = WavFormatDup(lpWav->lpwfx[FORMATPLAY])) == NULL)
  1268. fSuccess = TraceFALSE(NULL);
  1269. // adjust output device format to reflect current speed
  1270. //
  1271. else if (WavFormatSpeedAdjust(lpwfxWavOutOpen, lpWav->nSpeedLevel, 0) != 0)
  1272. fSuccess = TraceFALSE(NULL);
  1273. }
  1274. }
  1275. }
  1276. if (!fSuccess)
  1277. ;
  1278. // open output device
  1279. //
  1280. else if ((lpWav->hWavOut = WavOutOpen(WAVOUT_VERSION, lpWav->hInst, idDev,
  1281. lpwfxWavOutOpen == NULL ? lpWav->lpwfx[FORMATPLAY] : lpwfxWavOutOpen,
  1282. #ifdef MULTITHREAD
  1283. lpWav->dwFlags & WAV_MULTITHREAD ? (HWND)(DWORD_PTR)lpWav->dwThreadId :
  1284. #endif
  1285. lpWav->hwndNotify, 0, 0,
  1286. #ifdef TELOUT
  1287. ((lpWav->dwFlags & WAV_TELRFILE) ? WAVOUT_TELRFILE : 0) |
  1288. #endif
  1289. #ifdef MULTITHREAD
  1290. ((lpWav->dwFlags & WAV_MULTITHREAD) ? WAVOUT_MULTITHREAD : 0) |
  1291. #endif
  1292. ((dwFlags & WAV_OPENRETRY) ? WAVOUT_OPENRETRY : 0) |
  1293. ((lpWav->dwFlags & WAV_NOACM) ? WAVOUT_NOACM : 0))) == NULL)
  1294. fSuccess = TraceFALSE(NULL);
  1295. // save PlayStopped params for later
  1296. //
  1297. else if (lpWav->lpfnPlayStopped = lpfnPlayStopped, FALSE)
  1298. ;
  1299. else if (lpWav->hUserPlayStopped = hUserPlayStopped, FALSE)
  1300. ;
  1301. // set the device volume if necessary
  1302. //
  1303. else if (lpWav->nVolumeLevel != 50 &&
  1304. WavOutSetVolume(lpWav->hWavOut, -1, lpWav->nVolumeLevel) != 0)
  1305. fSuccess = TraceFALSE(NULL);
  1306. // set the device playback rate if necessary
  1307. //
  1308. else if (lpWav->nSpeedLevel != 100 &&
  1309. !(lpWav->dwFlagsSpeed & WAVSPEED_NOPLAYBACKRATE) &&
  1310. WavOutSetSpeed(lpWav->hWavOut, lpWav->nSpeedLevel) != 0)
  1311. fSuccess = TraceFALSE(NULL);
  1312. // setup acm conversion if play format different than file format
  1313. //
  1314. else if (WavFormatCmp(lpWav->lpwfx[FORMATFILE],
  1315. lpWav->lpwfx[FORMATPLAY]) != 0 &&
  1316. AcmConvertInit(lpWav->hAcm,
  1317. lpWav->lpwfx[FORMATFILE], lpWav->lpwfx[FORMATPLAY], NULL, 0) != 0)
  1318. {
  1319. fSuccess = TraceFALSE(NULL);
  1320. }
  1321. #if 0
  1322. // pause output device before sending chunks to play
  1323. //
  1324. else if (WavOutPause(lpWav->hWavOut) != 0)
  1325. fSuccess = TraceFALSE(NULL);
  1326. #endif
  1327. // associate wav handle with device id
  1328. //
  1329. if (fSuccess)
  1330. {
  1331. int idDev;
  1332. if ((idDev = WavOutGetId(lpWav->hWavOut)) < HWAVOUT_MIN ||
  1333. idDev >= HWAVOUT_MAX)
  1334. fSuccess = TraceFALSE(NULL);
  1335. else
  1336. ahWavOutCurr[idDev + HWAVOUT_OFFSET] = WavGetHandle(lpWav);
  1337. }
  1338. // remember the flags used in case we need them later
  1339. //
  1340. if (fSuccess)
  1341. lpWav->dwFlagsPlay = dwFlags;
  1342. // set the WAVSTATE_AUTOSTOP flag for later if necessary
  1343. //
  1344. if (fSuccess && !(dwFlags & WAV_NOAUTOSTOP))
  1345. lpWav->dwState |= WAVSTATE_AUTOSTOP;
  1346. // set the WAVSTATE_AUTOCLOSE flag for later if necessary
  1347. //
  1348. if (fSuccess && (dwFlags & WAV_AUTOCLOSE))
  1349. lpWav->dwState |= WAVSTATE_AUTOCLOSE;
  1350. // load output device queue with chunks to play
  1351. //
  1352. for (i = 0; fSuccess && i < lpWav->cPlayChunks; ++i)
  1353. {
  1354. if (WavPlayNextChunk(hWav) != 0)
  1355. fSuccess = TraceFALSE(NULL);
  1356. }
  1357. #if 0
  1358. // start playback
  1359. //
  1360. if (fSuccess && WavOutResume(lpWav->hWavOut) != 0)
  1361. fSuccess = TraceFALSE(NULL);
  1362. #endif
  1363. // loop until playback complete if WAV_PLAYSYNC flag specified
  1364. //
  1365. if (fSuccess && (dwFlags & WAV_PLAYSYNC))
  1366. {
  1367. #ifdef MULTITHREAD
  1368. // handle WAV_MULTITHREAD flag
  1369. //
  1370. if (fSuccess && (lpWav->dwFlags & WAV_MULTITHREAD))
  1371. {
  1372. // wait for the play to end
  1373. //
  1374. if (WaitForSingleObject(lpWav->hEventStopped, INFINITE) != WAIT_OBJECT_0)
  1375. {
  1376. fSuccess = TraceFALSE(NULL);
  1377. }
  1378. // clean up
  1379. //
  1380. else if (lpWav->hEventStopped != NULL)
  1381. {
  1382. if (!CloseHandle(lpWav->hEventStopped))
  1383. fSuccess = TraceFALSE(NULL);
  1384. else
  1385. lpWav->hEventStopped = NULL;
  1386. }
  1387. }
  1388. else
  1389. #endif
  1390. // check for valid pointer because WAV_AUTOCLOSE flag
  1391. // could cause hWav to be invalidated during this loop
  1392. //
  1393. while (WavGetPtr(hWav) != NULL &&
  1394. WavGetState(hWav) != WAV_STOPPED)
  1395. {
  1396. MSG msg;
  1397. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1398. {
  1399. TranslateMessage(&msg);
  1400. DispatchMessage(&msg);
  1401. }
  1402. else
  1403. WaitMessage();
  1404. }
  1405. }
  1406. // close output device only if error or playback complete
  1407. //
  1408. if (!fSuccess || (dwFlags & WAV_PLAYSYNC))
  1409. {
  1410. if (WavGetPtr(hWav) != NULL && WavStopPlay(hWav) != 0)
  1411. fSuccess = TraceFALSE(NULL);
  1412. }
  1413. // clean up
  1414. //
  1415. if (lpwfxWavOutOpen != NULL && WavFormatFree(lpwfxWavOutOpen) != 0)
  1416. fSuccess = TraceFALSE(NULL);
  1417. else
  1418. lpwfxWavOutOpen = NULL;
  1419. return fSuccess ? 0 : -1;
  1420. }
  1421. // WavRecordEx - record data to wav file
  1422. // <hWav> (i) handle returned from WavOpen
  1423. // <idDev> (i) wav input device id
  1424. // -1 use any suitable input device
  1425. // <lpfnRecordStopped> (i) function to call when record is stopped
  1426. // NULL do not notify
  1427. // <dwUserRecordStopped> (i) param to pass to lpfnRecordStopped
  1428. // <msMaxSize> (i) stop recording if file reaches this size
  1429. // 0 no maximum size
  1430. // <dwFlags> (i) control flags
  1431. // WAV_RECORDASYNC return when recording starts (default)
  1432. // WAV_RECORDSYNC return after recording completes
  1433. // WAV_NOSTOP if device already recording, don't stop it
  1434. // WAV_OPENRETRY if input device busy, retry for up to 2 sec
  1435. // return 0 if success
  1436. //
  1437. // NOTE: data from the input device is written to the wav file in chunks.
  1438. // Chunks are submitted to an input device queue, so that when one
  1439. // chunk is finished recording, another is ready to start recording.
  1440. // By default, each chunk is large enough to hold approximately 666 ms
  1441. // of sound, and 3 chunks are maintained in the input device queue.
  1442. // WavSetChunks() can be used to override the defaults.
  1443. //
  1444. // NOTE: if WAV_NOSTOP is specified in <dwFlags>, and the device specified
  1445. // by <idDev> is already in use, this function returns without recording.
  1446. // Unless this flag is specified, the specified device will be stopped
  1447. // so that the new sound can be recorded.
  1448. //
  1449. int WINAPI WavRecord(HWAV hWav, int idDev, DWORD dwFlags)
  1450. {
  1451. return WavRecordEx(hWav, idDev, NULL, 0, 0, dwFlags);
  1452. }
  1453. int DLLEXPORT WINAPI WavRecordEx(HWAV hWav, int idDev,
  1454. RECORDSTOPPEDPROC lpfnRecordStopped, DWORD dwUserRecordStopped,
  1455. long msMaxSize, DWORD dwFlags)
  1456. {
  1457. BOOL fSuccess = TRUE;
  1458. LPWAV lpWav;
  1459. int i;
  1460. LPWAVEFORMATEX lpwfxRecord = NULL;
  1461. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1462. fSuccess = TraceFALSE(NULL);
  1463. // make sure input device is not already open for this file
  1464. //
  1465. else if (lpWav->hWavIn != NULL)
  1466. fSuccess = TraceFALSE(NULL);
  1467. #ifdef MULTITHREAD
  1468. // we need to know when we can exit
  1469. //
  1470. else if ((lpWav->dwFlags & WAV_MULTITHREAD) &&
  1471. (dwFlags & WAV_RECORDSYNC) &&
  1472. (lpWav->hEventStopped = CreateEvent(
  1473. NULL, FALSE, FALSE, NULL)) == NULL)
  1474. {
  1475. fSuccess = TraceFALSE(NULL);
  1476. }
  1477. #endif
  1478. // make sure input device is not recording
  1479. //
  1480. else if (WavStopInputDevice(idDev, dwFlags) != 0)
  1481. fSuccess = TraceFALSE(NULL);
  1482. // set new recording format if device cannot handle the current format
  1483. //
  1484. else if (!WavInSupportsFormat(NULL, idDev, lpWav->lpwfx[FORMATRECORD]) &&
  1485. (lpwfxRecord = WavInFormatSuggest(NULL,
  1486. idDev, lpWav->lpwfx[FORMATRECORD],
  1487. (lpWav->dwFlags & WAV_NOACM) ? WAVIN_NOACM : 0)) != NULL &&
  1488. WavSetFormat(hWav, lpwfxRecord, WAV_FORMATRECORD) != 0)
  1489. {
  1490. fSuccess = TraceFALSE(NULL);
  1491. }
  1492. // create the notification callback window
  1493. //
  1494. else if (WavNotifyCreate(lpWav) != 0)
  1495. fSuccess = TraceFALSE(NULL);
  1496. // open input device
  1497. //
  1498. else if ((lpWav->hWavIn = WavInOpen(WAVIN_VERSION, lpWav->hInst,
  1499. idDev, lpWav->lpwfx[FORMATRECORD],
  1500. #ifdef MULTITHREAD
  1501. lpWav->dwFlags & WAV_MULTITHREAD ? (HWND)(DWORD_PTR)lpWav->dwThreadId :
  1502. #endif
  1503. lpWav->hwndNotify, 0, 0,
  1504. #ifdef TELIN
  1505. ((lpWav->dwFlags & WAV_TELRFILE) ? WAVIN_TELRFILE : 0) |
  1506. #endif
  1507. #ifdef MULTITHREAD
  1508. ((lpWav->dwFlags & WAV_MULTITHREAD) ? WAVOUT_MULTITHREAD : 0) |
  1509. #endif
  1510. ((dwFlags & WAV_OPENRETRY) ? WAVIN_OPENRETRY : 0) |
  1511. ((lpWav->dwFlags & WAV_NOACM) ? WAVIN_NOACM : 0))) == NULL)
  1512. fSuccess = TraceFALSE(NULL);
  1513. // save params for later
  1514. //
  1515. else if (lpWav->lpfnRecordStopped = lpfnRecordStopped, FALSE)
  1516. ;
  1517. else if (lpWav->dwUserRecordStopped = dwUserRecordStopped, FALSE)
  1518. ;
  1519. else if (lpWav->msMaxSize = msMaxSize, FALSE)
  1520. ;
  1521. // setup acm conversion if file format different than record format
  1522. //
  1523. else if (WavFormatCmp(lpWav->lpwfx[FORMATRECORD],
  1524. lpWav->lpwfx[FORMATFILE]) != 0 &&
  1525. AcmConvertInit(lpWav->hAcm,
  1526. lpWav->lpwfx[FORMATRECORD], lpWav->lpwfx[FORMATFILE], NULL, 0) != 0)
  1527. {
  1528. fSuccess = TraceFALSE(NULL);
  1529. }
  1530. // associate wav handle with device id
  1531. //
  1532. if (fSuccess)
  1533. {
  1534. int idDev;
  1535. if ((idDev = WavInGetId(lpWav->hWavIn)) < HWAVIN_MIN ||
  1536. idDev >= HWAVIN_MAX)
  1537. TraceFALSE(NULL);
  1538. else
  1539. ahWavInCurr[idDev + HWAVIN_OFFSET] = WavGetHandle(lpWav);
  1540. }
  1541. // remember the flags used in case we need them later
  1542. //
  1543. if (fSuccess)
  1544. lpWav->dwFlagsRecord = dwFlags;
  1545. // load input device queue with chunks to play
  1546. //
  1547. for (i = 0; fSuccess && i < lpWav->cRecordChunks; ++i)
  1548. {
  1549. if (WavRecordNextChunk(hWav) != 0)
  1550. fSuccess = TraceFALSE(NULL);
  1551. }
  1552. // set the WAVSTATE_AUTOSTOP flag for later if necessary
  1553. //
  1554. if (fSuccess && (dwFlags & WAV_AUTOSTOP))
  1555. lpWav->dwState |= WAVSTATE_AUTOSTOP;
  1556. // set the WAVSTATE_AUTOCLOSE flag for later if necessary
  1557. //
  1558. if (fSuccess && (dwFlags & WAV_AUTOCLOSE))
  1559. lpWav->dwState |= WAVSTATE_AUTOCLOSE;
  1560. // loop until recording complete if WAV_RECORDSYNC flag specified
  1561. //
  1562. if (fSuccess && (dwFlags & WAV_RECORDSYNC))
  1563. {
  1564. #ifdef MULTITHREAD
  1565. // handle WAV_MULTITHREAD flag
  1566. //
  1567. if (fSuccess && (lpWav->dwFlags & WAV_MULTITHREAD))
  1568. {
  1569. // wait for the record to end
  1570. //
  1571. if (WaitForSingleObject(lpWav->hEventStopped, INFINITE) != WAIT_OBJECT_0)
  1572. {
  1573. fSuccess = TraceFALSE(NULL);
  1574. }
  1575. // clean up
  1576. //
  1577. else if (lpWav->hEventStopped != NULL)
  1578. {
  1579. if (!CloseHandle(lpWav->hEventStopped))
  1580. fSuccess = TraceFALSE(NULL);
  1581. else
  1582. lpWav->hEventStopped = NULL;
  1583. }
  1584. }
  1585. else
  1586. #endif
  1587. while (WavGetState(hWav) != WAV_STOPPED)
  1588. {
  1589. MSG msg;
  1590. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  1591. {
  1592. TranslateMessage(&msg);
  1593. DispatchMessage(&msg);
  1594. }
  1595. else
  1596. WaitMessage();
  1597. }
  1598. }
  1599. // close input device only if error or recording complete
  1600. //
  1601. if (!fSuccess || (dwFlags & WAV_RECORDSYNC))
  1602. {
  1603. if (WavGetPtr(hWav) != NULL && WavStopRecord(hWav) != 0)
  1604. fSuccess = TraceFALSE(NULL);
  1605. }
  1606. if (lpwfxRecord != NULL && WavFormatFree(lpwfxRecord) != 0)
  1607. fSuccess = TraceFALSE(NULL);
  1608. else
  1609. lpwfxRecord = NULL;
  1610. return fSuccess ? 0 : -1;
  1611. }
  1612. // WavStop - stop playing and/or recording
  1613. // <hWav> (i) handle returned from WavOpen
  1614. // return 0 if success
  1615. //
  1616. int WINAPI WavStop(HWAV hWav)
  1617. {
  1618. BOOL fSuccess = TRUE;
  1619. // stop playing
  1620. //
  1621. if (WavStopPlay(hWav) != 0)
  1622. fSuccess = TraceFALSE(NULL);
  1623. // stop recording
  1624. //
  1625. if (WavStopRecord(hWav) != 0)
  1626. fSuccess = TraceFALSE(NULL);
  1627. return fSuccess ? 0 : -1;
  1628. }
  1629. // WavRead - read data from wav file
  1630. // <hWav> (i) handle returned from WavOpen
  1631. // <hpBuf> (o) buffer to contain bytes read
  1632. // <sizBuf> (i) size of buffer in bytes
  1633. // return bytes read (-1 if error)
  1634. //
  1635. // NOTE : Even if the read operation does not reach the end of file,
  1636. // the number of bytes returned could be less than <sizBuf> if data
  1637. // decompression is performed by the wav file's I/O procedure. See the
  1638. // <lpIOProc> parameter in WavOpen. It is safest to keep calling
  1639. // WavRead() until 0 bytes are read.
  1640. //
  1641. long DLLEXPORT WINAPI WavRead(HWAV hWav, void _huge *hpBuf, long sizBuf)
  1642. {
  1643. BOOL fSuccess = TRUE;
  1644. LPWAV lpWav;
  1645. long lBytesRead;
  1646. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1647. fSuccess = TraceFALSE(NULL);
  1648. else if (hpBuf == NULL)
  1649. fSuccess = TraceFALSE(NULL);
  1650. // make sure we don't read beyond the end of the data
  1651. // NOTE: cbData might not be accurate if file is growing dynamically,
  1652. // so it is ok to read beyond eof if sharing flags are set
  1653. //
  1654. else if (!(lpWav->dwFlags & WAV_DENYNONE) &&
  1655. !(lpWav->dwFlags & WAV_DENYREAD) &&
  1656. (sizBuf = min(sizBuf, lpWav->cbData - lpWav->lDataPos)) < 0)
  1657. fSuccess = TraceFALSE(NULL);
  1658. // do the read
  1659. //
  1660. else if ((lBytesRead = mmioRead(lpWav->hmmio, hpBuf, sizBuf)) < 0)
  1661. fSuccess = TraceFALSE(NULL);
  1662. else if (TracePrintf_1(NULL, 5,
  1663. TEXT("WavRead (%ld)\n"),
  1664. (long) lBytesRead), FALSE)
  1665. fSuccess = TraceFALSE(NULL);
  1666. // adjust current data position
  1667. // (and total data bytes, if file has grown)
  1668. //
  1669. else if ((lpWav->lDataPos += lBytesRead) > lpWav->cbData)
  1670. {
  1671. if ((lpWav->dwFlags & WAV_DENYNONE) ||
  1672. (lpWav->dwFlags & WAV_DENYREAD))
  1673. lpWav->cbData = lpWav->lDataPos;
  1674. else
  1675. fSuccess = TraceFALSE(NULL);
  1676. }
  1677. // calculate new stop position if stopped
  1678. //
  1679. if (fSuccess && WavCalcPositionStop(hWav, lpWav->lDataPos) != 0)
  1680. fSuccess = TraceFALSE(NULL);
  1681. return fSuccess ? lBytesRead : -1;
  1682. }
  1683. // WavWrite - write data to wav file
  1684. // <hWav> (i) handle returned from WavOpen
  1685. // <hpBuf> (i) buffer containing bytes to write
  1686. // <sizBuf> (i) size of buffer in bytes
  1687. // return bytes written (-1 if error)
  1688. //
  1689. // NOTE : Even if the write operation successfully completes,
  1690. // the number of bytes returned could be less than <sizBuf> if data
  1691. // compression is performed by the wav file's I/O procedure. See the
  1692. // <lpIOProc> parameter in WavOpen. It is safest to assume no error
  1693. // in WavWrite() occurred if the return value is greater than 0.
  1694. //
  1695. long DLLEXPORT WINAPI WavWrite(HWAV hWav, void _huge *hpBuf, long sizBuf)
  1696. {
  1697. BOOL fSuccess = TRUE;
  1698. LPWAV lpWav;
  1699. long lBytesWritten;
  1700. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1701. fSuccess = TraceFALSE(NULL);
  1702. // special case: truncate file at current position
  1703. //
  1704. else if (hpBuf == NULL && sizBuf == 0)
  1705. {
  1706. if (WavSetLength(hWav, WavGetPosition(hWav)) < 0)
  1707. return -1;
  1708. else
  1709. return 0;
  1710. }
  1711. else if (hpBuf == NULL)
  1712. fSuccess = TraceFALSE(NULL);
  1713. // do the write
  1714. //
  1715. else if ((lBytesWritten = mmioWrite(lpWav->hmmio, hpBuf, sizBuf)) < 0)
  1716. fSuccess = TraceFALSE(NULL);
  1717. // set dirty flags
  1718. //
  1719. else if (lpWav->ckdata.dwFlags |= MMIO_DIRTY,
  1720. lpWav->ckRIFF.dwFlags |= MMIO_DIRTY, FALSE)
  1721. ;
  1722. else if (TracePrintf_1(NULL, 5,
  1723. TEXT("WavWrite (%ld)\n"),
  1724. (long) lBytesWritten), FALSE)
  1725. fSuccess = TraceFALSE(NULL);
  1726. // adjust current data position
  1727. // (and total data bytes, if file has grown)
  1728. //
  1729. else if ((lpWav->lDataPos += lBytesWritten) > lpWav->cbData)
  1730. lpWav->cbData = lpWav->lDataPos;
  1731. // calculate new stop position if stopped
  1732. //
  1733. if (fSuccess && WavCalcPositionStop(hWav, lpWav->lDataPos) != 0)
  1734. fSuccess = TraceFALSE(NULL);
  1735. return fSuccess ? lBytesWritten : -1;
  1736. }
  1737. // WavSeek - seek within wav file data
  1738. // <hWav> (i) handle returned from WavOpen
  1739. // <lOffset> (i) bytes to move pointer
  1740. // <nOrigin> (i) position to move from
  1741. // 0 move pointer relative to start of data chunk
  1742. // 1 move pointer relative to current position
  1743. // 2 move pointer relative to end of data chunk
  1744. // return new file position (-1 if error)
  1745. //
  1746. long DLLEXPORT WINAPI WavSeek(HWAV hWav, long lOffset, int nOrigin)
  1747. {
  1748. BOOL fSuccess = TRUE;
  1749. LPWAV lpWav;
  1750. long lPos;
  1751. BOOL fWavTell;
  1752. BOOL fWavSeekTrace;
  1753. // WavSeek(..., 0, 1) is same as WavTell(); i.e. no position change
  1754. //
  1755. fWavTell = (BOOL) (lOffset == 0L && nOrigin == 1);
  1756. // traces only if position change with high trace level
  1757. //
  1758. fWavSeekTrace = (BOOL) (!fWavTell && TraceGetLevel(NULL) >= 6);
  1759. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1760. fSuccess = TraceFALSE(NULL);
  1761. // debug trace output before the seek
  1762. //
  1763. else if (fWavSeekTrace && WavSeekTraceBefore(lpWav, lOffset, nOrigin) != 0)
  1764. fSuccess = TraceFALSE(NULL);
  1765. // SEEK_SET: adjust offset relative to beginning of file
  1766. //
  1767. else if (nOrigin == 0 && (lOffset += lpWav->lDataOffset, FALSE))
  1768. fSuccess = TraceFALSE(NULL);
  1769. // SEEK_CUR: adjust offset relative to beginning of file
  1770. //
  1771. else if (nOrigin == 1 && (lOffset += lpWav->lDataOffset + lpWav->lDataPos, FALSE))
  1772. fSuccess = TraceFALSE(NULL);
  1773. // SEEK_END: adjust offset relative to beginning of file
  1774. //
  1775. else if (nOrigin == 2 && (lOffset += lpWav->lDataOffset + lpWav->cbData, FALSE))
  1776. fSuccess = TraceFALSE(NULL);
  1777. // seek is always relative to the beginning of file
  1778. //
  1779. else if (nOrigin = 0, FALSE)
  1780. ;
  1781. // do the seek
  1782. //
  1783. else if ((lPos = mmioSeek(lpWav->hmmio, lOffset, nOrigin)) < 0)
  1784. fSuccess = TraceFALSE(NULL);
  1785. // adjust current data position
  1786. //
  1787. else if ((lpWav->lDataPos = lPos - lpWav->lDataOffset) < 0)
  1788. fSuccess = TraceFALSE(NULL);
  1789. // adjust total data bytes, if file has grown
  1790. //
  1791. else if (lpWav->lDataPos > lpWav->cbData)
  1792. {
  1793. if ((lpWav->dwFlags & WAV_DENYNONE) ||
  1794. (lpWav->dwFlags & WAV_DENYREAD))
  1795. lpWav->cbData = lpWav->lDataPos;
  1796. else
  1797. fSuccess = TraceFALSE(NULL);
  1798. }
  1799. // calculate new stop position if stopped
  1800. // NOTE: we skip this if position unchanged
  1801. //
  1802. if (fSuccess && !fWavTell &&
  1803. WavCalcPositionStop(hWav, lpWav->lDataPos) != 0)
  1804. fSuccess = TraceFALSE(NULL);
  1805. // debug trace output after the seek
  1806. //
  1807. if (fSuccess && fWavSeekTrace &&
  1808. WavSeekTraceAfter(lpWav, lPos, lOffset, nOrigin) != 0)
  1809. fSuccess = TraceFALSE(NULL);
  1810. return fSuccess ? lpWav->lDataPos : -1;
  1811. }
  1812. // WavGetState - return current wav state
  1813. // <hWav> (i) handle returned from WavOpen
  1814. // return WAV_STOPPED, WAV_PLAYING, WAV_RECORDING, or 0 if error
  1815. //
  1816. WORD DLLEXPORT WINAPI WavGetState(HWAV hWav)
  1817. {
  1818. BOOL fSuccess = TRUE;
  1819. LPWAV lpWav;
  1820. WORD wState = WAV_STOPPED;
  1821. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1822. fSuccess = TraceFALSE(NULL);
  1823. else if (lpWav->hWavOut != NULL)
  1824. {
  1825. switch (WavOutGetState(lpWav->hWavOut))
  1826. {
  1827. case WAVOUT_PLAYING:
  1828. wState = WAV_PLAYING;
  1829. break;
  1830. case WAVOUT_STOPPING:
  1831. wState = WAV_STOPPING;
  1832. break;
  1833. case WAVOUT_STOPPED:
  1834. case WAVOUT_PAUSED:
  1835. wState = WAV_STOPPED;
  1836. break;
  1837. case 0:
  1838. default:
  1839. fSuccess = TraceFALSE(NULL);
  1840. break;
  1841. }
  1842. }
  1843. else if (lpWav->hWavIn != NULL)
  1844. {
  1845. switch (WavInGetState(lpWav->hWavIn))
  1846. {
  1847. case WAVIN_RECORDING:
  1848. wState = WAV_RECORDING;
  1849. break;
  1850. case WAVIN_STOPPING:
  1851. wState = WAV_STOPPING;
  1852. break;
  1853. case WAVIN_STOPPED:
  1854. wState = WAV_STOPPED;
  1855. break;
  1856. case 0:
  1857. default:
  1858. fSuccess = TraceFALSE(NULL);
  1859. break;
  1860. }
  1861. }
  1862. // if we are in the middle of WavStopPlay() or WavStopRecord()
  1863. // then set state to WAV_STOPPING, regardless of device state
  1864. //
  1865. if (fSuccess && ((lpWav->dwState & WAVSTATE_STOPPLAY) ||
  1866. (lpWav->dwState & WAVSTATE_STOPRECORD)))
  1867. {
  1868. wState = WAV_STOPPING;
  1869. }
  1870. return fSuccess ? wState : 0;
  1871. }
  1872. // WavGetLength - get current wav data length in milleseconds
  1873. // <hWav> (i) handle returned from WavOpen
  1874. // return milleseconds if success, otherwise -1
  1875. //
  1876. long DLLEXPORT WINAPI WavGetLength(HWAV hWav)
  1877. {
  1878. BOOL fSuccess = TRUE;
  1879. LPWAV lpWav;
  1880. long msLength;
  1881. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1882. fSuccess = TraceFALSE(NULL);
  1883. else
  1884. {
  1885. msLength = WavFormatBytesToMilleseconds(
  1886. lpWav->lpwfx[FORMATFILE], (DWORD) lpWav->cbData);
  1887. }
  1888. return fSuccess ? msLength : -1;
  1889. }
  1890. // WavSetLength - set current wav data length in milleseconds
  1891. // <hWav> (i) handle returned from WavOpen
  1892. // <msLength> (i) length in milleseconds
  1893. // return new length in milleseconds if success, otherwise -1
  1894. //
  1895. // NOTE: afterwards, the current wav data position is set to either
  1896. // the previous wav data position or <msLength>, whichever is smaller.
  1897. //
  1898. long DLLEXPORT WINAPI WavSetLength(HWAV hWav, long msLength)
  1899. {
  1900. BOOL fSuccess = TRUE;
  1901. LPWAV lpWav;
  1902. TracePrintf_1(NULL, 6,
  1903. TEXT("WavSetLength(%ld)\n"),
  1904. (long) msLength);
  1905. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1906. fSuccess = TraceFALSE(NULL);
  1907. // new length must be reasonable
  1908. //
  1909. else if (msLength < 0 || msLength > WavGetLength(hWav))
  1910. fSuccess = TraceFALSE(NULL);
  1911. else
  1912. {
  1913. long lBlockAlign;
  1914. // convert <msLength> to byte offset in file
  1915. //
  1916. lpWav->cbData = WavFormatMillesecondsToBytes(
  1917. lpWav->lpwfx[FORMATFILE], (DWORD) msLength);
  1918. // $FIXUP - add <nRound> parameter to
  1919. // WavFormatMillesecondsToBytes() and WavFormatBytesToMilleseconds()
  1920. //
  1921. if ((lBlockAlign = (long) lpWav->lpwfx[FORMATFILE]->nBlockAlign) > 0)
  1922. {
  1923. // round down to nearest block boundary
  1924. //
  1925. lpWav->cbData = lBlockAlign * (lpWav->cbData / lBlockAlign);
  1926. }
  1927. // set dirty flags
  1928. //
  1929. lpWav->ckdata.dwFlags |= MMIO_DIRTY;
  1930. lpWav->ckRIFF.dwFlags |= MMIO_DIRTY;
  1931. // adjust current data position if necessary
  1932. //
  1933. if (lpWav->lDataPos > lpWav->cbData)
  1934. {
  1935. lpWav->lDataPos = lpWav->cbData;
  1936. // calculate new stop position if stopped
  1937. //
  1938. if (fSuccess && WavCalcPositionStop(hWav, lpWav->lDataPos) != 0)
  1939. fSuccess = TraceFALSE(NULL);
  1940. }
  1941. }
  1942. return fSuccess ? WavGetLength(hWav) : -1;
  1943. }
  1944. // WavGetPosition - get current wav data position in milleseconds
  1945. // <hWav> (i) handle returned from WavOpen
  1946. // return milleseconds if success, otherwise -1
  1947. //
  1948. long DLLEXPORT WINAPI WavGetPosition(HWAV hWav)
  1949. {
  1950. BOOL fSuccess = TRUE;
  1951. LPWAV lpWav;
  1952. long msPosition;
  1953. if ((lpWav = WavGetPtr(hWav)) == NULL)
  1954. fSuccess = TraceFALSE(NULL);
  1955. else switch (WavGetState(hWav))
  1956. {
  1957. case WAV_PLAYING:
  1958. {
  1959. long msPositionPlay = 0L;
  1960. // get position relative to start of playback
  1961. //
  1962. if ((msPositionPlay = WavOutGetPosition(lpWav->hWavOut)) == -1)
  1963. fSuccess = TraceFALSE(NULL);
  1964. else
  1965. {
  1966. // if necessary, adjust position to compensate for non-standard speed
  1967. //
  1968. if (lpWav->nSpeedLevel != 100 && (
  1969. #ifdef AVTSM
  1970. !(lpWav->dwFlagsSpeed & WAVSPEED_NOTSM) ||
  1971. #endif
  1972. !(lpWav->dwFlagsSpeed & WAVSPEED_NOFORMATADJUST)))
  1973. {
  1974. msPositionPlay = msPositionPlay * lpWav->nSpeedLevel / 100;
  1975. }
  1976. // calc position relative to start of file
  1977. //
  1978. msPosition = lpWav->msPositionStop + msPositionPlay;
  1979. }
  1980. }
  1981. break;
  1982. case WAV_RECORDING:
  1983. {
  1984. long msPositionRecord = 0L;
  1985. // get position relative to start of recording
  1986. //
  1987. if ((msPositionRecord = WavInGetPosition(lpWav->hWavIn)) == -1)
  1988. fSuccess = TraceFALSE(NULL);
  1989. else
  1990. {
  1991. // calc position relative to start of file
  1992. //
  1993. msPosition = lpWav->msPositionStop + msPositionRecord;
  1994. }
  1995. }
  1996. break;
  1997. default:
  1998. {
  1999. long cbPosition;
  2000. // get current file position
  2001. //
  2002. if ((cbPosition = WavSeek(hWav, 0, 1)) == -1)
  2003. fSuccess = TraceFALSE(NULL);
  2004. // convert file position to milleseconds
  2005. //
  2006. else
  2007. {
  2008. msPosition = WavFormatBytesToMilleseconds(
  2009. lpWav->lpwfx[FORMATFILE], (DWORD) cbPosition);
  2010. }
  2011. }
  2012. break;
  2013. }
  2014. return fSuccess ? msPosition : -1;
  2015. }
  2016. // WavSetPosition - set current wav data position in milleseconds
  2017. // <hWav> (i) handle returned from WavOpen
  2018. // <msPosition> (i) position in milleseconds
  2019. // return new position in milleseconds if success, otherwise -1
  2020. //
  2021. long DLLEXPORT WINAPI WavSetPosition(HWAV hWav, long msPosition)
  2022. {
  2023. BOOL fSuccess = TRUE;
  2024. LPWAV lpWav;
  2025. WORD wStatePrev;
  2026. int idDevPrev;
  2027. long cbPosition;
  2028. long cbPositionNew;
  2029. long msPositionNew;
  2030. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2031. fSuccess = TraceFALSE(NULL);
  2032. else if (WavTempStop(hWav, &wStatePrev, &idDevPrev) != 0)
  2033. fSuccess = TraceFALSE(NULL);
  2034. else
  2035. {
  2036. long lBlockAlign;
  2037. TracePrintf_1(NULL, 6,
  2038. TEXT("WavSetPosition(%ld)\n"),
  2039. (long) msPosition);
  2040. // convert <msPosition> to byte offset in file
  2041. //
  2042. cbPosition = WavFormatMillesecondsToBytes(
  2043. lpWav->lpwfx[FORMATFILE], (DWORD) msPosition);
  2044. if ((lBlockAlign = (long) lpWav->lpwfx[FORMATFILE]->nBlockAlign) > 0)
  2045. {
  2046. // round down to nearest block boundary
  2047. //
  2048. cbPosition = lBlockAlign * (cbPosition / lBlockAlign);
  2049. }
  2050. // seek to new position
  2051. //
  2052. if ((cbPositionNew = WavSeek(hWav, cbPosition, 0)) == -1)
  2053. fSuccess = TraceFALSE(NULL);
  2054. // convert the new position to milleseconds
  2055. //
  2056. if (fSuccess)
  2057. {
  2058. msPositionNew = WavFormatBytesToMilleseconds(
  2059. lpWav->lpwfx[FORMATFILE], (DWORD) cbPositionNew);
  2060. }
  2061. if (WavTempResume(hWav, wStatePrev, idDevPrev) != 0)
  2062. fSuccess = TraceFALSE(NULL);
  2063. }
  2064. return fSuccess ? msPositionNew : -1;
  2065. }
  2066. // WavGetFormat - get wav format
  2067. // <hWav> (i) handle returned from WavOpen
  2068. // <dwFlags> (i) control flags
  2069. // WAV_FORMATFILE get format of data in file
  2070. // WAV_FORMATPLAY get format of output device
  2071. // WAV_FORMATRECORD get format of input device
  2072. // return pointer to specified format, NULL if error
  2073. //
  2074. // NOTE: the format structure returned is dynamically allocated.
  2075. // Use WavFormatFree() to free the buffer.
  2076. //
  2077. LPWAVEFORMATEX DLLEXPORT WINAPI WavGetFormat(HWAV hWav, DWORD dwFlags)
  2078. {
  2079. BOOL fSuccess = TRUE;
  2080. LPWAV lpWav;
  2081. int iType = 0;
  2082. LPWAVEFORMATEX lpwfx;
  2083. if (dwFlags & WAV_FORMATFILE)
  2084. iType = FORMATFILE;
  2085. if (dwFlags & WAV_FORMATPLAY)
  2086. iType = FORMATPLAY;
  2087. if (dwFlags & WAV_FORMATRECORD)
  2088. iType = FORMATRECORD;
  2089. //
  2090. // We need to take care if hWav is NULL
  2091. //
  2092. if( NULL != hWav )
  2093. {
  2094. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2095. fSuccess = TraceFALSE(NULL);
  2096. else if ((lpwfx = WavFormatDup(lpWav->lpwfx[iType])) == NULL)
  2097. fSuccess = TraceFALSE(NULL);
  2098. }
  2099. else
  2100. fSuccess = TraceFALSE(NULL);
  2101. return fSuccess ? lpwfx : NULL;
  2102. }
  2103. // WavSetFormat - set wav format
  2104. // <hWav> (i) handle returned from WavOpen
  2105. // <lpwfx> (i) wav format
  2106. // <dwFlags> (i) control flags
  2107. // WAV_FORMATFILE set format of data in file
  2108. // WAV_FORMATPLAY set format of output device
  2109. // WAV_FORMATRECORD set format of input device
  2110. // WAV_FORMATALL set all formats
  2111. // return 0 if success
  2112. //
  2113. int DLLEXPORT WINAPI WavSetFormat(HWAV hWav,
  2114. LPWAVEFORMATEX lpwfx, DWORD dwFlags)
  2115. {
  2116. BOOL fSuccess = TRUE;
  2117. LPWAV lpWav;
  2118. WORD wStatePrev;
  2119. int idDevPrev;
  2120. if (hWav != NULL && (lpWav = WavGetPtr(hWav)) == NULL)
  2121. fSuccess = TraceFALSE(NULL);
  2122. else if (!WavFormatIsValid(lpwfx) != 0)
  2123. fSuccess = TraceFALSE(NULL);
  2124. else if (WavTempStop(hWav, &wStatePrev, &idDevPrev) != 0)
  2125. fSuccess = TraceFALSE(NULL);
  2126. else
  2127. {
  2128. int iType;
  2129. for (iType = FORMATFILE; fSuccess && iType <= FORMATRECORD; ++iType)
  2130. {
  2131. if (iType == FORMATFILE && !(dwFlags & WAV_FORMATFILE))
  2132. continue;
  2133. if (iType == FORMATPLAY && !(dwFlags & WAV_FORMATPLAY))
  2134. continue;
  2135. if (iType == FORMATRECORD && !(dwFlags & WAV_FORMATRECORD))
  2136. continue;
  2137. // free previous format
  2138. //
  2139. if (lpWav->lpwfx[iType] != NULL &&
  2140. WavFormatFree(lpWav->lpwfx[iType]) != 0)
  2141. fSuccess = TraceFALSE(NULL);
  2142. // save new format
  2143. //
  2144. else if ((lpWav->lpwfx[iType] = WavFormatDup(lpwfx)) == NULL)
  2145. fSuccess = TraceFALSE(NULL);
  2146. // trace format text
  2147. //
  2148. else if (TraceGetLevel(NULL) >= 5)
  2149. {
  2150. TCHAR szText[512];
  2151. switch (iType)
  2152. {
  2153. case FORMATFILE:
  2154. TraceOutput(NULL, 5, TEXT("FORMATFILE:\t"));
  2155. break;
  2156. case FORMATPLAY:
  2157. TraceOutput(NULL, 5, TEXT("FORMATPLAY:\t"));
  2158. break;
  2159. case FORMATRECORD:
  2160. TraceOutput(NULL, 5, TEXT("FORMATRECORD:\t"));
  2161. break;
  2162. default:
  2163. break;
  2164. }
  2165. if (AcmFormatGetText(lpWav->hAcm,
  2166. lpWav->lpwfx[iType], szText, SIZEOFARRAY(szText), 0) != 0)
  2167. ; // fSuccess = TraceFALSE(NULL);
  2168. else
  2169. {
  2170. TracePrintf_1(NULL, 5,
  2171. TEXT("%s\n"),
  2172. (LPTSTR) szText);
  2173. #if 0
  2174. WavFormatDump(lpWav->lpwfx[iType]);
  2175. #endif
  2176. }
  2177. }
  2178. }
  2179. if (WavTempResume(hWav, wStatePrev, idDevPrev) != 0)
  2180. fSuccess = TraceFALSE(NULL);
  2181. }
  2182. return fSuccess ? 0 : -1;
  2183. }
  2184. // WavChooseFormat - choose and set audio format from dialog box
  2185. // <hWav> (i) handle returned from WavOpen
  2186. // <hwndOwner> (i) owner of dialog box
  2187. // NULL no owner
  2188. // <lpszTitle> (i) title of the dialog box
  2189. // NULL use default title ("Sound Selection")
  2190. // <dwFlags> (i) control flags
  2191. // WAV_FORMATFILE set format of data in file
  2192. // WAV_FORMATPLAY set format of output device
  2193. // WAV_FORMATRECORD set format of input device
  2194. // WAV_FORMATALL set all formats
  2195. // return 0 if success
  2196. //
  2197. int DLLEXPORT WINAPI WavChooseFormat(HWAV hWav, HWND hwndOwner, LPCTSTR lpszTitle, DWORD dwFlags)
  2198. {
  2199. BOOL fSuccess = TRUE;
  2200. LPWAV lpWav;
  2201. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2202. fSuccess = TraceFALSE(NULL);
  2203. else
  2204. {
  2205. LPWAVEFORMATEX lpwfx = NULL;
  2206. LPWAVEFORMATEX lpwfxNew = NULL;
  2207. DWORD dwFlagsChoose = 0;
  2208. // see which format we are choosing
  2209. //
  2210. if (dwFlags & WAV_FORMATFILE)
  2211. lpwfx = lpWav->lpwfx[FORMATFILE];
  2212. else if (dwFlags & WAV_FORMATPLAY)
  2213. lpwfx = lpWav->lpwfx[FORMATPLAY];
  2214. else if (dwFlags & WAV_FORMATRECORD)
  2215. lpwfx = lpWav->lpwfx[FORMATRECORD];
  2216. #if 0
  2217. // restrict choices if necessary
  2218. //
  2219. if (dwFlags == WAV_FORMATPLAY)
  2220. dwFlagsChoose |= ACM_FORMATPLAY;
  2221. if (dwFlags == WAV_FORMATRECORD)
  2222. dwFlagsChoose |= ACM_FORMATRECORD;
  2223. #endif
  2224. // get chosen format
  2225. //
  2226. if ((lpwfxNew = AcmFormatChoose(lpWav->hAcm,
  2227. hwndOwner, lpszTitle, lpwfx, dwFlagsChoose)) == NULL)
  2228. ; // no format chosen
  2229. // set chosen format
  2230. //
  2231. else if (WavSetFormat(hWav, lpwfxNew, dwFlags) != 0)
  2232. fSuccess = TraceFALSE(NULL);
  2233. // free chosen format struct
  2234. //
  2235. if (lpwfxNew != NULL && WavFormatFree(lpwfxNew) != 0)
  2236. fSuccess = TraceFALSE(NULL);
  2237. }
  2238. return fSuccess ? 0 : -1;
  2239. }
  2240. // WavGetVolume - get current volume level
  2241. // <hWav> (i) handle returned from WavOpen
  2242. // <idDev> (i) wav output device id
  2243. // -1 use any suitable output device
  2244. // <dwFlags> (i) reserved; must be zero
  2245. // return volume level (0 minimum through 100 maximum, -1 if error)
  2246. //
  2247. int DLLEXPORT WINAPI WavGetVolume(HWAV hWav, int idDev, DWORD dwFlags)
  2248. {
  2249. BOOL fSuccess = TRUE;
  2250. LPWAV lpWav;
  2251. int nLevel;
  2252. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2253. fSuccess = TraceFALSE(NULL);
  2254. else
  2255. nLevel = lpWav->nVolumeLevel;
  2256. return fSuccess ? nLevel : -1;
  2257. }
  2258. // WavSetVolume - set current volume level
  2259. // <hWav> (i) handle returned from WavOpen
  2260. // <idDev> (i) wav output device id
  2261. // -1 use any suitable output device
  2262. // <nLevel> (i) volume level
  2263. // 0 minimum volume
  2264. // 100 maximum volume
  2265. // <dwFlags> (i) control flags
  2266. // WAVVOLUME_MIXER set volume through mixer device
  2267. // return 0 if success
  2268. //
  2269. int DLLEXPORT WINAPI WavSetVolume(HWAV hWav, int idDev, int nLevel, DWORD dwFlags)
  2270. {
  2271. BOOL fSuccess = TRUE;
  2272. LPWAV lpWav;
  2273. TracePrintf_4(NULL, 6,
  2274. TEXT("WavSetVolume(hWav=%p, idDev=%d, nLevel=%d, dwFlags=%08X)\n"),
  2275. hWav,
  2276. idDev,
  2277. nLevel,
  2278. dwFlags);
  2279. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2280. fSuccess = TraceFALSE(NULL);
  2281. else if (nLevel == lpWav->nVolumeLevel)
  2282. ; // nothing to be done
  2283. else if (dwFlags & WAVVOLUME_MIXER)
  2284. {
  2285. HWAVMIXER hWavMixer = NULL;
  2286. if ((hWavMixer = WavMixerInit(WAVMIXER_VERSION, lpWav->hInst,
  2287. (LPARAM) idDev, 0, 0, WAVMIXER_WAVEOUT)) == NULL)
  2288. fSuccess = TraceFALSE(NULL);
  2289. else if (WavMixerSetVolume(hWavMixer, nLevel, 0) < 0)
  2290. fSuccess = TraceFALSE(NULL);
  2291. if (hWavMixer != NULL && WavMixerTerm(hWavMixer) != 0)
  2292. fSuccess = TraceFALSE(NULL);
  2293. }
  2294. else if (!(dwFlags & WAVVOLUME_MIXER))
  2295. {
  2296. if (!WavOutSupportsVolume(lpWav->hWavOut, idDev))
  2297. fSuccess = TraceFALSE(NULL);
  2298. // set the device volume if we are currently playing
  2299. //
  2300. else if (WavGetState(hWav) == WAV_PLAYING &&
  2301. WavOutSetVolume(lpWav->hWavOut, idDev, nLevel) != 0)
  2302. fSuccess = TraceFALSE(NULL);
  2303. }
  2304. if (fSuccess)
  2305. lpWav->nVolumeLevel = nLevel;
  2306. return fSuccess ? 0 : -1;
  2307. }
  2308. // WavSupportsVolume - check if audio can be played at specified volume
  2309. // <hWav> (i) handle returned from WavOpen
  2310. // <idDev> (i) wav output device id
  2311. // -1 any suitable output device
  2312. // <nLevel> (i) volume level
  2313. // 0 minimum volume
  2314. // 100 maximum volume
  2315. // <dwFlags> (i) control flags
  2316. // WAVVOLUME_MIXER check volume support through mixer device
  2317. // return TRUE if supported
  2318. //
  2319. BOOL DLLEXPORT WINAPI WavSupportsVolume(HWAV hWav, int idDev, int nLevel, DWORD dwFlags)
  2320. {
  2321. BOOL fSuccess = TRUE;
  2322. BOOL fSupportsVolume = FALSE;
  2323. LPWAV lpWav;
  2324. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2325. fSuccess = TraceFALSE(NULL);
  2326. else if (dwFlags & WAVVOLUME_MIXER)
  2327. {
  2328. HWAVMIXER hWavMixer = NULL;
  2329. if ((hWavMixer = WavMixerInit(WAVMIXER_VERSION, lpWav->hInst,
  2330. (LPARAM) idDev, 0, 0, WAVMIXER_WAVEOUT)) == NULL)
  2331. fSuccess = TraceFALSE(NULL);
  2332. else if (WavMixerSupportsVolume(hWavMixer, 0))
  2333. fSupportsVolume = TRUE;
  2334. if (hWavMixer != NULL && WavMixerTerm(hWavMixer) != 0)
  2335. fSuccess = TraceFALSE(NULL);
  2336. }
  2337. else if (!(dwFlags & WAVVOLUME_MIXER))
  2338. {
  2339. // see if the device driver supports volume directly
  2340. //
  2341. if (WavOutSupportsVolume(NULL, idDev))
  2342. fSupportsVolume = TRUE;
  2343. }
  2344. return fSuccess ? fSupportsVolume : FALSE;
  2345. }
  2346. // WavGetSpeed - get current speed level
  2347. // <hWav> (i) handle returned from WavOpen
  2348. // <idDev> (i) wav output device id
  2349. // -1 use any suitable output device
  2350. // <dwFlags> (i) reserved; must be zero
  2351. // return speed level (100 is normal, 50 is half, 200 is double, -1 if error)
  2352. //
  2353. int DLLEXPORT WINAPI WavGetSpeed(HWAV hWav, int idDev, DWORD dwFlags)
  2354. {
  2355. BOOL fSuccess = TRUE;
  2356. LPWAV lpWav;
  2357. int nLevel;
  2358. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2359. fSuccess = TraceFALSE(NULL);
  2360. else
  2361. nLevel = lpWav->nSpeedLevel;
  2362. return fSuccess ? nLevel : -1;
  2363. }
  2364. // WavSetSpeed - set current speed level
  2365. // <hWav> (i) handle returned from WavOpen
  2366. // <idDev> (i) wav output device id
  2367. // -1 use any suitable output device
  2368. // <nLevel> (i) speed level
  2369. // 50 half speed
  2370. // 100 normal speed
  2371. // 200 double speed, etc.
  2372. // <dwFlags> (i) control flags
  2373. #ifdef AVTSM
  2374. // WAVSPEED_NOTSM do not use time scale modification engine
  2375. #endif
  2376. // WAVSPEED_NOPLAYBACKRATE do not use device driver playback rate
  2377. // WAVSPEED_NOFORMATADJUST do not use adjusted format to open device
  2378. // WAVSPEED_NOACM do not use audio compression manager
  2379. // return 0 if success
  2380. //
  2381. // NOTE: In order to accomodate the specified speed change, it is _possible_
  2382. // that this function will in turn call WavSetFormat(hWav, ..., WAV_FORMATPLAY)
  2383. // to change the playback format of the specified file. You can prevent this
  2384. // side-effect by specifying the WAVSPEED_NOACM flag, but this reduces the likelihood
  2385. // that WavSetSpeed will succeed.
  2386. //
  2387. int DLLEXPORT WINAPI WavSetSpeed(HWAV hWav, int idDev, int nLevel, DWORD dwFlags)
  2388. {
  2389. BOOL fSuccess = TRUE;
  2390. LPWAV lpWav;
  2391. WORD wStatePrev;
  2392. int idDevPrev;
  2393. TracePrintf_4(NULL, 6,
  2394. TEXT("WavSetSpeed(hWav=%p, idDev=%d, nLevel=%d, dwFlags=%08X)\n"),
  2395. hWav,
  2396. idDev,
  2397. nLevel,
  2398. dwFlags);
  2399. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2400. fSuccess = TraceFALSE(NULL);
  2401. else if (nLevel == lpWav->nSpeedLevel)
  2402. ; // nothing to be done
  2403. else if (WavTempStop(hWav, &wStatePrev, &idDevPrev) != 0)
  2404. fSuccess = TraceFALSE(NULL);
  2405. else
  2406. {
  2407. if (nLevel == 100)
  2408. {
  2409. // normal speed is a special case
  2410. //
  2411. lpWav->nSpeedLevel = 100;
  2412. lpWav->dwFlagsSpeed = 0;
  2413. }
  2414. #ifdef AVTSM
  2415. else if (!(dwFlags & WAVSPEED_NOTSM) &&
  2416. WavSupportsSpeed(hWav, idDev, nLevel,
  2417. WAVSPEED_NOACM | WAVSPEED_NOFORMATADJUST | WAVSPEED_NOPLAYBACKRATE))
  2418. {
  2419. // use time scale modification engine
  2420. //
  2421. lpWav->nSpeedLevel = nLevel;
  2422. lpWav->dwFlagsSpeed = WAVSPEED_NOACM | WAVSPEED_NOFORMATADJUST | WAVSPEED_NOPLAYBACKRATE;
  2423. }
  2424. else if (!(dwFlags & WAVSPEED_NOTSM) &&
  2425. WavSupportsSpeed(hWav, idDev, nLevel,
  2426. WAVSPEED_NOFORMATADJUST | WAVSPEED_NOPLAYBACKRATE))
  2427. {
  2428. #if 1
  2429. WAVEFORMATEX wfxTsm;
  2430. // try a format that the tsm engine will handle
  2431. //
  2432. if (WavSetFormat(hWav, WavFormatPcm(
  2433. lpWav->lpwfx[FORMATPLAY]->nSamplesPerSec, 16, 1, &wfxTsm),
  2434. WAV_FORMATPLAY) != 0)
  2435. fSuccess = TraceFALSE(NULL);
  2436. #endif
  2437. // use time scale modification engine with adjusted format
  2438. //
  2439. lpWav->nSpeedLevel = nLevel;
  2440. lpWav->dwFlagsSpeed = WAVSPEED_NOFORMATADJUST | WAVSPEED_NOPLAYBACKRATE;
  2441. }
  2442. #endif
  2443. else if (!(dwFlags & WAVSPEED_NOPLAYBACKRATE) &&
  2444. WavSupportsSpeed(hWav, idDev, nLevel,
  2445. WAVSPEED_NOACM | WAVSPEED_NOFORMATADJUST | WAVSPEED_NOTSM))
  2446. {
  2447. // device supports playback rate directly
  2448. //
  2449. lpWav->nSpeedLevel = nLevel;
  2450. lpWav->dwFlagsSpeed = WAVSPEED_NOACM | WAVSPEED_NOFORMATADJUST | WAVSPEED_NOTSM;
  2451. }
  2452. else if (!(dwFlags & WAVSPEED_NOFORMATADJUST) &&
  2453. WavSupportsSpeed(hWav, idDev, nLevel,
  2454. WAVSPEED_NOACM | WAVSPEED_NOPLAYBACKRATE | WAVSPEED_NOTSM))
  2455. {
  2456. // device supports adjusted format without acm
  2457. //
  2458. lpWav->nSpeedLevel = nLevel;
  2459. lpWav->dwFlagsSpeed = WAVSPEED_NOACM | WAVSPEED_NOPLAYBACKRATE | WAVSPEED_NOTSM;
  2460. }
  2461. else if (!(dwFlags & WAVSPEED_NOFORMATADJUST) && !(dwFlags & WAVSPEED_NOACM) &&
  2462. WavSupportsSpeed(hWav, idDev, nLevel,
  2463. WAVSPEED_NOPLAYBACKRATE | WAVSPEED_NOTSM))
  2464. {
  2465. #if 1
  2466. LPWAVEFORMATEX lpwfxPlay = NULL;
  2467. if ((lpwfxPlay = WavFormatDup(lpWav->lpwfx[FORMATPLAY])) == NULL)
  2468. fSuccess = TraceFALSE(NULL);
  2469. // we must double sample rate so that adjusted format works
  2470. //
  2471. else if (nLevel < 100 &&
  2472. WavFormatSpeedAdjust(lpwfxPlay, 200, 0) != 0)
  2473. {
  2474. fSuccess = TraceFALSE(NULL);
  2475. }
  2476. // we must halve sample rate so that adjusted format works
  2477. //
  2478. else if (nLevel > 100 &&
  2479. WavFormatSpeedAdjust(lpwfxPlay, 50, 0) != 0)
  2480. {
  2481. fSuccess = TraceFALSE(NULL);
  2482. }
  2483. else if (WavSetFormat(hWav, lpwfxPlay, WAV_FORMATPLAY) != 0)
  2484. fSuccess = TraceFALSE(NULL);
  2485. if (lpwfxPlay != NULL && WavFormatFree(lpwfxPlay) != 0)
  2486. fSuccess = TraceFALSE(NULL);
  2487. else
  2488. lpwfxPlay = NULL;
  2489. #endif
  2490. // device supports adjusted format with acm
  2491. //
  2492. lpWav->nSpeedLevel = nLevel;
  2493. lpWav->dwFlagsSpeed = WAVSPEED_NOPLAYBACKRATE | WAVSPEED_NOTSM;
  2494. }
  2495. else
  2496. fSuccess = TraceFALSE(NULL);
  2497. if (WavTempResume(hWav, wStatePrev, idDevPrev) != 0)
  2498. fSuccess = TraceFALSE(NULL);
  2499. }
  2500. return fSuccess ? 0 : -1;
  2501. }
  2502. // WavSupportsSpeed - check if audio can be played at specified speed
  2503. // <hWav> (i) handle returned from WavOpen
  2504. // <idDev> (i) wav output device id
  2505. // -1 any suitable output device
  2506. // <nLevel> (i) speed level
  2507. // 50 half speed
  2508. // 100 normal speed
  2509. // 200 double speed, etc.
  2510. // <dwFlags> (i) control flags
  2511. #ifdef AVTSM
  2512. // WAVSPEED_NOTSM do not use time scale modification engine
  2513. #endif
  2514. // WAVSPEED_NOPLAYBACKRATE do not use device driver playback rate
  2515. // WAVSPEED_NOFORMATADJUST do not use adjusted format to open device
  2516. // WAVSPEED_NOACM do not use audio compression manager
  2517. // return TRUE if supported
  2518. //
  2519. BOOL DLLEXPORT WINAPI WavSupportsSpeed(HWAV hWav, int idDev, int nLevel, DWORD dwFlags)
  2520. {
  2521. BOOL fSuccess = TRUE;
  2522. BOOL fSupportsSpeed = FALSE;
  2523. LPWAV lpWav;
  2524. #ifdef AVTSM
  2525. WAVEFORMATEX wfxTsm;
  2526. #endif
  2527. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2528. fSuccess = TraceFALSE(NULL);
  2529. // normal speed is a special case
  2530. //
  2531. else if (nLevel == 100 &&
  2532. WavOutSupportsFormat(NULL, idDev, lpWav->lpwfx[FORMATPLAY]))
  2533. {
  2534. fSupportsSpeed = TRUE;
  2535. }
  2536. #ifdef AVTSM
  2537. // see if time scale modification will work
  2538. //
  2539. else if (!(dwFlags & WAVSPEED_NOTSM) &&
  2540. TsmSupportsSpeed(nLevel, lpWav->lpwfx[FORMATPLAY], 0))
  2541. {
  2542. fSupportsSpeed = TRUE;
  2543. }
  2544. // see if time scale modification will work with PCM 16-bit mono
  2545. //
  2546. else if (!(dwFlags & WAVSPEED_NOTSM) && !(dwFlags & WAVSPEED_NOACM) &&
  2547. TsmSupportsSpeed(nLevel, WavFormatPcm(
  2548. lpWav->lpwfx[FORMATPLAY]->nSamplesPerSec, 16, 1, &wfxTsm), 0))
  2549. {
  2550. fSupportsSpeed = TRUE;
  2551. }
  2552. #endif
  2553. // see if the device driver supports playback rate directly
  2554. //
  2555. else if (!(dwFlags & WAVSPEED_NOPLAYBACKRATE) &&
  2556. WavOutSupportsSpeed(NULL, idDev))
  2557. {
  2558. fSupportsSpeed = TRUE;
  2559. }
  2560. else if (!(dwFlags & WAVSPEED_NOFORMATADJUST))
  2561. {
  2562. LPWAVEFORMATEX lpwfx = NULL;
  2563. if ((lpwfx = WavFormatDup(lpWav->lpwfx[FORMATPLAY])) == NULL)
  2564. fSuccess = TraceFALSE(NULL);
  2565. else if (WavFormatSpeedAdjust(lpwfx, nLevel, 0) != 0)
  2566. fSuccess = TraceTRUE(NULL);
  2567. // see if device supports playback using adjusted format
  2568. //
  2569. else if (WavOutSupportsFormat(NULL, idDev, lpwfx))
  2570. {
  2571. fSupportsSpeed = TRUE;
  2572. }
  2573. if (lpwfx != NULL && WavFormatFree(lpwfx) != 0)
  2574. fSuccess = TraceFALSE(NULL);
  2575. else
  2576. lpwfx = NULL;
  2577. // as a last resort, see if doubling or halving the sample rate
  2578. // would allow us to use a wave format that has been adjusted
  2579. //
  2580. if (!fSupportsSpeed && !(dwFlags & WAVSPEED_NOACM))
  2581. {
  2582. LPWAVEFORMATEX lpwfx = NULL;
  2583. if (nLevel < 100)
  2584. nLevel = nLevel * 100 / 50;
  2585. else if (nLevel > 100)
  2586. nLevel = nLevel * 100 / 200;
  2587. if ((lpwfx = WavFormatDup(lpWav->lpwfx[FORMATPLAY])) == NULL)
  2588. fSuccess = TraceFALSE(NULL);
  2589. else if (WavFormatSpeedAdjust(lpwfx, nLevel, 0) != 0)
  2590. fSuccess = TraceTRUE(NULL);
  2591. // see if device supports playback using adjusted format
  2592. //
  2593. else if (WavOutSupportsFormat(NULL, idDev, lpwfx))
  2594. {
  2595. fSupportsSpeed = TRUE;
  2596. }
  2597. if (lpwfx != NULL && WavFormatFree(lpwfx) != 0)
  2598. fSuccess = TraceFALSE(NULL);
  2599. else
  2600. lpwfx = NULL;
  2601. }
  2602. }
  2603. return fSuccess ? fSupportsSpeed : FALSE;
  2604. }
  2605. // WavGetChunks - get chunk count and size
  2606. // <hWav> (i) handle returned from WavOpen
  2607. // NULL get default chunk count and size
  2608. // <lpcChunks> (o) buffer to hold chunk count
  2609. // NULL do not get chunk count
  2610. // <lpmsChunkSize> (o) buffer to hold chunk size
  2611. // NULL do not get chunk size
  2612. // <fWavOut> (i) TRUE for playback, FALSE for recording
  2613. // return 0 if success
  2614. //
  2615. int DLLEXPORT WINAPI WavGetChunks(HWAV hWav,
  2616. int FAR *lpcChunks, long FAR *lpmsChunkSize, BOOL fWavOut)
  2617. {
  2618. BOOL fSuccess = TRUE;
  2619. LPWAV lpWav;
  2620. if (hWav != NULL && (lpWav = WavGetPtr(hWav)) == NULL)
  2621. fSuccess = TraceFALSE(NULL);
  2622. else
  2623. {
  2624. if (lpcChunks != NULL)
  2625. {
  2626. if (hWav == NULL)
  2627. {
  2628. *lpcChunks = fWavOut ?
  2629. cPlayChunksDefault : cRecordChunksDefault;
  2630. }
  2631. else
  2632. {
  2633. *lpcChunks = fWavOut ?
  2634. lpWav->cPlayChunks : lpWav->cRecordChunks;
  2635. }
  2636. }
  2637. if (lpmsChunkSize != NULL)
  2638. {
  2639. if (hWav == NULL)
  2640. {
  2641. *lpmsChunkSize = fWavOut ?
  2642. msPlayChunkSizeDefault : msRecordChunkSizeDefault;
  2643. }
  2644. else
  2645. {
  2646. *lpmsChunkSize = fWavOut ?
  2647. lpWav->msPlayChunkSize : lpWav->msRecordChunkSize;
  2648. }
  2649. }
  2650. }
  2651. return fSuccess ? 0 : -1;
  2652. }
  2653. // WavSetChunks - set chunk count and size
  2654. // <hWav> (i) handle returned from WavOpen
  2655. // NULL set default chunk count and size
  2656. // <cChunks> (i) number of chunks in device queue
  2657. // -1 do not set chunk count
  2658. // <msChunkSize> (i) chunk size in milleseconds
  2659. // -1 do not set chunk size
  2660. // <fWavOut> (i) TRUE for playback, FALSE for recording
  2661. // return 0 if success
  2662. //
  2663. int DLLEXPORT WINAPI WavSetChunks(HWAV hWav, int cChunks, long msChunkSize, BOOL fWavOut)
  2664. {
  2665. BOOL fSuccess = TRUE;
  2666. LPWAV lpWav;
  2667. if (hWav != NULL && (lpWav = WavGetPtr(hWav)) == NULL)
  2668. fSuccess = TraceFALSE(NULL);
  2669. else if (fWavOut && cChunks != -1 &&
  2670. (cChunks < PLAYCHUNKCOUNT_MIN ||
  2671. cChunks > PLAYCHUNKCOUNT_MAX))
  2672. fSuccess = TraceFALSE(NULL);
  2673. else if (fWavOut && msChunkSize != -1 &&
  2674. (msChunkSize < PLAYCHUNKSIZE_MIN ||
  2675. msChunkSize > PLAYCHUNKSIZE_MAX))
  2676. fSuccess = TraceFALSE(NULL);
  2677. else if (!fWavOut && cChunks != -1 &&
  2678. (cChunks < RECORDCHUNKCOUNT_MIN ||
  2679. cChunks > RECORDCHUNKCOUNT_MAX))
  2680. fSuccess = TraceFALSE(NULL);
  2681. else if (!fWavOut && msChunkSize != -1 &&
  2682. (msChunkSize < RECORDCHUNKSIZE_MIN ||
  2683. msChunkSize > RECORDCHUNKSIZE_MAX))
  2684. fSuccess = TraceFALSE(NULL);
  2685. else
  2686. {
  2687. if (fWavOut && cChunks != -1)
  2688. {
  2689. if (hWav == NULL)
  2690. cPlayChunksDefault = cChunks;
  2691. else
  2692. lpWav->cPlayChunks = cChunks;
  2693. }
  2694. if (fWavOut && msChunkSize != -1)
  2695. {
  2696. if (hWav == NULL)
  2697. msPlayChunkSizeDefault = msChunkSize;
  2698. else
  2699. lpWav->msPlayChunkSize = msChunkSize;
  2700. }
  2701. if (!fWavOut && cChunks != -1)
  2702. {
  2703. if (hWav == NULL)
  2704. cRecordChunksDefault = cChunks;
  2705. else
  2706. lpWav->cRecordChunks = cChunks;
  2707. }
  2708. if (!fWavOut && msChunkSize != -1)
  2709. {
  2710. if (hWav == NULL)
  2711. msRecordChunkSizeDefault = msChunkSize;
  2712. else
  2713. lpWav->msRecordChunkSize = msChunkSize;
  2714. }
  2715. }
  2716. return fSuccess ? 0 : -1;
  2717. }
  2718. // WavCalcChunkSize - calculate chunk size in bytes
  2719. // <lpwfx> (i) wav format
  2720. // <msPlayChunkSize> (i) chunk size in milleseconds
  2721. // -1 default chunk size
  2722. // <fWavOut> (i) TRUE for playback, FALSE for recording
  2723. // return chunk size in bytes (-1 if success)
  2724. //
  2725. long DLLEXPORT WINAPI WavCalcChunkSize(LPWAVEFORMATEX lpwfx,
  2726. long msChunkSize, BOOL fWavOut)
  2727. {
  2728. BOOL fSuccess = TRUE;
  2729. long cbChunkSize;
  2730. if (msChunkSize == -1)
  2731. {
  2732. msChunkSize = fWavOut ?
  2733. PLAYCHUNKSIZE_DEFAULT : RECORDCHUNKSIZE_DEFAULT;
  2734. }
  2735. if (!WavFormatIsValid(lpwfx) != 0)
  2736. fSuccess = TraceFALSE(NULL);
  2737. else if (fWavOut &&
  2738. (msChunkSize < PLAYCHUNKSIZE_MIN ||
  2739. msChunkSize > PLAYCHUNKSIZE_MAX))
  2740. fSuccess = TraceFALSE(NULL);
  2741. else if (!fWavOut &&
  2742. (msChunkSize < RECORDCHUNKSIZE_MIN ||
  2743. msChunkSize > RECORDCHUNKSIZE_MAX))
  2744. fSuccess = TraceFALSE(NULL);
  2745. #if 0 // this only works for PCM
  2746. else
  2747. {
  2748. int nBytesPerSample;
  2749. // calculate bytes per sample
  2750. //
  2751. nBytesPerSample = lpwfx->nChannels *
  2752. (((lpwfx->wBitsPerSample - 1) / 8) + 1);
  2753. // calculate chunk size in bytes
  2754. //
  2755. cbChunkSize = msChunkSize *
  2756. lpwfx->nSamplesPerSec * nBytesPerSample / 1000L;
  2757. // round up to nearest 1K bytes
  2758. //
  2759. cbChunkSize = 1024L * ((cbChunkSize + 1023L) / 1024L);
  2760. }
  2761. #else
  2762. else
  2763. {
  2764. long lBlockAlign;
  2765. // calculate chunk size in bytes
  2766. //
  2767. cbChunkSize = msChunkSize * lpwfx->nAvgBytesPerSec / 1000L;
  2768. // round up to nearest block boundary
  2769. //
  2770. if ((lBlockAlign = (long) lpwfx->nBlockAlign) > 0)
  2771. {
  2772. cbChunkSize = lBlockAlign *
  2773. ((cbChunkSize + lBlockAlign - 1) / lBlockAlign);
  2774. }
  2775. }
  2776. #endif
  2777. return fSuccess ? cbChunkSize : -1;
  2778. }
  2779. // WavCopy - copy data from one open wav file to another
  2780. // <hWavSrc> (i) source handle returned from WavOpen
  2781. // <hWavDst> (i) destination handle returned from WavOpen
  2782. // <hpBuf> (o) pointer to copy buffer
  2783. // NULL allocate buffer internally
  2784. // <sizBuf> (i) size of copy buffer
  2785. // -1 default buffer size (16K)
  2786. // <lpfnUserAbort> (i) function that returns TRUE if user aborts
  2787. // NULL don't check for user abort
  2788. // <dwUser> (i) parameter passed to <lpfnUserAbort>
  2789. // <dwFlags> (i) control flags
  2790. // WAV_NOACM do not use audio compression manager
  2791. // return 0 if success (-1 if error, +1 if user abort)
  2792. //
  2793. int DLLEXPORT WINAPI WavCopy(HWAV hWavSrc, HWAV hWavDst,
  2794. void _huge *hpBuf, long sizBuf, USERABORTPROC lpfnUserAbort, DWORD dwUser, DWORD dwFlags)
  2795. {
  2796. BOOL fSuccess = TRUE;
  2797. LPWAV lpWavSrc;
  2798. LPWAV lpWavDst;
  2799. LPWAVEFORMATEX lpwfxSrc;
  2800. LPWAVEFORMATEX lpwfxDst;
  2801. BOOL fFreeBuf = (BOOL) (hpBuf == NULL);
  2802. BOOL fUserAbort = FALSE;
  2803. // calc buffer size if none supplied
  2804. //
  2805. if (sizBuf <= 0)
  2806. sizBuf = 16 * 1024;
  2807. if ((lpWavSrc = WavGetPtr(hWavSrc)) == NULL)
  2808. fSuccess = TraceFALSE(NULL);
  2809. else if ((lpWavDst = WavGetPtr(hWavDst)) == NULL)
  2810. fSuccess = TraceFALSE(NULL);
  2811. // get source file format
  2812. //
  2813. else if ((lpwfxSrc = WavGetFormat(hWavSrc, WAV_FORMATFILE)) == NULL)
  2814. fSuccess = TraceFALSE(NULL);
  2815. // get destination file format
  2816. //
  2817. else if ((lpwfxDst = WavGetFormat(hWavDst, WAV_FORMATFILE)) == NULL)
  2818. fSuccess = TraceFALSE(NULL);
  2819. // allocate buffer if none supplied
  2820. //
  2821. else if (hpBuf == NULL && (hpBuf = MemAlloc(NULL, sizBuf, 0)) == NULL)
  2822. fSuccess = TraceFALSE(NULL);
  2823. // do simple copy if no conversion is required
  2824. //
  2825. else if (WavFormatCmp(lpwfxSrc, lpwfxDst) == 0)
  2826. {
  2827. long lBytesReadTotal = 0;
  2828. long lBytesTotal = max(1, lpWavSrc->cbData - lpWavSrc->lDataPos);
  2829. while (fSuccess)
  2830. {
  2831. long lBytesRead;
  2832. long lBytesWritten;
  2833. // check for user abort, notify of percent complete
  2834. //
  2835. if (lpfnUserAbort != NULL &&
  2836. (*lpfnUserAbort)(dwUser, (int) (lBytesReadTotal / lBytesTotal)))
  2837. {
  2838. fUserAbort = TRUE;
  2839. break;
  2840. }
  2841. // fill copy buffer
  2842. //
  2843. else if ((lBytesRead = WavRead(hWavSrc, hpBuf, sizBuf)) < 0)
  2844. fSuccess = TraceFALSE(NULL);
  2845. // keep running total
  2846. //
  2847. else if ((lBytesReadTotal += lBytesRead) < 0)
  2848. fSuccess = TraceFALSE(NULL);
  2849. // check for end of file
  2850. //
  2851. else if (lBytesRead == 0)
  2852. break; // eof
  2853. // write the buffer
  2854. //
  2855. else if ((lBytesWritten = WavWrite(hWavDst, hpBuf, lBytesRead)) < 0)
  2856. fSuccess = TraceFALSE(NULL);
  2857. }
  2858. // notify of 100% complete
  2859. //
  2860. if (fSuccess && lpfnUserAbort != NULL)
  2861. (*lpfnUserAbort)(dwUser, 100);
  2862. }
  2863. // different formats require conversion during copy
  2864. //
  2865. else
  2866. {
  2867. long lBytesReadTotal = 0;
  2868. long lBytesTotal = max(1, lpWavSrc->cbData - lpWavSrc->lDataPos);
  2869. HACM hAcm = NULL;
  2870. long sizBufRead;
  2871. void _huge *hpBufRead = NULL;
  2872. // turn on WAV_NOACM flag if either file was opened with it
  2873. //
  2874. if ((lpWavSrc->dwFlags & WAV_NOACM) ||
  2875. (lpWavDst->dwFlags & WAV_NOACM))
  2876. dwFlags |= WAV_NOACM;
  2877. // start acm engine
  2878. //
  2879. if ((hAcm = AcmInit(ACM_VERSION, lpWavSrc->hInst,
  2880. (dwFlags & WAV_NOACM) ? ACM_NOACM : 0)) == NULL)
  2881. fSuccess = TraceFALSE(NULL);
  2882. // start conversion engine
  2883. //
  2884. else if (AcmConvertInit(hAcm, lpwfxSrc, lpwfxDst, NULL, 0) != 0)
  2885. fSuccess = TraceFALSE(NULL);
  2886. // calc how many bytes required for read buffer
  2887. //
  2888. else if ((sizBufRead = AcmConvertGetSizeSrc(hAcm, sizBuf)) <= 0)
  2889. fSuccess = TraceFALSE(NULL);
  2890. // allocate read buffer
  2891. //
  2892. else if ((hpBufRead = (void _huge *) MemAlloc(NULL,
  2893. sizBufRead, 0)) == NULL)
  2894. {
  2895. fSuccess = TraceFALSE(NULL);
  2896. }
  2897. // do the conversion during the copy
  2898. //
  2899. else while (fSuccess)
  2900. {
  2901. long lBytesRead;
  2902. long lBytesConverted;
  2903. long lBytesWritten;
  2904. // check for user abort, notify of percent complete
  2905. //
  2906. if (lpfnUserAbort != NULL &&
  2907. (*lpfnUserAbort)(dwUser, (int) (lBytesReadTotal / lBytesTotal)))
  2908. {
  2909. fUserAbort = TRUE;
  2910. break;
  2911. }
  2912. // fill read buffer
  2913. //
  2914. else if ((lBytesRead = WavRead(hWavSrc, hpBufRead, sizBufRead)) < 0)
  2915. fSuccess = TraceFALSE(NULL);
  2916. // keep running total
  2917. //
  2918. else if ((lBytesReadTotal += lBytesRead) < 0)
  2919. fSuccess = TraceFALSE(NULL);
  2920. // check for end of file
  2921. //
  2922. else if (lBytesRead == 0)
  2923. break; // eof
  2924. // convert the data
  2925. //
  2926. else if ((lBytesConverted = AcmConvert(hAcm,
  2927. hpBufRead, lBytesRead, hpBuf, sizBuf, 0)) < 0)
  2928. {
  2929. fSuccess = TraceFALSE(NULL);
  2930. }
  2931. // write the buffer
  2932. //
  2933. else if ((lBytesWritten = WavWrite(hWavDst,
  2934. hpBuf, lBytesConverted)) < 0)
  2935. {
  2936. fSuccess = TraceFALSE(NULL);
  2937. }
  2938. }
  2939. // notify of 100% complete
  2940. //
  2941. if (fSuccess && lpfnUserAbort != NULL)
  2942. (*lpfnUserAbort)(dwUser, 100);
  2943. // clean up
  2944. //
  2945. if (hpBufRead != NULL &&
  2946. (hpBufRead = MemFree(NULL, hpBufRead)) != NULL)
  2947. fSuccess = TraceFALSE(NULL);
  2948. // NOTE: AcmConvertTerm() is called from AcmTerm()
  2949. //
  2950. if (hAcm != NULL && AcmTerm(hAcm) != 0)
  2951. fSuccess = TraceFALSE(NULL);
  2952. }
  2953. // clean up
  2954. //
  2955. if (hpBuf != NULL && fFreeBuf &&
  2956. (hpBuf = MemFree(NULL, hpBuf)) != NULL)
  2957. fSuccess = TraceFALSE(NULL);
  2958. if (!fSuccess)
  2959. return -1;
  2960. else if (fUserAbort)
  2961. return +1;
  2962. else
  2963. return 0;
  2964. }
  2965. #ifdef AVTSM
  2966. // WavReadFormatSpeed - read data from wav file, then format it for speed
  2967. // <hWav> (i) handle returned from WavOpen
  2968. // <hpBufSpeed> (o) buffer to contain bytes read
  2969. // <sizBufSpeed> (i) size of buffer in bytes
  2970. // return bytes formatted for speed in <hpBuf> (-1 if error)
  2971. //
  2972. // NOTE: this function reads a block of data, and then converts it
  2973. // from the file format to the speed format, unless those formats
  2974. // are identical.
  2975. //
  2976. long DLLEXPORT WINAPI WavReadFormatSpeed(HWAV hWav, void _huge *hpBufSpeed, long sizBufSpeed)
  2977. {
  2978. BOOL fSuccess = TRUE;
  2979. LPWAV lpWav;
  2980. long sizBufPlay;
  2981. void _huge *hpBufPlay = NULL;
  2982. long lBytesPlay;
  2983. long lBytesSpeed = 0;
  2984. if ((lpWav = WavGetPtr(hWav)) == NULL)
  2985. fSuccess = TraceFALSE(NULL);
  2986. // see if speed conversion required
  2987. //
  2988. else if (lpWav->nSpeedLevel == 100 ||
  2989. (lpWav->dwFlagsSpeed & WAVSPEED_NOTSM))
  2990. {
  2991. // no, so just convert file format to play format
  2992. //
  2993. if ((lBytesSpeed = WavReadFormatPlay(hWav, hpBufSpeed, sizBufSpeed)) < 0)
  2994. fSuccess = TraceFALSE(NULL);
  2995. }
  2996. // calc how many bytes required for play buffer
  2997. //
  2998. else if ((sizBufPlay = sizBufSpeed * (lpWav->nSpeedLevel - 2) / 100) <= 0)
  2999. fSuccess = TraceFALSE(NULL);
  3000. // round down to nearest block boundary
  3001. //
  3002. else if (lpWav->lpwfx[FORMATPLAY]->nBlockAlign > 0 &&
  3003. (sizBufPlay = lpWav->lpwfx[FORMATPLAY]->nBlockAlign *
  3004. (sizBufPlay / lpWav->lpwfx[FORMATPLAY]->nBlockAlign)) <= 0)
  3005. {
  3006. fSuccess = TraceFALSE(NULL);
  3007. }
  3008. // allocate play buffer
  3009. //
  3010. else if ((hpBufPlay = (void _huge *) MemAlloc(NULL,
  3011. sizBufPlay, 0)) == NULL)
  3012. {
  3013. fSuccess = TraceFALSE(NULL);
  3014. }
  3015. // fill play buffer
  3016. //
  3017. else if ((lBytesPlay = WavReadFormatPlay(hWav, hpBufPlay, sizBufPlay)) < 0)
  3018. fSuccess = TraceFALSE(NULL);
  3019. // convert the data from playback format to speed format
  3020. //
  3021. else if (lBytesPlay > 0 &&
  3022. (lBytesSpeed = TsmConvert(lpWav->hTsm,
  3023. hpBufPlay, lBytesPlay, hpBufSpeed, sizBufSpeed, 0)) < 0)
  3024. {
  3025. fSuccess = TraceFALSE(NULL);
  3026. }
  3027. // clean up
  3028. //
  3029. if (hpBufPlay != NULL &&
  3030. (hpBufPlay = MemFree(NULL, hpBufPlay)) != NULL)
  3031. fSuccess = TraceFALSE(NULL);
  3032. return fSuccess ? lBytesSpeed : -1;
  3033. }
  3034. #endif
  3035. // WavReadFormatPlay - read data from wav file, then format it for playback
  3036. // <hWav> (i) handle returned from WavOpen
  3037. // <hpBufPlay> (o) buffer to contain bytes read
  3038. // <sizBufPlay> (i) size of buffer in bytes
  3039. // return bytes formatted for playback in <hpBuf> (-1 if error)
  3040. //
  3041. // NOTE: this function reads a block of data, and then converts it
  3042. // from the file format to the playback format, unless those formats
  3043. // are identical.
  3044. //
  3045. long DLLEXPORT WINAPI WavReadFormatPlay(HWAV hWav, void _huge *hpBufPlay, long sizBufPlay)
  3046. {
  3047. BOOL fSuccess = TRUE;
  3048. LPWAV lpWav;
  3049. long sizBufRead;
  3050. void _huge *hpBufRead = NULL;
  3051. long lBytesRead;
  3052. long lBytesPlay = 0;
  3053. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3054. fSuccess = TraceFALSE(NULL);
  3055. // see if format conversion required
  3056. //
  3057. else if (WavFormatCmp(lpWav->lpwfx[FORMATFILE],
  3058. lpWav->lpwfx[FORMATPLAY]) == 0)
  3059. {
  3060. // no, so just read block directly into the play buffer
  3061. //
  3062. if ((lBytesPlay = WavRead(hWav, hpBufPlay, sizBufPlay)) < 0)
  3063. fSuccess = TraceFALSE(NULL);
  3064. }
  3065. // calc how many bytes required for read buffer
  3066. //
  3067. else if ((sizBufRead = AcmConvertGetSizeSrc(lpWav->hAcm,
  3068. sizBufPlay)) <= 0)
  3069. fSuccess = TraceFALSE(NULL);
  3070. // allocate read buffer
  3071. //
  3072. else if ((hpBufRead = (void _huge *) MemAlloc(NULL,
  3073. sizBufRead, 0)) == NULL)
  3074. {
  3075. fSuccess = TraceFALSE(NULL);
  3076. }
  3077. // fill read buffer
  3078. //
  3079. else if ((lBytesRead = WavRead(hWav, hpBufRead, sizBufRead)) < 0)
  3080. fSuccess = TraceFALSE(NULL);
  3081. // convert the data from file format to playback format
  3082. //
  3083. else if (lBytesRead > 0 &&
  3084. (lBytesPlay = AcmConvert(lpWav->hAcm,
  3085. hpBufRead, lBytesRead, hpBufPlay, sizBufPlay, 0)) < 0)
  3086. {
  3087. fSuccess = TraceFALSE(NULL);
  3088. }
  3089. // clean up
  3090. //
  3091. if (hpBufRead != NULL &&
  3092. (hpBufRead = MemFree(NULL, hpBufRead)) != NULL)
  3093. fSuccess = TraceFALSE(NULL);
  3094. return fSuccess ? lBytesPlay : -1;
  3095. }
  3096. // WavWriteFormatRecord - write data to file after formatting it for file
  3097. // <hWav> (i) handle returned from WavOpen
  3098. // <hpBufRecord> (i) buffer containing bytes in record format
  3099. // <sizBufRecord> (i) size of buffer in bytes
  3100. // return bytes written (-1 if error)
  3101. //
  3102. // NOTE: this function converts a block of data from the record
  3103. // format to the file format (unless those formats are identical),
  3104. // and then writes the data to disk.
  3105. //
  3106. long DLLEXPORT WINAPI WavWriteFormatRecord(HWAV hWav, void _huge *hpBufRecord, long sizBufRecord)
  3107. {
  3108. BOOL fSuccess = TRUE;
  3109. LPWAV lpWav;
  3110. long sizBufWrite;
  3111. void _huge *hpBufWrite = NULL;
  3112. long lBytesWrite;
  3113. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3114. fSuccess = TraceFALSE(NULL);
  3115. // see if format conversion required
  3116. //
  3117. else if (WavFormatCmp(lpWav->lpwfx[FORMATRECORD],
  3118. lpWav->lpwfx[FORMATFILE]) == 0)
  3119. {
  3120. // no, so just write record buffer directly to the file
  3121. //
  3122. if ((lBytesWrite = WavWrite(hWav, hpBufRecord, sizBufRecord)) < 0)
  3123. fSuccess = TraceFALSE(NULL);
  3124. }
  3125. // calc how many bytes required for write buffer
  3126. //
  3127. else if ((sizBufWrite = AcmConvertGetSizeDst(lpWav->hAcm,
  3128. sizBufRecord)) <= 0)
  3129. fSuccess = TraceFALSE(NULL);
  3130. // allocate write buffer
  3131. //
  3132. else if ((hpBufWrite = (void _huge *) MemAlloc(NULL,
  3133. sizBufWrite, 0)) == NULL)
  3134. {
  3135. fSuccess = TraceFALSE(NULL);
  3136. }
  3137. // convert the data from record format to file format
  3138. //
  3139. else if ((lBytesWrite = AcmConvert(lpWav->hAcm,
  3140. hpBufRecord, sizBufRecord, hpBufWrite, sizBufWrite, 0)) < 0)
  3141. {
  3142. fSuccess = TraceFALSE(NULL);
  3143. }
  3144. // write buffer to disk
  3145. //
  3146. else if ((lBytesWrite = WavWrite(hWav, hpBufWrite, lBytesWrite)) < 0)
  3147. fSuccess = TraceFALSE(NULL);
  3148. // clean up
  3149. //
  3150. if (hpBufWrite != NULL &&
  3151. (hpBufWrite = MemFree(NULL, hpBufWrite)) != NULL)
  3152. fSuccess = TraceFALSE(NULL);
  3153. return fSuccess ? lBytesWrite : -1;
  3154. }
  3155. // WavGetOutputDevice - get handle to open wav output device
  3156. // <hWav> (i) handle returned from WavOpen
  3157. // return handle to wav output device (NULL if device not open or error)
  3158. //
  3159. // NOTE: this function is useful only during playback (after calling
  3160. // WavPlay() and before calling WavStop()). The returned device handle
  3161. // can then be used when calling the WavOut functions in wavout.h
  3162. //
  3163. HWAVOUT DLLEXPORT WINAPI WavGetOutputDevice(HWAV hWav)
  3164. {
  3165. BOOL fSuccess = TRUE;
  3166. LPWAV lpWav;
  3167. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3168. fSuccess = TraceFALSE(NULL);
  3169. return fSuccess ? lpWav->hWavOut : NULL;
  3170. }
  3171. // WavGetInputDevice - get handle to open wav input device
  3172. // <hWav> (i) handle returned from WavOpen
  3173. // return handle to wav input device (NULL if device not open or error)
  3174. //
  3175. // NOTE: this function is useful only during recording (after calling
  3176. // WavRecord() and before calling WavStop()). The returned device handle
  3177. // can then be used when calling the WavIn functions in wavin.h
  3178. //
  3179. HWAVIN DLLEXPORT WINAPI WavGetInputDevice(HWAV hWav)
  3180. {
  3181. BOOL fSuccess = TRUE;
  3182. LPWAV lpWav;
  3183. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3184. fSuccess = TraceFALSE(NULL);
  3185. return fSuccess ? lpWav->hWavIn : NULL;
  3186. }
  3187. // WavPlaySound - play wav file
  3188. // <dwVersion> (i) must be WAV_VERSION
  3189. // <hInst> (i) instance handle of calling module
  3190. // <idDev> (i) wav output device id
  3191. // -1 use any suitable output device
  3192. // <lpszFileName> (i) name of file to play
  3193. // NULL stop playing current sound, if any
  3194. // <lpwfx> (i) wave format
  3195. // NULL use format from header or default
  3196. // <lpIOProc> (i) address of i/o procedure to use
  3197. // NULL use default i/o procedure
  3198. // <lpadwInfo> (i) data to pass to i/o procedure during open
  3199. // NULL no data to pass
  3200. // <dwFlags> (i) control flags
  3201. // WAV_ASYNC return when playback starts (default)
  3202. // WAV_SYNC return after playback completes
  3203. // WAV_FILENAME <lpszFileName> points to a filename
  3204. // WAV_RESOURCE <lpszFileName> points to a resource
  3205. // WAV_MEMORY <lpszFileName> points to memory block
  3206. // WAV_NODEFAULT if sound not found, do not play default
  3207. // WAV_LOOP loop sound until WavPlaySound called again
  3208. // WAV_NOSTOP if device already playing, don't stop it
  3209. // WAV_NORIFF file has no RIFF/WAV header
  3210. // WAV_NOACM do not use audio compression manager
  3211. // WAV_OPENRETRY if output device busy, retry for up to 2 sec
  3212. #ifdef MULTITHREAD
  3213. // WAV_MULTITHREAD support multiple threads (default)
  3214. // WAV_SINGLETHREAD do not support multiple threads
  3215. // WAV_COINITIALIZE call CoInitialize in all secondary threads
  3216. #endif
  3217. // return 0 if success
  3218. //
  3219. // NOTE: if WAV_NORIFF is specified in <dwFlags>, then the
  3220. // <lpwfx> parameter must be specified. If <lpwfx> is NULL, the
  3221. // current default format is assumed.
  3222. // WavSetFormat() can be used to set or override the defaults.
  3223. //
  3224. // NOTE: if WAV_FILENAME is specified in <dwFlags>, then <lpszFileName>
  3225. // must point to a file name.
  3226. //
  3227. // NOTE: if WAV_RESOURCE is specified in <dwFlags>, then <lpszFileName>
  3228. // must point to a WAVE resource in the module specified by <hInst>.
  3229. // If the first character of the string is a pound sign (#), the remaining
  3230. // characters represent a decimal number that specifies the resource id.
  3231. //
  3232. // NOTE: if WAV_MEMORY is specified in <dwFlags>, then <lpszFileName>
  3233. // must be a pointer to a memory block containing a wav file image.
  3234. // The pointer must be obtained by calling MemAlloc().
  3235. //
  3236. // NOTE: if neither WAV_FILENAME, WAV_RESOURCE, or WAV_MEMORY is specified
  3237. // in <dwFlags>, the [sounds] section of win.ini or the registry is
  3238. // searched for an entry matching <lpszFileName>. If no matching entry
  3239. // is found, <lpszFileName> is assumed to be a file name.
  3240. //
  3241. // NOTE: if WAV_NODEFAULT is specified in <dwFlags>, no default sound
  3242. // will be played. Unless this flag is specified, the default system
  3243. // event sound entry will be played if the sound specified in
  3244. // <lpszFileName> is not found.
  3245. //
  3246. // NOTE: if WAV_LOOP is specified in <dwFlags>, the sound specified in
  3247. // <lpszFileName> will be played repeatedly, until WavPlaySound() is
  3248. // called again. The WAV_ASYNC flag must be specified when using this flag.
  3249. //
  3250. // NOTE: if WAV_NOSTOP is specified in <dwFlags>, and the device specified
  3251. // by <idDev> is already in use, this function returns without playing.
  3252. // Unless this flag is specified, the specified device will be stopped
  3253. // so that the new sound can be played.
  3254. //
  3255. // NOTE: if <lpIOProc> is not NULL, this i/o procedure will be called
  3256. // for opening, closing, reading, writing, and seeking the wav file.
  3257. // If <lpadwInfo> is not NULL, this array of three (3) DWORDs will be
  3258. // passed to the i/o procedure when the wav file is opened.
  3259. // See the Windows mmioOpen() and mmioInstallIOProc() function for details
  3260. // on these parameters. Also, the WAV_MEMORY and WAV_RESOURCE flags may
  3261. // only be used when <lpIOProc> is NULL.
  3262. //
  3263. int DLLEXPORT WINAPI WavPlaySound(DWORD dwVersion, HINSTANCE hInst,
  3264. int idDev, LPCTSTR lpszFileName, LPWAVEFORMATEX lpwfx,
  3265. LPMMIOPROC lpIOProc, DWORD FAR *lpadwInfo, DWORD dwFlags)
  3266. {
  3267. BOOL fSuccess = TRUE;
  3268. HWAV hWav = NULL;
  3269. LPCTSTR lpszSound = lpszFileName;
  3270. TCHAR szSound[_MAX_PATH];
  3271. // stop current sound if necessary
  3272. //
  3273. if (lpszFileName == NULL && WavStopOutputDevice(idDev, dwFlags) != 0)
  3274. fSuccess = TraceFALSE(NULL);
  3275. if (lpszSound != NULL)
  3276. {
  3277. // search win.ini or registry if necessary
  3278. //
  3279. if (!(dwFlags & WAV_FILENAME) &&
  3280. !(dwFlags & WAV_RESOURCE) &&
  3281. !(dwFlags & WAV_MEMORY))
  3282. {
  3283. if (GetProfileString(TEXT("Sounds"), lpszFileName, TEXT(""),
  3284. szSound, SIZEOFARRAY(szSound)) > 0)
  3285. {
  3286. LPTSTR lpszComma;
  3287. // ignore text description starting with comma
  3288. //
  3289. if ((lpszComma = StrChr(szSound, ',')) != NULL)
  3290. *lpszComma = '\0';
  3291. if (*szSound != '\0')
  3292. lpszSound = szSound;
  3293. }
  3294. }
  3295. // open sound
  3296. //
  3297. if ((hWav = WavOpen(WAV_VERSION, hInst, lpszSound, lpwfx,
  3298. lpIOProc, lpadwInfo, dwFlags | WAV_READ)) == NULL)
  3299. {
  3300. // play default sound unless WAV_NODEFAULT flag set
  3301. //
  3302. if (!(dwFlags & WAV_NODEFAULT))
  3303. {
  3304. // find system default sound
  3305. //
  3306. if (GetProfileString(TEXT("Sounds"), TEXT("SystemDefault"), TEXT(""),
  3307. szSound, SIZEOFARRAY(szSound)) > 0)
  3308. {
  3309. LPTSTR lpszComma;
  3310. // ignore text description starting with comma
  3311. //
  3312. if ((lpszComma = StrChr(szSound, ',')) != NULL)
  3313. *lpszComma = '\0';
  3314. // open system default sound
  3315. //
  3316. if (*szSound != '\0' &&
  3317. (hWav = WavOpen(WAV_VERSION, hInst, szSound,
  3318. NULL, NULL, NULL, WAV_READ)) == NULL)
  3319. fSuccess = TraceFALSE(NULL);
  3320. }
  3321. }
  3322. }
  3323. // play the sound
  3324. //
  3325. if (fSuccess && hWav != NULL)
  3326. {
  3327. if (dwFlags & WAV_ASYNC)
  3328. dwFlags |= WAV_PLAYASYNC;
  3329. if (dwFlags & WAV_SYNC)
  3330. dwFlags |= WAV_PLAYSYNC;
  3331. if (WavPlay(hWav, idDev, dwFlags | WAV_AUTOCLOSE) != 0)
  3332. fSuccess = TraceFALSE(NULL);
  3333. }
  3334. // clean up
  3335. //
  3336. if (!fSuccess && hWav != NULL && WavClose(hWav) != 0)
  3337. fSuccess = TraceFALSE(NULL);
  3338. }
  3339. return fSuccess ? 0 : -1;
  3340. }
  3341. // WavSendMessage - send a user-defined message to the i/o procedure
  3342. // <hWav> (i) handle returned from WavOpen
  3343. // <wMsg> (i) user-defined message id
  3344. // <lParam1> (i) parameter for the message
  3345. // <lParam2> (i) parameter for the message
  3346. // return value from the i/o procedure (0 if error or unrecognized message)
  3347. //
  3348. LRESULT DLLEXPORT WINAPI WavSendMessage(HWAV hWav,
  3349. UINT wMsg, LPARAM lParam1, LPARAM lParam2)
  3350. {
  3351. BOOL fSuccess = TRUE;
  3352. LPWAV lpWav;
  3353. LRESULT lResult;
  3354. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3355. fSuccess = TraceFALSE(NULL);
  3356. else if (lpWav->hmmio == NULL)
  3357. fSuccess = TraceFALSE(NULL);
  3358. else
  3359. lResult = mmioSendMessage(lpWav->hmmio, wMsg, lParam1, lParam2);
  3360. return fSuccess ? lResult : 0;
  3361. }
  3362. #ifdef TELTHUNK
  3363. // WavOpenEx - open an audio file, extra special version
  3364. // <dwVersion> (i) must be WAV_VERSION
  3365. // <hInst> (i) instance handle of calling module
  3366. // <lpszFileName> (i) name of file to open
  3367. // <dwReserved> (i) reserved; must be zero
  3368. // <dwFlagsOpen> (i) control flags to pass to WavOpen
  3369. // <dwFlagsEx> (i) control flags
  3370. // WOX_LOCAL file is on local client
  3371. // WOX_REMOTE file is on remote server
  3372. // WOX_WAVFMT file is in Microsoft RIFF/WAV format
  3373. // WOX_VOXFMT file is in Dialogic OKI ADPCM (vox) format
  3374. // WOX_WAVDEV file will be played on wav output device
  3375. // WOX_TELDEV file will be played on telephone device
  3376. // return handle (NULL if error)
  3377. //
  3378. HWAV DLLEXPORT WINAPI WavOpenEx(DWORD dwVersion, HINSTANCE hInst,
  3379. LPTSTR lpszFileName, DWORD dwReserved, DWORD dwFlagsOpen, DWORD dwFlagsEx)
  3380. {
  3381. BOOL fSuccess = TRUE;
  3382. HWAV hWav = NULL;
  3383. if ((dwFlagsEx & WOX_TELDEV) || (dwFlagsEx & WOX_REMOTE))
  3384. {
  3385. hWav = TelWavOpenEx(TELWAV_VERSION, hInst,
  3386. lpszFileName, 0, dwFlagsOpen, dwFlagsEx);
  3387. }
  3388. else
  3389. {
  3390. WAVEFORMATEX wfx;
  3391. LPWAVEFORMATEX lpwfx = NULL;
  3392. if (dwFlagsEx & WOX_VOXFMT)
  3393. {
  3394. dwFlagsOpen |= WAV_NORIFF;
  3395. lpwfx = VoxFormat(&wfx, -1);
  3396. }
  3397. hWav = WavOpen(WAV_VERSION, hInst,
  3398. lpszFileName, lpwfx, NULL, 0, dwFlagsOpen);
  3399. }
  3400. return fSuccess ? hWav : NULL;
  3401. }
  3402. #endif
  3403. ////
  3404. // helper functions
  3405. ////
  3406. // WavStopPlay - stop playing
  3407. // <hWav> (i) handle returned from WavOpen
  3408. // return 0 if success
  3409. //
  3410. static int WavStopPlay(HWAV hWav)
  3411. {
  3412. BOOL fSuccess = TRUE;
  3413. LPWAV lpWav;
  3414. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3415. fSuccess = TraceFALSE(NULL);
  3416. else
  3417. lpWav->dwState |= WAVSTATE_AUTOSTOP;
  3418. // close output device if necessary
  3419. //
  3420. if (fSuccess &&
  3421. !(lpWav->dwState & WAVSTATE_STOPPLAY) &&
  3422. lpWav->hWavOut != NULL)
  3423. {
  3424. long msPositionPlay = 0L;
  3425. // set a state flag so we never execute this code recursively
  3426. //
  3427. lpWav->dwState |= WAVSTATE_STOPPLAY;
  3428. // get current playback position
  3429. //
  3430. if ((msPositionPlay = WavOutGetPosition(lpWav->hWavOut)) == -1)
  3431. {
  3432. // let's ignore errors here and assume play position is 0;
  3433. //
  3434. msPositionPlay = 0L;
  3435. fSuccess = TraceTRUE(NULL);
  3436. }
  3437. else
  3438. {
  3439. // if necessary, adjust position to compensate for non-standard speed
  3440. //
  3441. if (lpWav->nSpeedLevel != 100 && (
  3442. #ifdef AVTSM
  3443. !(lpWav->dwFlagsSpeed & WAVSPEED_NOTSM) ||
  3444. #endif
  3445. !(lpWav->dwFlagsSpeed & WAVSPEED_NOFORMATADJUST)))
  3446. {
  3447. msPositionPlay = msPositionPlay * lpWav->nSpeedLevel / 100;
  3448. }
  3449. }
  3450. #if 1
  3451. TracePrintf_2(NULL, 6,
  3452. TEXT("lpWav->msPositionStop=%ld, msPositionPlay=%ld\n"),
  3453. (long) lpWav->msPositionStop,
  3454. (long) msPositionPlay);
  3455. #endif
  3456. // clear wav handle array entry
  3457. //
  3458. if (fSuccess)
  3459. {
  3460. int idDev;
  3461. if ((idDev = WavOutGetId(lpWav->hWavOut)) < HWAVOUT_MIN ||
  3462. idDev >= HWAVOUT_MAX)
  3463. fSuccess = TraceFALSE(NULL);
  3464. else
  3465. ahWavOutCurr[idDev + HWAVOUT_OFFSET] = NULL;
  3466. }
  3467. // close output device
  3468. //
  3469. if (WavOutClose(lpWav->hWavOut, 0) != 0)
  3470. fSuccess = TraceFALSE(NULL);
  3471. else if ((lpWav->hWavOut = NULL), FALSE)
  3472. fSuccess = TraceFALSE(NULL);
  3473. // destroy the notification callback window
  3474. //
  3475. else if (WavNotifyDestroy(lpWav) != 0)
  3476. fSuccess = TraceFALSE(NULL);
  3477. // move read/write pointer (back) to new stop position
  3478. //
  3479. else if (WavSetPosition(hWav, min(WavGetLength(hWav),
  3480. lpWav->msPositionStop + msPositionPlay)) == -1)
  3481. fSuccess = TraceFALSE(NULL);
  3482. // close acm conversion engine
  3483. //
  3484. else if (AcmConvertTerm(lpWav->hAcm) != 0)
  3485. fSuccess = TraceFALSE(NULL);
  3486. // notify user that play is stopped if necessary
  3487. //
  3488. if (lpWav->lpfnPlayStopped != NULL)
  3489. {
  3490. (*lpWav->lpfnPlayStopped)(hWav, lpWav->hUserPlayStopped, 0);
  3491. lpWav->lpfnPlayStopped = NULL;
  3492. lpWav->hUserPlayStopped = NULL;
  3493. }
  3494. // clear state flags
  3495. //
  3496. lpWav->dwState &= ~WAVSTATE_STOPPLAY;
  3497. // close wav file if specified
  3498. //
  3499. if (lpWav->dwState & WAVSTATE_AUTOCLOSE)
  3500. {
  3501. lpWav->dwState &= ~WAVSTATE_AUTOCLOSE;
  3502. if (WavClose(hWav) != 0)
  3503. fSuccess = TraceFALSE(NULL);
  3504. else
  3505. hWav = NULL; // handle no longer valid
  3506. }
  3507. }
  3508. #ifdef AVTSM
  3509. // shut down time scale modification engine if necessary
  3510. //
  3511. if (fSuccess && lpWav->hTsm != NULL)
  3512. {
  3513. if (TsmTerm(lpWav->hTsm) != 0)
  3514. fSuccess = TraceFALSE(NULL);
  3515. else
  3516. lpWav->hTsm = NULL;
  3517. }
  3518. #endif
  3519. return fSuccess ? 0 : -1;
  3520. }
  3521. // WavStopRecord - stop recording
  3522. // <hWav> (i) handle returned from WavOpen
  3523. // return 0 if success
  3524. //
  3525. static int WavStopRecord(HWAV hWav)
  3526. {
  3527. BOOL fSuccess = TRUE;
  3528. LPWAV lpWav;
  3529. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3530. fSuccess = TraceFALSE(NULL);
  3531. else
  3532. lpWav->dwState |= WAVSTATE_AUTOSTOP;
  3533. // close input device if necessary
  3534. //
  3535. if (fSuccess &&
  3536. !(lpWav->dwState & WAVSTATE_STOPRECORD) &&
  3537. lpWav->hWavIn != NULL)
  3538. {
  3539. long msPositionRecord = 0L;
  3540. // set a state flag so we never execute this code recursively
  3541. //
  3542. lpWav->dwState |= WAVSTATE_STOPRECORD;
  3543. // get current record position
  3544. //
  3545. if ((msPositionRecord = WavInGetPosition(lpWav->hWavIn)) == -1)
  3546. {
  3547. // let's ignore errors here and assume record position is 0;
  3548. //
  3549. msPositionRecord = 0L;
  3550. fSuccess = TraceTRUE(NULL);
  3551. }
  3552. #if 1
  3553. TracePrintf_2(NULL, 6,
  3554. TEXT("lpWav->msPositionStop=%ld, msPositionRecord=%ld\n"),
  3555. (long) lpWav->msPositionStop,
  3556. (long) msPositionRecord);
  3557. #endif
  3558. // clear wav handle array entry
  3559. //
  3560. if (fSuccess)
  3561. {
  3562. int idDev;
  3563. if ((idDev = WavInGetId(lpWav->hWavIn)) < HWAVIN_MIN ||
  3564. idDev >= HWAVIN_MAX)
  3565. TraceFALSE(NULL);
  3566. else
  3567. ahWavInCurr[idDev + HWAVIN_OFFSET] = NULL;
  3568. }
  3569. // close input device
  3570. //
  3571. if (WavInClose(lpWav->hWavIn, 0) != 0)
  3572. fSuccess = TraceFALSE(NULL);
  3573. else if ((lpWav->hWavIn = NULL), FALSE)
  3574. fSuccess = TraceFALSE(NULL);
  3575. // destroy the notification callback window
  3576. //
  3577. else if (WavNotifyDestroy(lpWav) != 0)
  3578. fSuccess = TraceFALSE(NULL);
  3579. // move read/write pointer to new stop position
  3580. //
  3581. else if (WavSetPosition(hWav, min(WavGetLength(hWav),
  3582. lpWav->msPositionStop + msPositionRecord)) == -1)
  3583. fSuccess = TraceFALSE(NULL);
  3584. // close acm conversion engine
  3585. //
  3586. else if (AcmConvertTerm(lpWav->hAcm) != 0)
  3587. fSuccess = TraceFALSE(NULL);
  3588. // truncate file if max file size exceeded
  3589. //
  3590. else if (lpWav->msMaxSize > 0 &&
  3591. WavGetLength(hWav) > lpWav->msMaxSize &&
  3592. WavSetLength(hWav, lpWav->msMaxSize) < 0)
  3593. fSuccess = TraceFALSE(NULL);
  3594. // clear state flags
  3595. //
  3596. lpWav->dwState &= ~WAVSTATE_STOPRECORD;
  3597. // notify user that record is stopped if necessary
  3598. //
  3599. if (lpWav->lpfnRecordStopped != NULL)
  3600. {
  3601. (*lpWav->lpfnRecordStopped)(hWav, lpWav->dwUserRecordStopped, 0);
  3602. lpWav->lpfnRecordStopped = NULL;
  3603. lpWav->dwUserRecordStopped = 0;
  3604. }
  3605. // close wav file if specified
  3606. //
  3607. if (lpWav->dwState & WAVSTATE_AUTOCLOSE)
  3608. {
  3609. lpWav->dwState &= ~WAVSTATE_AUTOCLOSE;
  3610. if (WavClose(hWav) != 0)
  3611. fSuccess = TraceFALSE(NULL);
  3612. else
  3613. hWav = NULL; // handle no longer valid
  3614. }
  3615. }
  3616. return fSuccess ? 0 : -1;
  3617. }
  3618. // WavStopOutputDevice - stop specified output device
  3619. // <idDev> (i) wav output device id
  3620. // -1 use any suitable output device
  3621. // <dwFlags> (i) control flags
  3622. // WAV_NOSTOP if device already playing, don't stop it
  3623. // return 0 if success
  3624. //
  3625. static int WavStopOutputDevice(int idDev, DWORD dwFlags)
  3626. {
  3627. BOOL fSuccess = TRUE;
  3628. // stop output device (unless WAV_NOSTOP flag set or device not open)
  3629. //
  3630. if (!(dwFlags & WAV_NOSTOP) && WavOutDeviceIsOpen(idDev))
  3631. {
  3632. HWAV hWavCurr;
  3633. // stop device using WavStopPlay if WavPlay was used
  3634. //
  3635. if ((hWavCurr = WavGetOutputHandle(idDev)) != NULL &&
  3636. WavStopPlay(hWavCurr) != 0)
  3637. fSuccess = TraceFALSE(NULL);
  3638. // otherwise stop device using sndPlaySound
  3639. //
  3640. else if (!sndPlaySound(NULL, 0))
  3641. fSuccess = TraceFALSE(NULL);
  3642. }
  3643. return fSuccess ? 0 : -1;
  3644. }
  3645. // WavStopInputDevice - stop specified input device
  3646. // <idDev> (i) wav input device id
  3647. // -1 use any suitable input device
  3648. // <dwFlags> (i) control flags
  3649. // WAV_NOSTOP if device already recording, don't stop it
  3650. // return 0 if success
  3651. //
  3652. static int WavStopInputDevice(int idDev, DWORD dwFlags)
  3653. {
  3654. BOOL fSuccess = TRUE;
  3655. // stop input device (unless WAV_NOSTOP flag set or device not open)
  3656. //
  3657. if (!(dwFlags & WAV_NOSTOP) && WavInDeviceIsOpen(idDev))
  3658. {
  3659. HWAV hWavCurr;
  3660. // stop device using WavStopRecord if WavRecord was used
  3661. //
  3662. if ((hWavCurr = WavGetInputHandle(idDev)) != NULL &&
  3663. WavStopRecord(hWavCurr) != 0)
  3664. fSuccess = TraceFALSE(NULL);
  3665. // otherwise stop device using sndPlaySound
  3666. //
  3667. else if (!sndPlaySound(NULL, 0))
  3668. fSuccess = TraceFALSE(NULL);
  3669. }
  3670. return fSuccess ? 0 : -1;
  3671. }
  3672. // WavGetOutputHandle - get wav handle being played on specified device
  3673. // <idDev> (i) wav output device id
  3674. // return wav handle (NULL if error or if output device not in use)
  3675. //
  3676. static HWAV WavGetOutputHandle(int idDev)
  3677. {
  3678. BOOL fSuccess = TRUE;
  3679. HWAV hWav;
  3680. if (idDev < HWAVOUT_MIN || idDev >= HWAVOUT_MAX)
  3681. fSuccess = TraceFALSE(NULL);
  3682. else
  3683. hWav = ahWavOutCurr[idDev + HWAVOUT_OFFSET];
  3684. return fSuccess ? hWav : NULL;
  3685. }
  3686. // WavGetInputHandle - get wav handle being recorded on specified device
  3687. // <idDev> (i) wav input device id
  3688. // return wav handle (NULL if error or if input device not in use)
  3689. //
  3690. static HWAV WavGetInputHandle(int idDev)
  3691. {
  3692. BOOL fSuccess = TRUE;
  3693. HWAV hWav;
  3694. if (idDev < HWAVIN_MIN || idDev >= HWAVIN_MAX)
  3695. fSuccess = TraceFALSE(NULL);
  3696. else
  3697. hWav = ahWavInCurr[idDev + HWAVIN_OFFSET];
  3698. return fSuccess ? hWav : NULL;
  3699. }
  3700. // WavPlayNextChunk - fill next chunk and submit it to the output device
  3701. // <hWav> (i) handle returned from WavOpen
  3702. // return 0 if success
  3703. //
  3704. static int WavPlayNextChunk(HWAV hWav)
  3705. {
  3706. BOOL fSuccess = TRUE;
  3707. LPWAV lpWav;
  3708. LPVOID lpBuf = NULL;
  3709. long sizBuf;
  3710. long lBytesRead = 0;
  3711. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3712. fSuccess = TraceFALSE(NULL);
  3713. // calculate the size of output chunk
  3714. //
  3715. //
  3716. // we have to verify if lpWav is a valid pointer
  3717. //
  3718. else if ((sizBuf = WavCalcChunkSize(lpWav->lpwfx[FORMATPLAY],
  3719. lpWav->msPlayChunkSize, TRUE)) <= 0)
  3720. {
  3721. fSuccess = TraceFALSE(NULL);
  3722. }
  3723. #ifdef TELOUT // $FIXUP - need to work on this
  3724. // special case - if we are using the telephone to play audio
  3725. // from a file that already resides on the server, just pass
  3726. // the file handle to TelOutPlay rather than a buffer
  3727. //
  3728. else if (WavOutGetId(lpWav->hWavOut) == TELOUT_DEVICEID &&
  3729. (lpWav->dwFlags & WAV_TELRFILE))
  3730. {
  3731. long hrfile;
  3732. long lSize;
  3733. long lPos;
  3734. // retrieve handle to remote file from i/o procedure
  3735. //
  3736. if ((hrfile = (long)
  3737. WavSendMessage(hWav, MMIOM_GETINFO, 0, 0)) == (long) -1)
  3738. fSuccess = TraceFALSE(NULL);
  3739. // retrieve size of remote file from i/o procedure
  3740. //
  3741. else if ((lSize = (long)
  3742. WavSendMessage(hWav, MMIOM_GETINFO, 1, 0)) == (long) -1)
  3743. fSuccess = TraceFALSE(NULL);
  3744. // get current file position
  3745. //
  3746. else if ((lPos = mmioSeek(lpWav->hmmio, 0, SEEK_CUR)) == -1)
  3747. fSuccess = TraceFALSE(NULL);
  3748. // force the remote file pointer to be at that position
  3749. //
  3750. else if (WavOutGetState(lpWav->hWavOut) == WAVOUT_STOPPED)
  3751. {
  3752. long lPosActual;
  3753. if ((lPosActual = mmioSendMessage(lpWav->hmmio,
  3754. MMIOM_SEEK, lPos, SEEK_SET)) != lPos)
  3755. {
  3756. fSuccess = TraceTRUE(NULL); // not an error
  3757. }
  3758. }
  3759. // loop until we read some data or we know we are finished
  3760. //
  3761. while (fSuccess && lBytesRead == 0)
  3762. {
  3763. // calculate how many bytes would be read
  3764. //
  3765. lBytesRead = max(0, min(sizBuf, lSize - lPos));
  3766. TracePrintf_4(NULL, 5,
  3767. TEXT("lBytesRead(%ld) = max(0, min(sizBuf(%ld), lSize(%ld) - lPos(%ld)));\n"),
  3768. (long) lBytesRead,
  3769. (long) sizBuf,
  3770. (long) lSize,
  3771. (long) lPos);
  3772. // advance the file position, skipping over the (virtual) chunk
  3773. //
  3774. if (lBytesRead > 0 &&
  3775. mmioSeek(lpWav->hmmio, lBytesRead, SEEK_CUR) == -1)
  3776. fSuccess = TraceFALSE(NULL);
  3777. // submit the (virtual) chunk to the output device for playback
  3778. //
  3779. else if (lBytesRead > 0 &&
  3780. TelOutPlay((HTELOUT) lpWav->hWavOut,
  3781. lpBuf, lBytesRead, hrfile) != 0)
  3782. fSuccess = TraceFALSE(NULL);
  3783. // if no more wav data to play,
  3784. //
  3785. else if (lBytesRead == 0)
  3786. {
  3787. // if WAV_AUTOSTOP flag set, we are finished
  3788. //
  3789. if (lpWav->dwState & WAVSTATE_AUTOSTOP)
  3790. {
  3791. // if output device is idle, then close output device
  3792. //
  3793. if (lpWav->hWavOut != NULL &&
  3794. WavOutGetState(lpWav->hWavOut) == WAVOUT_STOPPED &&
  3795. WavStopPlay(hWav) != 0)
  3796. {
  3797. fSuccess = TraceFALSE(NULL);
  3798. }
  3799. break;
  3800. }
  3801. // if not finished, yield and then try to read again
  3802. //
  3803. else
  3804. {
  3805. MSG msg;
  3806. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  3807. {
  3808. TranslateMessage(&msg);
  3809. DispatchMessage(&msg);
  3810. }
  3811. else
  3812. WaitMessage();
  3813. }
  3814. }
  3815. }
  3816. return fSuccess ? 0 : -1;
  3817. }
  3818. #endif
  3819. else if ((lpBuf = (LPVOID) MemAlloc(NULL, sizBuf, 0)) == NULL)
  3820. fSuccess = TraceFALSE(NULL);
  3821. // loop until we read some data or we know we are finished
  3822. //
  3823. while (fSuccess && lBytesRead == 0)
  3824. {
  3825. // fill chunk with wav data
  3826. //
  3827. #ifdef AVTSM
  3828. if ((lBytesRead = WavReadFormatSpeed(hWav, lpBuf, sizBuf)) < 0)
  3829. #else
  3830. if ((lBytesRead = WavReadFormatPlay(hWav, lpBuf, sizBuf)) < 0)
  3831. #endif
  3832. fSuccess = TraceFALSE(NULL);
  3833. // submit the chunk to the output device for playback
  3834. //
  3835. else if (lBytesRead > 0 &&
  3836. WavOutPlay(lpWav->hWavOut, lpBuf, lBytesRead) != 0)
  3837. {
  3838. fSuccess = TraceFALSE(NULL);
  3839. }
  3840. // if no more wav data to play,
  3841. //
  3842. else if (lBytesRead == 0)
  3843. {
  3844. // if WAV_AUTOSTOP flag set, we are finished
  3845. //
  3846. if (lpWav->dwState & WAVSTATE_AUTOSTOP)
  3847. {
  3848. // if output device is idle, then close output device
  3849. //
  3850. if (lpWav->hWavOut != NULL &&
  3851. WavOutGetState(lpWav->hWavOut) == WAVOUT_STOPPED &&
  3852. WavStopPlay(hWav) != 0)
  3853. {
  3854. fSuccess = TraceFALSE(NULL);
  3855. }
  3856. break;
  3857. }
  3858. // if not finished, yield and then try to read again
  3859. //
  3860. else
  3861. {
  3862. MSG msg;
  3863. if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE))
  3864. {
  3865. TranslateMessage(&msg);
  3866. DispatchMessage(&msg);
  3867. }
  3868. else
  3869. WaitMessage();
  3870. }
  3871. }
  3872. }
  3873. // free buffer if it was not sent to output device
  3874. //
  3875. if (!fSuccess || lBytesRead == 0)
  3876. {
  3877. if (lpBuf != NULL && (lpBuf = MemFree(NULL, lpBuf)) != NULL)
  3878. fSuccess = TraceFALSE(NULL);
  3879. }
  3880. return fSuccess ? 0 : -1;
  3881. }
  3882. // WavRecordNextChunk - submit next chunk to the input device
  3883. // <hWav> (i) handle returned from WavOpen
  3884. // return 0 if success
  3885. //
  3886. static int WavRecordNextChunk(HWAV hWav)
  3887. {
  3888. BOOL fSuccess = TRUE;
  3889. //
  3890. // We have to initialize local variable
  3891. //
  3892. LPWAV lpWav = NULL;
  3893. LPVOID lpBuf = NULL;
  3894. long sizBuf;
  3895. if ((lpWav = WavGetPtr(hWav)) == NULL)
  3896. fSuccess = TraceFALSE(NULL);
  3897. else
  3898. {
  3899. //
  3900. // we should make sure lpWas is not NULL
  3901. //
  3902. // calculate the size of input chunk
  3903. //
  3904. if ((sizBuf = WavCalcChunkSize(lpWav->lpwfx[FORMATRECORD],
  3905. lpWav->msRecordChunkSize, FALSE)) <= 0)
  3906. {
  3907. fSuccess = TraceFALSE(NULL);
  3908. }
  3909. #ifdef TELOUT // $FIXUP - need to work on this
  3910. // special case - if we are using the telephone to record audio
  3911. // to a file that already resides on the server, just pass
  3912. // the file handle to TelOutRecord rather than a buffer
  3913. //
  3914. else if (WavInGetId(lpWav->hWavIn) == TELIN_DEVICEID &&
  3915. (lpWav->dwFlags & WAV_TELRFILE))
  3916. {
  3917. long hrfile;
  3918. // retrieve handle to remote file from i/o procedure
  3919. //
  3920. if ((hrfile = (long)
  3921. WavSendMessage(hWav, MMIOM_GETINFO, 0, 0)) == (long) -1)
  3922. fSuccess = TraceFALSE(NULL);
  3923. // submit the (virtual) chunk to the output device for playback
  3924. //
  3925. else if (TelInRecord((HTELIN) lpWav->hWavIn,
  3926. lpBuf, sizBuf, hrfile) != 0)
  3927. fSuccess = TraceFALSE(NULL);
  3928. return fSuccess ? 0 : -1;
  3929. }
  3930. #endif
  3931. else if ((lpBuf = (LPVOID) MemAlloc(NULL, sizBuf, 0)) == NULL)
  3932. fSuccess = TraceFALSE(NULL);
  3933. // submit the chunk to the input device for recording
  3934. //
  3935. else if (WavInRecord(lpWav->hWavIn, lpBuf, sizBuf) != 0)
  3936. {
  3937. fSuccess = TraceFALSE(NULL);
  3938. }
  3939. }
  3940. // free buffer if it was not sent to input device
  3941. //
  3942. if (!fSuccess)
  3943. {
  3944. if (lpBuf != NULL && (lpBuf = MemFree(NULL, lpBuf)) != NULL)
  3945. fSuccess = TraceFALSE(NULL);
  3946. }
  3947. return fSuccess ? 0 : -1;
  3948. }
  3949. static int WavNotifyCreate(LPWAV lpWav)
  3950. {
  3951. BOOL fSuccess = TRUE;
  3952. WNDCLASS wc;
  3953. #ifdef MULTITHREAD
  3954. // handle WAV_MULTITHREAD flag
  3955. //
  3956. if (fSuccess && (lpWav->dwFlags & WAV_MULTITHREAD))
  3957. {
  3958. DWORD dwRet;
  3959. // we need to know when callback thread begins execution
  3960. //
  3961. if ((lpWav->hEventThreadCallbackStarted = CreateEvent(
  3962. NULL, FALSE, FALSE, NULL)) == NULL)
  3963. {
  3964. fSuccess = TraceFALSE(NULL);
  3965. }
  3966. // create the callback thread
  3967. //
  3968. else if ((lpWav->hThreadCallback = CreateThread(
  3969. NULL,
  3970. 0,
  3971. WavCallbackThread,
  3972. (LPVOID) lpWav,
  3973. 0,
  3974. &lpWav->dwThreadId)) == NULL)
  3975. {
  3976. fSuccess = TraceFALSE(NULL);
  3977. }
  3978. // wait for the callback thread to begin execution
  3979. //
  3980. else if ((dwRet = WaitForSingleObject(
  3981. lpWav->hEventThreadCallbackStarted, 10000)) != WAIT_OBJECT_0)
  3982. {
  3983. fSuccess = TraceFALSE(NULL);
  3984. }
  3985. // clean up
  3986. //
  3987. if (lpWav->hEventThreadCallbackStarted != NULL)
  3988. {
  3989. if (!CloseHandle(lpWav->hEventThreadCallbackStarted))
  3990. fSuccess = TraceFALSE(NULL);
  3991. else
  3992. lpWav->hEventThreadCallbackStarted = NULL;
  3993. }
  3994. }
  3995. else
  3996. #endif
  3997. {
  3998. // register notify class unless it has been already
  3999. //
  4000. if (GetClassInfo(lpWav->hInst, WAVCLASS, &wc) == 0)
  4001. {
  4002. wc.hCursor = NULL;
  4003. wc.hIcon = NULL;
  4004. wc.lpszMenuName = NULL;
  4005. wc.hInstance = lpWav->hInst;
  4006. wc.lpszClassName = WAVCLASS;
  4007. wc.hbrBackground = NULL;
  4008. wc.lpfnWndProc = WavNotify;
  4009. wc.style = 0L;
  4010. wc.cbWndExtra = sizeof(lpWav);
  4011. wc.cbClsExtra = 0;
  4012. if (!RegisterClass(&wc))
  4013. fSuccess = TraceFALSE(NULL);
  4014. }
  4015. // create the notify window
  4016. //
  4017. if (fSuccess && lpWav->hwndNotify == NULL &&
  4018. (lpWav->hwndNotify = CreateWindowEx(
  4019. 0L,
  4020. WAVCLASS,
  4021. NULL,
  4022. 0L,
  4023. 0, 0, 0, 0,
  4024. NULL,
  4025. NULL,
  4026. lpWav->hInst,
  4027. lpWav)) == NULL)
  4028. {
  4029. fSuccess = TraceFALSE(NULL);
  4030. }
  4031. }
  4032. return fSuccess ? 0 : -1;
  4033. }
  4034. static int WavNotifyDestroy(LPWAV lpWav)
  4035. {
  4036. BOOL fSuccess = TRUE;
  4037. // destroy notify window
  4038. //
  4039. if (lpWav->hwndNotify != NULL &&
  4040. !DestroyWindow(lpWav->hwndNotify))
  4041. {
  4042. fSuccess = TraceFALSE(NULL);
  4043. }
  4044. else
  4045. lpWav->hwndNotify = NULL;
  4046. #ifdef MULTITHREAD
  4047. if (lpWav->hThreadCallback != NULL)
  4048. {
  4049. if (!CloseHandle(lpWav->hThreadCallback))
  4050. fSuccess = TraceFALSE(NULL);
  4051. else
  4052. lpWav->hThreadCallback = NULL;
  4053. }
  4054. #endif
  4055. return fSuccess ? 0 : -1;
  4056. }
  4057. #ifdef MULTITHREAD
  4058. DWORD WINAPI WavCallbackThread(LPVOID lpvThreadParameter)
  4059. {
  4060. BOOL fSuccess = TRUE;
  4061. MSG msg;
  4062. LPWAV lpWav = (LPWAV) lpvThreadParameter;
  4063. // initialize COM
  4064. //
  4065. if (lpWav->dwFlags & WAV_COINITIALIZE)
  4066. {
  4067. if ((lpWav->hrCoInitialize = CoInitialize(NULL)) != S_OK &&
  4068. lpWav->hrCoInitialize != S_FALSE)
  4069. {
  4070. fSuccess = TraceFALSE(NULL);
  4071. TracePrintf_1(NULL, 5,
  4072. TEXT("CoInitialize failed (%08X)\n"),
  4073. (unsigned long) lpWav->hrCoInitialize);
  4074. }
  4075. }
  4076. // make sure message queue is created before calling SetEvent
  4077. //
  4078. PeekMessage(&msg, NULL, 0, 0, PM_NOREMOVE);
  4079. // notify main thread that callback thread has begun execution
  4080. //
  4081. if (!SetEvent(lpWav->hEventThreadCallbackStarted))
  4082. {
  4083. fSuccess = TraceFALSE(NULL);
  4084. }
  4085. while (fSuccess && GetMessage(&msg, NULL, 0, 0))
  4086. {
  4087. WavNotify((HWND) lpWav, msg.message, msg.wParam, msg.lParam);
  4088. // exit thread when when have processed last expected message
  4089. //
  4090. if (msg.message == WM_WAVOUT_CLOSE || msg.message == WM_WAVIN_CLOSE)
  4091. {
  4092. // notify main thread that we are terminating
  4093. //
  4094. if (lpWav->hEventStopped != NULL &&
  4095. !SetEvent(lpWav->hEventStopped))
  4096. {
  4097. fSuccess = TraceFALSE(NULL);
  4098. }
  4099. break;
  4100. }
  4101. }
  4102. // uninitialize COM
  4103. //
  4104. if (lpWav->dwFlags & WAV_COINITIALIZE)
  4105. {
  4106. if (lpWav->hrCoInitialize == S_OK || lpWav->hrCoInitialize == S_FALSE)
  4107. {
  4108. CoUninitialize();
  4109. lpWav->hrCoInitialize = E_UNEXPECTED;
  4110. }
  4111. }
  4112. return 0;
  4113. }
  4114. #endif
  4115. // WavNotify - window procedure for wav notify
  4116. //
  4117. LRESULT DLLEXPORT CALLBACK WavNotify(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam)
  4118. {
  4119. BOOL fSuccess = TRUE;
  4120. LRESULT lResult;
  4121. LPWAV lpWav;
  4122. #ifdef MULTITHREAD
  4123. if (!IsWindow(hwnd))
  4124. lpWav = (LPWAV) hwnd;
  4125. else
  4126. #endif
  4127. // retrieve lpWav from window extra bytes
  4128. //
  4129. lpWav = (LPWAV) GetWindowLongPtr(hwnd, 0);
  4130. switch (msg)
  4131. {
  4132. case WM_NCCREATE:
  4133. {
  4134. LPCREATESTRUCT lpcs = (LPCREATESTRUCT) lParam;
  4135. LPWAV lpWav = (LPWAV) lpcs->lpCreateParams;
  4136. // store lpWav in window extra bytes
  4137. //
  4138. SetWindowLongPtr(hwnd, 0, (LONG_PTR) lpWav);
  4139. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  4140. }
  4141. break;
  4142. case WM_WAVOUT_OPEN:
  4143. {
  4144. TracePrintf_0(NULL, 5,
  4145. TEXT("WM_WAVOUT_OPEN\n"));
  4146. lResult = 0L;
  4147. #ifdef MULTITHREAD
  4148. if ((HANDLE) wParam != NULL)
  4149. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4150. #endif
  4151. }
  4152. break;
  4153. case WM_WAVOUT_CLOSE:
  4154. {
  4155. TracePrintf_0(NULL, 5,
  4156. TEXT("WM_WAVOUT_CLOSE\n"));
  4157. // handle no longer valid
  4158. //
  4159. lpWav->hWavOut = NULL;
  4160. lResult = 0L;
  4161. #ifdef MULTITHREAD
  4162. if ((HANDLE) wParam != NULL)
  4163. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4164. #endif
  4165. }
  4166. break;
  4167. case WM_WAVOUT_PLAYDONE:
  4168. {
  4169. LPPLAYDONE lpplaydone = (LPPLAYDONE) lParam;
  4170. TracePrintf_0(NULL, 5,
  4171. TEXT("WM_WAVOUT_PLAYDONE\n"));
  4172. if (lpplaydone == NULL)
  4173. fSuccess = TraceFALSE(NULL);
  4174. else if (lpplaydone->lpBuf != NULL &&
  4175. (lpplaydone->lpBuf = MemFree(NULL, lpplaydone->lpBuf)) != NULL)
  4176. fSuccess = TraceFALSE(NULL);
  4177. else switch (WavOutGetState(lpWav->hWavOut))
  4178. {
  4179. case WAVOUT_STOPPED:
  4180. // make sure to close output device when play complete
  4181. //
  4182. if (lpWav->dwState & WAVSTATE_AUTOSTOP)
  4183. {
  4184. #ifdef MULTITHREAD
  4185. if (lpWav->dwFlags & WAV_MULTITHREAD)
  4186. PostThreadMessage(lpWav->dwThreadId, WM_WAVOUT_STOPPLAY, 0, 0);
  4187. else
  4188. #endif
  4189. PostMessage(lpWav->hwndNotify, WM_WAVOUT_STOPPLAY, 0, 0);
  4190. break;
  4191. }
  4192. // else fall through
  4193. case WAVOUT_PLAYING:
  4194. // load output device queue with next chunk to play
  4195. //
  4196. if (WavPlayNextChunk(WavGetHandle(lpWav)) != 0)
  4197. fSuccess = TraceFALSE(NULL);
  4198. break;
  4199. default:
  4200. break;
  4201. }
  4202. lResult = 0L;
  4203. #ifdef MULTITHREAD
  4204. if ((HANDLE) wParam != NULL)
  4205. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4206. #endif
  4207. }
  4208. break;
  4209. case WM_WAVOUT_STOPPLAY:
  4210. {
  4211. TracePrintf_0(NULL, 5,
  4212. TEXT("WM_WAVOUT_STOPPLAY\n"));
  4213. if (WavStopPlay(WavGetHandle(lpWav)) != 0)
  4214. fSuccess = TraceFALSE(NULL);
  4215. lResult = 0L;
  4216. }
  4217. break;
  4218. case WM_WAVIN_OPEN:
  4219. {
  4220. TracePrintf_0(NULL, 5,
  4221. TEXT("WM_WAVIN_OPEN\n"));
  4222. lResult = 0L;
  4223. #ifdef MULTITHREAD
  4224. if ((HANDLE) wParam != NULL)
  4225. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4226. #endif
  4227. }
  4228. break;
  4229. case WM_WAVIN_CLOSE:
  4230. {
  4231. TracePrintf_0(NULL, 5,
  4232. TEXT("WM_WAVIN_CLOSE\n"));
  4233. // handle no longer valid
  4234. //
  4235. lpWav->hWavIn = NULL;
  4236. lResult = 0L;
  4237. #ifdef MULTITHREAD
  4238. if ((HANDLE) wParam != NULL)
  4239. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4240. #endif
  4241. }
  4242. break;
  4243. case WM_WAVIN_RECORDDONE:
  4244. {
  4245. LPRECORDDONE lprecorddone = (LPRECORDDONE) lParam;
  4246. long lBytesWritten;
  4247. TracePrintf_0(NULL, 5,
  4248. TEXT("WM_WAVIN_RECORDDONE\n"));
  4249. if (lprecorddone == NULL)
  4250. fSuccess = TraceFALSE(NULL);
  4251. // write wav data from chunk to file
  4252. //
  4253. else if (lprecorddone->lpBuf != NULL &&
  4254. lprecorddone->lBytesRecorded > 0 &&
  4255. (lBytesWritten = WavWriteFormatRecord(WavGetHandle(lpWav),
  4256. lprecorddone->lpBuf, lprecorddone->lBytesRecorded)) < 0)
  4257. {
  4258. fSuccess = TraceFALSE(NULL);
  4259. }
  4260. // free the record buffer, allocated in WavRecordNextChunk()
  4261. //
  4262. //
  4263. // we have to verify if lprecorddone is a valid pointer
  4264. //
  4265. if (lprecorddone != NULL && lprecorddone->lpBuf != NULL &&
  4266. (lprecorddone->lpBuf = MemFree(NULL,
  4267. lprecorddone->lpBuf)) != NULL)
  4268. {
  4269. fSuccess = TraceFALSE(NULL);
  4270. }
  4271. // stop recording if max size exceeded
  4272. //
  4273. else if (lpWav->msMaxSize > 0 &&
  4274. WavGetLength(WavGetHandle(lpWav)) > lpWav->msMaxSize)
  4275. {
  4276. #ifdef MULTITHREAD
  4277. if (lpWav->dwFlags & WAV_MULTITHREAD)
  4278. PostThreadMessage(lpWav->dwThreadId, WM_WAVIN_STOPRECORD, 0, 0);
  4279. else
  4280. #endif
  4281. PostMessage(lpWav->hwndNotify, WM_WAVIN_STOPRECORD, 0, 0);
  4282. }
  4283. else switch (WavInGetState(lpWav->hWavIn))
  4284. {
  4285. case WAVIN_STOPPED:
  4286. // make sure to close input device when record complete
  4287. //
  4288. if (lpWav->dwState & WAVSTATE_AUTOSTOP)
  4289. {
  4290. #ifdef MULTITHREAD
  4291. if (lpWav->dwFlags & WAV_MULTITHREAD)
  4292. PostThreadMessage(lpWav->dwThreadId, WM_WAVIN_STOPRECORD, 0, 0);
  4293. else
  4294. #endif
  4295. PostMessage(lpWav->hwndNotify, WM_WAVIN_STOPRECORD, 0, 0);
  4296. break;
  4297. }
  4298. // else fall through
  4299. case WAVIN_RECORDING:
  4300. // load input device queue with next chunk to record
  4301. //
  4302. if (WavRecordNextChunk(WavGetHandle(lpWav)) != 0)
  4303. fSuccess = TraceFALSE(NULL);
  4304. break;
  4305. default:
  4306. break;
  4307. }
  4308. lResult = 0L;
  4309. #ifdef MULTITHREAD
  4310. if ((HANDLE) wParam != NULL)
  4311. SetEventMessageProcessed(lpWav, (HANDLE) wParam);
  4312. #endif
  4313. }
  4314. break;
  4315. case WM_WAVIN_STOPRECORD:
  4316. {
  4317. TracePrintf_0(NULL, 5,
  4318. TEXT("WM_WAVIN_STOPRECORD\n"));
  4319. if (WavStopRecord(WavGetHandle(lpWav)) != 0)
  4320. fSuccess = TraceFALSE(NULL);
  4321. lResult = 0L;
  4322. }
  4323. break;
  4324. default:
  4325. lResult = DefWindowProc(hwnd, msg, wParam, lParam);
  4326. break;
  4327. }
  4328. return lResult;
  4329. }
  4330. // WavCalcPositionStop - calculate new stop position if stopped
  4331. // <hWav> (i) handle returned from WavOpen
  4332. // <cbPosition> (i) new stop position, in bytes
  4333. // return 0 if success
  4334. //
  4335. static int WavCalcPositionStop(HWAV hWav, long cbPosition)
  4336. {
  4337. BOOL fSuccess = TRUE;
  4338. LPWAV lpWav;
  4339. if ((lpWav = WavGetPtr(hWav)) == NULL)
  4340. fSuccess = TraceFALSE(NULL);
  4341. // recalculate stop position only if currently stopped
  4342. // (if playing or recording, defer recalc until stop occurs)
  4343. //
  4344. #if 0
  4345. else if (WavGetState(hWav) == WAV_STOPPED)
  4346. #else
  4347. else if (lpWav->hWavOut == NULL && lpWav->hWavIn == NULL)
  4348. #endif
  4349. {
  4350. // convert byte position to milleseconds
  4351. // save the new stop position
  4352. //
  4353. lpWav->msPositionStop = WavFormatBytesToMilleseconds(
  4354. lpWav->lpwfx[FORMATFILE], (DWORD) cbPosition);
  4355. #if 1
  4356. TracePrintf_2(NULL, 6,
  4357. TEXT("lpWav->msPositionStop=%ld, cbPosition=%ld\n"),
  4358. (long) lpWav->msPositionStop,
  4359. (long) cbPosition);
  4360. #endif
  4361. }
  4362. return fSuccess ? 0 : -1;
  4363. }
  4364. // WavSeekTraceBefore - debug trace output before the seek
  4365. // <lpWav> (i) pointer to WAV struct
  4366. // <lOffset> (i) bytes to move pointer
  4367. // <nOrigin> (i) position to move from
  4368. // return 0 if success
  4369. //
  4370. static int WavSeekTraceBefore(LPWAV lpWav, long lOffset, int nOrigin)
  4371. {
  4372. BOOL fSuccess = TRUE;
  4373. TracePrintf_2(NULL, 6,
  4374. TEXT("WavSeek(..., lOffset=%ld, nOrigin=%d)\n"),
  4375. (long) lOffset,
  4376. (int) nOrigin);
  4377. TracePrintf_4(NULL, 6,
  4378. TEXT("Before: lpWav->lDataOffset=%ld, lpWav->lDataPos=%ld, lpWav->cbData=%ld, lpWav->msPositionStop=%ld\n"),
  4379. (long) lpWav->lDataOffset,
  4380. (long) lpWav->lDataPos,
  4381. (long) lpWav->cbData,
  4382. (long) lpWav->msPositionStop);
  4383. return fSuccess ? 0 : -1;
  4384. }
  4385. // WavSeekTraceAfter - debug trace output after the seek
  4386. // <lpWav> (i) pointer to WAV struct
  4387. // <lPos> (i) position returned from mmioSeek
  4388. // <lOffset> (i) bytes to move pointer
  4389. // <nOrigin> (i) position to move from
  4390. // return 0 if success
  4391. //
  4392. static int WavSeekTraceAfter(LPWAV lpWav, long lPos, long lOffset, int nOrigin)
  4393. {
  4394. BOOL fSuccess = TRUE;
  4395. TracePrintf_3(NULL, 6,
  4396. TEXT("%ld = mmioSeek(..., lOffset=%ld, nOrigin=%d)\n"),
  4397. (long) lPos,
  4398. (long) lOffset,
  4399. (int) nOrigin);
  4400. TracePrintf_4(NULL, 6,
  4401. TEXT("After: lpWav->lDataOffset=%ld, lpWav->lDataPos=%ld, lpWav->cbData=%ld, lpWav->msPositionStop=%ld\n"),
  4402. (long) lpWav->lDataOffset,
  4403. (long) lpWav->lDataPos,
  4404. (long) lpWav->cbData,
  4405. (long) lpWav->msPositionStop);
  4406. return fSuccess ? 0 : -1;
  4407. }
  4408. // WavGetPtr - verify that wav handle is valid,
  4409. // <hWav> (i) handle returned from WavInit
  4410. // return corresponding wav pointer (NULL if error)
  4411. //
  4412. static LPWAV WavGetPtr(HWAV hWav)
  4413. {
  4414. BOOL fSuccess = TRUE;
  4415. LPWAV lpWav;
  4416. if ((lpWav = (LPWAV) hWav) == NULL)
  4417. fSuccess = TraceFALSE(NULL);
  4418. else if (IsBadWritePtr(lpWav, sizeof(WAV)))
  4419. fSuccess = TraceFALSE(NULL);
  4420. #ifdef CHECKTASK
  4421. // make sure current task owns the wav handle
  4422. //
  4423. else if (lpWav->hTask != GetCurrentTask())
  4424. fSuccess = TraceFALSE(NULL);
  4425. #endif
  4426. return fSuccess ? lpWav : NULL;
  4427. }
  4428. // WavGetHandle - verify that wav pointer is valid,
  4429. // <lpWav> (i) pointer to WAV struct
  4430. // return corresponding wav handle (NULL if error)
  4431. //
  4432. static HWAV WavGetHandle(LPWAV lpWav)
  4433. {
  4434. BOOL fSuccess = TRUE;
  4435. HWAV hWav;
  4436. if ((hWav = (HWAV) lpWav) == NULL)
  4437. fSuccess = TraceFALSE(NULL);
  4438. return fSuccess ? hWav : NULL;
  4439. }
  4440. // WavInitGetPtr - verify that wavinit handle is valid,
  4441. // <hWavInit> (i) handle returned from WavInitInit
  4442. // return corresponding wavinit pointer (NULL if error)
  4443. //
  4444. static LPWAVINIT WavInitGetPtr(HWAVINIT hWavInit)
  4445. {
  4446. BOOL fSuccess = TRUE;
  4447. LPWAVINIT lpWavInit;
  4448. if ((lpWavInit = (LPWAVINIT) hWavInit) == NULL)
  4449. fSuccess = TraceFALSE(NULL);
  4450. else if (IsBadWritePtr(lpWavInit, sizeof(WAVINIT)))
  4451. fSuccess = TraceFALSE(NULL);
  4452. #ifdef CHECKTASK
  4453. // make sure current task owns the wavinit handle
  4454. //
  4455. else if (lpWavInit->hTask != GetCurrentTask())
  4456. fSuccess = TraceFALSE(NULL);
  4457. #endif
  4458. return fSuccess ? lpWavInit : NULL;
  4459. }
  4460. // WavInitGetHandle - verify that wavinit pointer is valid,
  4461. // <lpWavInit> (i) pointer to WAVINIT struct
  4462. // return corresponding wavinit handle (NULL if error)
  4463. //
  4464. static HWAVINIT WavInitGetHandle(LPWAVINIT lpWavInit)
  4465. {
  4466. BOOL fSuccess = TRUE;
  4467. HWAVINIT hWavInit;
  4468. if ((hWavInit = (HWAVINIT) lpWavInit) == NULL)
  4469. fSuccess = TraceFALSE(NULL);
  4470. return fSuccess ? hWavInit : NULL;
  4471. }
  4472. #ifdef MULTITHREAD
  4473. static int SetEventMessageProcessed(LPWAV lpWav, HANDLE hEventMessageProcessed)
  4474. {
  4475. BOOL fSuccess = TRUE;
  4476. if (lpWav == NULL)
  4477. fSuccess = TraceFALSE(NULL);
  4478. else if (!(lpWav->dwFlags & WAV_MULTITHREAD))
  4479. ; // nothing to do
  4480. else if (hEventMessageProcessed == NULL)
  4481. fSuccess = TraceFALSE(NULL);
  4482. // notify SendMessageEx that message has been processed
  4483. //
  4484. else if (!SetEvent(hEventMessageProcessed))
  4485. fSuccess = TraceFALSE(NULL);
  4486. return fSuccess ? 0 : -1;
  4487. }
  4488. #endif
  4489. // WavTempStop - stop playback or recording if necessary, save prev state
  4490. // <hWav> (i) handle returned from WavInit
  4491. // <lpwStatePrev> (o) return previous state here
  4492. // <lpidDevPrev> (o) return device id here
  4493. // return 0 if success
  4494. //
  4495. static int WavTempStop(HWAV hWav, LPWORD lpwStatePrev, LPINT lpidDevPrev)
  4496. {
  4497. BOOL fSuccess = TRUE;
  4498. LPWAV lpWav;
  4499. WORD wStatePrev;
  4500. //
  4501. // We have to initialize the local variable
  4502. //
  4503. int idDevPrev = 0;
  4504. if ((lpWav = WavGetPtr(hWav)) == NULL)
  4505. fSuccess = TraceFALSE(NULL);
  4506. // make sure we not playing or recording
  4507. // $FIXUP - we need to make sure that WAV_PLAYSYNC and
  4508. // WAV_AUTOCLOSE flags are ignored during this stop
  4509. //
  4510. else switch ((wStatePrev = WavGetState(hWav)))
  4511. {
  4512. case WAV_PLAYING:
  4513. if ((idDevPrev = WavOutGetId(lpWav->hWavOut)) < -1)
  4514. fSuccess = TraceFALSE(NULL);
  4515. else if (WavStop(hWav) != 0)
  4516. fSuccess = TraceFALSE(NULL);
  4517. break;
  4518. case WAV_RECORDING:
  4519. if ((idDevPrev = WavInGetId(lpWav->hWavIn)) < -1)
  4520. fSuccess = TraceFALSE(NULL);
  4521. else if (WavStop(hWav) != 0)
  4522. fSuccess = TraceFALSE(NULL);
  4523. break;
  4524. default:
  4525. break;
  4526. }
  4527. if (fSuccess)
  4528. {
  4529. *lpwStatePrev = wStatePrev;
  4530. *lpidDevPrev = idDevPrev;
  4531. }
  4532. return fSuccess ? 0 : -1;
  4533. }
  4534. // WavTempResume - resume playback or recording if necessary, using prev state
  4535. // <hWav> (i) handle returned from WavInit
  4536. // <wStatePrev> (i) previous state returned from WavTempStop
  4537. // <idDevPrev> (i) device id returned from WavTempStop
  4538. // return 0 if success
  4539. //
  4540. static int WavTempResume(HWAV hWav, WORD wStatePrev, int idDevPrev)
  4541. {
  4542. BOOL fSuccess = TRUE;
  4543. LPWAV lpWav;
  4544. if ((lpWav = WavGetPtr(hWav)) == NULL)
  4545. fSuccess = TraceFALSE(NULL);
  4546. // resume playback or recording if necessary
  4547. //
  4548. else switch (wStatePrev)
  4549. {
  4550. case WAV_PLAYING:
  4551. if (WavPlay(hWav, idDevPrev, lpWav->dwFlagsPlay) != 0)
  4552. fSuccess = TraceFALSE(NULL);
  4553. break;
  4554. case WAV_RECORDING:
  4555. if (WavRecord(hWav, idDevPrev, lpWav->dwFlagsRecord) != 0)
  4556. fSuccess = TraceFALSE(NULL);
  4557. break;
  4558. default:
  4559. break;
  4560. }
  4561. return fSuccess ? 0 : -1;
  4562. }