rate: add some sanity checking
[sox.git] / src / stat.c
blobcdea27cca1aea851772e0ddf6a4ea3e4e37bb521
1 /* libSoX statistics "effect" file.
3 * Compute various statistics on file and print them.
5 * Output is unmodified from input.
7 * July 5, 1991
8 * Copyright 1991 Lance Norskog And Sundry Contributors
9 * This source code is freely redistributable and may be used for
10 * any purpose. This copyright notice must be maintained.
11 * Lance Norskog And Sundry Contributors are not responsible for
12 * the consequences of using this software.
15 #include "sox_i.h"
17 #include <string.h>
19 /* Private data for stat effect */
20 typedef struct {
21 double min, max, mid;
22 double asum;
23 double sum1, sum2; /* amplitudes */
24 double dmin, dmax;
25 double dsum1, dsum2; /* deltas */
26 double scale; /* scale-factor */
27 double last; /* previous sample */
28 uint64_t read; /* samples processed */
29 int volume;
30 int srms;
31 int fft;
32 unsigned long bin[4];
33 float *re_in;
34 float *re_out;
35 unsigned long fft_size;
36 unsigned long fft_offset;
37 } priv_t;
41 * Process options
43 static int sox_stat_getopts(sox_effect_t * effp, int argc, char **argv)
45 priv_t * stat = (priv_t *) effp->priv;
47 stat->scale = SOX_SAMPLE_MAX;
48 stat->volume = 0;
49 stat->srms = 0;
50 stat->fft = 0;
52 --argc, ++argv;
53 for (; argc > 0; argc--, argv++) {
54 if (!(strcmp(*argv, "-v")))
55 stat->volume = 1;
56 else if (!(strcmp(*argv, "-s"))) {
57 if (argc <= 1) {
58 lsx_fail("-s option: invalid argument");
59 return SOX_EOF;
61 argc--, argv++; /* Move to next argument. */
62 if (!sscanf(*argv, "%lf", &stat->scale)) {
63 lsx_fail("-s option: invalid argument");
64 return SOX_EOF;
66 } else if (!(strcmp(*argv, "-rms")))
67 stat->srms = 1;
68 else if (!(strcmp(*argv, "-freq")))
69 stat->fft = 1;
70 else if (!(strcmp(*argv, "-d")))
71 stat->volume = 2;
72 else {
73 lsx_fail("Summary effect: unknown option");
74 return SOX_EOF;
78 return SOX_SUCCESS;
82 * Prepare processing.
84 static int sox_stat_start(sox_effect_t * effp)
86 priv_t * stat = (priv_t *) effp->priv;
87 int i;
89 stat->min = stat->max = stat->mid = 0;
90 stat->asum = 0;
91 stat->sum1 = stat->sum2 = 0;
93 stat->dmin = stat->dmax = 0;
94 stat->dsum1 = stat->dsum2 = 0;
96 stat->last = 0;
97 stat->read = 0;
99 for (i = 0; i < 4; i++)
100 stat->bin[i] = 0;
102 stat->fft_size = 4096;
103 stat->re_in = stat->re_out = NULL;
105 if (stat->fft) {
106 stat->fft_offset = 0;
107 stat->re_in = lsx_malloc(sizeof(float) * stat->fft_size);
108 stat->re_out = lsx_malloc(sizeof(float) * (stat->fft_size / 2 + 1));
111 return SOX_SUCCESS;
115 * Print power spectrum to given stream
117 static void print_power_spectrum(unsigned samples, double rate, float *re_in, float *re_out)
119 float ffa = rate / samples;
120 unsigned i;
122 lsx_power_spectrum_f((int)samples, re_in, re_out);
123 for (i = 0; i < samples / 2; i++) /* FIXME: should be <= samples / 2 */
124 fprintf(stderr, "%f %f\n", ffa * i, re_out[i]);
128 * Processed signed long samples from ibuf to obuf.
129 * Return number of samples processed.
131 static int sox_stat_flow(sox_effect_t * effp, const sox_sample_t *ibuf, sox_sample_t *obuf,
132 size_t *isamp, size_t *osamp)
134 priv_t * stat = (priv_t *) effp->priv;
135 int done, x, len = min(*isamp, *osamp);
136 short count = 0;
138 if (len) {
139 if (stat->read == 0) /* 1st sample */
140 stat->min = stat->max = stat->mid = stat->last = (*ibuf)/stat->scale;
142 if (stat->fft) {
143 for (x = 0; x < len; x++) {
144 SOX_SAMPLE_LOCALS;
145 stat->re_in[stat->fft_offset++] = SOX_SAMPLE_TO_FLOAT_32BIT(ibuf[x], effp->clips);
147 if (stat->fft_offset >= stat->fft_size) {
148 stat->fft_offset = 0;
149 print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out);
155 for (done = 0; done < len; done++) {
156 long lsamp = *ibuf++;
157 double delta, samp = (double)lsamp / stat->scale;
158 /* work in scaled levels for both sample and delta */
159 stat->bin[(lsamp >> 30) + 2]++;
160 *obuf++ = lsamp;
162 if (stat->volume == 2) {
163 fprintf(stderr,"%08lx ",lsamp);
164 if (count++ == 5) {
165 fprintf(stderr,"\n");
166 count = 0;
170 /* update min/max */
171 if (stat->min > samp)
172 stat->min = samp;
173 else if (stat->max < samp)
174 stat->max = samp;
175 stat->mid = stat->min / 2 + stat->max / 2;
177 stat->sum1 += samp;
178 stat->sum2 += samp*samp;
179 stat->asum += fabs(samp);
181 delta = fabs(samp - stat->last);
182 if (delta < stat->dmin)
183 stat->dmin = delta;
184 else if (delta > stat->dmax)
185 stat->dmax = delta;
187 stat->dsum1 += delta;
188 stat->dsum2 += delta*delta;
190 stat->last = samp;
192 stat->read += len;
195 *isamp = *osamp = len;
196 /* Process all samples */
198 return SOX_SUCCESS;
202 * Process tail of input samples.
204 static int sox_stat_drain(sox_effect_t * effp, sox_sample_t *obuf UNUSED, size_t *osamp)
206 priv_t * stat = (priv_t *) effp->priv;
208 /* When we run out of samples, then we need to pad buffer with
209 * zeros and then run FFT one last time to process any unprocessed
210 * samples.
212 if (stat->fft && stat->fft_offset) {
213 unsigned int x;
215 for (x = stat->fft_offset; x < stat->fft_size; x++)
216 stat->re_in[x] = 0;
218 print_power_spectrum((unsigned) stat->fft_size, effp->in_signal.rate, stat->re_in, stat->re_out);
221 *osamp = 0;
222 return SOX_EOF;
226 * Do anything required when you stop reading samples.
227 * Don't close input file!
229 static int sox_stat_stop(sox_effect_t * effp)
231 priv_t * stat = (priv_t *) effp->priv;
232 double amp, scale, rms = 0, freq;
233 double x, ct;
235 ct = stat->read;
237 if (stat->srms) { /* adjust results to units of rms */
238 double f;
239 rms = sqrt(stat->sum2/ct);
240 f = 1.0/rms;
241 stat->max *= f;
242 stat->min *= f;
243 stat->mid *= f;
244 stat->asum *= f;
245 stat->sum1 *= f;
246 stat->sum2 *= f*f;
247 stat->dmax *= f;
248 stat->dmin *= f;
249 stat->dsum1 *= f;
250 stat->dsum2 *= f*f;
251 stat->scale *= rms;
254 scale = stat->scale;
256 amp = -stat->min;
257 if (amp < stat->max)
258 amp = stat->max;
260 /* Just print the volume adjustment */
261 if (stat->volume == 1 && amp > 0) {
262 fprintf(stderr, "%.3f\n", SOX_SAMPLE_MAX/(amp*scale));
263 return SOX_SUCCESS;
265 if (stat->volume == 2)
266 fprintf(stderr, "\n\n");
267 /* print out the info */
268 fprintf(stderr, "Samples read: %12" PRIu64 "\n", stat->read);
269 fprintf(stderr, "Length (seconds): %12.6f\n", (double)stat->read/effp->in_signal.rate/effp->in_signal.channels);
270 if (stat->srms)
271 fprintf(stderr, "Scaled by rms: %12.6f\n", rms);
272 else
273 fprintf(stderr, "Scaled by: %12.1f\n", scale);
274 fprintf(stderr, "Maximum amplitude: %12.6f\n", stat->max);
275 fprintf(stderr, "Minimum amplitude: %12.6f\n", stat->min);
276 fprintf(stderr, "Midline amplitude: %12.6f\n", stat->mid);
277 fprintf(stderr, "Mean norm: %12.6f\n", stat->asum/ct);
278 fprintf(stderr, "Mean amplitude: %12.6f\n", stat->sum1/ct);
279 fprintf(stderr, "RMS amplitude: %12.6f\n", sqrt(stat->sum2/ct));
281 fprintf(stderr, "Maximum delta: %12.6f\n", stat->dmax);
282 fprintf(stderr, "Minimum delta: %12.6f\n", stat->dmin);
283 fprintf(stderr, "Mean delta: %12.6f\n", stat->dsum1/(ct-1));
284 fprintf(stderr, "RMS delta: %12.6f\n", sqrt(stat->dsum2/(ct-1)));
285 freq = sqrt(stat->dsum2/stat->sum2)*effp->in_signal.rate/(M_PI*2);
286 fprintf(stderr, "Rough frequency: %12d\n", (int)freq);
288 if (amp>0)
289 fprintf(stderr, "Volume adjustment: %12.3f\n", SOX_SAMPLE_MAX/(amp*scale));
291 if (stat->bin[2] == 0 && stat->bin[3] == 0)
292 fprintf(stderr, "\nProbably text, not sound\n");
293 else {
295 x = (float)(stat->bin[0] + stat->bin[3]) / (float)(stat->bin[1] + stat->bin[2]);
297 if (x >= 3.0) { /* use opposite encoding */
298 if (effp->in_encoding->encoding == SOX_ENCODING_UNSIGNED)
299 fprintf(stderr,"\nTry: -t raw -e signed-integer -b 8 \n");
300 else
301 fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n");
302 } else if (x <= 1.0 / 3.0)
303 ; /* correctly decoded */
304 else if (x >= 0.5 && x <= 2.0) { /* use ULAW */
305 if (effp->in_encoding->encoding == SOX_ENCODING_ULAW)
306 fprintf(stderr,"\nTry: -t raw -e unsigned-integer -b 8 \n");
307 else
308 fprintf(stderr,"\nTry: -t raw -e mu-law -b 8 \n");
309 } else
310 fprintf(stderr, "\nCan't guess the type\n");
313 /* Release FFT memory */
314 free(stat->re_in);
315 free(stat->re_out);
317 return SOX_SUCCESS;
321 static sox_effect_handler_t sox_stat_effect = {
322 "stat",
323 "[ -s N ] [ -rms ] [-freq] [ -v ] [ -d ]",
324 SOX_EFF_MCHAN | SOX_EFF_MODIFY,
325 sox_stat_getopts,
326 sox_stat_start,
327 sox_stat_flow,
328 sox_stat_drain,
329 sox_stat_stop,
330 NULL, sizeof(priv_t)
333 const sox_effect_handler_t *lsx_stat_effect_fn(void)
335 return &sox_stat_effect;