278 lines
5.2 KiB
C++
278 lines
5.2 KiB
C++
|
#include "precomp.h"
|
||
|
#include "mixer.h"
|
||
|
#include "agc.h"
|
||
|
|
||
|
|
||
|
|
||
|
// this should be moved to the mixer class - but right
|
||
|
// now we already have two instances of that class (one in NAC, the other in CONF)
|
||
|
static BOOL GetVolume(CMixerDevice *pMixer, DWORD *pdwVol)
|
||
|
{
|
||
|
DWORD dwSub=0, dwMain=0;
|
||
|
BOOL fSubAvail, fMainAvail;
|
||
|
|
||
|
if (pMixer == NULL)
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
fSubAvail = pMixer->GetSubVolume(&dwSub);
|
||
|
fMainAvail = pMixer->GetMainVolume(&dwMain);
|
||
|
|
||
|
if ((!fSubAvail) && (!fMainAvail))
|
||
|
{
|
||
|
*pdwVol = 0;
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
if ((fSubAvail) && (fMainAvail))
|
||
|
{
|
||
|
*pdwVol = ((dwSub + dwMain)/2);
|
||
|
}
|
||
|
|
||
|
else if (fSubAvail)
|
||
|
{
|
||
|
*pdwVol = dwSub;
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
*pdwVol = dwMain;
|
||
|
}
|
||
|
|
||
|
return TRUE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// check to see if volume has changed since the last update of the mixer
|
||
|
// if so, we update m_dsLastVolumeSetting and return TRUE
|
||
|
BOOL AGC::HasVolumeChanged()
|
||
|
{
|
||
|
DWORD dwVol;
|
||
|
|
||
|
if (m_pMixer)
|
||
|
{
|
||
|
if (GetVolume(m_pMixer, &dwVol))
|
||
|
{
|
||
|
if (dwVol != m_dwLastVolumeSetting)
|
||
|
{
|
||
|
m_dwLastVolumeSetting = dwVol;
|
||
|
return TRUE;
|
||
|
}
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// raise the volume my the increment amount
|
||
|
inline BOOL AGC::RaiseVolume()
|
||
|
{
|
||
|
DWORD dwVol;
|
||
|
|
||
|
if (m_pMixer)
|
||
|
{
|
||
|
if (GetVolume(m_pMixer, &dwVol))
|
||
|
{
|
||
|
if (dwVol < (AGC_MAXVOL-AGC_INCREMENT))
|
||
|
{
|
||
|
dwVol += AGC_INCREMENT;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
dwVol = AGC_MAXVOL;
|
||
|
}
|
||
|
m_pMixer->SetVolume(dwVol);
|
||
|
GetVolume(m_pMixer, &m_dwLastVolumeSetting);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
// lower the volume by the increment amount
|
||
|
inline BOOL AGC::LowerVolume()
|
||
|
{
|
||
|
DWORD dwRet;
|
||
|
|
||
|
if (m_pMixer)
|
||
|
{
|
||
|
if (GetVolume(m_pMixer, &dwRet))
|
||
|
{
|
||
|
if (dwRet > (AGC_INCREMENT+AGC_INCREMENT/2))
|
||
|
m_dwLastVolumeSetting = dwRet - AGC_INCREMENT;
|
||
|
else
|
||
|
m_dwLastVolumeSetting = AGC_INCREMENT / 2;
|
||
|
|
||
|
m_pMixer->SetVolume(m_dwLastVolumeSetting);
|
||
|
GetVolume(m_pMixer, &m_dwLastVolumeSetting);
|
||
|
return TRUE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
return FALSE;
|
||
|
}
|
||
|
}
|
||
|
return FALSE;
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
AGC::AGC(CMixerDevice *pMixer) :
|
||
|
m_cPeaks(0), m_wCurrentPeak(0),
|
||
|
m_dwCollectionTime(0),
|
||
|
m_pMixer(pMixer),
|
||
|
m_wThreshStrength(AGC_DEFAULT_THRESH),
|
||
|
m_dwLastVolumeSetting(0),
|
||
|
m_nLastUpdateResult(AGC_NOUPDATE)
|
||
|
{;}
|
||
|
|
||
|
|
||
|
// resets all stats inside the AGC control except the mixer object
|
||
|
void AGC::Reset()
|
||
|
{
|
||
|
m_cPeaks = 0;
|
||
|
m_wCurrentPeak = 0;
|
||
|
m_dwCollectionTime = 0;
|
||
|
m_wThreshStrength = AGC_DEFAULT_THRESH;
|
||
|
m_dwLastVolumeSetting = 0;
|
||
|
m_nLastUpdateResult = AGC_NOUPDATE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// initialize the AGC control with an instance of a mixer object
|
||
|
// (you can also set the mixer in the constructor)
|
||
|
void AGC::SetMixer(CMixerDevice *pMixer)
|
||
|
{
|
||
|
m_pMixer = pMixer;
|
||
|
|
||
|
if (pMixer)
|
||
|
{
|
||
|
GetVolume(pMixer, &m_dwLastVolumeSetting);
|
||
|
pMixer->SetVolume(m_dwLastVolumeSetting);
|
||
|
}
|
||
|
}
|
||
|
|
||
|
|
||
|
|
||
|
// call this method for all recorded packets that
|
||
|
// are begin sent. mixer will get raised/lowered as
|
||
|
// appropriate. wPeakStrength can be any WORD that
|
||
|
// represents a volume amount, but is designed to be
|
||
|
// the highest sample value in a packet.
|
||
|
int AGC::Update(WORD wPeakStrength, DWORD dwLengthMS)
|
||
|
{
|
||
|
int nIndex;
|
||
|
DWORD dwTotal=0, dwMin=AGC_PEAKVOL, dwMax=0;
|
||
|
DWORD dwAvg=0;
|
||
|
BOOL nMaxPeaks=0;
|
||
|
|
||
|
ASSERT (PEAKARRAYSIZE >= 2);
|
||
|
|
||
|
|
||
|
if (wPeakStrength > m_wCurrentPeak)
|
||
|
{
|
||
|
m_wCurrentPeak = wPeakStrength;
|
||
|
}
|
||
|
|
||
|
m_dwCollectionTime += dwLengthMS;
|
||
|
|
||
|
// have we exceeded one second worth of collections
|
||
|
if (m_dwCollectionTime > 1000)
|
||
|
{
|
||
|
m_aPeaks[m_cPeaks++] = m_wCurrentPeak;
|
||
|
m_dwCollectionTime = 0;
|
||
|
m_wCurrentPeak = 0;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (m_cPeaks >= 2)
|
||
|
{
|
||
|
// compute the average volume and number of clips that occurred
|
||
|
for (nIndex = 0; nIndex < m_cPeaks; nIndex++)
|
||
|
{
|
||
|
dwTotal += m_aPeaks[nIndex];
|
||
|
if (m_aPeaks[nIndex] < dwMin)
|
||
|
{
|
||
|
dwMin = m_aPeaks[nIndex];
|
||
|
}
|
||
|
else if (m_aPeaks[nIndex] > dwMax)
|
||
|
{
|
||
|
dwMax = m_aPeaks[nIndex];
|
||
|
}
|
||
|
if (m_aPeaks[nIndex] >= AGC_PEAKVOL)
|
||
|
{
|
||
|
nMaxPeaks++;
|
||
|
}
|
||
|
}
|
||
|
|
||
|
dwAvg = (dwTotal-dwMin) / (PEAKARRAYSIZE-1);
|
||
|
|
||
|
|
||
|
// check for clipping every 2 seconds
|
||
|
if (((nMaxPeaks >= 1) && (dwAvg > AGC_HIGHVOL)) || (nMaxPeaks >=2))
|
||
|
{
|
||
|
// if the volume changed during (user manually adjusted sliders)
|
||
|
// then allow those settings to stay in effect for this update
|
||
|
if (HasVolumeChanged())
|
||
|
{
|
||
|
m_nLastUpdateResult = AGC_NOUPDATE;
|
||
|
}
|
||
|
else
|
||
|
{
|
||
|
m_cPeaks = 0;
|
||
|
LowerVolume();
|
||
|
m_nLastUpdateResult = AGC_UPDATE_LOWERVOL;
|
||
|
}
|
||
|
return m_nLastUpdateResult;
|
||
|
}
|
||
|
|
||
|
|
||
|
if (m_cPeaks >= PEAKARRAYSIZE)
|
||
|
{
|
||
|
m_cPeaks = 0;
|
||
|
|
||
|
// if the volume changed during (user manually adjusted sliders)
|
||
|
// then allow those settings to stay in effect for this update
|
||
|
if (HasVolumeChanged())
|
||
|
{
|
||
|
m_nLastUpdateResult = AGC_NOUPDATE;
|
||
|
}
|
||
|
|
||
|
|
||
|
// should we actually raise the volume ?
|
||
|
// if we just lowered the volume, don't raise it again
|
||
|
// prevents the system from appearing "jerky"
|
||
|
|
||
|
// if we just raised the volume, then don't raise immediately
|
||
|
// again... let silence detection catch up.
|
||
|
else if ((dwAvg < m_wThreshStrength) && (m_nLastUpdateResult == AGC_NOUPDATE))
|
||
|
{
|
||
|
RaiseVolume();
|
||
|
m_nLastUpdateResult = AGC_UPDATE_RAISEVOL;
|
||
|
}
|
||
|
|
||
|
else
|
||
|
{
|
||
|
m_nLastUpdateResult = AGC_NOUPDATE;
|
||
|
}
|
||
|
|
||
|
return m_nLastUpdateResult;
|
||
|
}
|
||
|
|
||
|
return AGC_NOUPDATE;
|
||
|
|
||
|
}
|
||
|
|
||
|
// return NOUPDATE, but don't set m_nLastUpdateResult since
|
||
|
// there was no decision made.
|
||
|
return AGC_NOUPDATE;
|
||
|
|
||
|
}
|
||
|
|
||
|
|