mirror of
https://github.com/microsoft/Microsoft-3D-Movie-Maker.git
synced 2024-11-22 02:12:33 +01:00
1396 lines
31 KiB
C++
1396 lines
31 KiB
C++
/* Copyright (c) Microsoft Corporation.
|
|
Licensed under the MIT License. */
|
|
|
|
/***************************************************************************
|
|
Author: ShonK
|
|
Project: Kauai
|
|
Copyright (c) Microsoft Corporation
|
|
|
|
Sound manager class implementation.
|
|
|
|
***************************************************************************/
|
|
#include "frame.h"
|
|
ASSERTNAME
|
|
|
|
|
|
RTCLASS(SNDV)
|
|
RTCLASS(SNDM)
|
|
RTCLASS(SNDMQ)
|
|
RTCLASS(SNQUE)
|
|
|
|
long SNDV::_siiLast;
|
|
|
|
|
|
/***************************************************************************
|
|
This is the volume to use as the system volume if it is determined
|
|
by a device that the system lies when asked what the current
|
|
volume setting is. Eg, for many drivers, midiOutGetVolume on Win95
|
|
always returns full volume. When we determine that this is the case,
|
|
we'll use this value instead. Any device that determines that its
|
|
reading is valid should set this so other devices can use the same
|
|
value.
|
|
***************************************************************************/
|
|
ulong vluSysVolFake = (ulong)-1;
|
|
|
|
|
|
/***************************************************************************
|
|
Start a synchronized group.
|
|
***************************************************************************/
|
|
void SNDV::BeginSynch(void)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
End a synchronized group.
|
|
***************************************************************************/
|
|
void SNDV::EndSynch(void)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for the sound manager.
|
|
***************************************************************************/
|
|
SNDM::SNDM(void)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for the sound manager.
|
|
***************************************************************************/
|
|
SNDM::~SNDM(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
if (pvNil != _pglsndmpe)
|
|
{
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
ReleasePpo(&sndmpe.psndv);
|
|
}
|
|
ReleasePpo(&_pglsndmpe);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a SNDM.
|
|
***************************************************************************/
|
|
void SNDM::AssertValid(ulong grf)
|
|
{
|
|
SNDM_PAR::AssertValid(0);
|
|
AssertPo(_pglsndmpe, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the SNDM.
|
|
***************************************************************************/
|
|
void SNDM::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
long isndmpe;
|
|
SNDMPE sndmpe;
|
|
|
|
SNDM_PAR::MarkMem();
|
|
MarkMemObj(_pglsndmpe);
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
MarkMemObj(sndmpe.psndv);
|
|
}
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Create the sound manager.
|
|
***************************************************************************/
|
|
PSNDM SNDM::PsndmNew(void)
|
|
{
|
|
PSNDM psndm;
|
|
|
|
if (pvNil == (psndm = NewObj SNDM))
|
|
return pvNil;
|
|
|
|
if (!psndm->_FInit())
|
|
ReleasePpo(&psndm);
|
|
|
|
AssertNilOrPo(psndm, 0);
|
|
return psndm;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Initialize the sound manager.
|
|
***************************************************************************/
|
|
bool SNDM::_FInit(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
|
|
if (pvNil == (_pglsndmpe = GL::PglNew(size(SNDMPE))))
|
|
return fFalse;
|
|
|
|
_pglsndmpe->SetMinGrow(1);
|
|
_fActive = fTrue;
|
|
|
|
AssertThis(0);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Find the device that sounds of the given ctg are to be played on.
|
|
***************************************************************************/
|
|
bool SNDM::_FFindCtg(CTG ctg, SNDMPE *psndmpe, long *pisndmpe)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(psndmpe);
|
|
AssertNilOrVarMem(pisndmpe);
|
|
long isndmpe;
|
|
SNDMPE sndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
if (sndmpe.ctg == ctg)
|
|
{
|
|
if (pvNil != psndmpe)
|
|
*psndmpe = sndmpe;
|
|
if (pvNil != pisndmpe)
|
|
*pisndmpe = isndmpe;
|
|
return fTrue;
|
|
}
|
|
}
|
|
|
|
TrashVar(psndmpe);
|
|
if (pvNil != pisndmpe)
|
|
*pisndmpe = _pglsndmpe->IvMac();
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Add a device to the device map to handle the particular ctg.
|
|
***************************************************************************/
|
|
bool SNDM::FAddDevice(CTG ctg, PSNDV psndv)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(psndv, 0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
long cact;
|
|
|
|
psndv->AddRef();
|
|
if (_FFindCtg(ctg, &sndmpe, &isndmpe))
|
|
{
|
|
ReleasePpo(&sndmpe.psndv);
|
|
sndmpe.psndv = psndv;
|
|
_pglsndmpe->Put(isndmpe, &sndmpe);
|
|
}
|
|
else
|
|
{
|
|
sndmpe.ctg = ctg;
|
|
sndmpe.psndv = psndv;
|
|
if (!_pglsndmpe->FInsert(isndmpe, &sndmpe))
|
|
{
|
|
ReleasePpo(&psndv);
|
|
return fFalse;
|
|
}
|
|
}
|
|
|
|
psndv->Activate(_fActive);
|
|
for (cact = 0; cact < _cactSuspend; cact++)
|
|
psndv->Suspend(fTrue);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the sound device that is registered for the given ctg.
|
|
***************************************************************************/
|
|
PSNDV SNDM::PsndvFromCtg(CTG ctg)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
|
|
if (!_FFindCtg(ctg, &sndmpe))
|
|
return pvNil;
|
|
|
|
return sndmpe.psndv;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Remove the sound device for the given ctg.
|
|
***************************************************************************/
|
|
void SNDM::RemoveSndv(CTG ctg)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
if (!_FFindCtg(ctg, &sndmpe, &isndmpe))
|
|
return;
|
|
|
|
_pglsndmpe->Delete(isndmpe);
|
|
ReleasePpo(&sndmpe.psndv);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the sound manager is active.
|
|
***************************************************************************/
|
|
bool SNDM::FActive(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
return _fActive;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Activate or deactivate the sound manager.
|
|
***************************************************************************/
|
|
void SNDM::Activate(bool fActive)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
if (FPure(fActive) == FPure(_fActive))
|
|
return;
|
|
|
|
_fActive = FPure(fActive);
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Activate(fActive);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Suspend or resume the sound manager.
|
|
***************************************************************************/
|
|
void SNDM::Suspend(bool fSuspend)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
if (fSuspend)
|
|
_cactSuspend++;
|
|
else
|
|
_cactSuspend--;
|
|
|
|
Assert(_cactSuspend >= FPure(fSuspend), "bad _cactSuspend");
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Suspend(fSuspend);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Set the volume of all the devices.
|
|
***************************************************************************/
|
|
void SNDM::SetVlm(long vlm)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->SetVlm(vlm);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Get the max of the volumes of all the devices.
|
|
***************************************************************************/
|
|
long SNDM::VlmCur(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
long vlm;
|
|
|
|
vlm = 0;
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
vlm = LwMax(vlm, sndmpe.psndv->VlmCur());
|
|
}
|
|
|
|
return vlm;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Play the given sound.
|
|
***************************************************************************/
|
|
long SNDM::SiiPlay(PRCA prca, CTG ctg, CNO cno, long sqn, long vlm,
|
|
long cactPlay, ulong dtsStart, long spr, long scl)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
SNDMPE sndmpe;
|
|
|
|
if (!_FFindCtg(ctg, &sndmpe))
|
|
return _SiiAlloc();
|
|
|
|
return sndmpe.psndv->SiiPlay(prca, ctg, cno, sqn, vlm, cactPlay, dtsStart,
|
|
spr, scl);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Stop the given sound instance.
|
|
***************************************************************************/
|
|
void SNDM::Stop(long sii)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Stop(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Stop all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDM::StopAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->StopAll(sqn, scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Pause the given sound.
|
|
***************************************************************************/
|
|
void SNDM::Pause(long sii)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Pause(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Pause all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDM::PauseAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->PauseAll(sqn, scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Resume the given sound.
|
|
***************************************************************************/
|
|
void SNDM::Resume(long sii)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Resume(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Resume all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDM::ResumeAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->ResumeAll(sqn, scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the given sound is playing.
|
|
***************************************************************************/
|
|
bool SNDM::FPlaying(long sii)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
if (sndmpe.psndv->FPlaying(sii))
|
|
return fTrue;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether any sounds of the given queue and class are playing
|
|
(one or both of (sqn, scl) may be nil).
|
|
***************************************************************************/
|
|
bool SNDM::FPlayingAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
if (sndmpe.psndv->FPlayingAll(sqn, scl))
|
|
return fTrue;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Free anything that's no longer in use.
|
|
***************************************************************************/
|
|
void SNDM::Flush(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->Flush();
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Start a synchronized group.
|
|
***************************************************************************/
|
|
void SNDM::BeginSynch(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->BeginSynch();
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
End a synchronized group.
|
|
***************************************************************************/
|
|
void SNDM::EndSynch(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDMPE sndmpe;
|
|
long isndmpe;
|
|
|
|
for (isndmpe = 0; isndmpe < _pglsndmpe->IvMac(); isndmpe++)
|
|
{
|
|
_pglsndmpe->Get(isndmpe, &sndmpe);
|
|
sndmpe.psndv->EndSynch();
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
A convenient base class for a multiple queue sound device.
|
|
***************************************************************************/
|
|
|
|
/***************************************************************************
|
|
Destructor for a multiple queue sound device.
|
|
***************************************************************************/
|
|
SNDMQ::~SNDMQ(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
if (pvNil != _pglsnqd)
|
|
{
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
ReleasePpo(&snqd.psnque);
|
|
}
|
|
ReleasePpo(&_pglsnqd);
|
|
}
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a SNDMQ.
|
|
***************************************************************************/
|
|
void SNDMQ::AssertValid(ulong grf)
|
|
{
|
|
SNDMQ_PAR::AssertValid(0);
|
|
AssertPo(_pglsnqd, 0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the SNDMQ.
|
|
***************************************************************************/
|
|
void SNDMQ::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
SNDMQ_PAR::MarkMem();
|
|
MarkMemObj(_pglsnqd);
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
MarkMemObj(snqd.psnque);
|
|
}
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Initialize the multiple queue device.
|
|
***************************************************************************/
|
|
bool SNDMQ::_FInit(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
|
|
if (pvNil == (_pglsnqd = GL::PglNew(size(SNQD))))
|
|
return fFalse;
|
|
|
|
_fActive = fTrue;
|
|
AssertThis(0);
|
|
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Ensure a queue exists for the given sqn and return it.
|
|
***************************************************************************/
|
|
bool SNDMQ::_FEnsureQueue(long sqn, SNQD *psnqd, long *pisnqd)
|
|
{
|
|
AssertThis(0);
|
|
AssertNilOrVarMem(psnqd);
|
|
AssertNilOrVarMem(pisnqd);
|
|
|
|
long isnqd, isnqdEmpty;
|
|
SNQD snqd;
|
|
|
|
isnqdEmpty = ivNil;
|
|
for (isnqd = _pglsnqd->IvMac(); isnqd-- > 0; )
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if (snqd.sqn == sqn && sqn != ksqnNone)
|
|
{
|
|
// we found it
|
|
goto LFound;
|
|
}
|
|
|
|
if (ivNil == isnqdEmpty && !snqd.psnque->FPlayingAll())
|
|
{
|
|
// here's an empty queue
|
|
isnqdEmpty = isnqd;
|
|
if (sqn == ksqnNone)
|
|
break;
|
|
}
|
|
}
|
|
|
|
if (ivNil != (isnqd = isnqdEmpty))
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
snqd.sqn = sqn;
|
|
_pglsnqd->Put(isnqd, &snqd);
|
|
goto LFound;
|
|
}
|
|
|
|
snqd.sqn = sqn;
|
|
if (pvNil == (snqd.psnque = _PsnqueNew()) ||
|
|
!_pglsnqd->FAdd(&snqd, &isnqd))
|
|
{
|
|
ReleasePpo(&snqd.psnque);
|
|
TrashVar(psnqd);
|
|
TrashVar(pisnqd);
|
|
return fFalse;
|
|
}
|
|
|
|
LFound:
|
|
if (pvNil != psnqd)
|
|
*psnqd = snqd;
|
|
if (pvNil != pisnqd)
|
|
*pisnqd = isnqd;
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the device is active.
|
|
***************************************************************************/
|
|
bool SNDMQ::FActive(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
return _fActive;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Activate or deactivate the device.
|
|
***************************************************************************/
|
|
void SNDMQ::Activate(bool fActive)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (FPure(fActive) == FPure(_fActive))
|
|
return;
|
|
|
|
_fActive = FPure(fActive);
|
|
_Suspend(_cactSuspend > 0 || !_fActive);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Suspend or resume the device.
|
|
***************************************************************************/
|
|
void SNDMQ::Suspend(bool fSuspend)
|
|
{
|
|
AssertThis(0);
|
|
|
|
if (fSuspend)
|
|
_cactSuspend++;
|
|
else
|
|
_cactSuspend--;
|
|
|
|
Assert(_cactSuspend >= FPure(fSuspend), "bad _cactSuspend");
|
|
_Suspend(_cactSuspend > 0 || !_fActive);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Play the given sound.
|
|
***************************************************************************/
|
|
long SNDMQ::SiiPlay(PRCA prca, CTG ctg, CNO cno, long sqn, long vlm,
|
|
long cactPlay, ulong dtsStart, long spr, long scl)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
long sii = _SiiAlloc();
|
|
|
|
if (sqn == sqnNil)
|
|
sqn = ksqnNone;
|
|
|
|
if (_FEnsureQueue(sqn, &snqd, &isnqd))
|
|
{
|
|
snqd.psnque->Enqueue(sii, prca, ctg, cno, vlm, cactPlay, dtsStart,
|
|
spr, scl);
|
|
}
|
|
else
|
|
Warn("couldn't allocate queue");
|
|
|
|
return sii;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Stop the given sound instance.
|
|
***************************************************************************/
|
|
void SNDMQ::Stop(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
snqd.psnque->Stop(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Stop all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDMQ::StopAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if (sqnNil == sqn || snqd.sqn == sqn)
|
|
snqd.psnque->StopAll(scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Pause the given sound.
|
|
***************************************************************************/
|
|
void SNDMQ::Pause(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
snqd.psnque->Pause(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Pause all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDMQ::PauseAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if (sqnNil == sqn || snqd.sqn == sqn)
|
|
snqd.psnque->PauseAll(scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Resume the given sound.
|
|
***************************************************************************/
|
|
void SNDMQ::Resume(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
snqd.psnque->Resume(sii);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Resume all sounds of the given queue and class (one or both may be nil).
|
|
***************************************************************************/
|
|
void SNDMQ::ResumeAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if (sqnNil == sqn || snqd.sqn == sqn)
|
|
snqd.psnque->ResumeAll(scl);
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the given sound is playing.
|
|
***************************************************************************/
|
|
bool SNDMQ::FPlaying(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if (snqd.psnque->FPlaying(sii))
|
|
return fTrue;
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether any sounds of the given queue and class are playing
|
|
(one or both of (sqn, scl) may be nil).
|
|
***************************************************************************/
|
|
bool SNDMQ::FPlayingAll(long sqn, long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
for (isnqd = 0; isnqd < _pglsnqd->IvMac(); isnqd++)
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
if ((sqnNil == sqn ||
|
|
snqd.sqn == sqn) && snqd.psnque->FPlayingAll(scl))
|
|
{
|
|
return fTrue;
|
|
}
|
|
}
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Free anything that's no longer being used.
|
|
***************************************************************************/
|
|
void SNDMQ::Flush()
|
|
{
|
|
AssertThis(0);
|
|
long isnqd;
|
|
SNQD snqd;
|
|
|
|
// Don't free the last channel
|
|
for (isnqd = _pglsnqd->IvMac(); isnqd-- > 0; )
|
|
{
|
|
_pglsnqd->Get(isnqd, &snqd);
|
|
snqd.psnque->Flush();
|
|
if (!snqd.psnque->FPlayingAll() && _pglsnqd->IvMac() > 1)
|
|
{
|
|
ReleasePpo(&snqd.psnque);
|
|
_pglsnqd->Delete(isnqd);
|
|
}
|
|
}
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Constructor for an sound queue.
|
|
***************************************************************************/
|
|
SNQUE::SNQUE(void)
|
|
{
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Destructor for an sound queue.
|
|
***************************************************************************/
|
|
SNQUE::~SNQUE(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
|
|
_Enter();
|
|
if (pvNil != _pglsndin)
|
|
{
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > 0; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
ReleasePpo(&sndin.pbaco);
|
|
}
|
|
ReleasePpo(&_pglsndin);
|
|
}
|
|
_Leave();
|
|
}
|
|
|
|
|
|
#ifdef DEBUG
|
|
/***************************************************************************
|
|
Assert the validity of a SNQUE.
|
|
***************************************************************************/
|
|
void SNQUE::AssertValid(ulong grf)
|
|
{
|
|
SNQUE_PAR::AssertValid(0);
|
|
|
|
_Enter();
|
|
AssertPo(_pglsndin, 0);
|
|
AssertIn(_isndinCur, 0, _pglsndin->IvMac() + 1);
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Mark memory for the SNQUE.
|
|
***************************************************************************/
|
|
void SNQUE::MarkMem(void)
|
|
{
|
|
AssertValid(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
SNQUE_PAR::MarkMem();
|
|
|
|
_Enter();
|
|
MarkMemObj(_pglsndin);
|
|
for (isndin = 0; isndin < _pglsndin->IvMac(); isndin++)
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
MarkMemObj(sndin.pbaco);
|
|
}
|
|
_Leave();
|
|
}
|
|
#endif //DEBUG
|
|
|
|
|
|
/***************************************************************************
|
|
Initialize the sound queue. Allocate the _pglsndin.
|
|
***************************************************************************/
|
|
bool SNQUE::_FInit(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
|
|
if (pvNil == (_pglsndin = GL::PglNew(size(SNDIN))))
|
|
return fFalse;
|
|
|
|
AssertThis(0);
|
|
return fTrue;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Enter any critical section that's necessary to ensure access to
|
|
member variables.
|
|
***************************************************************************/
|
|
void SNQUE::_Enter(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Leave any critical section that's necessary to ensure access to
|
|
member variables.
|
|
***************************************************************************/
|
|
void SNQUE::_Leave(void)
|
|
{
|
|
AssertBaseThis(0);
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Free any sounds below _isndinCur.
|
|
***************************************************************************/
|
|
void SNQUE::_Flush(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
|
|
while (_isndinCur > 0)
|
|
{
|
|
_isndinCur--;
|
|
_pglsndin->Get(_isndinCur, &sndin);
|
|
_pglsndin->Delete(_isndinCur);
|
|
ReleasePpo(&sndin.pbaco);
|
|
}
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Put the given sound on the queue.
|
|
***************************************************************************/
|
|
void SNQUE::Enqueue(long sii, PRCA prca, CTG ctg, CNO cno, long vlm,
|
|
long cactPlay, ulong dtsStart, long spr, long scl)
|
|
{
|
|
AssertThis(0);
|
|
AssertPo(prca, 0);
|
|
SNDIN sndin;
|
|
long isndin;
|
|
|
|
if (pvNil == (sndin.pbaco = _PbacoFetch(prca, ctg, cno)))
|
|
return;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
sndin.sii = sii;
|
|
sndin.vlm = vlm;
|
|
sndin.cactPlay = cactPlay;
|
|
sndin.dtsStart = dtsStart;
|
|
sndin.spr = spr;
|
|
sndin.scl = scl;
|
|
sndin.cactPause = 0;
|
|
if (!_pglsndin->FAdd(&sndin, &isndin))
|
|
{
|
|
ReleasePpo(&sndin.pbaco);
|
|
_Leave();
|
|
return;
|
|
}
|
|
|
|
_Queue(isndin);
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return the priority of the frontmost sound in the queue.
|
|
***************************************************************************/
|
|
long SNQUE::SprCur(void)
|
|
{
|
|
AssertThis(0);
|
|
SNDIN sndin;
|
|
long spr;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
if (_pglsndin->IvMac() >= _isndinCur)
|
|
spr = klwMin;
|
|
else
|
|
{
|
|
_pglsndin->Get(_isndinCur, &sndin);
|
|
spr = sndin.spr;
|
|
}
|
|
|
|
_Leave();
|
|
return spr;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If the given sound is in our queue, nuke it.
|
|
***************************************************************************/
|
|
void SNQUE::Stop(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (sndin.sii == sii)
|
|
{
|
|
if (0 <= sndin.cactPause)
|
|
{
|
|
sndin.cactPause = -1;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
_Queue(isndin);
|
|
}
|
|
|
|
_Leave();
|
|
return;
|
|
}
|
|
}
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Nuke all sounds of the given sound class. sclNil means nuke all.
|
|
***************************************************************************/
|
|
void SNQUE::StopAll(long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
long isndinMin = klwMax;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (0 <= sndin.cactPause && (sclNil == scl || sndin.scl == scl))
|
|
{
|
|
sndin.cactPause = -1;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
isndinMin = isndin;
|
|
}
|
|
}
|
|
|
|
if (isndinMin < klwMax)
|
|
_Queue(isndinMin);
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If the given sound is in our queue, pause it.
|
|
***************************************************************************/
|
|
void SNQUE::Pause(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (sndin.sii == sii)
|
|
{
|
|
if (0 <= sndin.cactPause)
|
|
{
|
|
sndin.cactPause++;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
if (1 == sndin.cactPause)
|
|
_PauseQueue(isndin);
|
|
}
|
|
|
|
_Leave();
|
|
return;
|
|
}
|
|
}
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Pause all sounds of the given sound class. sclNil means nuke all.
|
|
***************************************************************************/
|
|
void SNQUE::PauseAll(long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
long isndinMin = klwMax;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (0 <= sndin.cactPause && (sclNil == scl || sndin.scl == scl))
|
|
{
|
|
if (0 == sndin.cactPause++)
|
|
isndinMin = isndin;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
}
|
|
}
|
|
|
|
if (isndinMin < klwMax)
|
|
_PauseQueue(isndinMin);
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
If the given sound is in our queue, make sure it's not paused.
|
|
***************************************************************************/
|
|
void SNQUE::Resume(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (sndin.sii == sii)
|
|
{
|
|
if (0 < sndin.cactPause)
|
|
{
|
|
sndin.cactPause--;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
if (0 == sndin.cactPause)
|
|
_ResumeQueue(isndin);
|
|
}
|
|
|
|
_Leave();
|
|
return;
|
|
}
|
|
}
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Resume all sounds of the given sound class. sclNil means nuke all.
|
|
***************************************************************************/
|
|
void SNQUE::ResumeAll(long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
long isndinMin = klwMax;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (0 < sndin.cactPause && (sclNil == scl || sndin.scl == scl))
|
|
{
|
|
if (0 == --sndin.cactPause)
|
|
isndinMin = isndin;
|
|
_pglsndin->Put(isndin, &sndin);
|
|
}
|
|
}
|
|
|
|
if (isndinMin < klwMax)
|
|
_ResumeQueue(isndinMin);
|
|
|
|
_Leave();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether the given sound is in our queue.
|
|
***************************************************************************/
|
|
bool SNQUE::FPlaying(long sii)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (sndin.sii == sii)
|
|
{
|
|
_Leave();
|
|
return 0 <= sndin.cactPause;
|
|
}
|
|
}
|
|
|
|
_Leave();
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Return whether any sounds of the given sound class are in our queue.
|
|
sclNil means any sounds at all.
|
|
***************************************************************************/
|
|
bool SNQUE::FPlayingAll(long scl)
|
|
{
|
|
AssertThis(0);
|
|
long isndin;
|
|
SNDIN sndin;
|
|
|
|
_Enter();
|
|
_Flush();
|
|
|
|
for (isndin = _pglsndin->IvMac(); isndin-- > _isndinCur; )
|
|
{
|
|
_pglsndin->Get(isndin, &sndin);
|
|
if (0 <= sndin.cactPause && (sclNil == scl || sndin.scl == scl))
|
|
{
|
|
_Leave();
|
|
return fTrue;
|
|
}
|
|
}
|
|
|
|
_Leave();
|
|
|
|
return fFalse;
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Free anything that's not being used. This should only be called from
|
|
the main thread.
|
|
***************************************************************************/
|
|
void SNQUE::Flush(void)
|
|
{
|
|
AssertThis(0);
|
|
|
|
_Flush();
|
|
}
|
|
|
|
|
|
/***************************************************************************
|
|
Scale the given system volume by the given Kauai volume.
|
|
***************************************************************************/
|
|
ulong LuVolScale(ulong luVol, long vlm)
|
|
{
|
|
Assert(kvlmFull == 0x10000, "this code assumes kvlmFull is 0x10000");
|
|
ulong luHigh, luLow;
|
|
ushort suHigh, suLow;
|
|
|
|
MulLu(SuLow(luVol), vlm, &luHigh, &luLow);
|
|
suLow = (luHigh > 0) ? (ushort)(-1) : SuHigh(luLow);
|
|
|
|
MulLu(SuHigh(luVol), vlm, &luHigh, &luLow);
|
|
suHigh = (luHigh > 0) ? (ushort)(-1) : SuHigh(luLow);
|
|
|
|
return LuHighLow(suHigh, suLow);
|
|
}
|
|
|
|
|