Microsoft-3D-Movie-Maker/SRC/ENGINE/SREC.CPP

437 lines
10 KiB
C++

/***************************************************************************
srec.cpp: Sound recording class
Primary Author: ****** (based on ***** original srec)
Review Status: reviewed
***************************************************************************/
#include "soc.h"
ASSERTNAME
RTCLASS(SREC)
/***************************************************************************
Create a new SREC
***************************************************************************/
PSREC SREC::PsrecNew(long csampSec, long cchan, long cbSample, ulong dtsMax)
{
PSREC psrec;
psrec = NewObj(SREC);
if (pvNil == psrec)
return pvNil;
if (!psrec->_FInit(csampSec, cchan, cbSample, dtsMax))
{
ReleasePpo(&psrec);
return pvNil;
}
AssertPo(psrec, 0);
return psrec;
}
/***************************************************************************
Init this SREC
***************************************************************************/
bool SREC::_FInit(long csampSec, long cchan, long cbSample, ulong dtsMax)
{
AssertBaseThis(0);
AssertIn(cchan, 0, ksuMax);
long cwid;
_csampSec = csampSec;
_cchan = cchan;
_cbSample = cbSample;
_dtsMax = dtsMax;
_hwavein = pvNil;
_priff = pvNil;
_fBufferAdded = fFalse;
_fRecording = fFalse;
_fHaveSound = fFalse;
vpsndm->Suspend(fTrue); // turn off sndm so we can get wavein device
// See if sound recording is possible at all
cwid = waveInGetNumDevs();
if (0 == cwid)
{
PushErc(ercSocNoWaveIn);
return fFalse;
}
// allocate a 10 second buffer
_wavehdr.dwBufferLength = (cchan * csampSec * cbSample * dtsMax)/1000;
if(!FAllocPv((void **)&_priff, sizeof(RIFF) + _wavehdr.dwBufferLength, fmemClear, mprNormal))
return fFalse;
_wavehdr.lpData = (LPBYTE)PvAddBv(_priff, sizeof(RIFF));
// init RIFF structure
_priff->Set(_cchan, _csampSec, _cbSample, 0);
if (fFalse == _FOpenRecord())
{
return fFalse;
}
// get audioman
_pmixer = GetAudioManMixer();
if (pvNil == _pmixer)
return fFalse;
// get a channel
_pmixer->AllocChannel(&_pchannel);
if (pvNil == _pchannel)
return fFalse;
return fTrue;
}
/***************************************************************************
Clean up and delete this SREC
***************************************************************************/
SREC::~SREC(void)
{
AssertBaseThis(0);
// make sure nothing is playing or recording
if (_fRecording || _fPlaying)
FStop();
if (_hwavein)
_FCloseRecord();
ReleasePpo(&_pchannel);
ReleasePpo(&_pmixer);
FreePpv((void **)&_priff);
vpsndm->Suspend(fFalse); // restore sound mgr
}
/***************************************************************************
Open Device for recording
***************************************************************************/
bool SREC::_FOpenRecord(void)
{
AssertBaseThis(0);
_fRecording = fFalse;
if (pvNil == _hwavein)
{
// open a wavein device
if (waveInOpen(&_hwavein, WAVE_MAPPER, (WAVEFORMAT *)_priff->PwfxGet(), (DWORD)_WaveInProc, (DWORD)this, CALLBACK_FUNCTION))
{
// it doesn't support this format
return fFalse;
}
// prepare header on block of data
_wavehdr.dwUser = (DWORD) this;
if (waveInPrepareHeader(_hwavein, &_wavehdr, sizeof(WAVEHDR)))
{
waveInClose(_hwavein);
_hwavein = pvNil;
return fFalse;
}
}
// add buffer to device
if (!_fBufferAdded)
if (waveInAddBuffer(_hwavein, &_wavehdr, sizeof(WAVEHDR)))
{
_FCloseRecord();
_fRecording = fFalse;
_hwavein = pvNil;
return fFalse;
}
else
_fBufferAdded = fTrue;
return fTrue;
}
/***************************************************************************
Close Device for recording
***************************************************************************/
bool SREC::_FCloseRecord(void)
{
AssertThis(0);
if (_hwavein)
{
// stop if necessary
waveInReset(_hwavein);
// unprepare header
waveInUnprepareHeader(_hwavein, &_wavehdr, sizeof(WAVEHDR));
_fRecording = fFalse;
// close
waveInClose(_hwavein);
_hwavein = pvNil;
}
return fTrue;
}
/***************************************************************************
Figure out if we're recording or not
***************************************************************************/
void SREC::_UpdateStatus(void)
{
AssertThis(0);
// ------------------------------------
// Check playing mode
// ------------------------------------
if ((_fPlaying) && !_pchannel->IsPlaying())
{
// then we just stopped
Sleep(250L); // sleep a little bit to cover AudioMan bug
vpsndm->Suspend(fTrue); // suspend sound mgr
}
_fPlaying = _pchannel->IsPlaying();
// ------------------------------------
// Check Recording mode
// If we are recording, AND our HaveSound flag
// is set, then we must have just finished, so
// process the data, and turn off the recording flag
// ------------------------------------
if ((_fRecording) && (_fHaveSound))
{
LPSOUND psnd = pvNil; // original psnd
LPSOUND psndBias = pvNil; // psnd Bias correction filter
LPSOUND psndTrim = pvNil; // psnd Trim filter
_fRecording = fFalse;
if (_wavehdr.dwBytesRecorded == 0)
{
_fHaveSound = fFalse;
return;
}
// using the Audioman APIs, apply the gain and Trim filter, and save it back out
// to a different temp file.
_wavehdr.dwBytesRecorded -= 8*(_cchan * _cbSample); // chop off last 8 samples worth, since some audio cards put garbage on end of data
_priff->Set(_cchan, _csampSec, _cbSample, _wavehdr.dwBytesRecorded);
// now use AudioMan API to load the temp file, apply a trim filter and place
// trimmed sound out to our temp file
if (FAILED(AllocSoundFromMemory(&psnd, (LPBYTE)_priff, _priff->Cb())))
{
PushErc(ercOomNew);
_fHaveSound = fFalse;
return;
}
_fHaveSound = fTrue;
if (FAILED(AllocBiasFilter(&psndBias, psnd)))
{
// then just return the sound raw
_psnd = psnd;
return;
}
// release the original sound, since it's now owned by the psndGain
ReleasePpo(&psnd);
if (FAILED(AllocTrimFilter(&_psnd, psndBias)))
{
// then just return the sound with the bias filter on it...
_psnd = psndBias;
return;
}
// release the psndBias, since it's now owned by the psndTrim
ReleasePpo(&psndBias);
}
}
/***************************************************************************
Figure out if we're recording or not
***************************************************************************/
void SREC::_WaveInProc(HWAVEIN hwi, UINT uMsg, DWORD dwInstance, DWORD dwParam1, DWORD dwParam2)
{
// the psrec pointer is a pointer to the class which generated the event and owns the device
SREC *psrec = (SREC *)dwInstance;
switch(uMsg)
{
case WIM_DATA:
{
// any time we get a block of data, we are done, we set our flag
// to true, allowing _UpdateStatus to notice that we are _fRecording and _fHaveSound
// at which point it will process the data...
psrec->_fHaveSound = fTrue;
psrec->_fBufferAdded = fFalse;
}
}
}
/***************************************************************************
Start recording
***************************************************************************/
bool SREC::FStart(void)
{
AssertThis(0);
Assert(!_fRecording, "stop previous recording first");
// make sure we are open
if (_fPlaying)
FStop();
if (!_FOpenRecord())
return fFalse;
_fHaveSound = fFalse;
_fRecording = fFalse;
_wavehdr.dwBytesRecorded = 0;
// now record data
if (waveInStart(_hwavein))
return fFalse;
_fRecording = fTrue;
return fTrue;
}
/***************************************************************************
Stop recording or playing
***************************************************************************/
bool SREC::FStop(void)
{
AssertThis(0);
Assert(_fRecording || _fPlaying, "Nothing to stop");
// if we are recording
if (_fRecording)
{
// then stop the recording device
waveInStop(_hwavein);
}
else if (_fPlaying) // if we are playing
{
// then stop the playing device
_pchannel->Stop();
}
// update status accordingly
_UpdateStatus();
return fTrue;
}
/***************************************************************************
Start playing the current sound
***************************************************************************/
bool SREC::FPlay(void)
{
AssertThis(0);
Assert(_fHaveSound, "No sound to play");
// open the _fniTrim file with MCI
_FCloseRecord();
if (_psnd && _pchannel)
{
vpsndm->StopAll(); //stop any outstanding bogus sounds from button pushs
vpsndm->Suspend(fFalse); // restore sound mgr
_pchannel->Stop(); // stop our channel (should be nop)
_pchannel->SetSoundSrc(_psnd); // give it our sound
_pchannel->SetPosition(0); // seek to the beginning
if (FAILED(_pchannel->Play())) // play the sound
{
_UpdateStatus(); // this will check play status, and clean up accordingly
}
else
_fPlaying = fTrue;
}
return _fPlaying;
}
/***************************************************************************
Are we recording?
***************************************************************************/
bool SREC::FRecording(void)
{
AssertThis(0);
_UpdateStatus();
return _fRecording;
}
/***************************************************************************
Are we playing the current sound?
***************************************************************************/
bool SREC::FPlaying(void)
{
AssertThis(0);
_UpdateStatus();
return _fPlaying;
}
/***************************************************************************
Save the current sound to the given FNI
***************************************************************************/
bool SREC::FSave(PFNI pfni)
{
AssertThis(0);
Assert(_fHaveSound, "Nothing to save!");
STN stn;
if (_psnd)
{
pfni->GetStnPath(&stn);
// now save _psnd to the FNI passed in
if (FAILED(SoundToFileAsWave(_psnd, stn.Psz())))
{
PushErc(ercSocWaveSaveFailure);
return fFalse;
}
return fTrue;
}
return fFalse;
}
#ifdef DEBUG
/***************************************************************************
Assert the validity of the SREC.
***************************************************************************/
void SREC::AssertValid(ulong grf)
{
SREC_PAR::AssertValid(fobjAllocated);
Assert(pvNil != _pmixer, "No mixer?");
Assert(pvNil != _pchannel, "No Channel?");
}
/***************************************************************************
Mark memory used by the SREC
***************************************************************************/
void SREC::MarkMem(void)
{
AssertThis(0);
MarkPv(_priff);
SREC_PAR::MarkMem();
}
#endif //DEBUG