|
|
/******************************************************************************
Copyright (C) Microsoft Corporation 1991-1992. All rights reserved.
Title: avisound.c - Code for playing audio in AVI files.
*****************************************************************************/ #include "graphic.h"
#define AUDIO_PANIC 10
static UINT nAudioPanic;
//
// redefine StreamFromFOURCC to only handle 0-9 streams!
//
#undef StreamFromFOURCC
#define StreamFromFOURCC(fcc) (UINT)(HIBYTE(LOWORD(fcc)) - (BYTE)'0')
void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2);
#ifndef WIN32
#define GetDS() (HGLOBAL)HIWORD((DWORD)(LPVOID)&ghModule)
#endif //WIN16
DWORD FAR PASCAL SetUpAudio(NPMCIGRAPHIC npMCI, BOOL fPlaying) { UINT w; LPWAVEHDR lpWaveHdr; STREAMINFO *psi;
if (npMCI->nAudioStreams == 0) { npMCI->wABs = 0; npMCI->wABOptimal = 0; return 0L; }
nAudioPanic = GetProfileInt(TEXT("MCIAVI"), TEXT("AudioPanic"), AUDIO_PANIC);
psi = SI(npMCI->nAudioStream); Assert(psi->sh.fccType == streamtypeAUDIO); Assert(psi->cbFormat); Assert(psi->lpFormat);
if (!npMCI->pWF) { npMCI->pWF = (NPWAVEFORMAT)LocalAlloc(LPTR, (UINT)psi->cbFormat);
if (!npMCI->pWF) { return MCIERR_OUT_OF_MEMORY; } }
hmemcpy(npMCI->pWF,psi->lpFormat,psi->cbFormat);
npMCI->wEarlyAudio = (UINT)psi->sh.dwInitialFrames; npMCI->dwAudioLength = psi->sh.dwLength * psi->sh.dwSampleSize;
if (npMCI->dwAudioLength < 1000L) { DPF(("AudioLength is bogus")); npMCI->dwAudioLength = muldiv32((npMCI->pWF->nAvgBytesPerSec + 100) * npMCI->lFrames,npMCI->dwMicroSecPerFrame,1000000L); }
//
// choose the audio playback method depending on how we are going to
// recive audio data from the file.
//
switch (npMCI->wPlaybackAlg) { case MCIAVI_ALG_HARDDISK: case MCIAVI_ALG_AUDIOONLY:
if (!npMCI->pf && !npMCI->hmmioAudio) { MMIOINFO mmioInfo;
_fmemset(&mmioInfo, 0, sizeof(MMIOINFO)); mmioInfo.htask = (HANDLE) npMCI->hCallingTask; //ntmmsystem bug, should be threadid which is dword
npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo, MMIO_READ | MMIO_DENYWRITE);
if (npMCI->hmmioAudio == NULL) npMCI->hmmioAudio = mmioOpen(npMCI->szFilename, &mmioInfo, MMIO_READ);
if (!npMCI->hmmioAudio) { Assert(0); return MCIERR_DRIVER_INTERNAL; } }
// fall through to CDROM
case MCIAVI_ALG_CDROM: //!!!! we need to tune this!!!!
// !!! We use four 1/2 second buffers. This is arbitrary.
npMCI->wABs = 4; npMCI->wABOptimal = 0; npMCI->dwABSize = npMCI->pWF->nAvgBytesPerSec / 2; break;
case MCIAVI_ALG_INTERLEAVED: /* Fix up some values based on the header information */ npMCI->dwABSize = muldiv32(npMCI->dwMicroSecPerFrame, npMCI->pWF->nAvgBytesPerSec,1000000L) + 2047;
npMCI->dwABSize &= ~(2047L);
npMCI->wABs = npMCI->wEarlyAudio + 2 + (WORD) npMCI->dwBufferedVideo;
/* Soundblaster hack: waveoutdone only accurate to 2K. */
//!!!!!!!!!! is this right.
if (npMCI->dwMicroSecPerFrame) { npMCI->wABOptimal = npMCI->wABs - (UINT) (muldiv32(2048, 1, muldiv32(npMCI->dwMicroSecPerFrame, npMCI->pWF->nAvgBytesPerSec,1000000L))); } else { npMCI->wABOptimal = 0; }
//!!! hack so we can do burst reading, up to 1sec
//npMCI->wABs += (int)muldiv32(1000000l, 1, npMCI->dwMicroSecPerFrame);
DPF2(("Using %u audio buffers, of which %u should be full.\n", npMCI->wABs, npMCI->wABOptimal)); break;
default: Assert(0); return 0L; }
npMCI->dwABSize -= npMCI->dwABSize % npMCI->pWF->nBlockAlign;
if (!fPlaying) return 0L;
/* This code adjusts the wave format block to play
** the audio at the correct speed to match the frame rate. */
npMCI->pWF->nSamplesPerSec = muldiv32(npMCI->pWF->nSamplesPerSec, npMCI->dwMicroSecPerFrame, npMCI->dwPlayMicroSecPerFrame);
npMCI->pWF->nAvgBytesPerSec = muldiv32(npMCI->pWF->nAvgBytesPerSec, npMCI->dwMicroSecPerFrame, npMCI->dwPlayMicroSecPerFrame);
if (npMCI->pWF->wFormatTag == WAVE_FORMAT_PCM) { /* Make sure this is exactly right... */ npMCI->pWF->nAvgBytesPerSec = npMCI->pWF->nSamplesPerSec * npMCI->pWF->nBlockAlign; }
/* Kill any currently playing sound */ sndPlaySound(NULL, 0);
DPF2(("Opening wave device....\n")); /* Try to open a wave device. */ w = waveOutOpen(&npMCI->hWave, (UINT)WAVE_MAPPER, (LPWAVEFORMATEX) npMCI->pWF, //(const LPWAVEFORMATEX) npMCI->pWF,
(DWORD) &mciaviWaveOutFunc, (DWORD) (LPMCIGRAPHIC) npMCI, (DWORD)CALLBACK_FUNCTION);
if (w) { DPF(("Unable to open wave device.\n"));
npMCI->hWave = NULL; return w == WAVERR_BADFORMAT ? MCIERR_WAVE_OUTPUTSUNSUITABLE : MCIERR_WAVE_OUTPUTSINUSE; }
npMCI->dwFlags &= ~MCIAVI_LOSTAUDIO;
#ifndef WIN32 // No need to lock it on NT - although we could with Virtual mem
// functions
//
// page lock our DS so our wave callback function can
// touch it without worry. see mciaviWaveOutFunc()
//
GlobalPageLock(GetDS()); #endif //WIN16
/* Pause the wave output device, so it won't start playing
** when we're loading up the buffers. */ if (waveOutPause(npMCI->hWave) != 0) { DPF(("Error from waveOutPause!\n")); return MCIERR_DRIVER_INTERNAL; }
if (npMCI->dwFlags & MCIAVI_VOLUMESET) { DeviceSetVolume(npMCI, npMCI->dwVolume); } else { DeviceGetVolume(npMCI); }
npMCI->lpAudio = GlobalAllocPtr(GMEM_MOVEABLE | GMEM_SHARE, npMCI->wABs * (npMCI->dwABSize + sizeof(WAVEHDR)));
if (!npMCI->lpAudio) { return MCIERR_OUT_OF_MEMORY; }
npMCI->dwAudioPlayed = 0L; npMCI->wNextAB = 0; npMCI->dwUsedThisAB = 0;
/* Allocate and prepare our buffers */ for (w = 0; w < npMCI->wABs; w++) { lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
lpWaveHdr->lpData = (HPSTR) npMCI->lpAudio + npMCI->wABs * sizeof(WAVEHDR) + w * npMCI->dwABSize; lpWaveHdr->dwBufferLength = npMCI->dwABSize; lpWaveHdr->dwBytesRecorded = 0L; lpWaveHdr->dwUser = 0L; lpWaveHdr->dwFlags = 0L; lpWaveHdr->dwLoops = 0L; lpWaveHdr->lpNext = 0L; lpWaveHdr->reserved = 0; }
for (w = 0; w < npMCI->wABs; w++) { lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
if (waveOutPrepareHeader(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR)) != 0) { return MCIERR_OUT_OF_MEMORY; } lpWaveHdr->dwFlags |= WHDR_DONE; }
return 0L; }
DWORD FAR PASCAL CleanUpAudio(NPMCIGRAPHIC npMCI) { UINT w;
/* Clear flags relating to playing audio */ npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED);
if (npMCI->lpAudio) { waveOutRestart(npMCI->hWave); // just in case we are paused
waveOutReset(npMCI->hWave);
for (w = 0; w < npMCI->wABs; w++) { LPWAVEHDR lpWaveHdr;
lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (w * sizeof(WAVEHDR)));
#if 0
lpWaveHdr->lpData = npMCI->lpAudio + npMCI->wABs * sizeof(WAVEHDR) + w * npMCI->dwABSize; lpWaveHdr->dwBufferLength = npMCI->dwABSize; #endif
/* Do we need to check for an error from this? */ waveOutUnprepareHeader(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR)); } GlobalFreePtr(npMCI->lpAudio); npMCI->lpAudio = NULL;
Assert(npMCI->wABFull == 0); }
DPF2(("Closing wave device.\n")); waveOutClose(npMCI->hWave); npMCI->hWave = 0;
#ifndef WIN32
GlobalPageUnlock(GetDS()); #endif //WIN16
return 0L; }
BOOL NEAR PASCAL WaitForFreeAudioBuffer(NPMCIGRAPHIC npMCI, BOOL FAR *lpfHurry) { LPWAVEHDR lpWaveHdr;
lpWaveHdr = (LPWAVEHDR) (npMCI->lpAudio + (npMCI->wNextAB * sizeof(WAVEHDR)));
/* Use the number of full audio buffers to decide if we're behind. */ if (npMCI->wABFull < npMCI->wABOptimal) { *lpfHurry = TRUE; }
/* If all of the audio buffers are full, we have to wait. */ if (npMCI->wABFull == npMCI->wABs) {
DWORD time = timeGetTime();
#define AUDIO_WAIT_TIMEOUT 2000
DOUT2("waiting for audio buffer.");
// we better not wait if the device is not playing!
Assert(!(npMCI->dwFlags & MCIAVI_WAVEPAUSED));
#ifdef XDEBUG
GetAsyncKeyState(VK_ESCAPE); GetAsyncKeyState(VK_F2); GetAsyncKeyState(VK_F3); GetAsyncKeyState(VK_F4); #endif
while (npMCI->wABFull == npMCI->wABs) {
if (npMCI->dwFlags & MCIAVI_STOP) return FALSE;
aviTaskYield();
//
// the "Fahrenheit VA Audio Wave Driver" may get confused
// if you call waveOutPause() and waveOutRestart() alot
// and it will stay paused no matter what you do, it has
// all our buffers and it still does not make any sound
// you can call waveOutRestart() until you are blue in
// the face, it will do nothing.
//
// so this is why this routine can time out, after waiting
// 2 seconds or so we just toss all the audio in the buffers
// and start over.
//
if (timeGetTime() - time > AUDIO_WAIT_TIMEOUT) { DOUT("Gave up waiting, reseting wave device\n"); waveOutReset(npMCI->hWave); break; }
#ifdef XDEBUG
if (GetAsyncKeyState(VK_ESCAPE) & 0x0001) { DPF(("STOPPED WAITING! wABFull = %d, wABs = %d\n", npMCI->wABFull,npMCI->wABs)); return FALSE; }
if (GetAsyncKeyState(VK_F2) & 0x0001) { DOUT("Trying waveOutRestart\n"); waveOutRestart(npMCI->hWave); }
if (GetAsyncKeyState(VK_F3) & 0x0001) { DOUT("Trying waveOutReset\n"); waveOutReset(npMCI->hWave); }
if (GetAsyncKeyState(VK_F4) & 0x0001) {
int i,n;
for (i=n=0; i<(int)npMCI->wABs; i++) {
if (((LPWAVEHDR)npMCI->lpAudio)[i].dwFlags & WHDR_DONE) { DPF(("Buffer #%d is done!\n", i)); n++; } else { DPF(("Buffer #%d is not done\n", i)); } }
if (n > 0) DPF(("%d buffers are done but our callback did not get called!\n", n)); } #endif
}
DOUT2("done\n"); }
/* Debugging check that wave has finished playing--should never happen */ Assert(lpWaveHdr->dwFlags & WHDR_DONE);
#if 0
lpWaveHdr->lpData = npMCI->lpAudio + npMCI->wABs * sizeof(WAVEHDR) + npMCI->wNextAB * npMCI->dwABSize; #endif
return TRUE; }
#ifndef WIN32
#pragma optimize("", off)
#endif
BOOL NEAR PASCAL ReadSomeAudio(NPMCIGRAPHIC npMCI, BYTE _huge * lpAudio, DWORD dwStart, DWORD FAR * pdwLength) { DWORD dwIndex = 0; DWORD ckidAudio; DWORD dwAudioPos = 0L; AVIINDEXENTRY far * lpIndexEntry;
Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK || npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
Assert(npMCI->hpIndex);
/*
** Figure out what type of chunk we're looking for, */ ckidAudio = MAKEAVICKID(cktypeWAVEbytes, npMCI->nAudioStream);
lpIndexEntry = (AVIINDEXENTRY FAR *) npMCI->hpIndex;
for (dwIndex = 0; dwIndex < npMCI->macIndex; dwIndex++, ++((AVIINDEXENTRY _huge *) lpIndexEntry)) {
if (lpIndexEntry->ckid != ckidAudio) continue; if (dwAudioPos + lpIndexEntry->dwChunkLength > dwStart) { DWORD dwLengthNow; DWORD dwSeekTo; dwLengthNow = lpIndexEntry->dwChunkLength; dwSeekTo = lpIndexEntry->dwChunkOffset + 8; if (dwAudioPos + dwLengthNow > dwStart + *pdwLength) { /* Attempted optimization: If we've already read some
** data, and we can't read the next whole chunk, let's ** leave it for later. */ if (dwAudioPos > dwStart && (!(npMCI->dwFlags & MCIAVI_REVERSE))) break; dwLengthNow = dwStart + *pdwLength - dwAudioPos; } if (dwAudioPos < dwStart) { dwLengthNow -= (dwStart - dwAudioPos); dwSeekTo += (dwStart - dwAudioPos); }
mmioSeek(npMCI->hmmioAudio, dwSeekTo, SEEK_SET);
if (mmioRead(npMCI->hmmioAudio, lpAudio, dwLengthNow) != (LONG) dwLengthNow) { DPF(("Error reading audio data (%lx bytes at %lx)\n", dwLengthNow, dwSeekTo)); return FALSE; } lpAudio += dwLengthNow; } dwAudioPos += lpIndexEntry->dwChunkLength; if (dwAudioPos >= dwStart + *pdwLength) return TRUE; }
if (dwAudioPos < dwStart) *pdwLength = 0; // return FALSE?
else *pdwLength = dwAudioPos - dwStart;
return TRUE; } #ifndef WIN32
#pragma optimize("", on)
#endif
BOOL NEAR PASCAL ReverseWaveBuffer(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr) { DWORD dwLeft = lpWaveHdr->dwBufferLength; BYTE _huge *hp1; BYTE _huge *hp2; DWORD dwBlock = npMCI->pWF->nBlockAlign; BYTE bTemp; DWORD dw;
Assert(npMCI->dwFlags & MCIAVI_REVERSE); Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK || npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
/* This routine doesn't like it when the data doesn't end on a
** block boundary, so make it so. This should never happen. */ Assert((dwLeft % dwBlock) == 0); dwLeft -= dwLeft % dwBlock;
hp1 = lpWaveHdr->lpData; hp2 = ((HPSTR) lpWaveHdr->lpData) + (dwLeft - dwBlock);
while ((LONG) dwLeft > (LONG) dwBlock) { for (dw = 0; dw < dwBlock; dw++) { bTemp = *hp1; *hp1++ = *hp2; *hp2++ = bTemp; } hp2 -= dwBlock * 2; dwLeft -= dwBlock * 2; }
return TRUE; }
void FAR PASCAL BuildVolumeTable(NPMCIGRAPHIC npMCI) { int vol; int i;
if (!npMCI->pWF || npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM) return;
if (((NPPCMWAVEFORMAT) npMCI->pWF)->wBitsPerSample != 8) return;
vol = (LOWORD(npMCI->dwVolume) + HIWORD(npMCI->dwVolume)) / 2; vol = (int) (((LONG) vol * 256) / 500);
if (!npMCI->pVolumeTable) npMCI->pVolumeTable = (void *)LocalAlloc(LPTR, 256);
if (!npMCI->pVolumeTable) return;
for (i = 0; i < 256; i++) { npMCI->pVolumeTable[i] = (BYTE) min(255, max(0, (int) ((((LONG) (i - 128) * vol) / 256) + 128))); } }
BOOL NEAR PASCAL AdjustVolume(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr) { DWORD dwLeft = lpWaveHdr->dwBufferLength; BYTE FAR *pb;
if (npMCI->pWF->wFormatTag != WAVE_FORMAT_PCM) return FALSE;
if (!npMCI->pVolumeTable) return FALSE;
if (((NPPCMWAVEFORMAT)npMCI->pWF)->wBitsPerSample != 8) return FALSE;
pb = lpWaveHdr->lpData;
#ifndef WIN32
if (OFFSETOF(pb) + dwLeft > 64l*1024) { while (dwLeft--) { *pb = npMCI->pVolumeTable[*pb]; ((BYTE _huge *)pb)++; } } else { while ((int)dwLeft--) *pb++ = npMCI->pVolumeTable[*pb]; } #else
while ((int)dwLeft--) *pb++ = npMCI->pVolumeTable[*pb]; #endif
return TRUE; }
BOOL NEAR PASCAL PlaySomeAudio(NPMCIGRAPHIC npMCI, LPWAVEHDR lpWaveHdr) { if (npMCI->pVolumeTable) AdjustVolume(npMCI, lpWaveHdr);
lpWaveHdr->dwFlags &= ~WHDR_DONE;
/* If we're playing and we've used all of our audio buffers, pause the
** wave device until we can fill more of them up. ** ** we need to be carefull not to do this on the last frame!!! */ if ((npMCI->wTaskState == TASKPLAYING) && !(npMCI->dwFlags & MCIAVI_WAVEPAUSED) && (npMCI->wABFull == 0 || npMCI->nAudioBehind > nAudioPanic)) {
if (npMCI->wABFull > 0) { DPF(("Audio panic stop\n")); } else { DPF(("Audio queue empty; pausing wave device\n")); }
//
// some audio cards dont like starving it confuses them
// it is kind of rude any way. we are going to cause a audio break
// anyway so if we lose a little bit of audio (a few frames or so)
// no one will even notice (any worse than the audio break)
//
if (npMCI->wABFull <= 1) { DOUT("Trying audio hack!\n"); waveOutReset(npMCI->hWave); }
++npMCI->dwAudioBreaks; waveOutPause(npMCI->hWave);
ICDrawStop(npMCI->hicDraw); npMCI->dwFlags |= MCIAVI_WAVEPAUSED; }
if (waveOutWrite(npMCI->hWave, lpWaveHdr, sizeof(WAVEHDR)) != 0) { DPF(("Error from waveOutWrite!\n")); npMCI->dwTaskError = MCIERR_AVI_AUDIOERROR; return FALSE; } else { ++npMCI->wABFull;
/* Use the next wave buffer next time */ ++npMCI->wNextAB; if (npMCI->wNextAB == npMCI->wABs) npMCI->wNextAB = 0; npMCI->dwUsedThisAB = 0; }
if (npMCI->wABFull < min(npMCI->wABOptimal, npMCI->wABFull/2)) npMCI->nAudioBehind++; else npMCI->nAudioBehind=0;
/* If we paused the wave device to let ourselves catch up, and
** we've caught up enough, restart the device. */ if ((npMCI->dwFlags & MCIAVI_WAVEPAUSED) && npMCI->wTaskState == TASKPLAYING && npMCI->wABFull == npMCI->wABs) {
DPF2(("restarting wave device\n")); waveOutRestart(npMCI->hWave);
ICDrawStart(npMCI->hicDraw); npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED); npMCI->nAudioBehind = 0; }
return TRUE; }
/* Play the current record's audio */ BOOL NEAR PASCAL PlayRecordAudio(NPMCIGRAPHIC npMCI, BOOL FAR *pfHurryUp, BOOL FAR *pfPlayedAudio) { LPWAVEHDR lpWaveHdr; FOURCC ckid; DWORD cksize; LPSTR lpSave; LPSTR lpData; BOOL fRet = TRUE; ////BOOL fSilence;
LONG len; DWORD dwBytesTotal = 0L; DWORD dwBytesThisChunk;
Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_INTERLEAVED);
lpSave = npMCI->lp;
lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
*pfPlayedAudio = FALSE;
/* Remember!
** ** In the new file format, things shouldn't necessarily need to ** be ordered with the wave stuff always first. */
len = (LONG)npMCI->dwThisRecordSize;
while (len > 3 * sizeof(DWORD)) {
/* Look at the next chunk */ ckid = GET_DWORD(); cksize = GET_DWORD();
lpData = npMCI->lp;
len -= ((cksize + 1) & ~1) + 8; SKIP_BYTES((cksize + 1) & ~1);
if (StreamFromFOURCC(ckid) != (UINT)npMCI->nAudioStream) continue;
dwBytesThisChunk = cksize;
if (!dwBytesTotal) { if (!WaitForFreeAudioBuffer(npMCI, pfHurryUp)) /* We had to stop waiting--the stop flag was probably set. */ goto exit; }
if (dwBytesThisChunk > npMCI->dwABSize - dwBytesTotal) { DPF(("Audio Record is too big!\n")); dwBytesThisChunk = npMCI->dwABSize - dwBytesTotal; }
hmemcpy((BYTE _huge *)lpWaveHdr->lpData + dwBytesTotal, lpData, dwBytesThisChunk);
dwBytesTotal += dwBytesThisChunk; }
if (dwBytesTotal) { *pfPlayedAudio = TRUE; lpWaveHdr->dwBufferLength = dwBytesTotal; fRet = PlaySomeAudio(npMCI, lpWaveHdr); }
/* Use the number of full audio buffers to decide if we're behind. */ if (npMCI->wABFull >= npMCI->wABOptimal) { *pfHurryUp = FALSE; }
exit: npMCI->lp = lpSave;
return fRet; }
/* For "preload audio" or "random access audio" modes, do what needs
** to be done to keep our buffers full. */ BOOL NEAR PASCAL KeepPlayingAudio(NPMCIGRAPHIC npMCI) { LPWAVEHDR lpWaveHdr; DWORD dwBytesTotal = 0L; LONG lNewAudioPos; ////BOOL fFirstTime = TRUE;
Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_HARDDISK || npMCI->wPlaybackAlg == MCIAVI_ALG_AUDIOONLY);
PlayMore: lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
if (npMCI->dwFlags & MCIAVI_REVERSE) { lNewAudioPos = npMCI->dwAudioPos - npMCI->dwABSize; if (lNewAudioPos < 0) lNewAudioPos = 0; dwBytesTotal = npMCI->dwAudioPos - lNewAudioPos; } else { lNewAudioPos = npMCI->dwAudioPos + npMCI->dwABSize; if (lNewAudioPos > (LONG) npMCI->dwAudioLength) lNewAudioPos = npMCI->dwAudioLength; dwBytesTotal = lNewAudioPos - npMCI->dwAudioPos; }
if (dwBytesTotal == 0) {
if (npMCI->dwFlags & MCIAVI_WAVEPAUSED) {
DOUT("no more audio to play, restarting wave device\n");
waveOutRestart(npMCI->hWave); ICDrawStart(npMCI->hicDraw); npMCI->dwFlags &= ~(MCIAVI_WAVEPAUSED); npMCI->nAudioBehind = 0; }
return TRUE; }
/* If all of the audio buffers are full, we have nothing to do */ if (npMCI->wABFull == npMCI->wABs) return TRUE;
#if 0
//!!!! Should we be yielding at all in here?
//!!! NO NO! not if updating!!!!
if (!fFirstTime) { aviTaskYield(); } fFirstTime = FALSE; #endif
if (npMCI->dwFlags & MCIAVI_REVERSE) npMCI->dwAudioPos = lNewAudioPos;
#ifdef USEAVIFILE
if (npMCI->pf) { LONG lPos; LONG lLength;
lPos = npMCI->dwAudioPos / SH(npMCI->nAudioStream).dwSampleSize; lLength = dwBytesTotal / SH(npMCI->nAudioStream).dwSampleSize;
AVIStreamRead(SI(npMCI->nAudioStream)->ps, lPos, lLength, lpWaveHdr->lpData, npMCI->dwABSize, NULL, NULL); } else #endif
{ if (!ReadSomeAudio(npMCI, lpWaveHdr->lpData, npMCI->dwAudioPos, &dwBytesTotal)) return FALSE; if (dwBytesTotal == 0) return TRUE; }
if (!(npMCI->dwFlags & MCIAVI_REVERSE)) npMCI->dwAudioPos += dwBytesTotal;
lpWaveHdr->dwBufferLength = dwBytesTotal;
if (npMCI->dwFlags & MCIAVI_REVERSE) { ReverseWaveBuffer(npMCI, lpWaveHdr); }
if (!PlaySomeAudio(npMCI, lpWaveHdr)) return FALSE;
// return TRUE;
goto PlayMore; }
/* Play the current chunk's audio */ BOOL NEAR PASCAL HandleAudioChunk(NPMCIGRAPHIC npMCI) { LPWAVEHDR lpWaveHdr; FOURCC ckid; DWORD cksize; BYTE _huge *lpData; BOOL fRet = TRUE; BOOL fSilence; DWORD dwBytesTotal = 0L; DWORD dwBytesThisChunk; DWORD dwBytesThisBuffer; BOOL fHurryUp;
Assert(npMCI->wPlaybackAlg == MCIAVI_ALG_CDROM);
while ((DWORD) (npMCI->lp - npMCI->lpBuffer) < npMCI->dwThisRecordSize - 3 * sizeof(DWORD)) {
/* Look at the next chunk */ ckid = GET_DWORD(); cksize = GET_DWORD();
lpData = npMCI->lp; SKIP_BYTES(cksize + (cksize & 1));
fSilence = (TWOCCFromFOURCC(ckid) == cktypeWAVEsilence);
if (fSilence) { if (cksize != sizeof(DWORD)) { DPF(("Wave silence chunk of bad length!\n")); fRet = FALSE; npMCI->dwTaskError = MCIERR_INVALID_FILE; goto exit; } dwBytesThisChunk = PEEK_DWORD(); } else { dwBytesThisChunk = cksize; }
while (dwBytesThisChunk > 0) { lpWaveHdr = ((LPWAVEHDR)npMCI->lpAudio) + npMCI->wNextAB;
if (!WaitForFreeAudioBuffer(npMCI, &fHurryUp)) /* We had to stop waiting--the stop flag was probably set. */ goto exit; dwBytesThisBuffer = min(dwBytesThisChunk, npMCI->dwABSize - npMCI->dwUsedThisAB);
if (!fSilence) { /* Move the data into the buffer */ hmemcpy((BYTE _huge *) lpWaveHdr->lpData + npMCI->dwUsedThisAB, lpData, dwBytesThisBuffer); lpData += dwBytesThisBuffer; } else { /* Fill the buffer with silence */ /* This isn't right for 16-bit! */ #ifndef WIN32
#pragma message("WAVE silence chunks don't work right now.")
#endif
// fmemfill((BYTE _huge *)lpWaveHdr->lpData + npMCI->dwUsedThisAB,
// dwBytesThisBuffer, 0x80);
} dwBytesThisChunk -= dwBytesThisBuffer; npMCI->dwUsedThisAB += dwBytesThisBuffer;
// if (npMCI->dwUsedThisAB == npMCI->dwABSize) {
lpWaveHdr->dwBufferLength = npMCI->dwUsedThisAB;
fRet = PlaySomeAudio(npMCI, lpWaveHdr); // }
} }
exit: return fRet; }
/******************************************************************************
*****************************************************************************/
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api BOOL | StealWaveDevice | steal the audio device from another * instance of MCIAVI. * * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data * ***************************************************************************/
BOOL FAR PASCAL StealWaveDevice(NPMCIGRAPHIC npMCI) { extern NPMCIGRAPHIC npMCIList; // in graphic.c
NPMCIGRAPHIC np;
Assert(npMCI->hWave == NULL);
DPF(("StealWaveDevice '%s' hTask=%04X\n", (LPSTR)npMCI->szFilename, GetCurrentTask()));
//
// walk the list of open MCIAVI instances and find one that
// will give up the wave device
//
for (np=npMCIList; np; np = np->npMCINext) {
if (np->hWave) { DPF(("**** Stealing the wave device from '%s'.\n", (LPSTR)np->szFilename));
//!!!should we call DeviceMute() or just call cleanup audio?
//
//!!!can this cause evil reenter cases?
//
//!!!we are calling this from another task, will this work ok?
//!!!even in WIN32? mabey we should use SendMessage()
#if 1
SendMessage(np->hwndDefault, WM_AUDIO_OFF, 0, 0); #else
np->dwFlags |= MCIAVI_LOSTAUDIO; DeviceMute(np, TRUE); np->dwFlags |= MCIAVI_LOSTAUDIO; #endif
return TRUE; } }
DPF(("StealWaveDevice can't find a device to steal\n"));
return FALSE; }
/***************************************************************************
* * @doc INTERNAL MCIAVI * * @api BOOL | GiveWaveDevice | give away the audio device * instance of MCIAVI. * * @parm NPMCIGRAPHIC | npMCI | near ptr to the instance data * ***************************************************************************/
BOOL FAR PASCAL GiveWaveDevice(NPMCIGRAPHIC npMCI) { extern NPMCIGRAPHIC npMCIList; // in graphic.c
NPMCIGRAPHIC np;
Assert(npMCI->hWave == NULL);
DPF(("GiveWaveDevice '%s' hTask=%04X\n", (LPSTR)npMCI->szFilename, GetCurrentTask()));
//
// walk the list of open MCIAVI instances and find one that
// will give up the wave device
//
for (np=npMCIList; np; np = np->npMCINext) {
if (np->dwFlags & MCIAVI_LOSTAUDIO) { DPF(("**** Giving the wave device to '%s'.\n", (LPSTR)np->szFilename));
PostMessage(np->hwndDefault, WM_AUDIO_ON, 0, 0);
return TRUE; } }
return FALSE; }
#ifndef WIN32
#pragma alloc_text(FIX, mciaviWaveOutFunc)
#pragma optimize("", off)
#endif
void FAR PASCAL _LOADDS mciaviWaveOutFunc(HWAVEOUT hWaveOut, UINT wMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2) { NPMCIGRAPHIC npMCI; LPWAVEHDR lpwh;
#ifndef WIN32
#ifndef WANT_286
// If compiling -G3 we need to save the 386 registers
_asm _emit 0x66 ; pushad _asm _emit 0x60 #endif
#endif
npMCI = (NPMCIGRAPHIC)(UINT)dwInstance; lpwh = (LPWAVEHDR) dwParam1;
switch(wMsg) { case MM_WOM_DONE: npMCI->wABFull--; npMCI->dwAudioPlayed += lpwh->dwBufferLength; npMCI->dwTimingStart = timeGetTime(); break; }
#ifndef WIN32
#ifndef WANT_286
// If compiling -G3 we need to restore the 386 registers
_asm _emit 0x66 ; popad _asm _emit 0x61 #endif
#endif
}
#ifndef WIN32
#pragma optimize("", off)
#endif
|