ref: 6781f7b4630e07f84679fd8e79044a825751aac9
parent: b3524a9a9831d9d3dd49bfa8ee1d3ad55c1ff2a2
author: cbagwell <cbagwell>
date: Mon Jul 31 23:23:04 EDT 2000
Adding first version of fft code to stat effect.
--- a/sox.1
+++ b/sox.1
@@ -113,7 +113,7 @@
.br
split
.br
- stat [ \fIdebug\fB | \fI-v\fB ]
+ stat [ \fI-s n\fB ] [\fI-rms\fB ] [ \fI-v\fB ] [ \fI-d\fB ]
.br
stretch [ \fIfactor [ window fade shift fading ]\fB
.br
@@ -901,27 +901,44 @@
Turn a mono sample into a stereo sample by copying
the input channel to the left and right channels.
.TP 10
-stat [ debug | -v ]
+stat [ \fI-s n\fB ] [\fI-rms\fB ] [ \fI-v\fB ] [ \fI-d\fB ]
Do a statistical check on the input file,
-and print results on the standard error file.
-.B stat
-may copy the file untouched from input to output,
-if you select an output file.
+and print results on the standard error file. Audio data is passed
+unmodified from input to output file unless used along with the
+.B -e
+option.
+
The "Volume Adjustment:" field in the statistics
gives you the argument to the
.B -v
.I number
which will make the sample as loud as possible without clipping.
-There is an optional parameter
+
+The option
.B -v
-that will print out the "Volume Adjustment:" field's value and
+will print out the "Volume Adjustment:" field's value only and
return. This could be of use in scripts to auto convert the
-volume. There is an also an optional parameter
-.B debug
-that will place sox into debug mode and print out a hex dump of the
+volume.
+
+The
+.B -s n
+option is used to scale the input data by a given factor. The default value
+of n is the max value of a signed long variable (0x7fffffff). Internal effects
+always work with signed long PCM data and so the value should relate to this
+fact.
+
+The
+.B -rms
+option will convert all output average values to \fIroot mean square\fR
+format.
+
+There is also an optional parameter
+.B -d
+that will print out a hex dump of the
sound file from the internal buffer that is in 32-bit signed PCM data.
This is mainly only of use in tracking down endian problems that
creep in to sox on cross-platform versions.
+
.TP 10
stretch \fIfactor [window fade shift fading]\fB
Time stretch file by a given factor. Change duration without affecting the pitch.
@@ -984,16 +1001,13 @@
enforces certain effects.
If the two files have different sampling
rates, the requested effect must be one of
-.B copy,
+.B polyphase, rate,
or
-.B rate,
-." or
-." .B resample.
+.B resample.
If the two files have different numbers of channels,
the
.B avg
-." or other channel mixing
-effect must be requested.
+or other channel mixing effect must be requested.
.SH BUGS
The syntax is horrific. Thats the breaks when trying to handle all things from the command line.
.P
--- a/src/handlers.c
+++ b/src/handlers.c
@@ -601,6 +601,7 @@
extern int st_stat_getopts();
extern int st_stat_start();
extern int st_stat_flow();
+extern int st_stat_drain();
extern int st_stat_stop();
extern int st_stretch_getopts();
@@ -731,7 +732,7 @@
st_null_drain, st_split_stop},
{"stat", ST_EFF_MCHAN | ST_EFF_REPORT | ST_EFF_RATE | ST_EFF_CHAN,
st_stat_getopts, st_stat_start, st_stat_flow,
- st_null_drain, st_stat_stop},
+ st_stat_drain, st_stat_stop},
{"stretch", 0,
st_stretch_getopts, st_stretch_start, st_stretch_flow,
st_stretch_drain, st_stretch_stop},
--- a/src/stat.c
+++ b/src/stat.c
@@ -1,4 +1,3 @@
-
/*
* July 5, 1991
* Copyright 1991 Lance Norskog And Sundry Contributors
@@ -12,7 +11,9 @@
* Sound Tools statistics "effect" file.
*
* Build various statistics on file and print them.
- * No output.
+ *
+ * Output is unmodified from input.
+ *
*/
#include <math.h>
@@ -30,7 +31,13 @@
ULONG read; /* samples processed */
int volume;
int srms;
+ int fft;
ULONG bin[4];
+ double *re;
+ double *im;
+ ULONG fft_bits;
+ ULONG fft_size;
+ ULONG fft_offset;
} *stat_t;
@@ -47,13 +54,16 @@
stat->scale = MAXLONG;
stat->volume = 0;
stat->srms = 0;
+ stat->fft = 0;
+
while (n>0)
{
- if (!(strcmp(argv[0], "-v"))) {
+ if (!(strcmp(argv[0], "-v")))
+ {
stat->volume = 1;
- goto did1;
}
- if (!(strcmp(argv[0], "-s"))) {
+ else if (!(strcmp(argv[0], "-s")))
+ {
double scale;
if (n <= 1)
@@ -61,10 +71,6 @@
st_fail("-s option: invalid argument");
return (ST_EOF);
}
- if (!strcmp(argv[1],"rms")) {
- stat->srms=1;
- goto did2;
- }
if (!sscanf(argv[1], "%lf", &scale))
{
st_fail("-s option: invalid argument");
@@ -71,21 +77,20 @@
return (ST_EOF);
}
stat->scale = scale;
- goto did2;
+
+ /* Two option argument. Account for this */
+ --n; ++argv;
}
- if (!(strcmp(argv[0], "-rms"))) {
- double scale;
- if (n <= 1 || !sscanf(argv[1], "%lf", &scale))
- {
- st_fail("-s option expects float argument");
- return(ST_EOF);
- }
+ else if (!(strcmp(argv[0], "-rms")))
+ {
stat->srms = 1;
- goto did2;
}
- if (!(strcmp(argv[0], "debug"))) {
+ else if (!(strcmp(argv[0], "-freq")))
+ {
+ stat->fft = 1;
+ }
+ else if (!(strcmp(argv[0], "debug"))) {
stat->volume = 2;
- goto did1;
}
else
{
@@ -92,8 +97,7 @@
st_fail("Summary effect: unknown option");
return(ST_EOF);
}
- did2: --n; ++argv;
- did1: --n; ++argv;
+ --n; ++argv;
}
return (ST_SUCCESS);
}
@@ -106,6 +110,7 @@
{
stat_t stat = (stat_t) effp->priv;
int i;
+ LONG bitmask;
stat->min = stat->max = 0;
stat->asum = 0;
@@ -120,6 +125,37 @@
for (i = 0; i < 4; i++)
stat->bin[i] = 0;
+ stat->fft_size = 4096;
+ stat->re = 0;
+ stat->im = 0;
+
+ if (stat->fft)
+ {
+ bitmask = 0x80000000L;
+ stat->fft_bits = 31;
+ stat->fft_offset = 0;
+ while (bitmask && !(stat->fft_size & bitmask))
+ {
+ bitmask = bitmask >> 1;
+ stat->fft_bits--;
+ }
+
+ if (bitmask && (stat->fft_size & ~bitmask))
+ {
+ st_fail("FFT can only use sample buffers of 2^n. Buffer size used is %ld\n",stat->fft_size);
+ return(ST_EOF);
+ }
+
+ stat->re = malloc(sizeof(double) * stat->fft_size);
+ stat->im = malloc(sizeof(double) * stat->fft_size);
+
+ if (!stat->re || !stat->im)
+ {
+ st_fail("Unable to allocate memory for FFT buffers.\n");
+ return (ST_EOF);
+ }
+ }
+
return (ST_SUCCESS);
}
@@ -128,6 +164,8 @@
* Return number of samples processed.
*/
+extern int FFT(short dir,long m,double *x,double *y);
+
int st_stat_flow(effp, ibuf, obuf, isamp, osamp)
eff_t effp;
LONG *ibuf, *obuf;
@@ -134,8 +172,10 @@
LONG *isamp, *osamp;
{
stat_t stat = (stat_t) effp->priv;
- int len, done;
+ int len, done, x, x1;
short count;
+ float magnitude;
+ float ffa;
count = 0;
len = ((*isamp > *osamp) ? *osamp : *isamp);
@@ -144,6 +184,38 @@
if (stat->read == 0) /* 1st sample */
stat->min = stat->max = stat->last = (*ibuf)/stat->scale;
+ if (stat->fft)
+ {
+ for (x = 0; x < len; x++)
+ {
+ stat->re[stat->fft_offset] = ibuf[x];
+ stat->im[stat->fft_offset++] = 0;
+
+ if (stat->fft_offset >= stat->fft_size)
+ {
+ stat->fft_offset = 0;
+ FFT(1,stat->fft_bits,stat->re,stat->im);
+ ffa = (float)effp->ininfo.rate/stat->fft_size;
+ for (x1= 0; x1 < stat->fft_size/2; x1++)
+ {
+ if (x1 == 0 || x1 == 1)
+ {
+ magnitude = 0.0; /* no DC */
+ }
+ else
+ {
+ magnitude = sqrt(stat->re[x1]*stat->re[x1] + stat->im[x1]*stat->im[x1]);
+ if (x1 == (stat->fft_size/2) - 1)
+ magnitude *= 2.0;
+ }
+ printf("%f %f\n",ffa*x1, magnitude);
+ }
+ }
+
+ }
+ }
+
+
for(done = 0; done < len; done++) {
long lsamp;
double samp, delta;
@@ -153,9 +225,10 @@
stat->bin[RIGHT(lsamp,30)+2]++;
*obuf++ = lsamp;
+
if (stat->volume == 2)
{
- fprintf(stderr,"%f ",samp);
+ fprintf(stderr,"%08lx ",lsamp);
if (count++ == 5)
{
fprintf(stderr,"\n");
@@ -191,6 +264,57 @@
}
/*
+ * Process tail of input samples.
+ */
+int st_stat_drain(effp, obuf, osamp)
+eff_t effp;
+LONG *obuf;
+LONG *osamp;
+{
+ stat_t stat = (stat_t) effp->priv;
+ int x;
+ float magnitude;
+ float ffa;
+
+ /* When we run out of samples, then we need to pad buffer with
+ * zeros and then run FFT one last time. Only perform this
+ * operation if there are at least 1 sample in the buffer.
+ */
+
+ if (stat->fft && stat->fft_offset)
+ {
+ /* When we run out of samples, then we need to pad buffer with
+ * zeros and then run FFT one last time. Only perform this
+ * operation if there are at least 1 sample in the buffer.
+ */
+ for (x = stat->fft_offset; x < stat->fft_size; x++)
+ {
+ stat->re[x] = 0;
+ stat->im[x] = 0;
+ }
+ FFT(1,stat->fft_bits,stat->re,stat->im);
+ ffa = (float)effp->ininfo.rate/stat->fft_size;
+ for (x=0; x < stat->fft_size/2; x++)
+ {
+ if (x == 0 || x == 1)
+ {
+ magnitude = 0.0; /* no DC */
+ }
+ else
+ {
+ magnitude = sqrt(stat->re[x]*stat->re[x] + stat->im[x]*stat->im[x]);
+ if (x != (stat->fft_size/2) - 1)
+ magnitude *= 2.0;
+ }
+ printf("%f %f\n",ffa*x, magnitude);
+ }
+ }
+
+ *osamp = 0;
+ return (ST_SUCCESS);
+}
+
+/*
* Do anything required when you stop reading samples.
* Don't close input file!
*/
@@ -231,7 +355,7 @@
return (ST_SUCCESS);
}
if (stat->volume == 2) {
- fprintf(stderr, "\n");
+ fprintf(stderr, "\n\n");
}
/* print out the info */
fprintf(stderr, "Samples read: %12lu\n", stat->read);
@@ -293,6 +417,95 @@
fprintf (stderr, "\nCan't guess the type\n");
}
}
+
+ /* Release FFT memory if allocated */
+ if (stat->re)
+ free((void *)stat->re);
+ if (stat->im)
+ free((void *)stat->im);
+
return (ST_SUCCESS);
+}
+
+
+/*
+ This computes an in-place complex-to-complex FFT
+ x and y are the real and imaginary arrays of 2^(m-1) points.
+ dir = 1 gives forward transform
+ dir = -1 gives reverse transform
+*/
+int FFT(dir,m,re,im)
+short dir;
+long m;
+double *re,*im;
+{
+ long n,i,i1,j,k,i2,l,l1,l2;
+ double c1,c2,tre,tim,t1,t2,u1,u2,z;
+
+ /* Calculate the number of points */
+ n = 1;
+ for (i=0;i<m;i++)
+ n *= 2;
+
+ /* Do the bit reversal */
+ i2 = n >> 1;
+
+ j = 0;
+
+ for (i=0;i<n-1;i++) {
+ if (i < j) {
+ tre = re[i];
+ tim = im[i];
+ re[i] = re[j];
+ im[i] = im[j];
+ re[j] = tre;
+ im[j] = tim;
+ }
+ k = i2;
+ while (k <= j) {
+ j -= k;
+ k >>= 1;
+ }
+ j += k;
+ }
+
+ /* Compute the FFT */
+ c1 = -1.0;
+ c2 = 0.0;
+ l2 = 1;
+ for (l=0;l<m;l++) {
+ l1 = l2;
+ l2 <<= 1;
+ u1 = 1.0;
+ u2 = 0.0;
+ for (j=0;j<l1;j++) {
+ for (i=j;i<n;i+=l2) {
+ i1 = i + l1;
+ t1 = u1 * re[i1] - u2 * im[i1];
+ t2 = u1 * im[i1] + u2 * re[i1];
+ re[i1] = re[i] - t1;
+ im[i1] = im[i] - t2;
+ re[i] += t1;
+ im[i] += t2;
+ }
+ z = u1 * c1 - u2 * c2;
+ u2 = u1 * c2 + u2 * c1;
+ u1 = z;
+ }
+ c2 = sqrt((1.0 - c1) / 2.0);
+ if (dir == 1)
+ c2 = -c2;
+ c1 = sqrt((1.0 + c1) / 2.0);
+ }
+
+ /* Scaling for forward transform */
+ if (dir == 1) {
+ for (i=0;i<n;i++) {
+ re[i] /= n;
+ im[i] /= n;
+ }
+ }
+
+ return ST_SUCCESS;
}