windows-nt/Source/XPSP1/NT/enduser/netmeeting/av/nac/agc.cpp
2020-09-26 16:20:57 +08:00

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;
}