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

2715 lines
76 KiB

  1. /* (C) Copyright Microsoft Corporation 1991-1994. All Rights Reserved */
  2. /* wave.c
  3. *
  4. * Waveform input and output.
  5. */
  6. /** Revision History.
  7. * 4/2/91 LaurieGr (AKA LKG) Ported to WIN32 / WIN16 common code
  8. * 17/Feb/94 LaurieGr Merged Daytona and Motown versions.
  9. * READ ME
  10. * The new soundrec was changed to use multiple headers for the following
  11. * reason. The Win3.1 version of soundrec did one waveOutWrite (with one
  12. * WAVEHDR) for the entire buffer, this worked okay for relatively small
  13. * files, but the moment we started using large files (>
  14. * 3meg) it was becoming cumbersome since it needed all of that
  15. * data page-locked. It occasionally paged for > 1 min.
  16. * Note: The o-scope display for soundrec is also updated on
  17. * the WOM_DONE message, it no longer looks at the buffer given on the
  18. * waveOutWrite before the WOM_DONE message for the buffer
  19. * is received. This is why input mapping was not implemented
  20. * in ACM on product one, there were drawing artifacts in the
  21. * o-scope window.
  22. * The pausing algorithm was changed for the following reason.
  23. * If you launch two instances of soundrec (with two wave devices)
  24. * and do the following... Play a .wav file on instance #1
  25. * (allocates first device); play a .wav file on instance #2
  26. * (allocates second device); press stop on instance #1
  27. * (frees first device); press rewind on instance #2
  28. * (frees second device, allocates first device).
  29. * Essentially, you press rewind in soundrec and you
  30. * switch devices. Since there is no explicit stop,
  31. * the device should not be closed.
  32. */
  33. #include "nocrap.h"
  34. #include <windows.h>
  35. #include <windowsx.h>
  36. #include <mmsystem.h>
  37. #include <mmreg.h>
  38. #ifdef USE_MMCNTRLS
  39. #define NOTOOLBAR
  40. #define NOMENUHELP
  41. #define NODRAGLIST
  42. #define NOBITMAPBTN
  43. #define NOMENUHELP
  44. #define NODRAGLIST
  45. #include "mmcntrls.h"
  46. #else
  47. #include <commctrl.h>
  48. #include "buttons.h"
  49. #endif
  50. #define INCLUDE_OLESTUBS
  51. #include "SoundRec.h"
  52. #include "srecnew.h"
  53. #include "reg.h"
  54. #ifndef LPHWAVE
  55. typedef HWAVE FAR *LPHWAVE;
  56. #endif
  57. /* globals that maintain the state of the current waveform */
  58. BOOL gfSyncDriver; // true if open device is sync
  59. PWAVEFORMATEX gpWaveFormat; // format of WAVE file
  60. DWORD gcbWaveFormat; // size of WAVEFORMAT
  61. LPTSTR gpszInfo = NULL; // file info
  62. HPBYTE gpWaveSamples = NULL; // pointer to waveoform samples
  63. LONG glWaveSamples = 0; // number of samples total in buffer
  64. LONG glWaveSamplesValid = 0; // number of samples that are valid
  65. LONG glWavePosition = 0; // current wave position in samples from start
  66. LONG glStartPlayRecPos; // position when play or record started
  67. LONG glSnapBackTo = 0;
  68. HWAVEOUT ghWaveOut = NULL; // wave-out device (if playing)
  69. HWAVEIN ghWaveIn = NULL; // wave-out device (if recording)
  70. BOOL gfStoppingHard = FALSE; // StopWave() was called?
  71. // true during the call to FinishPlay()
  72. static BOOL fStopping = FALSE; // StopWave() was called?
  73. DWORD grgbStatusColor; // color of status text
  74. DWORD gdwCurrentBufferPos; // Current playback/record pos (bytes)
  75. DWORD gdwBytesPerBuffer; // Bytes in each buffer we give drvr
  76. DWORD gdwTotalLengthBytes; // Length of entire buffer in bytes
  77. DWORD gdwBufferDeltaMSecs; // # msecs added to end on record
  78. BOOL gfTimerStarted;
  79. WAVEHDR FAR *gapWaveHdr[MAX_WAVEHDRS];
  80. UINT guWaveHdrs; // 1/2 second of buffering?
  81. UINT guWaveHdrsInUse; // # we actually could write
  82. UINT gwMSecsPerBuffer; // 1/8 second
  83. #ifdef THRESHOLD
  84. int iNoiseLevel = 15; // 15% of full volume is defined to be quiet
  85. int iQuietLength = 1000; // 1000 samples in a row quiet means quiet
  86. #endif // THRESHOLD
  87. BOOL fFineControl = FALSE; // fine scroll control (SHIFT key down)
  88. /*------------------------------------------------------------------
  89. | fFineControl:
  90. | This turns on place-saving to help find your way
  91. | a wave file. It's controlled by the SHIFT key being down.
  92. | If the key is down when you scroll (see soundrec.c) then it scrolls
  93. | fine amounts - 1 sample or 10 samples rather than about 100 or 1000.
  94. | In addition, if the SHIFT key is down when a sound is started
  95. | playing or recording, the position will be remembered and it will
  96. | snap back to that position. fFineControl says whether we are
  97. | remembering such a position to snap back to. SnapBack does the
  98. | position reset and then turns the flag off. There is no such flag
  99. | or mode for scrolling, the SHIFT key state is examined on every
  100. | scroll command (again - see Soundrec.c)
  101. --------------------------------------------------------------------*/
  102. /* dbgShowMemUse: display memory usage figures on debugger */
  103. void dbgShowMemUse()
  104. {
  105. MEMORYSTATUS ms;
  106. GlobalMemoryStatus(&ms);
  107. // dprintf( "load %d\n PHYS tot %d avail %d\n PAGE tot %d avail %d\n VIRT tot %d avail %d\n"
  108. // , ms.dwMemoryLoad
  109. // , ms.dwTotalPhys, ms.dwAvailPhys
  110. // , ms.dwTotalPageFile, ms.dwAvailPageFile
  111. // , ms.dwTotalVirtual, ms.dwAvailVirtual
  112. // );
  113. } // dbgShowMemUse
  114. /* PLAYBACK and PAGING on NT
  115. |
  116. | In order to try to get decent performance at the highest data rates we
  117. | need to try very hard to get all the data into storage. The paging rate
  118. | on several x86 systems is only just about or even a little less than the
  119. | maximum data rate. We therefore do the following:
  120. | a. Pre-touch the first 1MB of data when we are asked to start playing.
  121. | If it is already in storage, this is almost instantaneous.
  122. | If it needs to be faulted in, there will be a delay, but it will be well
  123. | worth having this delay at the start rather than clicks and pops later.
  124. | (At 44KHz 16 bit stereo it could be about 7 secs, 11KHz 8 bit mono it
  125. | would only be about 1/2 sec anyway).
  126. | b. Kick off a separate thread to run through the data touching 1 byte per
  127. | page. This thread is Created when we start playing, periscopes the global
  128. | static flag fStopping and exits when it reaches the end of the buffer or when
  129. | that flag is set. The global thread handle is kept in ghPreTouch and this is
  130. | initially invalid. We WAIT on this handle (if valid) to clear the thread out
  131. | before creating a new one (so there will be at most one). We do NOT do any
  132. | of this for record. The paging does not have to happen in real time for
  133. | record. It can get quite a way behind and still manage.
  134. |
  135. | This whole thing is really a bit of a hack and sits uncomfortably on NT.
  136. | The memory management works by paging out the least recently used (LRU)
  137. | pages. By stepping right though a 10Meg buffer, we will cause a lot of
  138. | code to get paged out. It would be better to have a file and read it
  139. | in section by section into a much smaller buffer (like MPlayer does).
  140. Note that the use of multiple headers doesn't really affect anything.
  141. The headers merely point at different sections of the wave buffer.
  142. It merely makes the addressing of the starting point slightly different.
  143. */
  144. HANDLE ghPreTouch = NULL;
  145. typedef struct {
  146. LPBYTE Addr; // start of buffer to pre-touch
  147. DWORD Len; // length of buffer to pre-touch
  148. } PRETOUCHTHREADPARM;
  149. /* PreToucher
  150. **
  151. ** Asynchronous pre-toucher thread. The thread parameter dw
  152. ** is realy a poionter to a PRETOUCHTHREADPARAM
  153. */
  154. DWORD PreToucher(DWORD_PTR dw)
  155. {
  156. PRETOUCHTHREADPARM * pttp;
  157. long iSize;
  158. BYTE * pb;
  159. pttp = (PRETOUCHTHREADPARM *) dw;
  160. if (!pttp) return 0;
  161. iSize = pttp->Len;
  162. pb = pttp->Addr;
  163. GlobalFreePtr(pttp);
  164. if (!pb) return 0;
  165. while (iSize>0 && !fStopping) {
  166. volatile BYTE b;
  167. b = *pb;
  168. pb += 4096; // move to next page. Are they ALWAYS 4096?
  169. iSize -= 4096; // and count it off
  170. }
  171. // dprintf(("All pretouched!"));
  172. return 0;
  173. } // PreToucher
  174. /* StartPreTouchThread
  175. **
  176. ** Start a thread running which will run through the wave buffer
  177. ** pre-touching one byte every page to ensure that the stuff is
  178. ** faulted into memory before we actually need it.
  179. ** This was needed to make 44KHz 16 bit stereo work on a
  180. ** 25MHx 386 with 16MB memory running Windows NT.
  181. */
  182. void StartPreTouchThread(LPBYTE lpb, LONG cb)
  183. {
  184. /* before we start the thing running, pretouch the first bit of memory
  185. to give the paging a head start. THEN start the thread running.
  186. */
  187. { long bl = cb;
  188. BYTE * pb = lpb;
  189. if (bl>1000000) bl = 1000000; /* 1 Meg, arbitrarily */
  190. pb += bl;
  191. while (bl>0){
  192. volatile BYTE b;
  193. b = *pb;
  194. pb-=4096;
  195. bl -= 4096;
  196. }
  197. }
  198. {
  199. PRETOUCHTHREADPARM * pttp;
  200. DWORD dwThread;
  201. if (ghPreTouch!=NULL) {
  202. fStopping = TRUE;
  203. WaitForSingleObject(ghPreTouch, INFINITE);
  204. CloseHandle(ghPreTouch);
  205. ghPreTouch = NULL;
  206. }
  207. fStopping = FALSE;
  208. pttp = (PRETOUCHTHREADPARM *)GlobalAllocPtr(GHND, sizeof(PRETOUCHTHREADPARM));
  209. /* freed by the invoked thread */
  210. if (pttp!=NULL) {
  211. pttp->Addr = lpb;
  212. pttp->Len = cb;
  213. ghPreTouch = CreateThread(NULL, 0, (LPTHREAD_START_ROUTINE)PreToucher, pttp, 0, &dwThread);
  214. // If the CreateThread fails there will be a memory leak. It's very small,
  215. // unlikely and not frequent. Not worth fixing.
  216. }
  217. }
  218. } // StartPreTouchThread
  219. /* wfBytesToSamples(pwf, lBytes)
  220. *
  221. * convert a byte offset into a sample offset.
  222. *
  223. * lSamples = (lBytes/nAveBytesPerSec) * nSamplesPerSec
  224. *
  225. */
  226. LONG PASCAL wfBytesToSamples(WAVEFORMATEX* pwf, LONG lBytes)
  227. {
  228. return MulDiv(lBytes,pwf->nSamplesPerSec,pwf->nAvgBytesPerSec);
  229. }
  230. /* wfSamplesToBytes(pwf, lSample)
  231. *
  232. * convert a sample offset into a byte offset, with correct alignment
  233. * to nBlockAlign.
  234. *
  235. * lBytes = (lSamples/nSamplesPerSec) * nBytesPerSec
  236. *
  237. */
  238. LONG PASCAL wfSamplesToBytes(WAVEFORMATEX* pwf, LONG lSamples)
  239. {
  240. LONG lBytes;
  241. lBytes = MulDiv(lSamples,pwf->nAvgBytesPerSec,pwf->nSamplesPerSec);
  242. // now align the byte offset to nBlockAlign
  243. #ifdef ROUND_UP
  244. lBytes = ((lBytes + pwf->nBlockAlign-1) / pwf->nBlockAlign) * pwf->nBlockAlign;
  245. #else
  246. lBytes = (lBytes / pwf->nBlockAlign) * pwf->nBlockAlign;
  247. #endif
  248. return lBytes;
  249. }
  250. /* wfSamplesToTime(pwf, lSample)
  251. *
  252. * convert a sample offset into a time offset in miliseconds.
  253. *
  254. * lTime = (lSamples/nSamplesPerSec) * 1000
  255. *
  256. */
  257. LONG PASCAL wfSamplesToTime(WAVEFORMATEX* pwf, LONG lSamples)
  258. {
  259. return MulDiv(lSamples,1000,pwf->nSamplesPerSec);
  260. }
  261. /* wfTimeToSamples(pwf, lTime)
  262. *
  263. * convert a time index into a sample offset.
  264. *
  265. * lSamples = (lTime/1000) * nSamplesPerSec
  266. *
  267. */
  268. LONG PASCAL wfTimeToSamples(
  269. WAVEFORMATEX* pwf,
  270. LONG lTime)
  271. {
  272. return MulDiv(lTime,pwf->nSamplesPerSec,1000);
  273. }
  274. /*
  275. * function to determine if a WAVEFORMAT is a valid PCM format we support for
  276. * editing and such.
  277. *
  278. * we only handle the following formats...
  279. *
  280. * Mono 8bit
  281. * Mono 16bit
  282. * Stereo 8bit
  283. * Stereo 16bit
  284. * */
  285. BOOL PASCAL IsWaveFormatPCM(WAVEFORMATEX* pwf)
  286. {
  287. if (!pwf)
  288. return FALSE;
  289. if (pwf->wFormatTag != WAVE_FORMAT_PCM)
  290. return FALSE;
  291. if (pwf->nChannels < 1 || pwf->nChannels > 2)
  292. return FALSE;
  293. if ((pwf->wBitsPerSample != 8) && (pwf->wBitsPerSample != 16))
  294. return FALSE;
  295. return TRUE;
  296. } // IsWaveFormatPCM
  297. void PASCAL WaveFormatToString(LPWAVEFORMATEX lpwf, LPTSTR sz)
  298. {
  299. TCHAR achFormat[80];
  300. //
  301. // this is what we expect the resource strings to be...
  302. //
  303. // IDS_MONOFMT "Mono %d%c%03dkHz, %d-bit"
  304. // IDS_STEREOFMT "Stereo %d%c%03dkHz, %d-bit"
  305. //
  306. if (gfLZero || ((WORD)(lpwf->nSamplesPerSec / 1000) != 0)){
  307. LoadString(ghInst,lpwf->nChannels == 1 ? IDS_MONOFMT:IDS_STEREOFMT,
  308. achFormat, SIZEOF(achFormat));
  309. wsprintf(sz, achFormat,
  310. (UINT) (lpwf->nSamplesPerSec / 1000), chDecimal,
  311. (UINT) (lpwf->nSamplesPerSec % 1000),
  312. (UINT) (lpwf->nAvgBytesPerSec * 8 / lpwf->nSamplesPerSec / lpwf->nChannels));
  313. } else {
  314. LoadString(ghInst,lpwf->nChannels == 1 ? IDS_NOZEROMONOFMT:
  315. IDS_NOZEROSTEREOFMT, achFormat, SIZEOF(achFormat));
  316. wsprintf(sz, achFormat,
  317. chDecimal,
  318. (WORD) (lpwf->nSamplesPerSec % 1000),
  319. (WORD) (lpwf->nAvgBytesPerSec * 8 / lpwf->nSamplesPerSec / lpwf->nChannels));
  320. }
  321. } // WaveFormatToString
  322. #ifdef THRESHOLD
  323. /*
  324. * SkipToStart()
  325. *
  326. * move forward through sound file to the start of a noise.
  327. * What is defined as a noise is rather arbitrary. See NoiseLevel
  328. */
  329. void FAR PASCAL SkipToStart(void)
  330. { BYTE * pb; // pointer to 8 bit sample
  331. int * pi; // pointer to 16 bit sample
  332. BOOL f8; // 8 bit samples
  333. BOOL fStereo; // 2 channels
  334. int iLo; // minimum quiet value
  335. int iHi; // maximum quiet value
  336. fStereo = (gpWaveFormat->nChannels != 1);
  337. f8 = (pWaveFormat->wBitsPerSample == 8);
  338. if (f8)
  339. { int iDelta = MulDiv(128, iNoiseLevel, 100);
  340. iLo = 128 - iDelta;
  341. iHi = 128 + iDelta;
  342. }
  343. else
  344. { int iDelta = MulDiv(32767, iNoiseLevel, 100);
  345. iLo = 0 - iDelta;
  346. iHi = 0 + iDelta;
  347. }
  348. pb = (BYTE *) gpWaveSamples
  349. + wfSamplesToBytes(gpWaveFormat, glWavePosition);
  350. pi = (int *)pb;
  351. while (glWavePosition < glWaveSamplesValid)
  352. { if (f8)
  353. { if ( ((int)(*pb) > iHi) || ((int)(*pb) < iLo) )
  354. break;
  355. ++pb;
  356. if (fStereo)
  357. { if ( ((int)(*pb) > iHi) || ((int)(*pb) < iLo) )
  358. break;
  359. ++pb;
  360. }
  361. }
  362. else
  363. { if ( (*pi > iHi) || (*pi < iLo) )
  364. break;
  365. ++pi;
  366. if (fStereo)
  367. { if ( (*pi > iHi) || (*pi < iLo) )
  368. break;
  369. ++pi;
  370. }
  371. }
  372. ++glWavePosition;
  373. }
  374. UpdateDisplay(FALSE);
  375. } /* SkipToStart */
  376. /*
  377. * SkipToEnd()
  378. *
  379. * move forward through sound file to a quiet place.
  380. * What is defined as quiet is rather arbitrary.
  381. * (Currently less than 20% of full volume for 1000 samples)
  382. */
  383. void FAR PASCAL SkipToEnd(void)
  384. { BYTE * pb; // pointer to 8 bit sample
  385. int * pi; // pointer to 16 bit sample
  386. BOOL f8; // 8 bit samples
  387. BOOL fStereo; // 2 channels
  388. int cQuiet; // number of successive quiet samples so far
  389. LONG lQuietPos; // Start of quiet period
  390. LONG lPos; // Search counter
  391. int iLo; // minimum quiet value
  392. int iHi; // maximum quiet value
  393. fStereo = (gpWaveFormat->nChannels != 1);
  394. f8 = (gpWaveFormat->wBitsPerSample == 8);
  395. if (f8)
  396. { int iDelta = MulDiv(128, iNoiseLevel, 100);
  397. iLo = 128 - iDelta;
  398. iHi = 128 + iDelta;
  399. }
  400. else
  401. { int iDelta = MulDiv(32767, iNoiseLevel, 100);
  402. iLo = 0 - iDelta;
  403. iHi = 0 + iDelta;
  404. }
  405. pb = (BYTE *) gpWaveSamples
  406. + wfSamplesToBytes(gpWaveFormat, glWavePosition);
  407. pi = (int *)pb;
  408. cQuiet = 0;
  409. lQuietPos = glWavePosition;
  410. lPos = glWavePosition;
  411. while (lPos < glWaveSamplesValid)
  412. { BOOL fQuiet = TRUE;
  413. if (f8)
  414. { if ( ((int)(*pb) > iHi) || ((int)(*pb) < iLo) ) fQuiet = FALSE;
  415. if (fStereo)
  416. { ++pb;
  417. if ( ((int)(*pb) > iHi) || ((int)(*pb) < iLo) ) fQuiet = FALSE;
  418. }
  419. ++pb;
  420. }
  421. else
  422. { if ( (*pi > iHi) || (*pi < iLo) ) fQuiet = FALSE;
  423. if (fStereo)
  424. { ++pi;
  425. if ( (*pi > iHi) || (*pi < iLo) ) fQuiet = FALSE;
  426. }
  427. ++pi;
  428. }
  429. if (!fQuiet) cQuiet = 0;
  430. else if (cQuiet == 0)
  431. { lQuietPos = lPos;
  432. ++cQuiet;
  433. }
  434. else
  435. { ++cQuiet;
  436. if (cQuiet>=iQuietLength) break;
  437. }
  438. ++lPos;
  439. }
  440. glWavePosition = lQuietPos;
  441. UpdateDisplay(FALSE);
  442. } /* SkipToEnd */
  443. /*
  444. * IncreaseThresh()
  445. *
  446. * Increase the threshold of what counts as quiet by about 25%
  447. * Ensure it changes by at least 1 unless on the stop already
  448. *
  449. */
  450. void FAR PASCAL IncreaseThresh(void)
  451. { iNoiseLevel = MulDiv(iNoiseLevel+1, 5, 4);
  452. if (iNoiseLevel>100) iNoiseLevel = 100;
  453. } // IncreaseThreshold
  454. /*
  455. * DecreaseThresh()
  456. *
  457. * Decrease the threshold of what counts as quiet by about 25%
  458. * Ensure it changes by at least 1 unless on the stop already
  459. * It's a divisor, so we INcrease the divisor, but never to 0
  460. *
  461. */
  462. void FAR PASCAL DecreaseThresh(void)
  463. { iNoiseLevel = MulDiv(iNoiseLevel, 4, 5)-1;
  464. if (iNoiseLevel <=0) iNoiseLevel = 0;
  465. } // DecreaseThreshold
  466. #endif //THRESHOLD
  467. /* fOK = AllocWaveBuffer(lSamples, fErrorBox, fExact)
  468. *
  469. * If <gpWaveSamples> is NULL, allocate a buffer <lSamples> in size and
  470. * point <gpWaveSamples> to it.
  471. *
  472. * If <gpWaveSamples> already exists, then just reallocate it to be
  473. * <lSamples> in size.
  474. *
  475. * if fExact is FALSE, then when memory is tight, allocate less than
  476. * the amount asked for - so as to give reasonable performance,
  477. * if fExact is TRUE then when memory is short, FAIL.
  478. * NOTE: On NT on a 16MB machine it WILL GIVE you 20MB, i.e. it does
  479. * NOT FAIL - but may (unacceptably) take SEVERAL MINUTES to do so.
  480. * So better to monitor the situation ourselves and ask for less.
  481. *
  482. * On success, return TRUE. On failure, return FALSE but if and only
  483. * if fErrorBox is TRUE then display a MessageBox first.
  484. */
  485. BOOL FAR PASCAL AllocWaveBuffer(
  486. LONG lSamples, // samples to allocate
  487. BOOL fErrorBox, // TRUE if you want an error displayed
  488. BOOL fExact) // TRUE means allocate the full amount requested or FAIL
  489. {
  490. LONG_PTR lAllocSamples; // may be bigger than lSamples
  491. LONG_PTR lBytes; // bytes to allocate
  492. LONG_PTR lBytesReasonable; // bytes reasonable to use (phys mem avail).
  493. MEMORYSTATUS ms;
  494. lAllocSamples = lSamples;
  495. lBytes = wfSamplesToBytes(gpWaveFormat, lSamples);
  496. /* Add extra space to compensate for code generation bug which
  497. causes reference past end */
  498. /* don't allocate anything to be zero bytes long */
  499. lBytes += sizeof(DWORD_PTR);
  500. if (gpWaveSamples == NULL || glWaveSamplesValid == 0L)
  501. {
  502. if (gpWaveSamples != NULL)
  503. { DPF(TEXT("Freeing %x\n"),gpWaveSamples);
  504. GlobalFreePtr(gpWaveSamples);
  505. }
  506. GlobalMemoryStatus(&ms);
  507. lBytesReasonable = ms.dwAvailPhys; // could multiply by a fudge factor
  508. if (lBytesReasonable<1024*1024)
  509. lBytesReasonable = 1024*1024;
  510. if (lBytes>lBytesReasonable)
  511. {
  512. if (fExact) goto ERROR_OUTOFMEM; // Laurie's first goto in 10 years.
  513. // dprintf("Reducing buffer from %d to %d\n", lBytes, lBytesReasonable);
  514. lAllocSamples = wfBytesToSamples(gpWaveFormat,(long)lBytesReasonable);
  515. lBytes = lBytesReasonable+sizeof(DWORD_PTR);
  516. }
  517. /* allocate <lBytes> of memory */
  518. gpWaveSamples = GlobalAllocPtr(GHND|GMEM_SHARE, lBytes);
  519. if (gpWaveSamples == NULL)
  520. {
  521. DPF(TEXT("wave.c Alloc failed, point A. Wanted %d\n"), lBytes);
  522. glWaveSamples = glWaveSamplesValid = 0L;
  523. glWavePosition = 0L;
  524. goto ERROR_OUTOFMEM;
  525. }
  526. else {
  527. DPF(TEXT("wave.c Allocated %d bytes at %x\n"), lBytes, (DWORD_PTR)gpWaveSamples );
  528. }
  529. glWaveSamples = (long)lAllocSamples;
  530. }
  531. else
  532. {
  533. HPBYTE pch;
  534. GlobalMemoryStatus(&ms);
  535. lBytesReasonable = ms.dwAvailPhys;
  536. if (lBytesReasonable<1024*1024) lBytesReasonable = 1024*1024;
  537. if (lBytes > lBytesReasonable+wfSamplesToBytes(gpWaveFormat,glWaveSamplesValid))
  538. {
  539. if (fExact) goto ERROR_OUTOFMEM; // Laurie's second goto in 10 years.
  540. lBytesReasonable += wfSamplesToBytes(gpWaveFormat,glWaveSamplesValid);
  541. lAllocSamples = wfBytesToSamples(gpWaveFormat,(long)lBytesReasonable);
  542. lBytes = lBytesReasonable+4;
  543. }
  544. DPF(TEXT("wave.c ReAllocating %d bytes at %x\n"), lBytes, (DWORD_PTR)gpWaveSamples );
  545. pch = GlobalReAllocPtr(gpWaveSamples, lBytes, GHND|GMEM_SHARE);
  546. if (pch == NULL)
  547. {
  548. DPF(TEXT("wave.c Realloc failed. Wanted %d\n"), lBytes);
  549. goto ERROR_OUTOFMEM;
  550. }
  551. else{ DPF(TEXT("wave.c Reallocated %d at %x\n"), lBytes,(DWORD_PTR)pch);
  552. }
  553. gpWaveSamples = pch;
  554. glWaveSamples = (long)lAllocSamples;
  555. }
  556. /* make sure <glWaveSamplesValid> and <glWavePosition> don't point
  557. * to places they shouldn't
  558. */
  559. if (glWaveSamplesValid > glWaveSamples)
  560. glWaveSamplesValid = glWaveSamples;
  561. if (glWavePosition > glWaveSamplesValid)
  562. glWavePosition = glWaveSamplesValid;
  563. dbgShowMemUse();
  564. return TRUE;
  565. ERROR_OUTOFMEM:
  566. if (fErrorBox) {
  567. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  568. IDS_APPTITLE, IDS_OUTOFMEM);
  569. }
  570. dbgShowMemUse();
  571. return FALSE;
  572. } // AllocWaveBuffer
  573. /* CreateDefaultWaveFormat(lpWaveFormat)
  574. *
  575. * Fill in <*lpWaveFormat> with the "best" format that can be used
  576. * for recording. If recording does not seem to be available, return
  577. * FALSE and set to a default "least common denominator"
  578. * wave audio format.
  579. *
  580. */
  581. WORD wFormats[] =
  582. {
  583. FMT_16BIT | FMT_22k | FMT_MONO, /* Best: 16-bit 22KHz */
  584. FMT_16BIT | FMT_11k | FMT_MONO, /* Best: 16-bit 11KHz */
  585. FMT_8BIT | FMT_22k | FMT_MONO, /* Next: 8-bit 22KHz */
  586. FMT_8BIT | FMT_11k | FMT_MONO /* Last: 8-bit 11KHz */
  587. };
  588. #define NUM_FORMATS (sizeof(wFormats)/sizeof(wFormats[0]))
  589. /*
  590. * This relies on the behaviour of WAVE_MAPPER to supply a correct
  591. * header.
  592. *
  593. *---------------------------------------------------------------
  594. * 6/16/93 TimHa
  595. * Change back to getting a 'best' default format from the
  596. * above array of formats. This is only used if ACM 2.0 isn't
  597. * available to do a format for us.
  598. *---------------------------------------------------------------
  599. *
  600. * */
  601. BOOL PASCAL
  602. CreateDefaultWaveFormat(LPWAVEFORMATEX lpwf, UINT uDeviceID)
  603. {
  604. int i;
  605. lpwf->wFormatTag = WAVE_FORMAT_PCM;
  606. for (i = 0; i < NUM_FORMATS; i++) {
  607. if (CreateWaveFormat(lpwf, wFormats[i], (UINT)WAVE_MAPPER)){
  608. return TRUE;
  609. }
  610. }
  611. //
  612. // Couldn't find anything: leave worst format and return.
  613. //
  614. return FALSE;
  615. } /* CreateDefaultWaveFormat */
  616. /* BOOL PASCAL CreateWaveFormat(LPWAVEFORMATEX lpwf, WORD fmt, UINT uDeviceID)
  617. *
  618. * */
  619. BOOL PASCAL
  620. CreateWaveFormat(LPWAVEFORMATEX lpwf, WORD fmt, UINT uDeviceID)
  621. {
  622. if (fmt == FMT_DEFAULT)
  623. return CreateDefaultWaveFormat(lpwf, uDeviceID);
  624. lpwf->wFormatTag = WAVE_FORMAT_PCM;
  625. lpwf->nSamplesPerSec = (fmt & FMT_RATE) * 11025;
  626. lpwf->nChannels = (WORD)(fmt & FMT_STEREO) ? 2 : 1;
  627. lpwf->wBitsPerSample = (WORD)(fmt & FMT_16BIT) ? 16 : 8;
  628. lpwf->nBlockAlign = (WORD)lpwf->nChannels * ((lpwf->wBitsPerSample + 7) / 8);
  629. lpwf->nAvgBytesPerSec = lpwf->nSamplesPerSec * lpwf->nBlockAlign;
  630. return waveInOpen(NULL
  631. , uDeviceID
  632. , (LPWAVEFORMATEX)lpwf
  633. , 0L
  634. , 0L
  635. , WAVE_FORMAT_QUERY|WAVE_ALLOWSYNC) == 0;
  636. } /* CreateWaveFormat */
  637. /*
  638. * */
  639. BOOL NEAR PASCAL FreeWaveHeaders(void)
  640. {
  641. UINT i;
  642. DPF(TEXT("FreeWaveHeaders!\n"));
  643. // #pragma message("----FreeWaveHeaders: should probably call on exit!")
  644. //
  645. // free any previously allocated wave headers..
  646. //
  647. for (i = 0; i < MAX_WAVEHDRS; i++)
  648. {
  649. if (gapWaveHdr[i])
  650. {
  651. GlobalFreePtr(gapWaveHdr[i]);
  652. gapWaveHdr[i] = NULL;
  653. }
  654. }
  655. return (TRUE);
  656. } /* FreeWaveHeaders() */
  657. /*
  658. * */
  659. BOOL NEAR PASCAL
  660. AllocWaveHeaders(
  661. WAVEFORMATEX * pwfx,
  662. UINT uWaveHdrs)
  663. {
  664. UINT i;
  665. LPWAVEHDR pwh;
  666. FreeWaveHeaders();
  667. //
  668. // allocate all of the wave headers/buffers for streaming
  669. //
  670. for (i = 0; i < uWaveHdrs; i++)
  671. {
  672. pwh = GlobalAllocPtr(GMEM_MOVEABLE, sizeof(WAVEHDR));
  673. if (pwh == NULL)
  674. goto AWH_ERROR_NOMEM;
  675. pwh->lpData = NULL;
  676. pwh->dwBufferLength = 0L;
  677. pwh->dwFlags = 0L;
  678. pwh->dwLoops = 0L;
  679. gapWaveHdr[i] = pwh;
  680. }
  681. return (TRUE);
  682. AWH_ERROR_NOMEM:
  683. FreeWaveHeaders();
  684. return (FALSE);
  685. } /* AllocWaveHeaders() */
  686. /* WriteWaveHeader
  687. Writes wave header - also actually starts the wave I/O
  688. by WaveOutWrite or WaveInAddBuffer.
  689. */
  690. UINT NEAR PASCAL WriteWaveHeader(LPWAVEHDR pwh,BOOL fJustUnprepare)
  691. {
  692. UINT uErr;
  693. BOOL fInput;
  694. DWORD dwLengthToWrite;
  695. #if 1
  696. //see next "mmsystem workaround"
  697. BOOL fFudge;
  698. #endif
  699. fInput = (ghWaveIn != NULL);
  700. if (pwh->dwFlags & WHDR_PREPARED)
  701. {
  702. if (fInput)
  703. uErr = waveInUnprepareHeader(ghWaveIn, pwh, sizeof(WAVEHDR));
  704. else
  705. uErr = waveOutUnprepareHeader(ghWaveOut, pwh, sizeof(WAVEHDR));
  706. //
  707. // because Creative Labs thinks they know what they are doing when
  708. // they don't, we cannot rely on the unprepare succeeding like it
  709. // should after they have posted the header back to us... they fail
  710. // the waveInUnprepareHeader with WAVERR_STILLPLAYING (21h) even
  711. // though the header has been posted back with the WHDR_DONE bit
  712. // set!!
  713. //
  714. // absolutely smurphingly brilliant! and i thought Media Vision was
  715. // the leader in this type of 'Creativity'!! they have competition!
  716. //
  717. #if 0
  718. if (uErr)
  719. {
  720. if (fInput && (uErr == WAVERR_STILLPLAYING) && (pwh->dwFlags & WHDR_DONE))
  721. {
  722. DPF(TEXT("----PERFORMING STUPID HACK FOR CREATIVE LABS' SBPRO----\n"));
  723. pwh->dwFlags &= ~WHDR_PREPARED;
  724. }
  725. else
  726. {
  727. DPF(TEXT("----waveXXUnprepareHeader FAILED! [%.04Xh]\n"), uErr);
  728. return (uErr);
  729. }
  730. }
  731. #else
  732. if (uErr)
  733. {
  734. DPF(TEXT("----waveXXUnprepareHeader FAILED! [%.04Xh]\n"), uErr);
  735. return (uErr);
  736. }
  737. #endif
  738. }
  739. if (fJustUnprepare)
  740. return (0);
  741. dwLengthToWrite = gdwTotalLengthBytes - gdwCurrentBufferPos;
  742. if (gdwBytesPerBuffer < dwLengthToWrite)
  743. dwLengthToWrite = gdwBytesPerBuffer;
  744. //
  745. // if there is nothing to write (either no more data for output or no
  746. // more room for input), then return -1 which signifies this case...
  747. //
  748. if (dwLengthToWrite == 0L)
  749. {
  750. DPF(TEXT("WriteWaveHeader: no more data!\n"));
  751. return (UINT)-1;
  752. }
  753. #if 1
  754. //"mmsystem workaround" Apparently waveXXXPrepareHeader can't pagelock 1 byte, so make us 2
  755. fFudge = (dwLengthToWrite==1);
  756. pwh->dwBufferLength = dwLengthToWrite + ((fFudge)?1L:0L);
  757. #else
  758. pwh->dwBufferLength = dwLengthToWrite;
  759. #endif
  760. pwh->lpData = (LPSTR)&gpWaveSamples[gdwCurrentBufferPos];
  761. pwh->dwBytesRecorded= 0L;
  762. pwh->dwFlags = 0L;
  763. pwh->dwLoops = 0L;
  764. pwh->lpNext = NULL;
  765. pwh->reserved = 0L;
  766. if (fInput)
  767. uErr = waveInPrepareHeader(ghWaveIn, pwh, sizeof(WAVEHDR));
  768. else
  769. uErr = waveOutPrepareHeader(ghWaveOut, pwh, sizeof(WAVEHDR));
  770. if (uErr)
  771. {
  772. DPF(TEXT("waveXXPrepareHeader FAILED! [%.04Xh]\n"), uErr);
  773. return uErr;
  774. }
  775. #if 1
  776. //"mmsystem workaround". Unfudge
  777. if (fFudge)
  778. pwh->dwBufferLength -= 1;
  779. #endif
  780. if (fInput)
  781. uErr = waveInAddBuffer(ghWaveIn, pwh, sizeof(WAVEHDR));
  782. else
  783. uErr = waveOutWrite(ghWaveOut, pwh, sizeof(WAVEHDR));
  784. if (uErr)
  785. {
  786. DPF(TEXT("waveXXAddBuffer FAILED! [%.04Xh]\n"), uErr);
  787. if (fInput)
  788. waveInUnprepareHeader(ghWaveIn, pwh, sizeof(WAVEHDR));
  789. else
  790. waveOutUnprepareHeader(ghWaveOut, pwh, sizeof(WAVEHDR));
  791. return uErr;
  792. }
  793. gdwCurrentBufferPos += dwLengthToWrite;
  794. return 0;
  795. } /* WriteWaveHeader() */
  796. /* if fFineControl is set then reset the position and clear the flag */
  797. void FAR PASCAL SnapBack(void)
  798. {
  799. if (fFineControl)
  800. {
  801. glWavePosition = glSnapBackTo;
  802. UpdateDisplay(TRUE);
  803. fFineControl = FALSE;
  804. }
  805. } /* SnapBack */
  806. /* fOK = NewWave()
  807. *
  808. * Destroy the current waveform, and create a new empty one.
  809. *
  810. * On success, return TRUE. On failure, display an error message
  811. * and return FALSE.
  812. */
  813. BOOL FAR PASCAL
  814. NewWave(WORD fmt, BOOL fNewDlg)
  815. {
  816. BOOL fOK = TRUE;
  817. DPF(TEXT("NewWave called: %s\n"),(gfEmbeddedObject?TEXT("Embedded"):TEXT("App")));
  818. #ifndef CHICAGO
  819. //
  820. // bring up the dialog to get a new waveformat IFF this was
  821. // selected from the File menu
  822. //
  823. if (fNewDlg)
  824. {
  825. PWAVEFORMATEX pWaveFormat;
  826. UINT cbWaveFormat;
  827. if (NewSndDialog(ghInst, ghwndApp, gpWaveFormat, gcbWaveFormat, &pWaveFormat, &cbWaveFormat))
  828. {
  829. /* User made a selection */
  830. /* destroy the current document */
  831. DestroyWave();
  832. gpWaveFormat = pWaveFormat;
  833. gcbWaveFormat = cbWaveFormat;
  834. gidDefaultButton = ID_RECORDBTN;
  835. }
  836. else
  837. {
  838. /* user cancelled or out of mem */
  839. /* should probably handle outofmem differently */
  840. goto RETURN_ERROR;
  841. }
  842. }
  843. else
  844. #endif
  845. {
  846. DWORD cbwfx;
  847. LPWAVEFORMATEX pwfx;
  848. if (!SoundRec_GetDefaultFormat(&pwfx, &cbwfx))
  849. {
  850. cbwfx = sizeof(WAVEFORMATEX);
  851. pwfx = (WAVEFORMATEX *)GlobalAllocPtr(GHND, sizeof(WAVEFORMATEX));
  852. if (pwfx == NULL)
  853. goto ERROR_OUTOFMEM;
  854. CreateWaveFormat(pwfx,fmt,(UINT)WAVE_MAPPER);
  855. }
  856. // destroy the current document
  857. DestroyWave();
  858. gcbWaveFormat = cbwfx;
  859. gpWaveFormat = pwfx;
  860. }
  861. if (gpWaveFormat == NULL)
  862. goto ERROR_OUTOFMEM;
  863. /* allocate an empty wave buffer */
  864. if (!AllocWaveBuffer(0L, TRUE, FALSE))
  865. {
  866. GlobalFreePtr(gpWaveFormat);
  867. gpWaveFormat = NULL;
  868. gcbWaveFormat = 0;
  869. goto RETURN_ERROR;
  870. }
  871. if (!AllocWaveHeaders(gpWaveFormat, guWaveHdrs))
  872. goto ERROR_OUTOFMEM;
  873. UpdateDisplay(TRUE);
  874. goto RETURN_SUCCESS;
  875. ERROR_OUTOFMEM:
  876. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  877. IDS_APPTITLE, IDS_OUTOFMEM);
  878. goto RETURN_ERROR;
  879. RETURN_ERROR:
  880. fOK = FALSE;
  881. RETURN_SUCCESS:
  882. #if 1
  883. //bombay bug #1609 HackFix We're not getting focus on the right guy!
  884. // UpdateDisplay should have done this
  885. if (IsWindowVisible(ghwndApp))
  886. {
  887. if (IsWindowEnabled(ghwndRecord))
  888. SetDlgFocus(ghwndRecord);
  889. else if (IsWindowEnabled(ghwndPlay))
  890. SetDlgFocus(ghwndPlay);
  891. else if (IsWindowEnabled(ghwndScroll))
  892. SetDlgFocus(ghwndScroll);
  893. }
  894. #endif
  895. return fOK;
  896. } // NewWave
  897. /* fOK = DestroyWave()
  898. *
  899. * Destroy the current wave. Do not access <gpWaveSamples> after this.
  900. *
  901. * On success, return TRUE. On failure, display an error message
  902. * and return FALSE.
  903. */
  904. BOOL FAR PASCAL
  905. DestroyWave(void)
  906. {
  907. DPF(TEXT("DestroyWave called\n"));
  908. if ((ghWaveIn != NULL) || (ghWaveOut != NULL))
  909. StopWave();
  910. if (gpWaveSamples != NULL)
  911. {
  912. DPF(TEXT("Freeing %x\n"),gpWaveSamples);
  913. GlobalFreePtr(gpWaveSamples);
  914. }
  915. if (gpWaveFormat != NULL)
  916. GlobalFreePtr(gpWaveFormat);
  917. if (gpszInfo != NULL)
  918. GlobalFreePtr(gpszInfo);
  919. //
  920. // DON'T free wave headers!
  921. //
  922. ////////FreeWaveHeaders();
  923. glWaveSamples = 0L;
  924. glWaveSamplesValid = 0L;
  925. glWavePosition = 0L;
  926. gcbWaveFormat = 0;
  927. gpWaveFormat = NULL;
  928. gpWaveSamples = NULL;
  929. gpszInfo = NULL;
  930. #ifdef NEWPAUSE
  931. //***extra cautionary cleanup
  932. if (ghPausedWave && gfPaused)
  933. {
  934. if (gfWasPlaying)
  935. waveOutClose((HWAVEOUT)ghPausedWave);
  936. else
  937. if (gfWasRecording)
  938. waveInClose((HWAVEIN)ghPausedWave);
  939. }
  940. gfPaused = FALSE;
  941. ghPausedWave = NULL;
  942. #endif
  943. return TRUE;
  944. } /* DestroyWave */
  945. UINT NEAR PASCAL SRecWaveOpen(LPHWAVE lphwave, LPWAVEFORMATEX lpwfx, BOOL fInput)
  946. {
  947. UINT uErr;
  948. if (!lphwave || !lpwfx)
  949. return (1);
  950. #ifdef NEWPAUSE
  951. if (gfPaused && ghPausedWave)
  952. {
  953. /* we are in a paused state. Restore the handle. */
  954. *lphwave = ghPausedWave;
  955. gfPaused = FALSE;
  956. ghPausedWave = NULL;
  957. return MMSYSERR_NOERROR;
  958. }
  959. #endif
  960. *lphwave = NULL;
  961. //
  962. // first open the wave device DISALLOWING sync drivers (sync drivers
  963. // do not work with a streaming buffer scheme; which is our preferred
  964. // mode of operation)
  965. //
  966. // if we cannot open a non-sync driver, then we will attempt for
  967. // a sync driver and disable the streaming buffer scheme..
  968. //
  969. #if 0
  970. gfSyncDriver = FALSE;
  971. #else
  972. //
  973. // if the control key is down, then FORCE use of non-streaming scheme.
  974. // all that this requires is that we set the gfSyncDriver flag
  975. //
  976. if (guWaveHdrs < 2)
  977. gfSyncDriver = TRUE;
  978. else
  979. {
  980. #if 0
  981. //********* Curtis, I don't know gfSyncDriver is always getting set now!
  982. //********* please find out! It probably has something to do with the
  983. //********* hook for f1 help
  984. if (GetAsyncKeyState(VK_CONTROL) & 0x8000)
  985. gfSyncDriver = TRUE;
  986. else
  987. gfSyncDriver = FALSE;
  988. #else
  989. gfSyncDriver = FALSE;
  990. #endif
  991. }
  992. #endif
  993. if (fInput)
  994. {
  995. uErr = waveInOpen((LPHWAVEIN)lphwave
  996. , (UINT)WAVE_MAPPER
  997. , (LPWAVEFORMATEX)lpwfx
  998. , (DWORD_PTR)ghwndApp
  999. , 0L
  1000. , CALLBACK_WINDOW);
  1001. if (uErr)
  1002. {
  1003. /**** bug #967. SPEAKER.DRV does not correctly return WAVERR_SYNC, but it
  1004. **** does return in error */
  1005. // if (uErr == WAVERR_SYNC)
  1006. // {
  1007. uErr = waveInOpen((LPHWAVEIN)lphwave
  1008. , (UINT)WAVE_MAPPER
  1009. , (LPWAVEFORMATEX)lpwfx
  1010. , (DWORD_PTR)ghwndApp
  1011. , 0L
  1012. , CALLBACK_WINDOW|WAVE_ALLOWSYNC);
  1013. if (uErr == MMSYSERR_NOERROR)
  1014. {
  1015. gfSyncDriver = TRUE;
  1016. }
  1017. // }
  1018. }
  1019. }
  1020. else
  1021. {
  1022. uErr = waveOutOpen((LPHWAVEOUT)lphwave
  1023. , (UINT)WAVE_MAPPER
  1024. , (LPWAVEFORMATEX)lpwfx
  1025. , (DWORD_PTR)ghwndApp
  1026. , 0L
  1027. , CALLBACK_WINDOW);
  1028. if (uErr)
  1029. {
  1030. /**** bug #967. SPEAKER.DRV does not correctly return WAVERR_SYNC, but it
  1031. **** does return in error */
  1032. ////////////if (uErr == WAVERR_SYNC)
  1033. ////////////{
  1034. uErr = waveOutOpen((LPHWAVEOUT)lphwave
  1035. , (UINT)WAVE_MAPPER
  1036. , (LPWAVEFORMATEX)lpwfx
  1037. , (DWORD_PTR)ghwndApp
  1038. , 0L
  1039. , CALLBACK_WINDOW|WAVE_ALLOWSYNC);
  1040. if (uErr == MMSYSERR_NOERROR)
  1041. {
  1042. gfSyncDriver = TRUE;
  1043. }
  1044. ////////////}
  1045. }
  1046. }
  1047. return (uErr);
  1048. } /* SRecWaveOpen() */
  1049. /* SRecPlayBegin
  1050. **
  1051. ** Sets
  1052. ** gdwCurrentBufferPos
  1053. ** gdwBytesPerBuffer
  1054. ** gfTimerStarted
  1055. ** fStopping
  1056. ** gfStoppingHard
  1057. ** grgbStatusColor
  1058. ** fCanPlay
  1059. ** glWavePosition
  1060. ** * gapWaveHdr[0]
  1061. ** Calls
  1062. ** StopWave
  1063. ** UpdateDisplay
  1064. ** WriteWaveHeader
  1065. */
  1066. BOOL NEAR PASCAL SRecPlayBegin(BOOL fSyncDriver)
  1067. {
  1068. BOOL fOK = TRUE;
  1069. WORD wIndex;
  1070. UINT uErr;
  1071. //
  1072. //
  1073. //
  1074. //
  1075. gdwCurrentBufferPos = wfSamplesToBytes(gpWaveFormat, glWavePosition);
  1076. if (fSyncDriver)
  1077. {
  1078. gdwBytesPerBuffer = gdwTotalLengthBytes - gdwCurrentBufferPos;
  1079. uErr = WriteWaveHeader(gapWaveHdr[0],FALSE);
  1080. if (uErr)
  1081. {
  1082. if (uErr == MMSYSERR_NOMEM)
  1083. {
  1084. // Prepare failed
  1085. goto PB_ERROR_OUTOFMEM;
  1086. }
  1087. goto PB_ERROR_WAVEOUTWRITE;
  1088. }
  1089. }
  1090. else
  1091. {
  1092. gdwBytesPerBuffer = wfTimeToSamples(gpWaveFormat, gwMSecsPerBuffer);
  1093. gdwBytesPerBuffer = wfSamplesToBytes(gpWaveFormat, gdwBytesPerBuffer);
  1094. #if defined(_WIN32)
  1095. StartPreTouchThread( &(gpWaveSamples[gdwCurrentBufferPos])
  1096. , gdwTotalLengthBytes - gdwCurrentBufferPos
  1097. );
  1098. #endif //_WIN32
  1099. //
  1100. // First wave header to be played is zero
  1101. //
  1102. fStopping = FALSE;
  1103. waveOutPause(ghWaveOut);
  1104. for (wIndex=0; wIndex < guWaveHdrs; wIndex++)
  1105. {
  1106. uErr = WriteWaveHeader(gapWaveHdr[wIndex],FALSE);
  1107. if (uErr)
  1108. {
  1109. //
  1110. // WriteWaveHeader will return -1 if there is no
  1111. // more data to write. This is not an error!
  1112. //
  1113. // It indicates that the previous block was the
  1114. // last one queued. Flag that we are doing cleanup
  1115. // (just waiting for headers to complete) and save
  1116. // which header is the last one to wait for.
  1117. //
  1118. if (uErr == (UINT)-1)
  1119. {
  1120. if (wIndex == 0)
  1121. {
  1122. StopWave();
  1123. goto PB_RETURN_SUCCESS;
  1124. }
  1125. break;
  1126. }
  1127. //
  1128. // If we run out of memory, but have already written
  1129. // at least 2 wave headers, we can still keep going.
  1130. // If we've written 0 or 1, we can't stream and will
  1131. // stop.
  1132. //
  1133. if (uErr == MMSYSERR_NOMEM)
  1134. {
  1135. if (wIndex > 1)
  1136. break;
  1137. // Prepare failed
  1138. StopWave();
  1139. goto PB_ERROR_OUTOFMEM;
  1140. }
  1141. StopWave();
  1142. goto PB_ERROR_WAVEOUTWRITE;
  1143. }
  1144. }
  1145. waveOutRestart(ghWaveOut);
  1146. }
  1147. /* update the display, including the status string */
  1148. UpdateDisplay(TRUE);
  1149. if (fSyncDriver)
  1150. {
  1151. /* do display updates */
  1152. gfTimerStarted = (BOOL)SetTimer(ghwndApp, 1, TIMER_MSEC, NULL);
  1153. }
  1154. /* if user stops, focus will go back to "Play" button */
  1155. gidDefaultButton = ID_PLAYBTN;
  1156. fStopping = FALSE;
  1157. goto PB_RETURN_SUCCESS;
  1158. PB_ERROR_WAVEOUTWRITE:
  1159. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1160. IDS_APPTITLE, IDS_CANTOPENWAVEOUT);
  1161. goto PB_RETURN_ERROR;
  1162. PB_ERROR_OUTOFMEM :
  1163. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1164. IDS_APPTITLE, IDS_OUTOFMEM);
  1165. ////goto PB_RETURN_ERROR;
  1166. PB_RETURN_ERROR:
  1167. fOK = FALSE;
  1168. PB_RETURN_SUCCESS:
  1169. return fOK;
  1170. } /* SRecPlayBegin() */
  1171. /* fOK = PlayWave()
  1172. *
  1173. * Start playing from the current position.
  1174. *
  1175. * On success, return TRUE. On failure, display an error message
  1176. * and return FALSE.
  1177. */
  1178. BOOL FAR PASCAL
  1179. PlayWave(void)
  1180. {
  1181. BOOL fOK = TRUE; // does this function succeed?
  1182. UINT uErr;
  1183. DPF(TEXT("PlayWave called\n"));
  1184. /* we are currently playing....*/
  1185. if (ghWaveOut != NULL)
  1186. return TRUE;
  1187. #if 1
  1188. // Still trying to get this right with some bogus estimations
  1189. // We shouldn't have to do this correction, but our conversions
  1190. // are never 1:1
  1191. // try to align us.
  1192. glWavePosition = wfSamplesToSamples(gpWaveFormat,glWavePosition);
  1193. {
  1194. long lBlockInSamples;
  1195. // if the distance between the glWaveSamplesValid and glWavePosition
  1196. // is less than a "block"
  1197. lBlockInSamples = wfBytesToSamples(gpWaveFormat,
  1198. gpWaveFormat->nBlockAlign);
  1199. if (glWaveSamplesValid - glWavePosition < lBlockInSamples)
  1200. glWavePosition -= lBlockInSamples;
  1201. if (glWavePosition < 0L)
  1202. glWavePosition = 0L;
  1203. }
  1204. #endif
  1205. //
  1206. // refuse to play a zero length wave file.
  1207. //
  1208. if (glWaveSamplesValid == glWavePosition)
  1209. goto RETURN_ERROR;
  1210. /* stop playing or recording */
  1211. StopWave();
  1212. gdwTotalLengthBytes = wfSamplesToBytes(gpWaveFormat, glWaveSamples);
  1213. /* open the wave output device */
  1214. uErr = SRecWaveOpen((LPHWAVE)&ghWaveOut, gpWaveFormat, FALSE);
  1215. if (uErr)
  1216. {
  1217. ghWaveOut = NULL;
  1218. /* cannot open the waveform output device -- if the problem
  1219. ** is that <gWaveFormat> is not supported, tell the user that
  1220. **
  1221. ** If the wave format is bad, then the play button is liable
  1222. ** to be grayed, and the user is not going to be able to ask
  1223. ** it to try to play, so we don't get here, so he doesn't get
  1224. ** a decent diagnostic!!!
  1225. */
  1226. if (uErr == WAVERR_BADFORMAT)
  1227. {
  1228. ErrorResBox(ghwndApp, ghInst,
  1229. MB_ICONEXCLAMATION | MB_OK, IDS_APPTITLE,
  1230. IDS_BADOUTPUTFORMAT);
  1231. goto RETURN_ERROR;
  1232. }
  1233. else
  1234. {
  1235. /* unknown error */
  1236. goto ERROR_WAVEOUTOPEN;
  1237. }
  1238. }
  1239. if (ghWaveOut == NULL)
  1240. goto ERROR_WAVEOUTOPEN;
  1241. /* start waveform output */
  1242. // if fFineControl is still set then this is a pause as it has never
  1243. // been properly stopped. This means that we should keep remembering
  1244. // the old position and stay in fine control mode, (else set new position)
  1245. if (!fFineControl) {
  1246. glSnapBackTo = glWavePosition;
  1247. fFineControl = (0 > GetKeyState(VK_SHIFT));
  1248. }
  1249. glStartPlayRecPos = glWavePosition;
  1250. //
  1251. // now kickstart the output...
  1252. //
  1253. if (SRecPlayBegin(gfSyncDriver) == FALSE)
  1254. {
  1255. waveOutClose(ghWaveOut);
  1256. ghWaveOut = NULL;
  1257. ghPausedWave = NULL;
  1258. gfPaused = FALSE;
  1259. goto RETURN_ERROR;
  1260. }
  1261. goto RETURN_SUCCESS;
  1262. ERROR_WAVEOUTOPEN:
  1263. if (!waveInGetNumDevs() && !waveOutGetNumDevs()) {
  1264. /* No recording or playback devices */
  1265. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1266. IDS_APPTITLE, IDS_NOWAVEFORMS);
  1267. } else {
  1268. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1269. IDS_APPTITLE, IDS_CANTOPENWAVEOUT);
  1270. }
  1271. //goto RETURN_ERROR;
  1272. RETURN_ERROR:
  1273. UpdateDisplay(TRUE);
  1274. /* fix bug 4454 (WinWorks won't close) --EricLe */
  1275. if (!IsWindowVisible(ghwndApp))
  1276. PostMessage(ghwndApp, WM_CLOSE, 0, 0L);
  1277. fOK = FALSE;
  1278. RETURN_SUCCESS:
  1279. return fOK;
  1280. } // PlayWave
  1281. BOOL NEAR PASCAL SRecRecordBegin(BOOL fSyncDriver)
  1282. {
  1283. UINT uErr;
  1284. long lSamples;
  1285. long lOneSec;
  1286. HCURSOR hcurSave;
  1287. DWORD dwBytesAvailable;
  1288. WORD w;
  1289. /* ok we go the wave device now allocate some memory to record into.
  1290. * try to get at most 60sec from the current position.
  1291. */
  1292. lSamples = glWavePosition + wfTimeToSamples(gpWaveFormat, gdwBufferDeltaMSecs);
  1293. lOneSec = wfTimeToSamples(gpWaveFormat, 1000);
  1294. hcurSave = SetCursor(LoadCursor(NULL, IDC_WAIT));
  1295. //
  1296. // set the current buffer position (in BYTES) to the current position
  1297. // of the thumb (in SAMPLES)...
  1298. //
  1299. gdwCurrentBufferPos = wfSamplesToBytes(gpWaveFormat, glWavePosition);
  1300. //
  1301. // compute the the size of each buffer for the async case only
  1302. //
  1303. if (!fSyncDriver)
  1304. {
  1305. gdwBytesPerBuffer = wfTimeToSamples(gpWaveFormat, gwMSecsPerBuffer);
  1306. gdwBytesPerBuffer = wfSamplesToBytes(gpWaveFormat, gdwBytesPerBuffer);
  1307. }
  1308. for (;;)
  1309. {
  1310. DPF(TEXT("RecordWave trying %ld samples %ld.%03ldsec\n"), lSamples, wfSamplesToTime(gpWaveFormat, lSamples)/1000, wfSamplesToTime(gpWaveFormat, lSamples) % 1000);
  1311. if (lSamples < glWaveSamplesValid)
  1312. lSamples = glWaveSamplesValid;
  1313. if (AllocWaveBuffer(lSamples, FALSE, FALSE))
  1314. {
  1315. dwBytesAvailable = wfSamplesToBytes(gpWaveFormat, glWaveSamples - glWavePosition);
  1316. gdwTotalLengthBytes = dwBytesAvailable + gdwCurrentBufferPos;
  1317. if (fSyncDriver)
  1318. {
  1319. //
  1320. // for the sync driver case, there is only one buffer--so
  1321. // set the size of our 'buffer' to be the total size...
  1322. //
  1323. gdwBytesPerBuffer = dwBytesAvailable;
  1324. //
  1325. // try to prepare and add the complete buffer--if this fails,
  1326. // then we will try a smaller buffer..
  1327. //
  1328. uErr = WriteWaveHeader(gapWaveHdr[0], FALSE);
  1329. if (uErr == 0)
  1330. break;
  1331. }
  1332. else
  1333. {
  1334. //
  1335. // Make sure we can prepare enough wave headers to stream
  1336. // even if realloc succeeded
  1337. //
  1338. for (w = 0; w < guWaveHdrs; w++)
  1339. {
  1340. uErr = WriteWaveHeader(gapWaveHdr[w], FALSE);
  1341. if (uErr)
  1342. {
  1343. //
  1344. // WriteWaveHeader will return -1 if there is no
  1345. // more data to write. This is not an error!
  1346. //
  1347. // It indicates that the previous block was the
  1348. // last one queued. Flag that we are doing cleanup
  1349. // (just waiting for headers to complete) and save
  1350. // which header is the last one to wait for.
  1351. //
  1352. if (uErr == (UINT)-1)
  1353. {
  1354. if (w == 0)
  1355. {
  1356. StopWave();
  1357. return (TRUE);
  1358. }
  1359. break;
  1360. }
  1361. //
  1362. // If we run out of memory, but have already written
  1363. // at least 2 wave headers, we can still keep going.
  1364. // If we've written 0 or 1, we can't stream and will
  1365. // stop.
  1366. //
  1367. if (uErr == MMSYSERR_NOMEM)
  1368. {
  1369. if (w > 1)
  1370. break;
  1371. StopWave();
  1372. goto BEGINREC_ERROR_OUTOFMEM;
  1373. }
  1374. goto BEGINREC_ERROR_WAVEINSTART;
  1375. }
  1376. }
  1377. //
  1378. // we wrote enough (we think), so break out of the realloc
  1379. // loop
  1380. //
  1381. break;
  1382. }
  1383. }
  1384. //
  1385. // we can't get the memory we want, so try 25% less.
  1386. //
  1387. if (lSamples <= glWaveSamplesValid ||
  1388. lSamples < glWavePosition + lOneSec)
  1389. {
  1390. SetCursor(hcurSave);
  1391. goto BEGINREC_ERROR_OUTOFMEM;
  1392. }
  1393. lSamples = glWavePosition + ((lSamples-glWavePosition)*75)/100;
  1394. }
  1395. SetCursor(hcurSave);
  1396. glStartPlayRecPos = glWavePosition;
  1397. BeginWaveEdit();
  1398. if (waveInStart(ghWaveIn) != 0)
  1399. goto BEGINREC_ERROR_WAVEINSTART;
  1400. /* update the display, including the status string */
  1401. UpdateDisplay(TRUE);
  1402. //
  1403. // only start timer in the sync driver case--async case we use the
  1404. // buffers being posted back as our display update timer...
  1405. //
  1406. if (fSyncDriver)
  1407. {
  1408. /* do display updates */
  1409. gfTimerStarted = (BOOL)SetTimer(ghwndApp, 1, TIMER_MSEC, NULL);
  1410. }
  1411. /* if user stops, focus will go back to "Record" button */
  1412. gidDefaultButton = ID_RECORDBTN;
  1413. fStopping = FALSE;
  1414. return TRUE;
  1415. BEGINREC_ERROR_OUTOFMEM:
  1416. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1417. IDS_APPTITLE, IDS_OUTOFMEM);
  1418. goto BEGINREC_ERROR;
  1419. BEGINREC_ERROR_WAVEINSTART:
  1420. /* This is necessary to un-add the buffer */
  1421. waveInReset(ghWaveIn);
  1422. EndWaveEdit(FALSE);
  1423. /* The wave device will get closed in WaveInData() */
  1424. // goto BEGINREC_ERROR;
  1425. BEGINREC_ERROR:
  1426. return FALSE;
  1427. } /* SRecRecordBegin() */
  1428. /* fOK = RecordWave()
  1429. *
  1430. * Start recording at the current position.
  1431. *
  1432. * On success, return TRUE. On failure, display an error message
  1433. * and return FALSE.
  1434. */
  1435. BOOL FAR PASCAL
  1436. RecordWave(void)
  1437. {
  1438. UINT uErr;
  1439. /* stop playing or recording */
  1440. StopWave();
  1441. glWavePosition = wfSamplesToSamples(gpWaveFormat, glWavePosition);
  1442. /* open the wave input device */
  1443. uErr = SRecWaveOpen((LPHWAVE)&ghWaveIn, gpWaveFormat, TRUE);
  1444. if (uErr)
  1445. {
  1446. /* cannot open the waveform input device -- if the problem
  1447. * is that <gWaveFormat> is not supported, advise the user to
  1448. * do File/New to record; if the problem is that recording is
  1449. * not supported even at 11KHz, tell the user
  1450. */
  1451. if (uErr == WAVERR_BADFORMAT)
  1452. {
  1453. WAVEFORMATEX wf;
  1454. /* is 11KHz mono recording supported? */
  1455. if (!CreateWaveFormat(&wf, FMT_11k|FMT_MONO|FMT_8BIT,
  1456. (UINT)WAVE_MAPPER))
  1457. {
  1458. /* even 11KHz mono recording is not supported */
  1459. ErrorResBox(ghwndApp, ghInst,
  1460. MB_ICONEXCLAMATION | MB_OK, IDS_APPTITLE,
  1461. IDS_INPUTNOTSUPPORT);
  1462. goto RETURN_ERROR;
  1463. }
  1464. else
  1465. {
  1466. /* 11KHz mono is supported, but the format
  1467. * of the current file is not supported
  1468. */
  1469. ErrorResBox(ghwndApp, ghInst,
  1470. MB_ICONEXCLAMATION | MB_OK, IDS_APPTITLE,
  1471. IDS_BADINPUTFORMAT);
  1472. goto RETURN_ERROR;
  1473. }
  1474. }
  1475. else
  1476. {
  1477. /* unknown error */
  1478. goto ERROR_WAVEINOPEN;
  1479. }
  1480. }
  1481. if (ghWaveIn == NULL)
  1482. goto ERROR_WAVEINOPEN;
  1483. if (!SRecRecordBegin(gfSyncDriver))
  1484. goto RETURN_ERROR;
  1485. goto RETURN_SUCCESS;
  1486. ERROR_WAVEINOPEN:
  1487. if (!waveInGetNumDevs() && !waveOutGetNumDevs()) {
  1488. /* No recording or playback devices */
  1489. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1490. IDS_APPTITLE, IDS_NOWAVEFORMS);
  1491. } else {
  1492. ErrorResBox(ghwndApp, ghInst, MB_ICONEXCLAMATION | MB_OK,
  1493. IDS_APPTITLE, IDS_CANTOPENWAVEIN);
  1494. }
  1495. // goto RETURN_ERROR;
  1496. RETURN_ERROR:
  1497. if (ghWaveIn)
  1498. waveInClose(ghWaveIn);
  1499. ghWaveIn = NULL;
  1500. ghPausedWave = NULL;
  1501. if (glWaveSamples > glWaveSamplesValid)
  1502. {
  1503. /* reallocate the wave buffer to be small */
  1504. AllocWaveBuffer(glWaveSamplesValid, TRUE, TRUE);
  1505. }
  1506. UpdateDisplay(TRUE);
  1507. RETURN_SUCCESS:
  1508. return TRUE;
  1509. } /* RecordWave */
  1510. /* YieldStop(void)
  1511. *
  1512. * Yeild for mouse and keyboard messages so that the stop can be
  1513. * processed.
  1514. */
  1515. BOOL NEAR PASCAL YieldStop(void)
  1516. {
  1517. BOOL f;
  1518. MSG msg;
  1519. f = FALSE;
  1520. // Perhaps someone might deign to write a line or two
  1521. // to explain why this loop is here twice and what it's actually doing?
  1522. while (PeekMessage(&msg, ghwndStop, WM_MOUSEFIRST, WM_MOUSELAST, PM_REMOVE | PM_NOYIELD))
  1523. {
  1524. f = TRUE;
  1525. TranslateMessage(&msg);
  1526. DispatchMessage(&msg);
  1527. }
  1528. while (PeekMessage(&msg, ghwndStop, WM_KEYFIRST, WM_KEYLAST, PM_REMOVE | PM_NOYIELD))
  1529. {
  1530. f = TRUE;
  1531. TranslateMessage(&msg);
  1532. DispatchMessage(&msg);
  1533. }
  1534. return (f);
  1535. } /* YieldStop() */
  1536. BOOL NEAR PASCAL IsAsyncStop(void)
  1537. {
  1538. //
  1539. // we need to check for the esc key being pressed--BUT, we don't want
  1540. // to stop unless ONLY the esc key is pressed. so if someone tries to
  1541. // bring up task man with xxx-esc, it will not stop the playing wave..
  1542. //
  1543. if (GetAsyncKeyState(VK_ESCAPE) & 0x8000)
  1544. {
  1545. if ((GetAsyncKeyState(VK_CONTROL) & 0x8000) ||
  1546. (GetAsyncKeyState(VK_MENU) & 0x8000) ||
  1547. (GetAsyncKeyState(VK_SHIFT) & 0x8000))
  1548. {
  1549. return (FALSE);
  1550. }
  1551. //
  1552. // looks like only the esc key..
  1553. //
  1554. return (TRUE);
  1555. }
  1556. return (FALSE);
  1557. } /* IsAsyncStop() */
  1558. /* WaveOutDone(hWaveOut, pWaveHdr)
  1559. *
  1560. * Called when wave block with header <pWaveHdr> is finished playing.
  1561. * This function causes playing to end.
  1562. */
  1563. void FAR PASCAL
  1564. WaveOutDone(
  1565. HWAVEOUT hWaveOut, // wave out device
  1566. LPWAVEHDR pWaveHdr) // wave header
  1567. {
  1568. BOOL f;
  1569. MSG msg;
  1570. WORD w;
  1571. BOOL fStillMoreToGo;
  1572. UINT u;
  1573. ////DPF(TEXT("WaveOutDone()\n"));
  1574. //
  1575. // check for plunger message--if we get this message, then we are done
  1576. // and need to close the wave device if it is still open...
  1577. //
  1578. if (pWaveHdr == NULL) {
  1579. #ifdef NEWPAUSE
  1580. if (!gfPausing) {
  1581. if (ghWaveOut) {
  1582. waveOutClose(ghWaveOut);
  1583. ghWaveOut = NULL;
  1584. ghPausedWave = NULL;
  1585. }
  1586. }
  1587. else
  1588. {
  1589. gfPaused = TRUE;
  1590. ghWaveOut = NULL;
  1591. }
  1592. #else
  1593. if (ghWaveOut) {
  1594. waveOutClose(ghWaveOut);
  1595. ghWaveOut = NULL;
  1596. }
  1597. #endif
  1598. } else /* pWaveHdr!=NULL */
  1599. if (gfSyncDriver) {
  1600. WriteWaveHeader(pWaveHdr, TRUE);
  1601. //
  1602. // !! must do this for sync drivers !!
  1603. //
  1604. if (!gfStoppingHard)
  1605. /* I really don't understand the details of this yet.
  1606. ** What you might call the random stab method of programming!
  1607. ** Laurie
  1608. */
  1609. glWavePosition = glWaveSamplesValid;
  1610. #ifdef NEWPAUSE
  1611. if (!gfPausing) {
  1612. waveOutClose(ghWaveOut);
  1613. ghWaveOut = NULL;
  1614. ghPausedWave = NULL;
  1615. } else {
  1616. ghWaveOut = NULL;
  1617. gfPaused = TRUE;
  1618. }
  1619. #else
  1620. waveOutClose(ghWaveOut);
  1621. ghWaveOut = NULL;
  1622. #endif
  1623. } else { /* pWaveHdr!=NULL & !gfSyncDriver */
  1624. if (!fStopping) {
  1625. while (1) {
  1626. glWavePosition += wfBytesToSamples(gpWaveFormat, pWaveHdr->dwBufferLength);
  1627. //
  1628. // Go into cleanup mode (stop writing new data) on any error
  1629. //
  1630. u = WriteWaveHeader(pWaveHdr, FALSE);
  1631. if (u) {
  1632. if (u == (UINT)-1) {
  1633. /* pWaveHdr!=NULL & !gfSyncDriver
  1634. & WriteWaveHeader() returned -1
  1635. */
  1636. fStopping = TRUE;
  1637. //
  1638. // we cannot assume that the wave position is going
  1639. // to end up exactly at the end with compressed data
  1640. // because of this, we cannot do this postion compare
  1641. // to see if we are 'completely' done (all headers
  1642. // posted back, etc
  1643. //
  1644. // so we jump to a piece of code that searches for
  1645. // any buffers that are still outstanding...
  1646. //
  1647. #if 0
  1648. if (glWavePosition >= glWaveSamplesValid)
  1649. {
  1650. waveOutClose(ghWaveOut);
  1651. ghWaveOut = NULL;
  1652. }
  1653. break;
  1654. #else
  1655. fStillMoreToGo = FALSE;
  1656. goto KLUDGE_FOR_NOELS_BUG;
  1657. #endif
  1658. }
  1659. DPF(TEXT("WaveOutDone: CRITICAL ERROR ON WRITING BUFFER [%.04Xh]\n"), u);
  1660. StopWave();
  1661. } else {
  1662. if (IsAsyncStop()) {
  1663. StopWave();
  1664. return;
  1665. }
  1666. if (YieldStop()) {
  1667. return;
  1668. }
  1669. }
  1670. f = PeekMessage(&msg, ghwndApp, MM_WOM_DONE, MM_WOM_DONE,
  1671. PM_REMOVE | PM_NOYIELD);
  1672. if (!f)
  1673. break;
  1674. //
  1675. // don't let plunger msg mess us up!
  1676. //
  1677. if (msg.lParam == 0L)
  1678. break;
  1679. pWaveHdr = (LPWAVEHDR)msg.lParam;
  1680. }
  1681. } else {
  1682. fStillMoreToGo = FALSE;
  1683. if (gfStoppingHard) {
  1684. while (1) {
  1685. DPF(TEXT("HARDSTOP PLAY: another one bites the dust!\n"));
  1686. WriteWaveHeader(pWaveHdr, TRUE);
  1687. f = PeekMessage(&msg, ghwndApp, MM_WOM_DONE, MM_WOM_DONE,
  1688. PM_REMOVE | PM_NOYIELD);
  1689. if (!f)
  1690. break;
  1691. //
  1692. // don't let plunger msg mess us up!
  1693. //
  1694. if (msg.lParam == 0L)
  1695. break;
  1696. pWaveHdr = (LPWAVEHDR)msg.lParam;
  1697. }
  1698. } else {
  1699. glWavePosition += wfBytesToSamples(gpWaveFormat, pWaveHdr->dwBufferLength);
  1700. WriteWaveHeader(pWaveHdr, TRUE);
  1701. KLUDGE_FOR_NOELS_BUG:
  1702. for (w = 0; w < guWaveHdrs; w++) {
  1703. if (gapWaveHdr[w]->dwFlags & WHDR_PREPARED) {
  1704. DPF(TEXT("PLAY: still more headers outstanding...\n"));
  1705. fStillMoreToGo = TRUE;
  1706. break;
  1707. }
  1708. }
  1709. }
  1710. if (!fStillMoreToGo) {
  1711. //
  1712. // if the user did not push stop (ie we played through
  1713. // normally) put the position at the end of the wave.
  1714. //
  1715. // note we need to do this for sync drivers and compressed
  1716. // wave's
  1717. //
  1718. if (!gfStoppingHard)
  1719. glWavePosition = glWaveSamplesValid;
  1720. #ifdef NEWPAUSE
  1721. if (!gfPausing) {
  1722. waveOutClose(ghWaveOut);
  1723. ghWaveOut = NULL;
  1724. ghPausedWave = NULL;
  1725. } else {
  1726. ghWaveOut = NULL;
  1727. gfPaused = TRUE;
  1728. }
  1729. #else
  1730. waveOutClose(ghWaveOut);
  1731. ghWaveOut = NULL;
  1732. #endif
  1733. {
  1734. if (gfCloseAtEndOfPlay)
  1735. PostMessage(ghwndApp, WM_CLOSE, 0, 0L);
  1736. }
  1737. }
  1738. }
  1739. }
  1740. UpdateDisplay(TRUE);
  1741. //
  1742. //
  1743. //
  1744. //
  1745. if (ghWaveOut == NULL) {
  1746. if (gfTimerStarted) {
  1747. KillTimer(ghwndApp, 1);
  1748. gfTimerStarted = FALSE;
  1749. }
  1750. SnapBack();
  1751. }
  1752. /* If we were showing the window temporarily while playing,
  1753. hide it now. */
  1754. if (ghWaveOut == NULL && gfHideAfterPlaying) {
  1755. DPF(TEXT("Done playing, so hide window.\n"));
  1756. ShowWindow(ghwndApp, SW_HIDE);
  1757. }
  1758. if (ghWaveOut == NULL && !IsWindowVisible(ghwndApp))
  1759. PostMessage(ghwndApp, WM_CLOSE, 0, 0L);
  1760. } /* WaveOutDone */
  1761. /* WaveInData(hWaveIn, pWaveHdr)
  1762. *
  1763. * Called when wave block with header <pWaveHdr> is finished being
  1764. * recorded. This function causes recording to end.
  1765. */
  1766. void FAR PASCAL
  1767. WaveInData(
  1768. HWAVEIN hWaveIn, // wave in device
  1769. LPWAVEHDR pWaveHdr) // wave header
  1770. {
  1771. BOOL f;
  1772. MSG msg;
  1773. WORD w;
  1774. BOOL fStillMoreToGo;
  1775. UINT u;
  1776. //
  1777. // check for plunger message--if we get this message, then we are done
  1778. // and need to close the wave device if it is still open...
  1779. //
  1780. if (pWaveHdr == NULL)
  1781. {
  1782. //*** BOMBAY:1370 how do we pause without closing the handle?
  1783. #ifdef NEWPAUSE
  1784. if (!gfPausing)
  1785. {
  1786. if (ghWaveIn)
  1787. {
  1788. waveInClose(ghWaveIn);
  1789. ghWaveIn = NULL;
  1790. ghPausedWave = NULL;
  1791. }
  1792. }
  1793. else
  1794. {
  1795. gfPaused = TRUE;
  1796. ghWaveIn = NULL;
  1797. }
  1798. #else
  1799. if (ghWaveIn)
  1800. {
  1801. waveInClose(ghWaveIn);
  1802. ghWaveIn = NULL;
  1803. }
  1804. #endif
  1805. }
  1806. else if (gfSyncDriver)
  1807. {
  1808. glWavePosition = glStartPlayRecPos + wfBytesToSamples(gpWaveFormat,
  1809. pWaveHdr->dwBytesRecorded);
  1810. if (glWaveSamplesValid < glWavePosition)
  1811. glWaveSamplesValid = glWavePosition;
  1812. WriteWaveHeader(pWaveHdr, TRUE);
  1813. //*** BOMBAY:1370 How do we pause without closing the handle?
  1814. #ifdef NEWPAUSE
  1815. if (!gfPausing)
  1816. {
  1817. waveInClose(ghWaveIn);
  1818. ghWaveIn = NULL;
  1819. ghPausedWave = NULL;
  1820. }
  1821. else
  1822. {
  1823. ghWaveIn = NULL;
  1824. gfPaused = TRUE;
  1825. }
  1826. #else
  1827. waveInClose(ghWaveIn);
  1828. ghWaveIn = NULL;
  1829. #endif
  1830. }
  1831. else
  1832. {
  1833. if (!fStopping)
  1834. {
  1835. while (1)
  1836. {
  1837. glWavePosition += wfBytesToSamples(gpWaveFormat, pWaveHdr->dwBytesRecorded);
  1838. //
  1839. // go into cleanup mode (stop writing new data) on any error
  1840. //
  1841. u = WriteWaveHeader(pWaveHdr, FALSE);
  1842. if (u)
  1843. {
  1844. //
  1845. // if the return value is '-1' then we are out of data
  1846. // space--but probably have headers outstanding so we
  1847. // need to wait for all headers to come in before
  1848. // shutting down.
  1849. //
  1850. if (u == (UINT)-1)
  1851. {
  1852. DPF(TEXT("WaveInData: stopping cuz out of data space\n"));
  1853. fStopping = TRUE;
  1854. break;
  1855. }
  1856. DPF(TEXT("WaveInData: CRITICAL ERROR ON ADDING BUFFER [%.04Xh]\n"), u);
  1857. StopWave();
  1858. }
  1859. else
  1860. {
  1861. if (IsAsyncStop())
  1862. {
  1863. StopWave();
  1864. return;
  1865. }
  1866. if (YieldStop())
  1867. return;
  1868. }
  1869. f = PeekMessage(&msg, ghwndApp, MM_WIM_DATA, MM_WIM_DATA,
  1870. PM_REMOVE | PM_NOYIELD);
  1871. if (!f)
  1872. break;
  1873. //
  1874. // don't let plunger msg mess us up!
  1875. //
  1876. if (msg.lParam == 0L)
  1877. break;
  1878. pWaveHdr = (LPWAVEHDR)msg.lParam;
  1879. }
  1880. }
  1881. else
  1882. {
  1883. fStillMoreToGo = FALSE;
  1884. if (gfStoppingHard)
  1885. {
  1886. while (1)
  1887. {
  1888. DPF(TEXT("HARDSTOP RECORD: another one bites the dust!\n"));
  1889. //
  1890. // NOTE! update the position cuz info could have been
  1891. // recorded and we have not received its callback yet..
  1892. // length will be zero if not used--so this works great
  1893. //
  1894. glWavePosition += wfBytesToSamples(gpWaveFormat, pWaveHdr->dwBytesRecorded);
  1895. WriteWaveHeader(pWaveHdr, TRUE);
  1896. f = PeekMessage(&msg, ghwndApp, MM_WIM_DATA, MM_WIM_DATA,
  1897. PM_REMOVE | PM_NOYIELD);
  1898. if (!f)
  1899. break;
  1900. //
  1901. // don't let plunger msg mess us up!
  1902. //
  1903. if (msg.lParam == 0L)
  1904. break;
  1905. pWaveHdr = (LPWAVEHDR)msg.lParam;
  1906. }
  1907. }
  1908. else
  1909. {
  1910. glWavePosition += wfBytesToSamples(gpWaveFormat, pWaveHdr->dwBytesRecorded);
  1911. //
  1912. // we're stopping, so get this header unprepared and proceed
  1913. // to shut this puppy down!
  1914. //
  1915. WriteWaveHeader(pWaveHdr, TRUE);
  1916. for (w = 0; w < guWaveHdrs; w++)
  1917. {
  1918. if (gapWaveHdr[w]->dwFlags & WHDR_PREPARED)
  1919. {
  1920. DPF(TEXT("RECORD: still more headers outstanding...\n"));
  1921. fStillMoreToGo = TRUE;
  1922. break;
  1923. }
  1924. }
  1925. }
  1926. if (!fStillMoreToGo)
  1927. {
  1928. //*** BOMBAY:1370 How do we pause without closing the handle?
  1929. #ifdef NEWPAUSE
  1930. if (!gfPausing)
  1931. {
  1932. waveInClose(ghWaveIn);
  1933. ghWaveIn = NULL;
  1934. ghPausedWave = NULL;
  1935. }
  1936. else
  1937. {
  1938. ghWaveIn = NULL;
  1939. gfPaused = TRUE;
  1940. }
  1941. #else
  1942. waveInClose(ghWaveIn);
  1943. ghWaveIn = NULL;
  1944. #endif
  1945. }
  1946. }
  1947. }
  1948. //
  1949. // update <glWaveSamplesValid>
  1950. //
  1951. UpdateDisplay(TRUE);
  1952. //
  1953. // if we closed the wave device, then we are completely done so do what
  1954. // we do when we are completely done...
  1955. //
  1956. // NOTE! we must have already called UpdateDisplay(TRUE) before doing
  1957. // the following!
  1958. //
  1959. if (ghWaveIn == NULL)
  1960. {
  1961. if (gfTimerStarted)
  1962. {
  1963. KillTimer(ghwndApp, 1);
  1964. gfTimerStarted = FALSE;
  1965. }
  1966. if (glWaveSamples > glWaveSamplesValid)
  1967. {
  1968. /* reallocate the wave buffer to be small */
  1969. AllocWaveBuffer(glWaveSamplesValid, TRUE, TRUE);
  1970. }
  1971. if (pWaveHdr)
  1972. {
  1973. /* ask user to save file if they close it */
  1974. EndWaveEdit(TRUE);
  1975. }
  1976. SnapBack();
  1977. }
  1978. } /* WaveInData */
  1979. /*
  1980. * @doc INTERNAL SOUNDREC
  1981. *
  1982. * @api void FAR PASCAL | FinishPlay | Processes messages until a stop
  1983. * has flushed all WOM_DONE/WIM_DONE messages out of the message queue.
  1984. *
  1985. * @rdesc None.
  1986. */
  1987. void FAR PASCAL FinishPlay(
  1988. void)
  1989. {
  1990. MSG msg;
  1991. while (GetMessage(&msg, NULL, 0, 0))
  1992. {
  1993. if (!TranslateAccelerator(ghwndApp, ghAccel, &msg))
  1994. {
  1995. TranslateMessage(&msg);
  1996. DispatchMessage(&msg);
  1997. }
  1998. #ifdef NEWPAUSE
  1999. // Why is this commented out?
  2000. // if (gfPausing && gfPaused)
  2001. // break;
  2002. #endif
  2003. if ((ghWaveOut == NULL) && (ghWaveIn == NULL))
  2004. break;
  2005. }
  2006. } /* FinishPlay() */
  2007. /* StopWave()
  2008. *
  2009. * Request waveform recording or playback to stop.
  2010. */
  2011. void FAR PASCAL
  2012. StopWave(void)
  2013. {
  2014. DPF(TEXT("------------StopWave() called!\n"));
  2015. if (ghWaveOut != NULL)
  2016. {
  2017. waveOutReset(ghWaveOut);
  2018. //
  2019. // post a 'plunger' message that will guarantee that at least one
  2020. // message goes through so we stop even in bizarre cases...
  2021. //
  2022. if (!gfSyncDriver)
  2023. {
  2024. DPF(TEXT("Post Plunger (WOM)\n"));
  2025. PostMessage(ghwndApp, MM_WOM_DONE, 0, 0L);
  2026. }
  2027. fStopping = TRUE; // the pre-touch thread periscopes this flag
  2028. if (ghPreTouch!=NULL){
  2029. WaitForSingleObject(ghPreTouch, INFINITE);
  2030. CloseHandle(ghPreTouch);
  2031. ghPreTouch = NULL;
  2032. }
  2033. }
  2034. else if (ghWaveIn != NULL)
  2035. {
  2036. waveInReset(ghWaveIn);
  2037. //
  2038. // post a 'plunger' message that will guarantee that at least one
  2039. // message goes through so we stop even in bizarre cases...
  2040. //
  2041. if (!gfSyncDriver)
  2042. {
  2043. DPF(TEXT("Post Plunger (WIM)\n"));
  2044. PostMessage(ghwndApp, MM_WIM_DATA, 0, 0L);
  2045. }
  2046. }
  2047. else
  2048. return;
  2049. fStopping = TRUE;
  2050. gfStoppingHard = TRUE;
  2051. /* get messages from event queue and dispatch them,
  2052. * until the MM_WOM_DONE or MM_WIM_DATA message is
  2053. * processed
  2054. */
  2055. FinishPlay();
  2056. gfStoppingHard = FALSE;
  2057. // Should StopWave() be calling UpdateDisplay()?
  2058. }
  2059. #if 0 // this is obsolete
  2060. /* EnableButtonRedraw(fAllowRedraw)
  2061. *
  2062. * Allow/disallow the buttons to redraw, depending on <fAllowRedraw>.
  2063. * This is designed to reduce button flicker.
  2064. */
  2065. void NEAR PASCAL
  2066. EnableButtonRedraw(BOOL fAllowRedraw)
  2067. {
  2068. SendMessage(ghwndPlay, WM_SETREDRAW, fAllowRedraw, 0);
  2069. SendMessage(ghwndStop, WM_SETREDRAW, fAllowRedraw, 0);
  2070. SendMessage(ghwndRecord, WM_SETREDRAW, fAllowRedraw, 0);
  2071. if (fAllowRedraw)
  2072. {
  2073. InvalidateRect(ghwndPlay, NULL, FALSE);
  2074. InvalidateRect(ghwndStop, NULL, FALSE);
  2075. InvalidateRect(ghwndRecord, NULL, FALSE);
  2076. }
  2077. }
  2078. #endif //0 - obsolete function
  2079. /* UpdateDisplay(fStatusChanged)
  2080. *
  2081. * Update the current position and file length on the display.
  2082. * If <fStatusChanged> is TRUE, also update the status line and button
  2083. * enable/disable state.
  2084. *
  2085. * As a side effect, update <glWaveSamplesValid> if <glWavePosition>
  2086. * is greater than <glWaveSamplesValid>.
  2087. */
  2088. void FAR PASCAL
  2089. UpdateDisplay(
  2090. BOOL fStatusChanged) // update status line
  2091. {
  2092. MMTIME mmtime;
  2093. UINT uErr;
  2094. int id;
  2095. TCHAR ach[120];
  2096. long lTime;
  2097. long lLen;
  2098. int iPos;
  2099. HWND hwndFocus;
  2100. BOOL fCanPlay;
  2101. BOOL fCanRecord;
  2102. hwndFocus = GetFocus();
  2103. if (fStatusChanged)
  2104. {
  2105. // EnableButtonRedraw(FALSE);
  2106. /* update the buttons and the status line */
  2107. if (ghWaveOut != NULL)
  2108. {
  2109. /* we are now playing */
  2110. id = IDS_STATUSPLAYING;
  2111. grgbStatusColor = RGB_PLAY;
  2112. SendMessage(ghwndPlay,BM_SETCHECK,TRUE,0L);
  2113. EnableWindow(ghwndPlay, FALSE);
  2114. EnableWindow(ghwndStop, TRUE);
  2115. EnableWindow(ghwndRecord, FALSE);
  2116. if ((hwndFocus == ghwndPlay) || (hwndFocus == ghwndRecord))
  2117. if (IsWindowVisible(ghwndApp))
  2118. SetDlgFocus(ghwndStop);
  2119. }
  2120. else
  2121. if (ghWaveIn != NULL)
  2122. {
  2123. /* we are now recording */
  2124. id = IDS_STATUSRECORDING;
  2125. grgbStatusColor = RGB_RECORD;
  2126. SendMessage(ghwndRecord,BM_SETCHECK,TRUE,0L);
  2127. EnableWindow(ghwndPlay, FALSE);
  2128. EnableWindow(ghwndStop, TRUE);
  2129. EnableWindow(ghwndRecord, FALSE);
  2130. if ((hwndFocus == ghwndPlay) || (hwndFocus == ghwndRecord))
  2131. if (IsWindowVisible(ghwndApp))
  2132. SetDlgFocus(ghwndStop);
  2133. }
  2134. else
  2135. {
  2136. fCanPlay = (0 == waveOutOpen(NULL
  2137. , (UINT)WAVE_MAPPER
  2138. , (LPWAVEFORMATEX)gpWaveFormat
  2139. , 0L
  2140. , 0L
  2141. , WAVE_FORMAT_QUERY|WAVE_ALLOWSYNC));
  2142. fCanRecord = (0 == waveInOpen(NULL
  2143. , (UINT)WAVE_MAPPER
  2144. , (LPWAVEFORMATEX)gpWaveFormat
  2145. , 0L
  2146. , 0L
  2147. , WAVE_FORMAT_QUERY|WAVE_ALLOWSYNC));
  2148. /* we are now stopped */
  2149. id = IDS_STATUSSTOPPED;
  2150. grgbStatusColor = RGB_STOP;
  2151. //
  2152. // 'un-stick' the buttons if they are currently
  2153. // stuck
  2154. //
  2155. SendMessage(ghwndPlay,BM_SETCHECK,FALSE,0L);
  2156. SendMessage(ghwndRecord,BM_SETCHECK,FALSE,0L);
  2157. EnableWindow(ghwndPlay, fCanPlay && glWaveSamplesValid > 0);
  2158. EnableWindow(ghwndStop, FALSE);
  2159. EnableWindow(ghwndRecord, fCanRecord);
  2160. if (hwndFocus && !IsWindowEnabled(hwndFocus) &&
  2161. GetActiveWindow() == ghwndApp && IsWindowVisible(ghwndApp))
  2162. {
  2163. if (gidDefaultButton == ID_RECORDBTN && fCanRecord)
  2164. SetDlgFocus(ghwndRecord);
  2165. else if (fCanPlay && glWaveSamplesValid > 0)
  2166. SetDlgFocus(ghwndPlay);
  2167. else
  2168. SetDlgFocus(ghwndScroll);
  2169. }
  2170. }
  2171. }
  2172. // EnableButtonRedraw(TRUE);
  2173. if (ghWaveOut != NULL || ghWaveIn != NULL)
  2174. {
  2175. if (gfTimerStarted)
  2176. {
  2177. glWavePosition = 0L;
  2178. mmtime.wType = TIME_SAMPLES;
  2179. if (ghWaveOut != NULL)
  2180. uErr = waveOutGetPosition(ghWaveOut, &mmtime, sizeof(mmtime));
  2181. else
  2182. uErr = waveInGetPosition(ghWaveIn, &mmtime, sizeof(mmtime));
  2183. if (uErr == MMSYSERR_NOERROR)
  2184. {
  2185. switch (mmtime.wType)
  2186. {
  2187. case TIME_SAMPLES:
  2188. glWavePosition = glStartPlayRecPos + mmtime.u.sample;
  2189. break;
  2190. case TIME_BYTES:
  2191. glWavePosition = glStartPlayRecPos + wfBytesToSamples(gpWaveFormat, mmtime.u.cb);
  2192. break;
  2193. }
  2194. }
  2195. }
  2196. }
  2197. /* SEMI-HACK: Guard against bad values */
  2198. if (glWavePosition < 0L) {
  2199. DPF(TEXT("Position before zero!\n"));
  2200. glWavePosition = 0L;
  2201. }
  2202. if (glWavePosition > glWaveSamples) {
  2203. DPF(TEXT("Position past end!\n"));
  2204. glWavePosition = glWaveSamples;
  2205. }
  2206. /* side effect: update <glWaveSamplesValid> */
  2207. if (glWaveSamplesValid < glWavePosition)
  2208. glWaveSamplesValid = glWavePosition;
  2209. /* display the current wave position */
  2210. lTime = wfSamplesToTime(gpWaveFormat, glWavePosition);
  2211. if (gfLZero || ((int)(lTime/1000) != 0))
  2212. wsprintf(ach, aszPositionFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
  2213. else
  2214. wsprintf(ach, aszNoZeroPositionFormat, chDecimal, (int)((lTime/10)%100));
  2215. SetDlgItemText(ghwndApp, ID_CURPOSTXT, ach);
  2216. /* display the current wave length */
  2217. //
  2218. // changes whether the right-hand status box displays max length or current
  2219. // position while recording... the status box used to display the max
  2220. // length... if the status box gets added back for some reason, then we
  2221. // MAY want to change this back to the old way..
  2222. //
  2223. #if 1
  2224. lLen = ghWaveIn ? glWaveSamples : glWaveSamplesValid;
  2225. #else
  2226. lLen = glWaveSamplesValid;
  2227. #endif
  2228. lTime = wfSamplesToTime(gpWaveFormat, lLen);
  2229. if (gfLZero || ((int)(lTime/1000) != 0))
  2230. wsprintf(ach, aszPositionFormat, (int)(lTime/1000), chDecimal, (int)((lTime/10)%100));
  2231. else
  2232. wsprintf(ach, aszNoZeroPositionFormat, chDecimal, (int)((lTime/10)%100));
  2233. SetDlgItemText(ghwndApp, ID_FILELENTXT, ach);
  2234. /* update the wave display */
  2235. InvalidateRect(ghwndWaveDisplay, NULL, fStatusChanged);
  2236. UpdateWindow(ghwndWaveDisplay);
  2237. /* update the scroll bar position */
  2238. if (glWaveSamplesValid > 0)
  2239. iPos = (int)MulDiv((DWORD) SCROLL_RANGE, glWavePosition, lLen);
  2240. else
  2241. iPos = 0;
  2242. //
  2243. // windows will re-draw the scrollbar even
  2244. // if the position does not change.
  2245. //
  2246. #if 0
  2247. if (iPos != GetScrollPos(ghwndScroll, SB_CTL))
  2248. SetScrollPos(ghwndScroll, SB_CTL, iPos, TRUE);
  2249. // if (iPos != GetScrollPos(ghwndScroll, SB_CTL))
  2250. // SendMessage(ghwndScroll, TBM_SETPOS, TRUE, (LPARAM)(WORD)iPos);
  2251. #endif
  2252. // Now we're using a much nicer trackbar
  2253. // SetScrollPos(ghwndScroll, SB_CTL, iPos, TRUE);
  2254. SendMessage(ghwndScroll,TBM_SETPOS, TRUE, (LPARAM)(WORD)iPos); // WORD worries me. LKG. ???
  2255. SendMessage(ghwndScroll,TBM_SETRANGEMAX, 0, (glWaveSamplesValid > 0)?SCROLL_RANGE:0);
  2256. EnableWindow(ghwndForward, glWavePosition < glWaveSamplesValid);
  2257. EnableWindow(ghwndRewind, glWavePosition > 0);
  2258. if (hwndFocus == ghwndForward && glWavePosition >= glWaveSamplesValid)
  2259. SetDlgFocus(ghwndRewind);
  2260. if (hwndFocus == ghwndRewind && glWavePosition == 0)
  2261. SetDlgFocus(ghwndForward);
  2262. #ifdef DEBUG
  2263. if ( ((ghWaveIn != NULL) || (ghWaveOut != NULL)) &&
  2264. (gapWaveHdr[0]->dwFlags & WHDR_DONE) )
  2265. //!! DPF2(TEXT("DONE BIT SET!\n"));
  2266. ;
  2267. #endif
  2268. } /* UpdateDisplay */