// PCMVolumeMaximizer.cpp: implementation of the PCMVolumeMaximizer class.
|
//
|
//////////////////////////////////////////////////////////////////////
|
|
#include <math.h>
|
|
#include "PCMVolumeMaximizer.h"
|
#include "AudioSample.h"
|
#include "Exception.h"
|
|
//////////////////////////////////////////////////////////////////////
|
// Construction/Destruction
|
//////////////////////////////////////////////////////////////////////
|
|
PCMVolumeMaximizer::PCMVolumeMaximizer() : averageVolumeCalculator(&tracer)
|
{
|
char subFacilityName[100];
|
sprintf(subFacilityName, "PCMVolumeMaximizer:%x", this);
|
tracer.SetSubFacilityName(subFacilityName);
|
SetTraceLevel();
|
maximizePercentile = 100.0;
|
maximumAmplification = 100;
|
averageVolumeCalculator.SetCalculationInterval(100);
|
}
|
|
PCMVolumeMaximizer::~PCMVolumeMaximizer()
|
{
|
|
}
|
|
int
|
PCMVolumeMaximizer::TransformStarted()
|
{
|
averageVolumeCalculator.Reset();
|
return 0;
|
}
|
|
int
|
PCMVolumeMaximizer::SetTraceLevel()
|
{
|
long SystemMask = 0;
|
if ((SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "AllComponents", 0x0)) == 0)
|
{
|
SystemMask = GetRegKeyLong(HKEY_CURRENT_USER, "Software\\Cisco Systems\\MTC\\Tracing", "PCMVolumeMaximizer", 0x100000);
|
}
|
tracer.SetSystemMask(SystemMask);
|
return 0;
|
}
|
|
int
|
PCMVolumeMaximizer::SetMaximizePercentile(double percentile)
|
{
|
if (percentile < 0.0)
|
{
|
percentile = 0.0;
|
}
|
if (percentile > 100.0)
|
{
|
percentile = 100.0;
|
}
|
maximizePercentile = percentile;
|
return 0;
|
}
|
|
int
|
PCMVolumeMaximizer::SetMaximumAmplification(unsigned int amplification)
|
{
|
if (amplification < 100)
|
{
|
amplification = 100;
|
}
|
maximumAmplification = amplification;
|
return 0;
|
}
|
|
int
|
PCMVolumeMaximizer::TransformAudioSamples(std::vector<std::pair<AudioSample *, AudioSource *> > &data, AudioSample **ppAudioSample)
|
{
|
int result = 0;
|
AudioSample *inSample = NULL;
|
if (data.size() > 0)
|
{
|
inSample = data[0].first;
|
}
|
try
|
{
|
if (!inSample)
|
{
|
throw Exception(-10, "inSample = NULL");
|
}
|
if (inSample->DataSize() <= 0)
|
{
|
throw Exception(-20, "inSample->DataSize is %d\n", inSample->DataSize());
|
}
|
if (maximumAmplification <= 100)
|
{
|
throw Exception(0, "maximumAmplification is %d\n", maximumAmplification);
|
}
|
|
WAVEFORMATEX wfx;
|
inSample->GetFormat(&wfx);
|
|
int bytesPerSample(0);
|
int numSamples(0);
|
int numBytes = inSample->DataSize();
|
double maxValue(0.0);
|
|
switch(wfx.wBitsPerSample)
|
{
|
case 8:
|
bytesPerSample = 1;
|
maxValue = 127;
|
break;
|
case 16:
|
bytesPerSample = 2;
|
maxValue = 32767;
|
break;
|
case 32:
|
bytesPerSample = 4;
|
maxValue = pow(2.0, 31) - 1;
|
break;
|
default:
|
throw Exception(-30, "sample audioformat wBitsPerSample = %d", wfx.wBitsPerSample);
|
break;
|
}
|
|
numSamples = numBytes/bytesPerSample;
|
|
// make a histogram of the volume values
|
memset(bins, 0, sizeof(unsigned int) * NUM_BINS);
|
|
char *dataPtr = (char *)(inSample->Data());
|
for (int i=0; i<numSamples; i++)
|
{
|
double sampleValue(0.0);
|
switch(bytesPerSample)
|
{
|
case 1:
|
sampleValue = abs((double)(*((char *)(dataPtr + (bytesPerSample * i)))));
|
break;
|
case 2:
|
sampleValue = abs((double)(*((short *)(dataPtr + (bytesPerSample * i)))));
|
break;
|
case 4:
|
sampleValue = abs((double)(*((long *)(dataPtr + (bytesPerSample * i)))));
|
break;
|
}
|
int binNumber = 256 * (sampleValue / maxValue);
|
(bins[binNumber])++;
|
}
|
|
// now find how many bins are to be amplified
|
int total(0);
|
int numBinsToAmplify(0);
|
for (i=NUM_BINS-1; i>=0; i--)
|
{
|
total += bins[i];
|
double percentile = (double)(numSamples - total) / (double)numSamples * 100;
|
if (percentile >= maximizePercentile)
|
{
|
continue;
|
}
|
numBinsToAmplify = i+1;
|
break;
|
}
|
|
// find out maximum amplification possible
|
double amplification = (double)NUM_BINS / (double)numBinsToAmplify;
|
if (amplification > (maximumAmplification / 100.0))
|
{
|
amplification = maximumAmplification / 100.0;
|
}
|
|
averageVolumeCalculator.TakeNextValue(amplification);
|
|
tracer.tracef(DET, "TransformAudioSamples : amplifying by %.2f\n", amplification);
|
// now amplify the sample
|
for (i=0; i<numSamples; i++)
|
{
|
double sampleValue(0.0);
|
double newValue(0.0);
|
switch(bytesPerSample)
|
{
|
case 1:
|
sampleValue = (double)(*((char *)(dataPtr + (bytesPerSample * i))));
|
newValue = sampleValue * amplification;
|
if (newValue > maxValue)
|
{
|
newValue = maxValue;
|
}
|
if (newValue < -maxValue)
|
{
|
newValue = -maxValue;
|
}
|
*((char *)(dataPtr + (bytesPerSample * i))) = newValue;
|
break;
|
case 2:
|
sampleValue = (double)(*((short *)(dataPtr + (bytesPerSample * i))));
|
newValue = sampleValue * amplification;
|
if (newValue > maxValue)
|
{
|
newValue = maxValue;
|
}
|
if (newValue < -maxValue)
|
{
|
newValue = -maxValue;
|
}
|
*((short *)(dataPtr + (bytesPerSample * i))) = newValue;
|
break;
|
case 4:
|
sampleValue = (double)(*((long *)(dataPtr + (bytesPerSample * i))));
|
newValue = sampleValue * amplification;
|
if (newValue > maxValue)
|
{
|
newValue = maxValue;
|
}
|
if (newValue < -maxValue)
|
{
|
newValue = -maxValue;
|
}
|
*((long *)(dataPtr + (bytesPerSample * i))) = newValue;
|
break;
|
}
|
}
|
}
|
catch (Exception ex)
|
{
|
if (result < 0)
|
{
|
tracer.tracef(ERR, "TransformAudioSamples : error %d. %s\n", ex.ErrorCode(), ex.ErrorMessage());
|
}
|
else
|
{
|
tracer.tracef(DET, "TransformAudioSamples : error %d. %s\n", ex.ErrorCode(), ex.ErrorMessage());
|
}
|
result = ex.ErrorCode();
|
}
|
if (result == 0)
|
{
|
*ppAudioSample = inSample;
|
if (inSample)
|
{
|
inSample->AddRef(this);
|
}
|
}
|
return result;
|
}
|