AudioGain.cc revision 7c478bd95313f5f23a4c958a745db2134aa03244
/*
* CDDL HEADER START
*
* The contents of this file are subject to the terms of the
* Common Development and Distribution License, Version 1.0 only
* (the "License"). You may not use this file except in compliance
* with the License.
*
* You can obtain a copy of the license at usr/src/OPENSOLARIS.LICENSE
* See the License for the specific language governing permissions
* and limitations under the License.
*
* When distributing Covered Code, include this CDDL HEADER in each
* file and include the License file at usr/src/OPENSOLARIS.LICENSE.
* If applicable, add the following below this CDDL HEADER, with the
* fields enclosed by brackets "[]" replaced with your own identifying
* information: Portions Copyright [yyyy] [name of copyright owner]
*
* CDDL HEADER END
*/
/*
* Copyright 2004 Sun Microsystems, Inc. All rights reserved.
* Use is subject to license terms.
*/
#pragma ident "%Z%%M% %I% %E% SMI"
#include <stdio.h>
#include <malloc.h>
#include <math.h>
#include <errno.h>
#include <memory.h>
#include <AudioGain.h>
#include <AudioTypePcm.h>
#define irint(d) ((int)d)
// initialize constants for instananeous gain normalization
// initialize constants for weighted gain normalization
const double AudioGain::NoSigWeight = .0000;
// u-law max value converted to floating point
// XXX - patchable dc time constant: TC = 1 / (sample rate / DCfreq)
int DCfreq = 500;
// patchable debugging flag
int debug_agc = 0;
// Constructor
AudioGain():
weighted_peaksum(0.), weighted_sum(0.),
weighted_avgsum(0.), weighted_cnt(0),
{
}
// Destructor
~AudioGain()
{
if (gain_cache != NULL) {
delete gain_cache;
}
}
// Return TRUE if we can handle this data type
{
}
// Return latest instantaneous gain
double AudioGain::
{
return ((double)instant_gain);
}
// Return latest weighted gain
double AudioGain::
{
double g;
// Accumulated sum is averaged by the cache size and number of sums
if ((weighted_cnt > 0) && (gain_cache_size > 0.)) {
g = weighted_avgsum / gain_cache_size;
g /= weighted_cnt;
g -= NoSigWeight;
if (g > HiSigWeightRange) {
g = 1.;
} else if (g < 0.) {
g = 0.;
} else {
g /= HiSigWeightRange;
}
} else {
g = 0.;
}
return (g);
}
// Return latest weighted peak
// Clears the weighted peak for next calculation.
double AudioGain::
{
double g;
// Peak sum is averaged by the cache size
if (gain_cache_size > 0.) {
g = weighted_peaksum / gain_cache_size;
g -= NoSigWeight;
if (g > HiSigWeightRange) {
g = 1.;
} else if (g < 0.) {
g = 0.;
} else {
g /= HiSigWeightRange;
}
} else {
g = 0.;
}
weighted_peaksum = 0.;
return (g);
}
// Return TRUE if signal clipped during last processed buffer
Clipped()
{
return (clipped);
}
// Flush gain state
void AudioGain::
Flush()
{
clipcnt = 0;
DCaverage = 0.;
instant_gain = 0.;
weighted_peaksum = 0.;
weighted_sum = 0.;
weighted_avgsum = 0.;
weighted_cnt = 0;
if (gain_cache != NULL) {
delete gain_cache;
gain_cache = NULL;
}
}
// Process an input buffer according to the specified flags
// The input buffer is consumed if the reference count is zero!
int type)
{
return (AUDIO_ERR_BADARG);
// report error and toss the buffer if it is not referenced
inbuf->Dereference();
return (err);
}
// Set up to convert to floating point; verify all header formats
goto process_error;
}
goto process_error;
}
// Convert to floating-point up front, if necessary
if (err)
goto process_error;
}
// Reference the resulting buffer to make sure it gets ditched later
// run through highpass filter to reject DC
if (type & AUDIO_GAIN_INSTANT)
if (type & AUDIO_GAIN_WEIGHTED)
inbuf->Dereference();
return (AUDIO_SUCCESS);
}
// Run the buffer through a simple, dc filter.
// Buffer is assumed to be floating-point double PCM
void AudioGain::
{
int i;
double val;
double dcweight;
double timeconstant;
double *inptr;
clipcnt = 0;
// Time constant corresponds to the number of samples for 500Hz
// loop through the input buffer, rewriting with weighted data
// XXX - should deal with multi-channel data!
// XXX - for now, check first channel only
// Two max values in a row constitutes clipping
if (lastpeak) {
clipcnt++;
} else {
}
} else {
}
// Add in this value to weighted average
if (val > 1.)
val = 1.;
else if (val < -1.)
val = -1.;
}
}
// Calculate a single energy value averaged from the input buffer
// Buffer is assumed to be floating-point double PCM
void AudioGain::
{
int i;
double val;
double sum;
double sv;
double *inptr;
// loop through the input buffer, calculating gain
// XXX - should deal with multi-channel data!
// XXX - for now, check first channel only
sum = 0.;
// Get absolute value
}
// calculate level meter value (between 0 & 1)
// Normalize to within a reasonable range
val -= LoSigInstantRange;
if (val > HiSigInstantRange) {
val = 1.;
} else if (val < 0.) {
val = 0.;
} else {
val /= HiSigInstantRange;
}
instant_gain = val;
if (debug_agc != 0) {
printf("audio_amplitude: avg = %7.5f log value = %7.5f, "
}
}
// Calculate a weighted gain for agc computations
// Buffer is assumed to be floating-point double PCM
void AudioGain::
{
int i;
double val;
double nosig;
double *inptr;
// Allocate gain cache...all calls will hopefully be the same length
if (gain_cache == NULL) {
gain_cache = new double[frames];
for (i = 0; i < frames; i++) {
gain_cache[i] = 0.;
}
} else if (sz > gain_cache_size) {
}
// Scale up the 'no signal' level to avoid a divide in the inner loop
// For each sample:
// calculate the sum of squares for a window around the sample;
// save the peak sum of squares;
// keep a running average of the sum of squares
//
// XXX - should deal with multi-channel data!
// XXX - for now, check first channel only
weighted_sum += val;
weighted_sum -= gain_cache[i];
if (weighted_sum > weighted_peaksum)
// Only count this sample towards the average if it is
// above threshold (this attempts to keep the volume
// from pumping up when there is no input signal).
if (weighted_sum > nosig) {
weighted_cnt++;
}
}
}