Microsoft-3D-Movie-Maker/SRC/ENGINE/MSND.CPP
2022-05-03 16:31:19 -07:00

957 lines
22 KiB
C++

/* Copyright (c) Microsoft Corporation.
Licensed under the MIT License. */
/***************************************************************************
msnd.cpp: Movie Sound class
Primary Authors: *****, *****
Status: Reviewed
A MSND (movie sound) owns a MIDI or WAVE child chunk, and also
specifies what sound type (sty) this sound is, and the default
volume for the sound.
Here's how the chunks look:
MSND
|
+---MIDI or WAVE (chid 0) // actual sound data
An MSND chunk with no child is a "no sound" or silent sound.
An MSND chunk with _fInvalid set requires no child.
***************************************************************************/
#include "soc.h"
#include "audioman.h"
ASSERTNAME
RTCLASS(MSND)
RTCLASS(MSQ)
BEGIN_CMD_MAP(MSQ, CMH)
ON_CID_ME(cidAlarm, &MSQ::FCmdAlarm, pvNil)
END_CMD_MAP_NIL()
// default sound import format
const WORD knSamplesPerSec = 11025;
const WORD knAvgBytesPerSec = 11025;
const WORD kwBitsPerSample = 8;
const WORD knChannels = 1;
const WORD knBlockAlign = 1;
/***************************************************************************
A PFNRPO to read a MSND from a file
***************************************************************************/
bool MSND::FReadMsnd(PCRF pcrf, CTG ctg, CNO cno, PBLCK pblck,
PBACO *ppbaco, long *pcb)
{
AssertPo(pcrf, 0);
AssertPo(pblck, 0);
AssertNilOrVarMem(ppbaco);
AssertVarMem(pcb);
MSND *pmsnd;
*pcb = size(MSND); // estimate MSND size
if (pvNil == ppbaco)
return fTrue;
pmsnd = NewObj MSND();
if (pvNil == pmsnd || !pmsnd->_FInit(pcrf->Pcfl(), ctg, cno))
{
TrashVar(ppbaco);
TrashVar(pcb);
ReleasePpo(&pmsnd);
return fFalse;
}
pmsnd->_prca = pcrf;
AssertPo(pmsnd, 0);
*ppbaco = pmsnd;
return fTrue;
}
/***************************************************************************
Retrieve information contained in the msnd chunk
***************************************************************************/
bool MSND::FGetMsndInfo(PCFL pcfl, CTG ctg, CNO cno, bool *pfInvalid, long *psty, long *pvlm)
{
AssertPo(pcfl, 0);
PMSND pmsnd;
pmsnd = NewObj MSND();
if (pvNil == pmsnd)
return pvNil;
if (!pmsnd->_FInit(pcfl, ctg, cno))
{
ReleasePpo(&pmsnd);
return fFalse;
}
if (pvNil != pfInvalid)
*pfInvalid = pmsnd->_fInvalid;
if (pvNil != psty)
*psty = pmsnd->_sty;
if (pvNil != pvlm)
*pvlm = pmsnd->_vlm;
ReleasePpo(&pmsnd);
return fTrue;
}
/***************************************************************************
Init a MSND from the given chunk of the given CFL
***************************************************************************/
bool MSND::_FInit(PCFL pcfl, CTG ctg, CNO cno)
{
AssertBaseThis(0);
AssertPo(pcfl, 0);
BLCK blck;
MSNDF msndf;
KID kid;
if (!pcfl->FFind(ctg, cno, &blck) || !blck.FUnpackData())
goto LFail;
if (blck.Cb() > size(MSNDF))
goto LFail;
if (!blck.FReadRgb(&msndf, size(MSNDF), 0))
goto LFail;
if (kboCur != msndf.bo)
SwapBytesBom(&msndf, kbomBkgdf);
Assert(kboCur == msndf.bo, "bad MSNDF");
if (!pcfl->FGetName(ctg, cno, &_stn))
return fFalse;
_sty = msndf.sty;
_vlm = msndf.vlmDefault;
_fInvalid = msndf.fInvalid;
if (_fInvalid)
return fTrue;
// If there is a SND child, it is not a "no sound"
if (pcfl->FGetKidChid(ctg, cno, kchidSnd, &kid))
{
_cnoSnd = kid.cki.cno;
_ctgSnd = kid.cki.ctg;
_fNoSound = fFalse;
}
else
_fNoSound = fTrue;
return fTrue;
LFail:
return fFalse;
}
/***************************************************************************
Write an MSND MIDI chunk to file *pcfl
ie, write the MSND chunk, its name, and the midi child
***************************************************************************/
bool MSND::FWriteMidi(PCFL pcflDest, PMIDS pmids, STN *pstnName, CNO *pcno)
{
AssertPo(pcflDest, 0);
AssertPo(pmids, 0);
AssertVarMem(pstnName);
AssertVarMem(pcno);
MSNDF msndf;
BLCK blck;
CNO cno;
msndf.bo = kboCur;
msndf.osk = koskCur;
msndf.sty = styMidi;
msndf.vlmDefault = kvlmFull;
msndf.fInvalid = fFalse;
// Create the msnd chunk
if (!pcflDest->FAddPv(&msndf, size(MSNDF), kctgMsnd, pcno))
return fFalse;
// Create the midi chunk as a child of the msnd chunk
if (!pcflDest->FAddChild(kctgMsnd, *pcno, kchidSnd, pmids->CbOnFile(), kctgMidi, &cno, &blck))
goto LFail;
if (!pmids->FWrite(&blck))
goto LFail;
if (!pcflDest->FSetName(kctgMsnd, *pcno, pstnName))
goto LFail;
return fTrue;
LFail:
pcflDest->Delete(kctgMsnd, *pcno); // Deletes the midi chunk also
return fFalse;
}
/***************************************************************************
Write an MSND Wave file to a file
ie, write the MSND chunk, its name, and the midi child
***************************************************************************/
bool MSND::FWriteWave(PFIL pfilSrc, PCFL pcflDest, long sty, STN *pstnName, CNO *pcno)
{
AssertPo(pfilSrc, 0);
AssertIn(sty, 0, styLim);
AssertVarMem(pstnName);
AssertVarMem(pcno);
MSNDF msndf;
CNO cno;
FLO floSrc;
FLO floDest;
msndf.bo = kboCur;
msndf.osk = koskCur;
msndf.sty = sty;
msndf.vlmDefault = kvlmFull;
msndf.fInvalid = fFalse;
floSrc.pfil = pfilSrc;
floSrc.cb = pfilSrc->FpMac();
floSrc.fp = 0;
// Create the msnd chunk
if (!pcflDest->FAddPv(&msndf, size(MSNDF), kctgMsnd, pcno))
return fFalse;
// Create the wave chunk as a child of the msnd chunk
if (!pcflDest->FAddChild(kctgMsnd, *pcno, kchidSnd, floSrc.cb, kctgWave, &cno))
goto LFail;
if (!pcflDest->FFindFlo(kctgWave, cno, &floDest))
goto LFail;
if (!floSrc.FCopy(&floDest))
goto LFail;
if (!pcflDest->FSetName(kctgMsnd, *pcno, pstnName))
goto LFail;
return fTrue;
LFail:
pcflDest->Delete(kctgMsnd, *pcno); // Deletes the wave chunk also
return fFalse;
}
/***************************************************************************
Copy the midi file to a chunk in the current movie
The *pcno is returned
***************************************************************************/
bool MSND::FCopyMidi(PFIL pfilSrc, PCFL pcflDest, CNO *pcno, PSTN pstn)
{
AssertPo(pfilSrc, 0);
AssertNilOrPo(pstn, 0);
PMIDS pmids = pvNil;
FNI fniSrc;
STN stnName;
pfilSrc->GetFni(&fniSrc);
if (pvNil == pstn)
fniSrc.GetLeaf(&stnName);
else
stnName = *pstn;
pmids = MIDS::PmidsReadNative(&fniSrc);
if (pmids == pvNil)
{
PushErc(ercSocBadSoundFile);
goto LFail;
}
// Create the chunk & write it to this movie
// Adopt it later as a child of kctgMvie
if (!MSND::FWriteMidi(pcflDest, pmids, &stnName, pcno))
goto LFail;
ReleasePpo(&pmids);
return fTrue;
LFail:
ReleasePpo(&pmids);
return fFalse;
}
/***************************************************************************
Copy the wave file to a chunk in the current movie
***************************************************************************/
bool MSND::FCopyWave(PFIL pfilSrc, PCFL pcflDest, long sty, CNO *pcno, PSTN pstn)
{
AssertPo(pfilSrc, 0);
AssertPo(pcflDest, 0);
AssertIn(sty, 0, styLim);
AssertVarMem(pcno);
Assert(sty != styMidi, "Illegal sty argument");
AssertNilOrPo(pstn, 0);
FNI fniSrc;
STN stnName; // sound name
STN stn; // src file path name
WAVEFORMATEX wfxSrc;
LPSOUND psnd = pvNil;
LPSOUND psndTemp = pvNil;
FIL *pfilNew = pvNil;
STN stnNew;
FNI fniNew;
WAVEFORMATEX *pwfxDst = pvNil;
DWORD cbwfx; // size of waveformatex needed
DWORD csampSrc; // number of source samples
DWORD cbSrc; // size of source in bytes
LPBYTE pbSrc = pvNil; // src data buffer
DWORD cbDst; // size of dest in bytes
LPBYTE pbDst = pvNil; // dst data buffer
HACMSTREAM hacmstream = pvNil;
ACMSTREAMHEADER acmhdr;
DWORD dwTag;
DWORD dwLength;
long cbOriginalFile = 0;
long cbCompressedFile = 0;
FP fpNew;
pfilSrc->GetFni(&fniSrc);
if (pvNil == pstn)
fniSrc.GetLeaf(&stnName);
else
stnName = *pstn;
fniSrc.GetStnPath(&stn);
if (!fniNew.FGetTemp())
goto LFail;
// get the original file size
if (pvNil == (pfilNew = FIL::PfilOpen(&fniSrc)))
goto LFailPushError;
cbOriginalFile = pfilNew->FpMac();
ReleasePpo(&pfilNew);
// open the file as a pSound
if (FAILED(AllocSoundFromFile(&psnd, stn.Psz(), 0, fTrue, pvNil)))
goto LFailPushError;
if (FAILED(psnd->GetFormat((LPWAVEFORMATEX)&wfxSrc, size(WAVEFORMATEX))))
goto LFailPushError;
// if the file format is not 11M8, then create a converter to 11M8
if ((wfxSrc.nSamplesPerSec != knSamplesPerSec) ||
(wfxSrc.wBitsPerSample != kwBitsPerSample )||
(wfxSrc.nChannels != knChannels ) )
{
// Convert the wave import to 3mm's 11M8
wfxSrc.nSamplesPerSec = knSamplesPerSec ;
wfxSrc.nAvgBytesPerSec = knAvgBytesPerSec ;
wfxSrc.wBitsPerSample = kwBitsPerSample;
wfxSrc.nChannels = knChannels ;
wfxSrc.nBlockAlign = knBlockAlign ;
if (FAILED(AllocConvertFilter(&psndTemp, psnd, (LPWAVEFORMATEX)&wfxSrc)))
goto LFailPushError;
ReleasePpo(&psnd);
psnd = psndTemp;
psndTemp = pvNil;
}
// now figure out how many total samples there are
csampSrc = psnd->GetSamples();
if (csampSrc == -1) // Don't allow infinite sources to be written
goto LFailPushError;
cbSrc = csampSrc * (wfxSrc.wBitsPerSample>>3) * wfxSrc.nChannels;
if (FAILED(psnd->SetMode(TRUE,TRUE))) // Activate the Sound Audio Stream
goto LFailPushError;
// allocate a buffer big enough to hold them all
if (!FAllocPv((LPVOID *)&pbSrc, cbSrc, fmemNil, mprNormal))
goto LFail;
// get all of the samples
if (FAILED(psnd->GetSampleData(pbSrc, 0, &csampSrc, NULL)))
goto LFailPushError;
// -------------------------------------
// inplace compress the samples to ADPCM
// figure out the correct size for dest waveformatex (so we get the codec info)
if (acmMetrics(NULL, ACM_METRIC_MAX_SIZE_FORMAT, &cbwfx))
goto LFailPushError;
// allocate a buffer of this size
if (!FAllocPv((LPVOID *)&pwfxDst, cbwfx, fmemNil, mprNormal))
goto LFail;
// allocate a destination buffer big enough to hold them all
cbDst = cbSrc;
if (!FAllocPv((LPVOID *)&pbDst, cbDst, fmemNil, mprNormal))
goto LFail;
// set up the dest wfx
pwfxDst->wFormatTag = WAVE_FORMAT_ADPCM;
pwfxDst->nChannels = knChannels;
pwfxDst->nSamplesPerSec = knSamplesPerSec;
// pwfxDst->wBitsPerSample, pwfxDst->nAvgBytesPerSec, and
// pwfxDst->nBlockAlign are calced by the acmFormatSuggest()
pwfxDst->cbSize = (WORD)cbwfx - sizeof(WAVEFORMATEX);
// fill in the coeffiecients in the destination WFX by calling acmFormatSuggest
if (acmFormatSuggest(NULL, &wfxSrc, pwfxDst, cbwfx, ACM_FORMATSUGGESTF_WFORMATTAG |
ACM_FORMATSUGGESTF_NCHANNELS | ACM_FORMATSUGGESTF_NSAMPLESPERSEC))
goto LFailPushError;
// open convert stream
if (acmStreamOpen(&hacmstream, NULL, &wfxSrc, pwfxDst, NULL, 0, 0, ACM_STREAMOPENF_NONREALTIME))
goto LFailPushError;
acmhdr.cbStruct = sizeof(ACMSTREAMHEADER);
acmhdr.fdwStatus = 0;
acmhdr.dwUser = 0;
acmhdr.pbSrc = pbSrc;
acmhdr.cbSrcLength = cbSrc;
acmhdr.cbSrcLengthUsed = 0;
acmhdr.dwSrcUser = 0;
acmhdr.pbDst = pbDst;
acmhdr.cbDstLength = cbDst;
acmhdr.cbDstLengthUsed = 0;
acmhdr.dwDstUser = 0;
// prep acm convert header
if (acmStreamPrepareHeader(hacmstream, &acmhdr, NULL))
goto LFailPushError;
// now convert
if (acmStreamConvert(hacmstream, &acmhdr, ACM_STREAMCONVERTF_END))
goto LFailPushError;
// unprep header
if (acmStreamUnprepareHeader(hacmstream, &acmhdr, NULL))
goto LFailPushError;
// close stream
acmStreamClose(hacmstream, NULL);
hacmstream = pvNil;
// OK, now we have the sound file converted in memory, write out the data file...
// open file
pfilNew = FIL::PfilCreate(&fniNew);
if (pvNil == pfilNew)
goto LFail;
fpNew = 0;
// write out 'riff' header
dwTag = RIFF_TAG;
if (!pfilNew->FWriteRgbSeq(&dwTag, sizeof(dwTag), &fpNew))
goto LFail;
cbCompressedFile = sizeof(RIFF) + pwfxDst->cbSize + 12 - 8 + acmhdr.cbDstLengthUsed; // +12 is for fact chunk chunk, -8 for is riff chunk
dwLength = cbCompressedFile;
if (!pfilNew->FWriteRgbSeq(&dwLength, sizeof(dwLength), &fpNew))
goto LFail;
// write WAVE tag
dwTag = WAVE_TAG;
if (!pfilNew->FWriteRgbSeq(&dwTag, sizeof(dwTag), &fpNew))
goto LFail;
// write out 'fmt '
dwTag = FMT__TAG;
if (!pfilNew->FWriteRgbSeq(&dwTag, sizeof(dwTag), &fpNew))
goto LFail;
dwLength = sizeof(WAVEFORMATEX) + pwfxDst->cbSize;
if (!pfilNew->FWriteRgbSeq(&dwLength, sizeof(dwLength), &fpNew))
goto LFail;
if (!pfilNew->FWriteRgbSeq(pwfxDst, dwLength, &fpNew))
goto LFail;
// write out 'fact'
dwTag = FACT_TAG;
if (!pfilNew->FWriteRgbSeq(&dwTag, sizeof(dwTag), &fpNew))
goto LFail;
dwLength = sizeof(DWORD);
if (!pfilNew->FWriteRgbSeq(&dwLength, sizeof(dwLength), &fpNew))
goto LFail;
dwLength = csampSrc;
if (!pfilNew->FWriteRgbSeq(&dwLength, sizeof(dwLength), &fpNew))
goto LFail;
// write out 'data'
dwTag = DATA_TAG;
if (!pfilNew->FWriteRgbSeq(&dwTag, sizeof(dwTag), &fpNew))
goto LFail;
dwLength = acmhdr.cbDstLengthUsed;
if (!pfilNew->FWriteRgbSeq(&dwLength, sizeof(dwLength), &fpNew))
goto LFail;
if (!pfilNew->FWriteRgbSeq(pbDst, dwLength, &fpNew))
goto LFail;
// clean up conversion
FreePpv((LPVOID *)&pwfxDst);// free up destination waveformat
FreePpv((LPVOID *)&pbSrc); // free convert src buffer
FreePpv((LPVOID *)&pbDst); // free convert dest buffer
ReleasePpo(&pfilNew); // release open file
if (psnd)
psnd->SetMode(FALSE,TRUE);
ReleasePpo(&psnd); // release sound
// -------------------------------------------------------------------
// Copy the original or converted file to a chunk in the current movie
// if the compressed file is larger then the original
if (cbCompressedFile > cbOriginalFile)
{
// then just use original file
if (pvNil == (pfilNew = FIL::PfilOpen(&fniSrc)))
goto LFail;
}
else
{
// then we use the newly compressed file
if (pvNil == (pfilNew = FIL::PfilOpen(&fniNew)))
goto LFail;
}
if (!MSND::FWriteWave(pfilNew, pcflDest, sty, &stnName, pcno))
goto LFail;
ReleasePpo(&pfilNew);
if (tYes == fniNew.TExists())
fniNew.FDelete();
return fTrue;
LFailPushError:
PushErc(ercSocBadSoundFile);
LFail:
if (hacmstream)
{
acmStreamClose(hacmstream, NULL);
hacmstream = pvNil;
}
if (psnd)
psnd->SetMode(FALSE,TRUE);
FreePpv((LPVOID *)&pwfxDst);// free dest waveformatex struct
FreePpv((LPVOID *)&pbSrc); // free convert src buffer
FreePpv((LPVOID *)&pbDst); // free convert dest buffer
ReleasePpo(&pfilNew);
ReleasePpo(&psnd);
if (tYes == fniNew.TExists())
fniNew.FDelete();
return fFalse;
}
/***************************************************************************
Invalidate a sound
***************************************************************************/
bool MSND::FInvalidate(void)
{
AssertThis(0);
KID kid;
MSNDF msndf;
// Invalidate the msnd on file
if (!Pcrf()->Pcfl()->FGetKidChid(kctgMsnd, Cno(), kchidSnd, &kid))
return fFalse;
msndf.bo = kboCur;
msndf.osk = koskCur;
msndf.sty = _sty;
msndf.vlmDefault = _vlm;
msndf.fInvalid = fTrue;
if (!Pcrf()->Pcfl()->FPutPv(&msndf, size(MSNDF), Ctg(), Cno()))
return fFalse;
Pcrf()->Pcfl()->DeleteChild(Ctg(), Cno(), kid.cki.ctg, kid.cki.cno);
// Invalidate the cache representation
_fInvalid = fTrue;
return fTrue;
}
/***************************************************************************
Clean up and delete this movie sound
***************************************************************************/
MSND::~MSND(void)
{
AssertBaseThis(0);
}
/***************************************************************************
Return the sqn for an msnd attached to an actor object of
id == objid
Static function
***************************************************************************/
long MSND::SqnActr(long sty, long objid)
{
AssertIn(sty, 0, styLim);
long sqnsty = sty << ksqnStyShift;
return (sqnActr | sqnsty | SwLow(objid));
}
/***************************************************************************
Return the sqn for an msnd attached to an actor object of
id == objid
Static function
***************************************************************************/
long MSND::SqnBkgd(long sty, long objid)
{
long sqnsty = sty << ksqnStyShift;
return (sqnBkgd | sqnsty | SwLow(objid));
}
/***************************************************************************
Return the priority for a tool,sty combination
***************************************************************************/
long MSND::Spr(long tool)
{
AssertThis(0);
Assert(tool == toolMatcher ||
tool == toolSounder ||
tool == toolLooper, "Invalid tool");
switch(_sty)
{
case styMidi:
Assert(tool != toolMatcher, "No midi motion matching");
return 1;
break;
case stySpeech:
if (tool == toolSounder)
return 1;
if (tool == toolMatcher)
return 5;
return 3;
break;
case stySfx:
if (tool == toolSounder)
return 2;
if (tool == toolMatcher)
return 6;
return 4;
default:
Assert(0, "Invalid sty in MSND: Spr");
}
return 0;
}
/***************************************************************************
Play this sound
***************************************************************************/
void MSND::Play(long objID, bool fLoop, bool fQueue, long vlm,
long spr, bool fActr, ulong dtsStart)
{
AssertThis(0);
long cactRepeat;
long sqn; // sound queue
long scl; // sound class
long sii;
static long _siiLastMidi;
static CTG _ctgLastMidi;
static CNO _cnoLastMidi;
if (_fInvalid)
return;
sqn = fActr ? SqnActr(objID) : SqnBkgd(objID);
cactRepeat = fLoop ? klwMax : 1;
scl = Scl(fLoop);
if (_sty == styMidi && _ctgSnd == _ctgLastMidi &&
_cnoSnd == _cnoLastMidi && vpsndm->FPlaying(_siiLastMidi))
{
// Don't restart midi if the same sound is still playing
return;
}
if (!fQueue || _fNoSound)
vpsndm->StopAll(sqn, sclNil);
if (!_fNoSound)
{
sii = vpsndm->SiiPlay(_prca, _ctgSnd, _cnoSnd, sqn, vlm, cactRepeat,
dtsStart, spr, scl);
}
if (_sty == styMidi)
{
_siiLastMidi = sii;
_ctgLastMidi = _ctgSnd;
_cnoLastMidi = _cnoSnd;
}
}
/***************************************************************************
New MSQ
***************************************************************************/
PMSQ MSQ::PmsqNew(void)
{
PMSQ pmsq;
if (pvNil == (pmsq = NewObj MSQ(khidMsq)))
return pvNil;
if (pvNil == (pmsq->_pglsqe = GL::PglNew(size(SQE), kcsqeGrow)))
{
ReleasePpo(&pmsq);
return pvNil;
}
if (pvNil == (pmsq->_pclok = NewObj CLOK(khidMsqClock)))
{
ReleasePpo(&pmsq);
return pvNil;
}
pmsq->_dtim = kdtim2Msq;
return pmsq;
}
/***************************************************************************
Enqueue a sound in the MSQ. Overwrites sounds of the same type.
***************************************************************************/
bool MSQ::FEnqueue(PMSND pmsnd, long objID, bool fLoop, bool fQueue,
long vlm, long spr, bool fActr, ulong dtsStart, bool fLowPri)
{
AssertThis(0);
AssertPo(pmsnd, 0);
SQE sqe;
SQE *psqe;
long sqn;
long sqnT;
long isqe;
if (_dtim == kdtimOffMsq)
return fTrue;
sqn = fActr ? MSND::SqnActr(pmsnd->Sty(), objID) : MSND::SqnBkgd(pmsnd->Sty(), objID);
if (!fQueue)
for (isqe = 0; isqe < _pglsqe->IvMac(); isqe++)
{
psqe = (SQE *)_pglsqe->QvGet(isqe);
sqnT = psqe->fActr ?
MSND::SqnActr(psqe->pmsnd->Sty(), psqe->objID) : MSND::SqnBkgd(psqe->pmsnd->Sty(), psqe->objID);
if (sqnT == sqn)
{
if (fLowPri)
return fTrue; // Nothing to enqueue; same type already taken
// Hi priority. Get rid of lower priority sound.
ReleasePpo(&psqe->pmsnd);
_pglsqe->Delete(isqe);
break;
}
}
sqe.pmsnd = pmsnd;
pmsnd->AddRef();
sqe.objID = objID;
sqe.fLoop = fLoop;
sqe.fQueue = fQueue;
sqe.vlmMod = vlm;
sqe.spr = spr;
sqe.fActr = fActr;
sqe.dtsStart = dtsStart;
if (fLowPri)
{
if (!_pglsqe->FPush(&sqe))
{
ReleasePpo(&sqe.pmsnd);
return fFalse;
}
}
else if (!_pglsqe->FEnqueue(&sqe))
{
ReleasePpo(&sqe.pmsnd);
return fFalse;
}
return fTrue;
}
/***************************************************************************
Dequeue and Play the MSQ sounds
If _dtim == kdtimOff, empty the queue
***************************************************************************/
void MSQ::PlayMsq(void)
{
AssertThis(0);
SQE sqe;
if (_pglsqe->IvMac() == 0)
return;
if (_dtim == kdtimOffMsq)
{
FlushMsq();
return;
}
if (0 < _pglsqe->IvMac())
{
vpsndm->BeginSynch();
while(_pglsqe->FDequeue(&sqe))
{
sqe.pmsnd->Play(sqe.objID, sqe.fLoop, sqe.fQueue, sqe.vlmMod,
sqe.spr, sqe.fActr, sqe.dtsStart);
ReleasePpo(&sqe.pmsnd);
}
vpsndm->EndSynch();
}
if (_dtim < kdtimLongMsq)
{
_pclok->Start(0);
if (!_pclok->FSetAlarm(_dtim, this))
{
StopAll();
return;
}
}
return;
}
/***************************************************************************
Flush Queue - without playing the sounds
***************************************************************************/
void MSQ::FlushMsq(void)
{
AssertThis(0);
SQE sqe;
while( _pglsqe->FDequeue(&sqe))
{
ReleasePpo(&sqe.pmsnd);
}
}
/***************************************************************************
FCmdAlarm - Timeout has elapsed. Stop all sounds
***************************************************************************/
bool MSQ::FCmdAlarm(PCMD pcmd)
{
AssertThis(0);
AssertVarMem(pcmd);
_pclok->Stop();
StopAll();
return fTrue;
}
/***************************************************************************
Clean up and delete this movie sound queue
***************************************************************************/
MSQ::~MSQ(void)
{
AssertBaseThis(0);
StopAll();
FlushMsq();
ReleasePpo(&_pglsqe);
ReleasePpo(&_pclok);
}
#ifdef DEBUG
/***************************************************************************
Assert the validity of the MSND.
***************************************************************************/
void MSND::AssertValid(ulong grf)
{
MSND_PAR::AssertValid(fobjAllocated);
AssertNilOrPo(_prca, 0);
AssertIn(_sty, 0, styLim);
}
/***************************************************************************
Mark memory used by the MSND
***************************************************************************/
void MSND::MarkMem(void)
{
AssertThis(0);
MSND_PAR::MarkMem();
// Note: don't mark _prca, because _prca marks us, and would cause
// an infinite recursive loop.
}
/***************************************************************************
Assert the validity of the MSQ.
***************************************************************************/
void MSQ::AssertValid(ulong grf)
{
MSQ_PAR::AssertValid(fobjAllocated);
AssertPo(_pglsqe, 0);
AssertPo(_pclok, 0);
}
/***************************************************************************
Mark memory used by the MSND
***************************************************************************/
void MSQ::MarkMem(void)
{
AssertThis(0);
MSQ_PAR::MarkMem();
MarkMemObj(_pglsqe);
MarkMemObj(_pclok);
}
#endif //DEBUG