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.

1050 lines
29 KiB

  1. /******************************************************************************
  2. Copyright (C) Microsoft Corporation 1991-1992. All rights reserved.
  3. Title: avisound.c - Code for playing audio in AVI files.
  4. *****************************************************************************/
  5. #include "graphic.h"
  6. #define AUDIO_PANIC 10
  7. static UINT nAudioPanic;
  8. //
  9. // redefine StreamFromFOURCC to only handle 0-9 streams!
  10. //
  11. #undef StreamFromFOURCC
  12. #define StreamFromFOURCC(fcc) (UINT)(HIBYTE(LOWORD(fcc)) - (BYTE)'0')
  13. void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg,
  14. DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
  15. #ifndef WIN32
  16. #define GetDS() (HGLOBAL)HIWORD((DWORD)(LPVOID)&ghModule)
  17. #endif //WIN16
  18. DWORD FAR PASCAL SetUpAudio(NPMCIGRAPHIC npMCI, BOOL fPlaying)
  19. {
  20. UINT w;
  21. LPWAVEHDR lpWaveHdr;
  22. STREAMINFO *psi;
  23. if (npMCI->nAudioStreams == 0) {
  24. npMCI->wABs = 0;
  25. npMCI->wABOptimal = 0;
  26. return 0L;
  27. }
  28. nAudioPanic = GetProfileInt(TEXT("MCIAVI"), TEXT("AudioPanic"), AUDIO_PANIC);
  29. psi = SI(npMCI->nAudioStream);
  30. Assert(psi->sh.fccType == streamtypeAUDIO);
  31. Assert(psi->cbFormat);
  32. Assert(psi->lpFormat);
  33. if (!npMCI->pWF) {
  34. npMCI->pWF = (NPWAVEFORMAT)LocalAlloc(LPTR, (UINT)psi->cbFormat);
  35. if (!npMCI->pWF) {
  36. return MCIERR_OUT_OF_MEMORY;
  37. }
  38. }
  39. hmemcpy(npMCI->pWF,psi->lpFormat,psi->cbFormat);
  40. npMCI->wEarlyAudio = (UINT)psi->sh.dwInitialFrames;
  41. npMCI->dwAudioLength = psi->sh.dwLength * psi->sh.dwSampleSize;
  42. if (npMCI->dwAudioLength < 1000L) {
  43. DPF(("AudioLength is bogus"));
  44. npMCI->dwAudioLength = muldiv32((npMCI->pWF->nAvgBytesPerSec + 100) *
  45. npMCI->lFrames,npMCI->dwMicroSecPerFrame,1000000L);
  46. }
  47. //
  48. // choose the audio playback method depending on how we are going to
  49. // recive audio data from the file.
  50. //
  51. switch (npMCI->wPlaybackAlg) {
  52. case MCIAVI_ALG_HARDDISK:
  53. case MCIAVI_ALG_AUDIOONLY:
  54. if (!npMCI->pf && !npMCI->hmmioAudio) {
  55. MMIOINFO mmioInfo;
  56. _fmemset(&mmioInfo, 0, sizeof(MMIOINFO));
  57. mmioInfo.htask = (HANDLE) npMCI->hCallingTask; //ntmmsystem bug, should be threadid which is dword
  58. npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo,
  59. MMIO_READ | MMIO_DENYWRITE);
  60. if (npMCI->hmmioAudio == NULL)
  61. npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo,
  62. MMIO_READ);
  63. if (!npMCI->hmmioAudio) {
  64. Assert(0);
  65. return MCIERR_DRIVER_INTERNAL;
  66. }
  67. }
  68. // fall through to CDROM
  69. case MCIAVI_ALG_CDROM:
  70. //!!!! we need to tune this!!!!
  71. // !!! We use four 1/2 second buffers. This is arbitrary.
  72. npMCI->wABs = 4;
  73. npMCI->wABOptimal = 0;
  74. npMCI->dwABSize = npMCI->pWF->nAvgBytesPerSec / 2;
  75. break;
  76. case MCIAVI_ALG_INTERLEAVED:
  77. /* Fix up some values based on the header information */
  78. npMCI->dwABSize = muldiv32(npMCI->dwMicroSecPerFrame,
  79. npMCI->pWF->nAvgBytesPerSec,1000000L) + 2047;
  80. npMCI->dwABSize &= ~(2047L);
  81. npMCI->wABs = npMCI->wEarlyAudio + 2 + (WORD) npMCI->dwBufferedVideo;
  82. /* Soundblaster hack: waveoutdone only accurate to 2K. */
  83. //!!!!!!!!!! is this right.
  84. if (npMCI->dwMicroSecPerFrame) {
  85. npMCI->wABOptimal = npMCI->wABs -
  86. (UINT) (muldiv32(2048, 1, muldiv32(npMCI->dwMicroSecPerFrame,
  87. npMCI->pWF->nAvgBytesPerSec,1000000L)));
  88. } else {
  89. npMCI->wABOptimal = 0;
  90. }
  91. //!!! hack so we can do burst reading, up to 1sec
  92. //npMCI->wABs += (int)muldiv32(1000000l, 1, npMCI->dwMicroSecPerFrame);
  93. DPF2(("Using %u audio buffers, of which %u should be full.\n", npMCI->wABs, npMCI->wABOptimal));
  94. break;
  95. default:
  96. Assert(0);
  97. return 0L;
  98. }
  99. npMCI->dwABSize -= npMCI->dwABSize % npMCI->pWF->nBlockAlign;
  100. if (!fPlaying)
  101. return 0L;
  102. /* This code adjusts the wave format block to play
  103. ** the audio at the correct speed to match the frame rate.
  104. */
  105. npMCI->pWF->nSamplesPerSec = muldiv32(npMCI->pWF->nSamplesPerSec,
  106. npMCI->dwMicroSecPerFrame,
  107. npMCI->dwPlayMicroSecPerFrame);
  108. npMCI->pWF->nAvgBytesPerSec = muldiv32(npMCI->pWF->nAvgBytesPerSec,
  109. npMCI->dwMicroSecPerFrame,
  110. npMCI->dwPlayMicroSecPerFrame);
  111. if (npMCI->pWF->wFormatTag == WAVE_FORMAT_PCM) {
  112. /* Make sure this is exactly right... */
  113. npMCI->pWF->nAvgBytesPerSec =
  114. npMCI->pWF->nSamplesPerSec * npMCI->pWF->nBlockAlign;
  115. }
  116. /* Kill any currently playing sound */
  117. sndPlaySound(NULL, 0);
  118. DPF2(("Opening wave device....\n"));
  119. /* Try to open a wave device. */
  120. w = waveOutOpen(&npMCI->hWave, (UINT)WAVE_MAPPER,
  121. (LPWAVEFORMATEX) npMCI->pWF,
  122. //(const LPWAVEFORMATEX) npMCI->pWF,
  123. (DWORD) &mciaviWaveOutFunc,
  124. (DWORD) (LPMCIGRAPHIC) npMCI,
  125. (DWORD)CALLBACK_FUNCTION);
  126. if (w) {
  127. DPF(("Unable to open wave device.\n"));
  128. npMCI->hWave = NULL;
  129. return w == WAVERR_BADFORMAT ?
  130. MCIERR_WAVE_OUTPUTSUNSUITABLE :
  131. MCIERR_WAVE_OUTPUTSINUSE;
  132. }
  133. npMCI->dwFlags &= ~MCIAVI_LOSTAUDIO;
  134. #ifndef WIN32 // No need to lock it on NT - although we could with Virtual mem
  135. // functions
  136. //
  137. // page lock our DS so our wave callback function can
  138. // touch it without worry. see mciaviWaveOutFunc()
  139. //
  140. GlobalPageLock(GetDS());
  141. #endif //WIN16
  142. /* Pause the wave output device, so it won't start playing
  143. ** when we're loading up the buffers.
  144. */
  145. if (waveOutPause(npMCI->hWave) != 0) {
  146. DPF(("Error from waveOutPause!\n"));
  147. return MCIERR_DRIVER_INTERNAL;
  148. }
  149. if (npMCI->dwFlags & MCIAVI_VOLUMESET) {
  150. DeviceSetVolume(npMCI, npMCI->dwVolume);
  151. } else {
  152. DeviceGetVolume(npMCI);
  153. }
  154. npMCI->lpAudio = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE,
  155. npMCI->wABs * (npMCI->dwABSize + sizeof(WAVEHDR)));
  156. if (!npMCI->lpAudio) {
  157. return MCIERR_OUT_OF_MEMORY;
  158. }
  159. npMCI->dwAudioPlayed = 0L;
  160. npMCI->wNextAB = 0;
  161. npMCI->dwUsedThisAB = 0;
  162. /* Allocate and prepare our buffers */
  163. for (w = 0; w < npMCI->wABs; w++) {
  164. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
  165. lpWaveHdr->lpData = (HPSTR) npMCI->lpAudio +
  166. npMCI->wABs * sizeof(WAVEHDR) +
  167. w * npMCI->dwABSize;
  168. lpWaveHdr->dwBufferLength = npMCI->dwABSize;
  169. lpWaveHdr->dwBytesRecorded = 0L;
  170. lpWaveHdr->dwUser = 0L;
  171. lpWaveHdr->dwFlags = 0L;
  172. lpWaveHdr->dwLoops = 0L;
  173. lpWaveHdr->lpNext = 0L;
  174. lpWaveHdr->reserved = 0;
  175. }
  176. for (w = 0; w < npMCI->wABs; w++) {
  177. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
  178. if (waveOutPrepareHeader(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR))
  179. != 0) {
  180. return MCIERR_OUT_OF_MEMORY;
  181. }
  182. lpWaveHdr->dwFlags |= WHDR_DONE;
  183. }
  184. return 0L;
  185. }
  186. DWORD FAR PASCAL CleanUpAudio(NPMCIGRAPHIC npMCI)
  187. {
  188. UINT w;
  189. /* Clear flags relating to playing audio */
  190. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  191. if (npMCI->lpAudio) {
  192. waveOutRestart(npMCI->hWave); // just in case we are paused
  193. waveOutReset(npMCI->hWave);
  194. for (w = 0; w < npMCI->wABs; w++) {
  195. LPWAVEHDR lpWaveHdr;
  196. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio
  197. + (w * sizeof(WAVEHDR)));
  198. #if 0
  199. lpWaveHdr->lpData = npMCI->lpAudio
  200. + npMCI->wABs * sizeof(WAVEHDR)
  201. + w * npMCI->dwABSize;
  202. lpWaveHdr->dwBufferLength = npMCI->dwABSize;
  203. #endif
  204. /* Do we need to check for an error from this? */
  205. waveOutUnprepareHeader(npMCI->hWave, lpWaveHdr,
  206. sizeof(WAVEHDR));
  207. }
  208. GlobalFreePtr(npMCI->lpAudio);
  209. npMCI->lpAudio = NULL;
  210. Assert(npMCI->wABFull == 0);
  211. }
  212. DPF2(("Closing wave device.\n"));
  213. waveOutClose(npMCI->hWave);
  214. npMCI->hWave = 0;
  215. #ifndef WIN32
  216. GlobalPageUnlock(GetDS());
  217. #endif //WIN16
  218. return 0L;
  219. }
  220. BOOL NEAR PASCAL WaitForFreeAudioBuffer(NPMCIGRAPHIC npMCI, BOOL FAR *lpfHurry)
  221. {
  222. LPWAVEHDR lpWaveHdr;
  223. lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio
  224. + (npMCI->wNextAB * sizeof(WAVEHDR)));
  225. /* Use the number of full audio buffers to decide if we're behind. */
  226. if (npMCI->wABFull < npMCI->wABOptimal) {
  227. *lpfHurry = TRUE;
  228. }
  229. /* If all of the audio buffers are full, we have to wait. */
  230. if (npMCI->wABFull == npMCI->wABs) {
  231. DWORD time = timeGetTime();
  232. #define AUDIO_WAIT_TIMEOUT 2000
  233. DOUT2("waiting for audio buffer.");
  234. // we better not wait if the device is not playing!
  235. Assert(!(npMCI->dwFlags & MCIAVI_WAVEPAUSED));
  236. #ifdef XDEBUG
  237. GetAsyncKeyState(VK_ESCAPE);
  238. GetAsyncKeyState(VK_F2);
  239. GetAsyncKeyState(VK_F3);
  240. GetAsyncKeyState(VK_F4);
  241. #endif
  242. while (npMCI->wABFull == npMCI->wABs) {
  243. if (npMCI->dwFlags & MCIAVI_STOP)
  244. return FALSE;
  245. aviTaskYield();
  246. //
  247. // the "Fahrenheit VA Audio Wave Driver" may get confused
  248. // if you call waveOutPause() and waveOutRestart() alot
  249. // and it will stay paused no matter what you do, it has
  250. // all our buffers and it still does not make any sound
  251. // you can call waveOutRestart() until you are blue in
  252. // the face, it will do nothing.
  253. //
  254. // so this is why this routine can time out, after waiting
  255. // 2 seconds or so we just toss all the audio in the buffers
  256. // and start over.
  257. //
  258. if (timeGetTime() - time > AUDIO_WAIT_TIMEOUT) {
  259. DOUT("Gave up waiting, reseting wave device\n");
  260. waveOutReset(npMCI->hWave);
  261. break;
  262. }
  263. #ifdef XDEBUG
  264. if (GetAsyncKeyState(VK_ESCAPE) & 0x0001) {
  265. DPF(("STOPPED WAITING! wABFull = %d, wABs = %d\n", npMCI->wABFull,npMCI->wABs));
  266. return FALSE;
  267. }
  268. if (GetAsyncKeyState(VK_F2) & 0x0001) {
  269. DOUT("Trying waveOutRestart\n");
  270. waveOutRestart(npMCI->hWave);
  271. }
  272. if (GetAsyncKeyState(VK_F3) & 0x0001) {
  273. DOUT("Trying waveOutReset\n");
  274. waveOutReset(npMCI->hWave);
  275. }
  276. if (GetAsyncKeyState(VK_F4) & 0x0001) {
  277. int i,n;
  278. for (i=n=0; i<(int)npMCI->wABs; i++) {
  279. if (((LPWAVEHDR)npMCI->lpAudio)[i].dwFlags & WHDR_DONE) {
  280. DPF(("Buffer #%d is done!\n", i));
  281. n++;
  282. }
  283. else {
  284. DPF(("Buffer #%d is not done\n", i));
  285. }
  286. }
  287. if (n > 0)
  288. DPF(("%d buffers are done but our callback did not get called!\n", n));
  289. }
  290. #endif
  291. }
  292. DOUT2("done\n");
  293. }
  294. /* Debugging check that wave has finished playing--should never happen */
  295. Assert(lpWaveHdr->dwFlags & WHDR_DONE);
  296. #if 0
  297. lpWaveHdr->lpData = npMCI->lpAudio +
  298. npMCI->wABs * sizeof(WAVEHDR) +
  299. npMCI->wNextAB * npMCI->dwABSize;
  300. #endif
  301. return TRUE;
  302. }
  303. #ifndef WIN32
  304. #pragma optimize("", off)
  305. #endif
  306. BOOL NEAR PASCAL ReadSomeAudio(NPMCIGRAPHIC npMCI, BYTE _huge * lpAudio,
  307. DWORD dwStart, DWORD FAR * pdwLength)
  308. {
  309. DWORD dwIndex = 0;
  310. DWORD ckidAudio;
  311. DWORD dwAudioPos = 0L;
  312. AVIINDEXENTRY far * lpIndexEntry;
  313. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  314. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  315. Assert(npMCI->hpIndex);
  316. /*
  317. ** Figure out what type of chunk we're looking for,
  318. */
  319. ckidAudio = MAKEAVICKID(cktypeWAVEbytes, npMCI->nAudioStream);
  320. lpIndexEntry = (AVIINDEXENTRY FAR *) npMCI->hpIndex;
  321. for (dwIndex = 0; dwIndex < npMCI->macIndex;
  322. dwIndex++, ++((AVIINDEXENTRY _huge *) lpIndexEntry)) {
  323. if (lpIndexEntry->ckid != ckidAudio)
  324. continue;
  325. if (dwAudioPos + lpIndexEntry->dwChunkLength > dwStart) {
  326. DWORD dwLengthNow;
  327. DWORD dwSeekTo;
  328. dwLengthNow = lpIndexEntry->dwChunkLength;
  329. dwSeekTo = lpIndexEntry->dwChunkOffset + 8;
  330. if (dwAudioPos + dwLengthNow > dwStart + *pdwLength) {
  331. /* Attempted optimization: If we've already read some
  332. ** data, and we can't read the next whole chunk, let's
  333. ** leave it for later.
  334. */
  335. if (dwAudioPos > dwStart && (!(npMCI->dwFlags & MCIAVI_REVERSE)))
  336. break;
  337. dwLengthNow = dwStart + *pdwLength - dwAudioPos;
  338. }
  339. if (dwAudioPos < dwStart) {
  340. dwLengthNow -= (dwStart - dwAudioPos);
  341. dwSeekTo += (dwStart - dwAudioPos);
  342. }
  343. mmioSeek(npMCI->hmmioAudio, dwSeekTo, SEEK_SET);
  344. if (mmioRead(npMCI->hmmioAudio, lpAudio, dwLengthNow)
  345. != (LONG) dwLengthNow) {
  346. DPF(("Error reading audio data (%lx bytes at %lx)\n", dwLengthNow, dwSeekTo));
  347. return FALSE;
  348. }
  349. lpAudio += dwLengthNow;
  350. }
  351. dwAudioPos += lpIndexEntry->dwChunkLength;
  352. if (dwAudioPos >= dwStart + *pdwLength)
  353. return TRUE;
  354. }
  355. if (dwAudioPos < dwStart)
  356. *pdwLength = 0; // return FALSE?
  357. else
  358. *pdwLength = dwAudioPos - dwStart;
  359. return TRUE;
  360. }
  361. #ifndef WIN32
  362. #pragma optimize("", on)
  363. #endif
  364. BOOL NEAR PASCAL ReverseWaveBuffer(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  365. {
  366. DWORD dwLeft = lpWaveHdr->dwBufferLength;
  367. BYTE _huge *hp1;
  368. BYTE _huge *hp2;
  369. DWORD dwBlock = npMCI->pWF->nBlockAlign;
  370. BYTE bTemp;
  371. DWORD dw;
  372. Assert(npMCI->dwFlags & MCIAVI_REVERSE);
  373. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  374. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  375. /* This routine doesn't like it when the data doesn't end on a
  376. ** block boundary, so make it so. This should never happen.
  377. */
  378. Assert((dwLeft % dwBlock) == 0);
  379. dwLeft -= dwLeft % dwBlock;
  380. hp1 = lpWaveHdr->lpData;
  381. hp2 = ((HPSTR) lpWaveHdr->lpData) + (dwLeft - dwBlock);
  382. while ((LONG) dwLeft > (LONG) dwBlock) {
  383. for (dw = 0; dw < dwBlock; dw++) {
  384. bTemp = *hp1;
  385. *hp1++ = *hp2;
  386. *hp2++ = bTemp;
  387. }
  388. hp2 -= dwBlock * 2;
  389. dwLeft -= dwBlock * 2;
  390. }
  391. return TRUE;
  392. }
  393. void FAR PASCAL BuildVolumeTable(NPMCIGRAPHIC npMCI)
  394. {
  395. int vol;
  396. int i;
  397. if (!npMCI->pWF || npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM)
  398. return;
  399. if (((NPPCMWAVEFORMAT) npMCI->pWF)->wBitsPerSample != 8)
  400. return;
  401. vol = (LOWORD(npMCI->dwVolume) + HIWORD(npMCI->dwVolume)) / 2;
  402. vol = (int) (((LONG) vol * 256) / 500);
  403. if (!npMCI->pVolumeTable)
  404. npMCI->pVolumeTable = (void *)LocalAlloc(LPTR, 256);
  405. if (!npMCI->pVolumeTable)
  406. return;
  407. for (i = 0; i < 256; i++) {
  408. npMCI->pVolumeTable[i] = (BYTE) min(255, max(0,
  409. (int) ((((LONG) (i - 128) * vol) / 256) + 128)));
  410. }
  411. }
  412. BOOL NEAR PASCAL AdjustVolume(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  413. {
  414. DWORD dwLeft = lpWaveHdr->dwBufferLength;
  415. BYTE FAR *pb;
  416. if (npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM)
  417. return FALSE;
  418. if (!npMCI->pVolumeTable)
  419. return FALSE;
  420. if (((NPPCMWAVEFORMAT)npMCI->pWF)->wBitsPerSample != 8)
  421. return FALSE;
  422. pb = lpWaveHdr->lpData;
  423. #ifndef WIN32
  424. if (OFFSETOF(pb) + dwLeft > 64l*1024) {
  425. while (dwLeft--) {
  426. *pb = npMCI->pVolumeTable[*pb];
  427. ((BYTE _huge *)pb)++;
  428. }
  429. }
  430. else {
  431. while ((int)dwLeft--)
  432. *pb++ = npMCI->pVolumeTable[*pb];
  433. }
  434. #else
  435. while ((int)dwLeft--)
  436. *pb++ = npMCI->pVolumeTable[*pb];
  437. #endif
  438. return TRUE;
  439. }
  440. BOOL NEAR PASCAL PlaySomeAudio(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr)
  441. {
  442. if (npMCI->pVolumeTable)
  443. AdjustVolume(npMCI, lpWaveHdr);
  444. lpWaveHdr->dwFlags &= ~WHDR_DONE;
  445. /* If we're playing and we've used all of our audio buffers, pause the
  446. ** wave device until we can fill more of them up.
  447. **
  448. ** we need to be carefull not to do this on the last frame!!!
  449. */
  450. if ((npMCI->wTaskState == TASKPLAYING) &&
  451. !(npMCI->dwFlags & MCIAVI_WAVEPAUSED) &&
  452. (npMCI->wABFull == 0 || npMCI->nAudioBehind > nAudioPanic)) {
  453. if (npMCI->wABFull > 0) {
  454. DPF(("Audio panic stop\n"));
  455. } else {
  456. DPF(("Audio queue empty; pausing wave device\n"));
  457. }
  458. //
  459. // some audio cards dont like starving it confuses them
  460. // it is kind of rude any way. we are going to cause a audio break
  461. // anyway so if we lose a little bit of audio (a few frames or so)
  462. // no one will even notice (any worse than the audio break)
  463. //
  464. if (npMCI->wABFull <= 1) {
  465. DOUT("Trying audio hack!\n");
  466. waveOutReset(npMCI->hWave);
  467. }
  468. ++npMCI->dwAudioBreaks;
  469. waveOutPause(npMCI->hWave);
  470. ICDrawStop(npMCI->hicDraw);
  471. npMCI->dwFlags |= MCIAVI_WAVEPAUSED;
  472. }
  473. if (waveOutWrite(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR)) != 0) {
  474. DPF(("Error from waveOutWrite!\n"));
  475. npMCI->dwTaskError = MCIERR_AVI_AUDIOERROR;
  476. return FALSE;
  477. } else {
  478. ++npMCI->wABFull;
  479. /* Use the next wave buffer next time */
  480. ++npMCI->wNextAB;
  481. if (npMCI->wNextAB == npMCI->wABs)
  482. npMCI->wNextAB = 0;
  483. npMCI->dwUsedThisAB = 0;
  484. }
  485. if (npMCI->wABFull < min(npMCI->wABOptimal, npMCI->wABFull/2))
  486. npMCI->nAudioBehind++;
  487. else
  488. npMCI->nAudioBehind=0;
  489. /* If we paused the wave device to let ourselves catch up, and
  490. ** we've caught up enough, restart the device.
  491. */
  492. if ((npMCI->dwFlags & MCIAVI_WAVEPAUSED) &&
  493. npMCI->wTaskState == TASKPLAYING &&
  494. npMCI->wABFull == npMCI->wABs) {
  495. DPF2(("restarting wave device\n"));
  496. waveOutRestart(npMCI->hWave);
  497. ICDrawStart(npMCI->hicDraw);
  498. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  499. npMCI->nAudioBehind = 0;
  500. }
  501. return TRUE;
  502. }
  503. /* Play the current record's audio */
  504. BOOL NEAR PASCAL PlayRecordAudio(NPMCIGRAPHIC npMCI, BOOL FAR *pfHurryUp,
  505. BOOL FAR *pfPlayedAudio)
  506. {
  507. LPWAVEHDR lpWaveHdr;
  508. FOURCC ckid;
  509. DWORD cksize;
  510. LPSTR lpSave;
  511. LPSTR lpData;
  512. BOOL fRet = TRUE;
  513. ////BOOL fSilence;
  514. LONG len;
  515. DWORD dwBytesTotal = 0L;
  516. DWORD dwBytesThisChunk;
  517. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED);
  518. lpSave = npMCI->lp;
  519. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  520. *pfPlayedAudio = FALSE;
  521. /* Remember!
  522. **
  523. ** In the new file format, things shouldn't necessarily need to
  524. ** be ordered with the wave stuff always first.
  525. */
  526. len = (LONG)npMCI->dwThisRecordSize;
  527. while (len > 3 * sizeof(DWORD)) {
  528. /* Look at the next chunk */
  529. ckid = GET_DWORD();
  530. cksize = GET_DWORD();
  531. lpData = npMCI->lp;
  532. len -= ((cksize + 1) & ~1) + 8;
  533. SKIP_BYTES((cksize + 1) & ~1);
  534. if (StreamFromFOURCC(ckid) != (UINT)npMCI->nAudioStream)
  535. continue;
  536. dwBytesThisChunk = cksize;
  537. if (!dwBytesTotal) {
  538. if (!WaitForFreeAudioBuffer(npMCI, pfHurryUp))
  539. /* We had to stop waiting--the stop flag was probably set. */
  540. goto exit;
  541. }
  542. if (dwBytesThisChunk > npMCI->dwABSize - dwBytesTotal) {
  543. DPF(("Audio Record is too big!\n"));
  544. dwBytesThisChunk = npMCI->dwABSize - dwBytesTotal;
  545. }
  546. hmemcpy((BYTE _huge *)lpWaveHdr->lpData + dwBytesTotal,
  547. lpData, dwBytesThisChunk);
  548. dwBytesTotal += dwBytesThisChunk;
  549. }
  550. if (dwBytesTotal) {
  551. *pfPlayedAudio = TRUE;
  552. lpWaveHdr->dwBufferLength = dwBytesTotal;
  553. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  554. }
  555. /* Use the number of full audio buffers to decide if we're behind. */
  556. if (npMCI->wABFull >= npMCI->wABOptimal) {
  557. *pfHurryUp = FALSE;
  558. }
  559. exit:
  560. npMCI->lp = lpSave;
  561. return fRet;
  562. }
  563. /* For "preload audio" or "random access audio" modes, do what needs
  564. ** to be done to keep our buffers full.
  565. */
  566. BOOL NEAR PASCAL KeepPlayingAudio(NPMCIGRAPHIC npMCI)
  567. {
  568. LPWAVEHDR lpWaveHdr;
  569. DWORD dwBytesTotal = 0L;
  570. LONG lNewAudioPos;
  571. ////BOOL fFirstTime = TRUE;
  572. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK ||
  573. npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
  574. PlayMore:
  575. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  576. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  577. lNewAudioPos = npMCI->dwAudioPos - npMCI->dwABSize;
  578. if (lNewAudioPos < 0)
  579. lNewAudioPos = 0;
  580. dwBytesTotal = npMCI->dwAudioPos - lNewAudioPos;
  581. } else {
  582. lNewAudioPos = npMCI->dwAudioPos + npMCI->dwABSize;
  583. if (lNewAudioPos > (LONG) npMCI->dwAudioLength)
  584. lNewAudioPos = npMCI->dwAudioLength;
  585. dwBytesTotal = lNewAudioPos - npMCI->dwAudioPos;
  586. }
  587. if (dwBytesTotal == 0) {
  588. if (npMCI->dwFlags & MCIAVI_WAVEPAUSED) {
  589. DOUT("no more audio to play, restarting wave device\n");
  590. waveOutRestart(npMCI->hWave);
  591. ICDrawStart(npMCI->hicDraw);
  592. npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
  593. npMCI->nAudioBehind = 0;
  594. }
  595. return TRUE;
  596. }
  597. /* If all of the audio buffers are full, we have nothing to do */
  598. if (npMCI->wABFull == npMCI->wABs)
  599. return TRUE;
  600. #if 0
  601. //!!!! Should we be yielding at all in here?
  602. //!!! NO NO! not if updating!!!!
  603. if (!fFirstTime) {
  604. aviTaskYield();
  605. }
  606. fFirstTime = FALSE;
  607. #endif
  608. if (npMCI->dwFlags & MCIAVI_REVERSE)
  609. npMCI->dwAudioPos = lNewAudioPos;
  610. #ifdef USEAVIFILE
  611. if (npMCI->pf) {
  612. LONG lPos;
  613. LONG lLength;
  614. lPos = npMCI->dwAudioPos / SH(npMCI->nAudioStream).dwSampleSize;
  615. lLength = dwBytesTotal / SH(npMCI->nAudioStream).dwSampleSize;
  616. AVIStreamRead(SI(npMCI->nAudioStream)->ps,
  617. lPos, lLength,
  618. lpWaveHdr->lpData,
  619. npMCI->dwABSize,
  620. NULL, NULL);
  621. }
  622. else
  623. #endif
  624. {
  625. if (!ReadSomeAudio(npMCI, lpWaveHdr->lpData,
  626. npMCI->dwAudioPos,
  627. &dwBytesTotal))
  628. return FALSE;
  629. if (dwBytesTotal == 0)
  630. return TRUE;
  631. }
  632. if (!(npMCI->dwFlags & MCIAVI_REVERSE))
  633. npMCI->dwAudioPos += dwBytesTotal;
  634. lpWaveHdr->dwBufferLength = dwBytesTotal;
  635. if (npMCI->dwFlags & MCIAVI_REVERSE) {
  636. ReverseWaveBuffer(npMCI, lpWaveHdr);
  637. }
  638. if (!PlaySomeAudio(npMCI, lpWaveHdr))
  639. return FALSE;
  640. // return TRUE;
  641. goto PlayMore;
  642. }
  643. /* Play the current chunk's audio */
  644. BOOL NEAR PASCAL HandleAudioChunk(NPMCIGRAPHIC npMCI)
  645. {
  646. LPWAVEHDR lpWaveHdr;
  647. FOURCC ckid;
  648. DWORD cksize;
  649. BYTE _huge *lpData;
  650. BOOL fRet = TRUE;
  651. BOOL fSilence;
  652. DWORD dwBytesTotal = 0L;
  653. DWORD dwBytesThisChunk;
  654. DWORD dwBytesThisBuffer;
  655. BOOL fHurryUp;
  656. Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_CDROM);
  657. while ((DWORD) (npMCI->lp - npMCI->lpBuffer)
  658. < npMCI->dwThisRecordSize - 3 * sizeof(DWORD)) {
  659. /* Look at the next chunk */
  660. ckid = GET_DWORD();
  661. cksize = GET_DWORD();
  662. lpData = npMCI->lp;
  663. SKIP_BYTES(cksize + (cksize & 1));
  664. fSilence = (TWOCCFromFOURCC(ckid) == cktypeWAVEsilence);
  665. if (fSilence) {
  666. if (cksize != sizeof(DWORD)) {
  667. DPF(("Wave silence chunk of bad length!\n"));
  668. fRet = FALSE;
  669. npMCI->dwTaskError = MCIERR_INVALID_FILE;
  670. goto exit;
  671. }
  672. dwBytesThisChunk = PEEK_DWORD();
  673. } else {
  674. dwBytesThisChunk = cksize;
  675. }
  676. while (dwBytesThisChunk > 0) {
  677. lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
  678. if (!WaitForFreeAudioBuffer(npMCI, &fHurryUp))
  679. /* We had to stop waiting--the stop flag was probably set. */
  680. goto exit;
  681. dwBytesThisBuffer = min(dwBytesThisChunk,
  682. npMCI->dwABSize - npMCI->dwUsedThisAB);
  683. if (!fSilence) {
  684. /* Move the data into the buffer */
  685. hmemcpy((BYTE _huge *) lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  686. lpData,
  687. dwBytesThisBuffer);
  688. lpData += dwBytesThisBuffer;
  689. } else {
  690. /* Fill the buffer with silence */
  691. /* This isn't right for 16-bit! */
  692. #ifndef WIN32
  693. #pragma message("WAVE silence chunks don't work right now.")
  694. #endif
  695. // fmemfill((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
  696. // dwBytesThisBuffer, 0x80);
  697. }
  698. dwBytesThisChunk -= dwBytesThisBuffer;
  699. npMCI->dwUsedThisAB += dwBytesThisBuffer;
  700. // if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
  701. lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
  702. fRet = PlaySomeAudio(npMCI, lpWaveHdr);
  703. // }
  704. }
  705. }
  706. exit:
  707. return fRet;
  708. }
  709. /******************************************************************************
  710. *****************************************************************************/
  711. /***************************************************************************
  712. *
  713. * @doc INTERNAL MCIAVI
  714. *
  715. * @api BOOL | StealWaveDevice | steal the audio device from another
  716. * instance of MCIAVI.
  717. *
  718. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  719. *
  720. ***************************************************************************/
  721. BOOL FAR PASCAL StealWaveDevice(NPMCIGRAPHIC npMCI)
  722. {
  723. extern NPMCIGRAPHIC npMCIList; // in graphic.c
  724. NPMCIGRAPHIC np;
  725. Assert(npMCI->hWave == NULL);
  726. DPF(("StealWaveDevice '%s' hTask=%04X\n", (LPSTR)npMCI->szFilename, GetCurrentTask()));
  727. //
  728. // walk the list of open MCIAVI instances and find one that
  729. // will give up the wave device
  730. //
  731. for (np=npMCIList; np; np = np->npMCINext) {
  732. if (np->hWave) {
  733. DPF(("**** Stealing the wave device from '%s'.\n", (LPSTR)np->szFilename));
  734. //!!!should we call DeviceMute() or just call cleanup audio?
  735. //
  736. //!!!can this cause evil reenter cases?
  737. //
  738. //!!!we are calling this from another task, will this work ok?
  739. //!!!even in WIN32? mabey we should use SendMessage()
  740. #if 1
  741. SendMessage(np->hwndDefault, WM_AUDIO_OFF, 0, 0);
  742. #else
  743. np->dwFlags |= MCIAVI_LOSTAUDIO;
  744. DeviceMute(np, TRUE);
  745. np->dwFlags |= MCIAVI_LOSTAUDIO;
  746. #endif
  747. return TRUE;
  748. }
  749. }
  750. DPF(("StealWaveDevice can't find a device to steal\n"));
  751. return FALSE;
  752. }
  753. /***************************************************************************
  754. *
  755. * @doc INTERNAL MCIAVI
  756. *
  757. * @api BOOL | GiveWaveDevice | give away the audio device
  758. * instance of MCIAVI.
  759. *
  760. * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data
  761. *
  762. ***************************************************************************/
  763. BOOL FAR PASCAL GiveWaveDevice(NPMCIGRAPHIC npMCI)
  764. {
  765. extern NPMCIGRAPHIC npMCIList; // in graphic.c
  766. NPMCIGRAPHIC np;
  767. Assert(npMCI->hWave == NULL);
  768. DPF(("GiveWaveDevice '%s' hTask=%04X\n", (LPSTR)npMCI->szFilename, GetCurrentTask()));
  769. //
  770. // walk the list of open MCIAVI instances and find one that
  771. // will give up the wave device
  772. //
  773. for (np=npMCIList; np; np = np->npMCINext) {
  774. if (np->dwFlags & MCIAVI_LOSTAUDIO) {
  775. DPF(("**** Giving the wave device to '%s'.\n", (LPSTR)np->szFilename));
  776. PostMessage(np->hwndDefault, WM_AUDIO_ON, 0, 0);
  777. return TRUE;
  778. }
  779. }
  780. return FALSE;
  781. }
  782. #ifndef WIN32
  783. #pragma alloc_text(FIX, mciaviWaveOutFunc)
  784. #pragma optimize("", off)
  785. #endif
  786. void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg,
  787. DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
  788. {
  789. NPMCIGRAPHIC npMCI;
  790. LPWAVEHDR lpwh;
  791. #ifndef WIN32
  792. #ifndef WANT_286
  793. // If compiling -G3 we need to save the 386 registers
  794. _asm _emit 0x66 ; pushad
  795. _asm _emit 0x60
  796. #endif
  797. #endif
  798. npMCI = (NPMCIGRAPHIC)(UINT)dwInstance;
  799. lpwh = (LPWAVEHDR) dwParam1;
  800. switch(wMsg) {
  801. case MM_WOM_DONE:
  802. npMCI->wABFull--;
  803. npMCI->dwAudioPlayed += lpwh->dwBufferLength;
  804. npMCI->dwTimingStart = timeGetTime();
  805. break;
  806. }
  807. #ifndef WIN32
  808. #ifndef WANT_286
  809. // If compiling -G3 we need to restore the 386 registers
  810. _asm _emit 0x66 ; popad
  811. _asm _emit 0x61
  812. #endif
  813. #endif
  814. }
  815. #ifndef WIN32
  816. #pragma optimize("", off)
  817. #endif