

/*
 * July 5, 1991
 * Copyright 1991 Lance Norskog And Sundry Contributors
 * This source code is freely redistributable and may be used for
 * any purpose.  This copyright notice must be maintained. 
 * Lance Norskog And Sundry Contributors are not responsible for 
 * the consequences of using this software.
 */

/*
 * Sound Tools statistics "effect" file.
 *
 * Build various statistics on file and print them.
 * No output.
 */

#include "st.h"

/* Private data for STAT effect */
typedef struct statstuff {
	long	min, max, mean;		/* amplitudes */
	long	dmin, dmax, dmean;	/* deltas */
	long	last;			/* previous sample */
	int	first;
	int	total;
	int	volume;
} *stat_t;

#define	abs(val)	(((val) < 0) ? -(val) : (val))

/*
 * Process options
 */
stat_getopts(effp, n, argv) 
eff_t effp;
int n;
char **argv;
{
	stat_t stat = (stat_t) effp->priv;

	stat->volume = 0;
	if (n)
		if (strcmp(argv[0], "-V"))
			stat->volume = 1;
		else
			fail("Summary effect takes no options.");
}

/*
 * Prepare processing.
 */
stat_start(effp)
eff_t effp;
{
	stat_t stat = (stat_t) effp->priv;

	stat->min = stat->dmin = 0x7fffffff;
	stat->max = stat->dmax = 0x80000000;
	stat->first = 1;
}

/*
 * Processed signed long samples from ibuf to obuf.
 * Return number of samples processed.
 */

stat_flow(effp, ibuf, obuf, isamp, osamp)
eff_t effp;
long *ibuf, *obuf;
int *isamp, *osamp;
{
	stat_t stat = (stat_t) effp->priv;
	int len, done;
	long samp, delta;
	
	len = ((*isamp > *osamp) ? *osamp : *isamp);
	for(done = 0; done < len; done++) {
		/* work in absolute levels for both sample and delta */
		samp = *ibuf++;
	        *obuf++ = samp;

		samp = abs(samp);
		if (samp < stat->min)
			stat->min = samp;
		if (samp > stat->max)
			stat->max = samp;
		if (stat->first) {
			stat->first = 0;
			stat->mean = samp;
			stat->dmean = 0;
		} else  {
			/* overflow avoidance */
			if ((stat->mean > 0x20000000) || (samp > 0x20000000))
				stat->mean = stat->mean/2 + samp/2;
			else
				stat->mean = (stat->mean + samp)/2;

			delta = abs(samp - stat->last);
			if (delta < stat->dmin)
				stat->dmin = delta;
			if (delta > stat->dmax)
				stat->dmax = delta;
			/* overflow avoidance */
			if ((delta > 0x20000000) || (stat->dmean > 0x20000000))
				stat->dmean = stat->dmean/2 + delta/2;
			else
				stat->dmean = (stat->dmean + delta)/2;
		}
		stat->last = samp;
	}
	/* Process all samples */
}

/*
 * Do anything required when you stop reading samples.  
 * Don't close input file! 
 */
stat_stop(effp)
eff_t effp;
{
	stat_t stat = (stat_t) effp->priv;
	double amp, range;

	stat->min   = RIGHT(stat->min, 16);
	stat->max   = RIGHT(stat->max, 16);
	stat->mean  = RIGHT(stat->mean, 16);
	stat->dmin  = RIGHT(stat->dmin, 16);
	stat->dmax  = RIGHT(stat->dmax, 16);
	stat->dmean = RIGHT(stat->dmean, 16);

	range = 32767.0;

	amp = - stat->min;
	if (amp < stat->max)
		amp = stat->max;
	/* Just print the volume adjustment */
	if (stat->volume) {
		fprintf(stderr, "%.3f\n", 32767.0/amp);
		return;
	}
	/* print them out */
	fprintf(stderr, "Maximum amplitude: %.3f\n", stat->max/range);
	fprintf(stderr, "Minimum amplitude: %.3f\n", stat->min/range);
	fprintf(stderr, "Mean    amplitude: %.3f\n", stat->mean/range);

	fprintf(stderr, "Maximum delta:     %.3f\n", stat->dmax/range);
	fprintf(stderr, "Minimum delta:     %.3f\n", stat->dmin/range);
	fprintf(stderr, "Mean    delta:     %.3f\n", stat->dmean/range);

	fprintf(stderr, "Volume adjustment: %.3f\n", 32767.0/amp);
}




