1
0
mirror of https://github.com/cookiengineer/audacity synced 2025-05-03 09:09:47 +02:00
audacity/lib-src/iAVC/iAVC.cpp
2010-01-24 09:19:39 +00:00

644 lines
25 KiB
C++

//////////////////////////////////////////////////////////////////////
// iAVC -- integer Automatic Volume Control (on samples given it)
//
// Copyright (C) 2002 Vincent A. Busam
// 15754 Adams Ridge
// Los Gatos, CA 95033
// email: vince@busam.com
//
// This library is free software; you can redistribute it and/or
// modify it under the terms of the GNU Lesser General Public
// License as published by the Free Software Foundation; either
// version 2.1 of the License, or (at your option) any later version.
//
// This library is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
// Lesser General Public License for more details.
//
// You should have received a copy of the GNU Lesser General Public
// License along with this library; if not, write to the Free Software
// Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
// If you change the algorithm or find other sets of values that improve the
// output results, please send me a copy so that I can incorporate them into
// iAVC. Of course, you are not required to send me any updates under the
// LGPL license, but please consider doing so under the spirit of open source
// and in appreciation of being able to take advantage of my efforts expended
// in developing iAVC.
// This code implements a "poor man's" dynamic range compression algorithm
// that was build on hueristics. It's purpose is to perform dynamic range
// compression in real time using only integer arithmetic. Processing time
// is more important than memory. It acts like an automatic volume control,
// frequently adjusting the volume (gain) based on an average of the current
// sound samples
#if !defined(IAVC_INLINE) || ( !defined(IAVC_SETNEXTSAMPLE) && !defined(IAVC_GETNEXTSAMPLE) && !defined(IAVC_ADJUSTMULTIPLIER) )
#ifdef _WINDOWS
//#include "stdafx.h" // don't use precompiled headers on this file
#endif
#ifndef __cplusplus
// You really should consider using C++.
// Granted it is not needed or even useful in all situations, but real
// object oriented design and code (not faux OO code like in MFC)
// has lots of benefits.
#endif
#include "iAVC.h"
#if (defined ( _WINDOWS ) | defined ( _DEBUG ))
#define c_WithDebug 1 // should be = 1
#else
#define c_WithDebug 0
#endif
#ifdef IDEBUGLOG
#include "LogFlags.h"
#include "../Logger/IDebugLog.h"
#else
#ifdef _DEBUG
#ifdef _WINDOWS
#define _MFC_OVERRIDES_NEW
#include <crtdbg.h> // user _RPTF0 to get file name and line in output
#define log0(fn,lf,ulid,fmt) _RPT0(_CRT_WARN,fmt);
#define log1(fn,lf,ulid,fmt,p1) _RPT1(_CRT_WARN,fmt,p1);
#define log2(fn,lf,ulid,fmt,p1,p2) _RPT2(_CRT_WARN,fmt,p1,p2);
#define log3(fn,lf,ulid,fmt,p1,p2,p3) _RPT3(_CRT_WARN,fmt,p1,p2,p3);
#define log4(fn,lf,ulid,fmt,p1,p2,p3,p4) _RPT4(_CRT_WARN,fmt,p1,p2,p3,p4);
#define log5(fn,lf,ulid,fmt,p1,p2,p3,p4,p5) _RPT5(_CRT_WARN,fmt,p1,p2,p3,p4,p5);
#elif
#define log0(fn,lf,ulid,fmt) fprintf(stderr,fmt);
#define log1(fn,lf,ulid,fmt,p1) fprintf(stderr,fmt,p1);
#define log2(fn,lf,ulid,fmt,p1,p2) fprintf(stderr,fmt,p1,p2);
#define log3(fn,lf,ulid,fmt,p1,p2,p3) fprintf(stderr,fmt,p1,p2,p3);
#define log4(fn,lf,ulid,fmt,p1,p2,p3,p4) fprintf(stderr,fmt,p1,p2,p3,p4);
#define log5(fn,lf,ulid,fmt,p1,p2,p3,p4,p5) fprintf(stderr,fmt,p1,p2,p3,p4,p5);
#endif // _WINDOWS
#else
#define log0(fn,lf,ulid,fmt) ;
#define log1(fn,lf,ulid,fmt,p1) ;
#define log2(fn,lf,ulid,fmt,p1,p2) ;
#define log3(fn,lf,ulid,fmt,p1,p2,p3) ;
#define log4(fn,lf,ulid,fmt,p1,p2,p3,p4) ;
#define log5(fn,lf,ulid,fmt,p1,p2,p3,p4,p5) ;
#endif // _DEBUG
#endif
///////////////////////////////////////////////////////////////////////////////
///////////////////////////////////////////////////////////////////////////////
//
// iAVC constructor
//
///////////////////////////////////////////////////////////////////////////////
AutoVolCtrl::AutoVolCtrl()
{
m_pSampleList = NULL;
m_nSampleWindowSize = DEFAULT_SAMPLE_WINDOW_SIZE;
m_nSamplesInAvg = DEFAULT_ADJUSTER_WINDOW_SIZE;
m_nLookAheadWindowSize = DEFAULT_LOOKAHEAD_WINDOW_SIZE;
m_nMinSamplesBeforeSwitch = DEFAULT_MINIMUM_SAMPLES_BEFORE_SWITCH;
m_nNumTracks = DEFAULT_NUMBER_OF_TRACKS;
m_nMaxChangePct = DEFAULT_MAX_PCT_CHANGE_AT_ONCE;
m_nMaxSampleValue = DEFAULT_MAX_SAMPLE_VALUE;
SetSampleWindowSize ( m_nSampleWindowSize,
m_nSamplesInAvg,
m_nLookAheadWindowSize );
Reset();
// set multipliers to a nil transform
for ( int i = 0 ; i < MULTIPLY_PCT_ARRAY_SIZE ; ++i )
m_nMultiplyPct [ i ] = IAVCMULTIPLYPCT ( APPLY_MULTIPLY_FACTOR ( 1 ) ); // default to no transform
}
///////////////////////////////////////////////////////////////////////////////
//
// iAVC destructor
//
///////////////////////////////////////////////////////////////////////////////
AutoVolCtrl::~AutoVolCtrl()
{
// Dump diagnostic information
log1(CN_iAVC,LL_DEBUG,0, "Sample Window Size %d\n", m_nSampleWindowSize );
log1(CN_iAVC,LL_DEBUG,0, "Adjuster Window Size %d\n", m_nSamplesInAvg );
log1(CN_iAVC,LL_DEBUG,0, "Min Samples to Switch %d\n", m_nMinSamplesBeforeSwitch );
log1(CN_iAVC,LL_DEBUG,0, "Pct Change threshold %d\n", m_nMaxChangePct );
log1(CN_iAVC,LL_DEBUG,0, "Number of Samples = %d\n", m_nTotalSamples );
log1(CN_iAVC,LL_DEBUG,0, "Multiplier changes = %d\n", m_nNumMultiplerChanges );
log1(CN_iAVC,LL_DEBUG,0, "Number of clips = %d\n", m_nClips );
if ( m_pSampleList != NULL )
delete []m_pSampleList;
}
///////////////////////////////////////////////////////////////////////////////
//
// Reset
//
///////////////////////////////////////////////////////////////////////////////
void AutoVolCtrl::Reset()
{
ZeroSampleWindow();
SetMinSamplesBeforeSwitch ( m_nMinSamplesBeforeSwitch );
SetMaxPctChangeAtOnce ( m_nMaxChangePct ); // e.g. 10%
SetNumberTracks ( m_nNumTracks );
m_nMaxSampleValue = DEFAULT_MAX_SAMPLE_VALUE; //TODO: make a method so caller can set
// set our internal data
m_nSampleAvgSum = 0;
m_nSamplesInSum = 0;
m_nCurrentMultiplier = APPLY_MULTIPLY_FACTOR ( 1 );
m_nTotalSamples = 0;
m_nNumMultiplerChanges = 0;
m_nClips = 0;
m_nLookaheadSum = 0;
m_nSamplesInLookahead = 0;
m_nNumSamplesBeforeNextSwitch = 0; // allows switch on first GetSample
}
///////////////////////////////////////////////////////////////////////////////
//
// SetSampleWindowSize
//
///////////////////////////////////////////////////////////////////////////////
bool AutoVolCtrl::SetSampleWindowSize ( unsigned long nSampleWindowSize,
unsigned long nAdjusterWindowSize,
unsigned long nLookAheadWindowSize )
{
if ( nSampleWindowSize > MAX_SAMPLE_WINDOW_SIZE )
return false; // sums may overflow and we use int for indicies
if ( nSampleWindowSize < nAdjusterWindowSize + nLookAheadWindowSize )
return false;
m_nSamplesInAvg = nAdjusterWindowSize;
m_nLookAheadWindowSize = nLookAheadWindowSize;
if ( m_nSampleWindowSize != nSampleWindowSize || m_pSampleList == NULL )
{ // window size has changed
m_nSampleWindowSize = nSampleWindowSize;
if ( m_pSampleList )
delete m_pSampleList;
m_pSampleList = new Sample [ m_nSampleWindowSize ];
}
// initialize a circular list of samples
for ( unsigned long j = 0 ; j < m_nSampleWindowSize ; ++j )
{
m_pSampleList [ j ].m_pNext = &(m_pSampleList[j + 1]);
m_pSampleList [ j ].m_nLeft = 0;
m_pSampleList [ j ].m_nRight = 0;
m_pSampleList [ j ].m_nSampleValid = 0; // false
m_pSampleList [ j ].m_nSampleAbsAvg = 0;
// set average partner
m_pSampleList [ j ].m_pAvgPartner = ( j < m_nSamplesInAvg ) ?
&(m_pSampleList [ m_nSampleWindowSize - m_nSamplesInAvg + j]) :
&(m_pSampleList [ j - m_nSamplesInAvg ]) ;
// set lookahead partner
m_pSampleList [ j ].m_pLookaheadPartner = ( j < m_nLookAheadWindowSize ) ?
&(m_pSampleList [ m_nSampleWindowSize - m_nLookAheadWindowSize + j]) :
&(m_pSampleList [ j - m_nLookAheadWindowSize ]) ;
}
m_pSampleList [ m_nSampleWindowSize - 1 ].m_pNext = &(m_pSampleList[0]); // last points to first
ZeroSampleWindow();
if ( c_WithDebug )
{
//for ( j = 0 ; j < m_nSampleWindowSize ; ++j )
//{
// unsigned long nNext = ( m_pSampleList [ j ].m_pNext - m_pSampleList );
// unsigned long nAvgp = ( m_pSampleList [ j ].m_pAvgPartner - m_pSampleList );
// unsigned long nLkap = ( m_pSampleList [ j ].m_pLookaheadPartner - m_pSampleList );
// log4(CN_iAVC,LL_DEBUG,0, "this=%d, next=%d, AvgPartner=%d, LookAheadPartner = %d",
// j, nNext, nAvgp, nLkap );
//}
}
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetMinSamplesBeforeSwitch
//
///////////////////////////////////////////////////////////////////////////////
bool AutoVolCtrl::SetMinSamplesBeforeSwitch ( unsigned long nMinSamplesBeforeSwitch )
{
if ( m_nSampleWindowSize < nMinSamplesBeforeSwitch ||
nMinSamplesBeforeSwitch < MIN_MINIMUM_SAMPLES_BEFORE_SWITCH )
return false;
m_nMinSamplesBeforeSwitch = nMinSamplesBeforeSwitch;
m_nNumSamplesBeforeNextSwitch = 0;
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetMaxPctChangeAtOnce
//
///////////////////////////////////////////////////////////////////////////////
void AutoVolCtrl::SetMaxPctChangeAtOnce ( IAVCMULTIPLYPCT nPctChange )
{
m_nMaxChangePct = nPctChange;
}
///////////////////////////////////////////////////////////////////////////////
//
// SetMultipliers
//
///////////////////////////////////////////////////////////////////////////////
void AutoVolCtrl::SetMultipliers ( unsigned short int nValueWanted [ MULTIPLY_PCT_ARRAY_SIZE ] )
{
for ( int i = 1 ; i < MULTIPLY_PCT_ARRAY_SIZE ; ++i )
{
m_nMultiplyPct [ i ] = APPLY_MULTIPLY_FACTOR ( nValueWanted [ i ] ) / IAVCMULTIPLYPCT ( i );
if ( ( i % 1000 ) == 0 )
log3(CN_iAVC,LL_DEBUG,0, "SetMultipliers at sample %d, =%d (0x%X)\n",
i,
MULTIPLY_FACTOR_TO_INT_X256(m_nMultiplyPct [ i ]),
MULTIPLY_FACTOR_TO_INT_X256(m_nMultiplyPct [ i ]) );
}
m_nMultiplyPct [ 0 ] = m_nMultiplyPct [ 1 ];
}
///////////////////////////////////////////////////////////////////////////////
//
// SetNumberTracks
//
///////////////////////////////////////////////////////////////////////////////
bool AutoVolCtrl::SetNumberTracks ( unsigned int nNumTracks )
{
if ( nNumTracks > MAX_NUMBER_OF_TRACKS )
return false;
m_nNumTracks = nNumTracks;
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// ZeroSampleWindow
//
///////////////////////////////////////////////////////////////////////////////
void AutoVolCtrl::ZeroSampleWindow()
{
// initialize a circular list of samples
for ( unsigned long j = 0 ; j < m_nSampleWindowSize ; ++j )
{
m_pSampleList [ j ].m_nLeft = 0;
m_pSampleList [ j ].m_nRight = 0;
m_pSampleList [ j ].m_nSampleValid = 0; // false
m_pSampleList [ j ].m_nSampleAbsAvg = 0;
}
// set subscripts for where next data goes or comes from
m_pNextSet = &m_pSampleList [ 0 ];
m_pNextGet = &m_pSampleList [ 0 ];
}
///////////////////////////////////////////////////////////////////////////////
//
// SetNextSample
//
///////////////////////////////////////////////////////////////////////////////
bool AutoVolCtrl::SetNextSample ( IAVCSAMPLETYPE left, IAVCSAMPLETYPE right )
{
#endif // !defined...
#if defined(IAVC_SETNEXTSAMPLE)
// take out of our sum the sample m_nSamplesInAvg before the sample just before the lookahead window
Sample* pAddToSum = m_pNextSet->m_pLookaheadPartner; // node just before lookahead window
Sample* pRemoveFromSum = pAddToSum->m_pAvgPartner; // node to remove from sample sum
//if ( m_nTotalSamples <= 2200 )
//{ // TEMP
// log8(CN_iAVC,LL_DEBUG,0,
// "# = %d, sum = %d,"
// ", nextSet=%d, AddToAvg=%d (%d), RemoveFromAvg=%d (%d), newAbsAvg=%d",
// m_nSamplesInSum,
// long(m_nSampleAvgSum),
// m_pNextSet - m_pSampleList,
// pAddToSum - m_pSampleList, long(pAddToSum->m_nSampleAbsAvg),
// pRemoveFromSum - m_pSampleList, long(pRemoveFromSum->m_nSampleAbsAvg),
// long( absVal ( left ) + absVal ( right ) ) / m_nNumTracks );
//}
// take this sample out of the sample sum (if valid)
m_nSampleAvgSum -= pRemoveFromSum->m_nSampleAbsAvg;
m_nSamplesInSum -= pRemoveFromSum->m_nSampleValid;
// form average value for this cell
m_pNextSet->m_nSampleAbsAvg = ( absVal ( left ) + absVal ( right ) ) / m_nNumTracks;
if ( m_pNextSet->m_nSampleAbsAvg > DEFAULT_MAX_SAMPLE_VALUE ) // 9/1/02 Safety code needed for Audacity
m_pNextSet->m_nSampleAbsAvg = DEFAULT_MAX_SAMPLE_VALUE;
// put in new sample
m_pNextSet->m_nLeft = left;
m_pNextSet->m_nRight = right;
m_pNextSet->m_nSampleValid = 1; // true, node will now always have a valid sample in it
// add a node's samples into the sample sum (if valid)
m_nSampleAvgSum += pAddToSum->m_nSampleAbsAvg;
m_nSamplesInSum += pAddToSum->m_nSampleValid;
//NOTUSED - not using lookahead
//if ( m_nLookAheadWindowSize > 0 )
//{ // Figure out lookahead average for our lookahead partner
// Sample* pLookaheadPartner = pAddToSum; // take this nodes samples out of lookahead sum
// // take this sample out of the sum (if valid)
// m_nLookaheadSum -= pLookaheadPartner->m_nSampleAbsAvg;
// m_nSamplesInLookahead -= pLookaheadPartner->m_nSampleValid;
//
// // add into the lookahead sum the new values
// ++m_nSamplesInLookahead;
// m_nLookaheadSum += m_pNextSet->m_nSampleAbsAvg;
//}
m_pNextSet = m_pNextSet->m_pNext;
#endif // defined(IAVC_SETNEXTSAMPLE)
#if !defined(IAVC_INLINE) || ( !defined(IAVC_SETNEXTSAMPLE) && !defined(IAVC_GETNEXTSAMPLE) && !defined(IAVC_ADJUSTMULTIPLIER) )
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// GetNextSample
//
///////////////////////////////////////////////////////////////////////////////
bool AutoVolCtrl::GetNextSample ( IAVCSAMPLETYPE & left, IAVCSAMPLETYPE & right )
{
#endif // !defined...
#if defined(IAVC_GETNEXTSAMPLE)
// Note: If Puts circle around before we get the samples, then we'll lose one
// whole round of samples.
int nClip; // not used unless c_WithDebug is true
#if defined(IAVC_INLINE)
#undef IAVC_GETNEXTSAMPLE
#define IAVC_ADJUSTMULTIPLIER
//#pragma message("inlining AdjustMultiplier 1st time")
#include "iAVC.cpp"
#define IAVC_GETNEXTSAMPLE
#undef IAVC_ADJUSTMULTIPLIER
#else
if ( m_pNextGet == m_pNextSet )
{
return false; // no sample to give
}
AdjustMultiplier();
#endif
if ( c_WithDebug )
{
++m_nTotalSamples;
if ( ( m_nTotalSamples % 10000 ) <= 1 )
{
log4(CN_iAVC,LL_DEBUG,0,
"Sample %d, Number of samples in sum = %d, sample sum = %d, sample avg = %d\n",
m_nTotalSamples,
m_nSamplesInSum,
long ( AVG_TO_MULTIPLIER_SUBSCRIPT(m_nSampleAvgSum) ),
long ( AVG_TO_MULTIPLIER_SUBSCRIPT(m_nSampleAvgSum/m_nSamplesInSum) ) );
}
nClip = 0;
if ( IF_CLIP ( left ) || IF_CLIP ( right ) || m_nTotalSamples == 55666 )
{
log2(CN_iAVC,LL_ERROR,0,"ERROR: Sample out of range, left=%d, right=%d\n",
AVG_TO_MULTIPLIER_SUBSCRIPT( m_pNextGet->m_nLeft ),
AVG_TO_MULTIPLIER_SUBSCRIPT( m_pNextGet->m_nRight ) );
}
}
IAVCSUMTYPE nLeft;
IAVCSUMTYPE nRight;
nLeft = UNDO_MULTIPLY_FACTOR ( m_nCurrentMultiplier * m_pNextGet->m_nLeft );
nRight = UNDO_MULTIPLY_FACTOR ( m_nCurrentMultiplier * m_pNextGet->m_nRight );
if ( IF_CLIP ( nLeft ) || IF_CLIP ( nRight ) )
{ // We had a clip, see if we can adjust multiplier down.
// What do we do? If this is a momentary pop, like a pop on a record, we should
// do nothing. But most audio today is probably from CDs and therefore
// probably clean. So let's be bold and ASSUME that we're just moving into
// a loud section from a softer section (which can be why we have a high
// multiplier for this sample). In this case, let's just change the multiplier
// now and not wait for the end of the next change window. To figure out the
// new multiplier, we'll just use this sample.
long nCurSampleAvgSubscript = AVG_TO_MULTIPLIER_SUBSCRIPT(m_pNextGet->m_nSampleAbsAvg);
if ( nCurSampleAvgSubscript < 0 ) // Safety code, should not be needed
nCurSampleAvgSubscript = 0;
else if ( nCurSampleAvgSubscript >= MULTIPLY_PCT_ARRAY_SIZE )
nCurSampleAvgSubscript = MULTIPLY_PCT_ARRAY_SIZE - 1;
m_nCurrentMultiplier = m_nMultiplyPct [ nCurSampleAvgSubscript ]; // always positive
m_nNumSamplesBeforeNextSwitch = m_nMinSamplesBeforeSwitch;
if ( c_WithDebug )
{
nClip = 1;
}
// // This path will take extra time, but shouldn't occur very often.
// m_nNumSamplesBeforeNextSwitch = 0; // for multiplier adjustment
// ++m_nNumSamplesBeforeNextSwitch; // don't do this twice for a sample, already invoked AdjustMultiplier
//
//#if defined(IAVC_INLINE)
//#undef IAVC_GETNEXTSAMPLE
//#define IAVC_ADJUSTMULTIPLIER
////#pragma message("inlining AdjustMultiplier 2nd time")
//#include "DynRangeComp.cpp"
//#define IAVC_GETNEXTSAMPLE
//#undef IAVC_ADJUSTMULTIPLIER
//#else
// AdjustMultiplier();
//#endif
nLeft = UNDO_MULTIPLY_FACTOR ( m_nCurrentMultiplier * m_pNextGet->m_nLeft );
nRight = UNDO_MULTIPLY_FACTOR ( m_nCurrentMultiplier * m_pNextGet->m_nRight );
if ( IF_CLIP ( nLeft ) || IF_CLIP ( nRight ) )
{
nLeft = m_pNextGet->m_nLeft; // don't clip, use original values instead
nRight = m_pNextGet->m_nRight; // don't clip, use original values instead
}
}
left = nLeft;
right = nRight;
if ( c_WithDebug )
{
if ( nClip != 0 )
{
m_nClips += nClip;
if ( ( m_nClips % 1 ) == 0 )
{ // m_nTotalSamples may be off if buffered (i.e. more put samples than get samples done)
log4(CN_iAVC,LL_DEBUG,0, "Sample %d clipped, orig left=%d, right=%d, multiplier=0x%X\n",
m_nTotalSamples,
AVG_TO_MULTIPLIER_SUBSCRIPT(m_pNextGet->m_nLeft),
AVG_TO_MULTIPLIER_SUBSCRIPT(m_pNextGet->m_nRight),
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier) );
}
}
if ( ( m_nTotalSamples % 5000 ) == 0 )
{
log3(CN_iAVC,LL_DEBUG,0, "Sample %d, multiplier=%d (0x%X),...\n",
m_nTotalSamples,
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier) );
log4(CN_iAVC,LL_DEBUG,0, " , Transformed %d->%d %d->%d\n",
long(AVG_TO_MULTIPLIER_SUBSCRIPT(m_pNextGet->m_nLeft)),
long(AVG_TO_MULTIPLIER_SUBSCRIPT(left)),
long(AVG_TO_MULTIPLIER_SUBSCRIPT(m_pNextGet->m_nRight)),
long(AVG_TO_MULTIPLIER_SUBSCRIPT(right)) );
}
}
m_pNextGet = m_pNextGet->m_pNext;
#endif // defined(IAVC_GETNEXTSAMPLE)
#if !defined(IAVC_INLINE) || ( !defined(IAVC_SETNEXTSAMPLE) && !defined(IAVC_GETNEXTSAMPLE) && !defined(IAVC_ADJUSTMULTIPLIER) )
return true;
}
///////////////////////////////////////////////////////////////////////////////
//
// AdjustMultiplier
//
///////////////////////////////////////////////////////////////////////////////
void AutoVolCtrl::AdjustMultiplier()
{
// TEMPORARY DEBUG CODE
if ( c_WithDebug && m_nTotalSamples >= 466930L && m_nTotalSamples <= 466973L )
{
log3(CN_iAVC,LL_DEBUG,0, "DEBUG at sample %d, mul now=0x%X (%d)\n",
m_nTotalSamples,
long(m_nCurrentMultiplier),
long(m_nCurrentMultiplier) );
long nLookaheadAvg; // needs to be long since used as a subscript
if ( m_nSamplesInLookahead > 0 )
nLookaheadAvg= long ( m_nLookaheadSum/m_nSamplesInLookahead );
else
nLookaheadAvg = 0;
log4(CN_iAVC,LL_DEBUG,0, " sample max=%d, sample win avg=%d, lookahead avg=%d, avg multiplier=0x%X\n",
long(maxVal(absVal(m_pNextGet->m_nLeft),absVal(m_pNextGet->m_nRight))),
long(m_nSampleAvgSum / m_nSamplesInSum),
nLookaheadAvg,
long(m_nMultiplyPct [ nLookaheadAvg ]) );
}
#endif // !defined...
#if defined(IAVC_ADJUSTMULTIPLIER)
//#pragma message("inlining AdjustMultiplier")
--m_nNumSamplesBeforeNextSwitch;
if ( m_nNumSamplesBeforeNextSwitch <= 0 )
{ // long time since last change, see if it is time to change the multiplier
long nCurSampleAvgSubscript = ( m_nSamplesInSum <= 0 ) ? 0 :
( AVG_TO_MULTIPLIER_SUBSCRIPT(m_nSampleAvgSum) / m_nSamplesInSum );
if ( nCurSampleAvgSubscript < 0 ) // Safety code, should not be needed
nCurSampleAvgSubscript = 0;
else if ( nCurSampleAvgSubscript >= MULTIPLY_PCT_ARRAY_SIZE )
nCurSampleAvgSubscript = MULTIPLY_PCT_ARRAY_SIZE - 1;
IAVCMULTIPLYPCT nNewMultiplier = m_nMultiplyPct [ nCurSampleAvgSubscript ]; // always positive
IAVCMULTIPLYPCT nMultiplierDiff = nNewMultiplier - m_nCurrentMultiplier; // positive or negative
// if new multiplier is 1, force change to get to 1 (nChangeThreshold always positive)
IAVCMULTIPLYPCT nChangeThreshold = ( nMultiplierDiff != 0 &&
nNewMultiplier == APPLY_MULTIPLY_FACTOR ( 1 ) ) ?
nMultiplierDiff :
IAVCMULTIPLYPCT ( m_nCurrentMultiplier * m_nMaxChangePct / 100 ); // % of current multiplier
//NOTUSED - not using lookahead
//unsigned long nLookaheadAvg;
//if ( m_nSamplesInLookahead > 0 )
// nLookaheadAvg = m_nLookaheadSum/m_nSamplesInLookahead;
//else
// nLookaheadAvg = 0;
//long nLookaheadMultiplier = m_nMultiplyPct [ nLookaheadAvg ];
if ( nMultiplierDiff >= nChangeThreshold )
{ // adjust multiplier up
log4(CN_iAVC,LL_DEBUG,0, "Multiplier UP old=%d, new=%d, diff=%d, threshold=%d\n",
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(nNewMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(nMultiplierDiff),
MULTIPLY_FACTOR_TO_INT_X256(nChangeThreshold) );
m_nCurrentMultiplier = nNewMultiplier; // or m_nCurrentMultiplier += nChangeThreshold;
m_nNumSamplesBeforeNextSwitch = m_nMinSamplesBeforeSwitch;
if ( c_WithDebug )
{
++m_nNumMultiplerChanges;
log4(CN_iAVC,LL_DEBUG,0, "Multiplier UP at sample %d, current avg=%d, now=%d (0x%X)\n",
m_nTotalSamples,
nCurSampleAvgSubscript,
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier) );
//NOTUSED - not using lookahead
//log2(CN_iAVC,LL_DEBUG,0, " lookahead: avg=%d, avg multiplier=0x%X\n",
// long(nLookaheadAvg),
// long(nLookaheadMultiplier) );
}
}
else if ( nMultiplierDiff <= - nChangeThreshold )
{ // adjust multiplier down
log4(CN_iAVC,LL_DEBUG,0, "Multiplier DOWN old=%d, new=%d, diff=%d, threshold=%d\n",
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(nNewMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(nMultiplierDiff),
MULTIPLY_FACTOR_TO_INT_X256(nChangeThreshold) );
m_nCurrentMultiplier = nNewMultiplier; // or m_nCurrentMultiplier -= nChangeThreshold;
m_nNumSamplesBeforeNextSwitch = m_nMinSamplesBeforeSwitch;
if ( c_WithDebug )
{
++m_nNumMultiplerChanges;
log4(CN_iAVC,LL_DEBUG,0, "Multiplier DOWN at sample %d, current avg=%d, now=%d (0x%X)\n",
m_nTotalSamples,
nCurSampleAvgSubscript,
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier),
MULTIPLY_FACTOR_TO_INT_X256(m_nCurrentMultiplier) );
//NOTUSED - not using lookahead
//log2(CN_iAVC,LL_DEBUG,0, " lookahead: avg=%d, avg multiplier=0x%X\n",
// long(nLookaheadAvg),
// long(nLookaheadMultiplier) );
}
}
}
#endif // defined(IAVC_ADJUSTMULTIPLIER)
#if !defined(IAVC_INLINE) || ( !defined(IAVC_SETNEXTSAMPLE) && !defined(IAVC_GETNEXTSAMPLE) && !defined(IAVC_ADJUSTMULTIPLIER) )
return;
}
#endif // !defined...