437 lines
10 KiB
C++
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
|
|
|