1 /* Copyright (C) 1999--2005 Chris Vaill
2    This file is part of normalize.
3 
4    This program is free software; you can redistribute it and/or modify
5    it under the terms of the GNU General Public License as published by
6    the Free Software Foundation; either version 2 of the License, or
7    (at your option) any later version.
8 
9    This program is distributed in the hope that it will be useful,
10    but WITHOUT ANY WARRANTY; without even the implied warranty of
11    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
12    GNU General Public License for more details.
13 
14    You should have received a copy of the GNU General Public License
15    along with this program; if not, write to the Free Software
16    Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301  USA*/
17 
18 #define _POSIX_C_SOURCE 2
19 
20 #include "config.h"
21 
22 #include <stdio.h>
23 #include <time.h>
24 #if STDC_HEADERS
25 # include <stdlib.h>
26 # include <string.h>
27 #else
28 # if HAVE_STDLIB_H
29 #  include <stdlib.h>
30 # endif
31 # if HAVE_STRING_H
32 #  include <string.h>
33 # else
34 #  ifndef HAVE_STRCHR
35 #   define strchr index
36 #   define strrchr rindex
37 #  endif
38 #  ifndef HAVE_MEMCPY
39 #   define memcpy(d,s,n) bcopy((s),(d),(n))
40 #   define memmove(d,s,n) bcopy((s),(d),(n))
41 #  endif
42 # endif
43 #endif
44 #if HAVE_MATH_H
45 # include <math.h>
46 #endif
47 #if HAVE_CTYPE_H
48 # include <ctype.h>
49 #endif
50 #if HAVE_UNISTD_H
51 # include <unistd.h>
52 #endif
53 #if HAVE_ERRNO_H
54 # include <errno.h>
55 #endif
56 #if HAVE_SYS_TYPES_H
57 # include <sys/types.h>
58 #endif
59 #if HAVE_SYS_STAT_H
60 # include <sys/stat.h>
61 #endif
62 #if HAVE_FCNTL_H
63 # include <fcntl.h>
64 #endif
65 #if HAVE_SYS_MMAN_H
66 # include <sys/mman.h>
67 #endif
68 
69 #ifdef ENABLE_NLS
70 # define _(msgid) gettext (msgid)
71 # include <libintl.h>
72 # if HAVE_LOCALE_H
73 #  include <locale.h>
74 # endif
75 #else
76 # define _(msgid) (msgid)
77 #endif
78 #define N_(msgid) (msgid)
79 
80 #include "getopt.h"
81 #include "common.h"
82 
83 extern double signal_max_power(char *, struct signal_info *);
84 extern double signal_max_power_stream(FILE *, char *, struct signal_info *);
85 extern int apply_gain(char *fname, double, struct signal_info *);
86 
87 void compute_levels(struct signal_info *sis, char **fnames, int nfiles);
88 double average_levels(struct signal_info *sis, int nfiles, double threshold);
89 int strncaseeq(const char *s1, const char *s2, size_t n);
90 char *basename(char *path);
91 void *xmalloc(size_t size);
92 
93 extern char version[];
94 char *progname;
95 struct progress_struct progress_info;
96 
97 void
usage_short()98 usage_short()
99 {
100   fprintf(stderr, _("Usage: %s [OPTION]... [FILE]...\n"), progname);
101   fprintf(stderr, _("Try `%s --help' for more information.\n"), progname);
102 }
103 
104 void
usage()105 usage()
106 {
107   printf(_("\
108 Usage: %s [OPTION]... [FILE]...\n\
109 Normalize volume of multiple audio files\n\
110 \n\
111   -a, --amplitude=AMP          normalize the volume to the target amplitude\n\
112                                  AMP [default -12dBFS]\n\
113   -b, --batch                  batch mode: get average of all levels, and\n\
114                                  use one adjustment, based on the average\n\
115                                  level, for all files\n\
116       --clipping               turn off limiter; do clipping instead\n\
117       --fractions              display levels as fractions of maximum\n\
118                                  amplitude instead of decibels\n\
119   -g, --gain=ADJ               don't compute levels, just apply adjustment\n\
120                                  ADJ to the files.  Use the suffix \"dB\"\n\
121                                  to indicate a gain in decibels.\n\
122   -l, --limiter=LEV            limit all samples above LEV [default -6dBFS]\n\
123   -m, --mix                    mix mode: get average of all levels, and\n\
124                                  normalize volume of each file to the\n\
125                                  average\n\
126   -n, --no-adjust              compute and display the volume adjustment,\n\
127                                  but don't apply it to any of the files\n\
128       --peak                   adjust by peak level instead of using\n\
129                                  loudness analysis\n\
130   -q, --quiet                  quiet (decrease verbosity to zero)\n\
131   -t, --average-threshold=T    when computing average level, ignore any\n\
132                                  levels more than T decibels from average\n\
133   -T, --adjust-threshold=T     don't bother applying any adjustment smaller\n\
134                                  than T decibels\n\
135   -v, --verbose                increase verbosity\n\
136   -w, --output-bitwidth=W      force adjusted files to have W-bit samples\n\
137 \n\
138   -V, --version                display version information and exit\n\
139   -h, --help                   display this help and exit\n\
140 \n\
141 Report bugs to <chrisvaill@gmail.com>.\n"), progname);
142 }
143 
144 enum {
145   OPT_CLIPPING     = 0x101,
146   OPT_PEAK         = 0x102,
147   OPT_FRACTIONS    = 0x103,
148   OPT_ID3_COMPAT   = 0x104,
149   OPT_ID3_UNSYNC   = 0x105,
150   OPT_NO_PROGRESS  = 0x106,
151   OPT_QUERY        = 0x107,
152   OPT_FRONTEND     = 0x108,
153 };
154 
155 /* options */
156 int verbose = VERBOSE_PROGRESS;
157 int do_print_only = FALSE;
158 int do_apply_gain = TRUE;
159 double target = 0.2511886431509580; /* -12dBFS */
160 double threshold = -1.0; /* in decibels */
161 int do_compute_levels = TRUE;
162 int output_bitwidth = 0;
163 int gain_in_decibels = FALSE;
164 int batch_mode = FALSE;
165 int mix_mode = FALSE;
166 int use_limiter = TRUE;
167 int use_peak = FALSE;
168 int use_fractions = FALSE;
169 int show_progress = TRUE;
170 int do_query = FALSE;
171 int frontend = FALSE;
172 double lmtr_lvl = 0.5;
173 double adjust_thresh = 0.125; /* don't adjust less than this many dB */
174 int id3_compat = FALSE;
175 int id3_unsync = FALSE;
176 
177 int
main(int argc,char * argv[])178 main(int argc, char *argv[])
179 {
180   int c, i, nfiles, ret;
181   struct signal_info *sis, *psi;
182   double level = 0.0, gain = 1.0, dBdiff = 0.0;
183   char **fnames, *p;
184   char cbuf[32];
185   struct stat st;
186   int file_needs_adjust = FALSE;
187 
188   struct option longopts[] = {
189     {"help", 0, NULL, 'h'},
190     {"version", 0, NULL, 'V'},
191     {"no-adjust", 0, NULL, 'n'},
192     {"quiet", 0, NULL, 'q'},
193     {"verbose", 0, NULL, 'v'},
194     {"batch", 0, NULL, 'b'},
195     {"amplitude", 1, NULL, 'a'},
196     {"average-threshold", 1, NULL, 't'},
197     {"threshold", 1, NULL, 't'}, /* deprecate */
198     {"gain", 1, NULL, 'g'},
199     {"limiter", 1, NULL, 'l'},
200     {"adjust-threshold", 1, NULL, 'T'},
201     {"mix", 0, NULL, 'm'},
202     {"compression", 0, NULL, 'c'}, /* deprecate */
203     {"limit", 0, NULL, 'c'}, /* deprecate */
204     {"output-bitwidth", 1, NULL, 'w'},
205     {"clipping", 0, NULL, OPT_CLIPPING},
206     {"peak", 0, NULL, OPT_PEAK},
207     {"fractions", 0, NULL, OPT_FRACTIONS},
208     {"id3-compat", 0, NULL, OPT_ID3_COMPAT},
209     {"id3-unsync", 0, NULL, OPT_ID3_UNSYNC},
210     {"no-progress", 0, NULL, OPT_NO_PROGRESS},
211     {"query", 0, NULL, OPT_QUERY},
212     {"frontend", 0, NULL, OPT_FRONTEND},
213     {NULL, 0, NULL, 0}
214   };
215 
216 #ifdef __EMX__
217   /* This gives wildcard expansion on Non-POSIX shells with OS/2 */
218   _wildcard(&argc, &argv);
219 #endif
220 
221   /* get program name */
222   progname = basename(argv[0]);
223   if (strlen(progname) > 16)
224     progname[16] = '\0';
225 
226 #if ENABLE_NLS
227   setlocale(LC_ALL, "");
228   bindtextdomain(PACKAGE, LOCALEDIR);
229   textdomain(PACKAGE);
230 #endif
231 
232   /* get args */
233   while ((c = getopt_long(argc, argv, "hVnvqbmcT:l:g:a:t:w:", longopts, NULL)) != EOF) {
234     switch(c) {
235     case 'a':
236       target = strtod(optarg, &p);
237 
238       /* check if "dB" or "dBFS" is given after number */
239       while(isspace(*p))
240 	p++;
241       if (strncaseeq(p, "db", 2)) {
242 	/* amplitude given as dBFS */
243 
244 	if (target > 0) {
245 	  target = -target;
246 	  fprintf(stderr, _("%s: normalizing to %f dBFS\n"), progname, target);
247 	}
248 
249 	/* translate to fraction */
250 	target = DBFSTOAMP(target);
251 
252       } else {
253 
254 	/* amplitude given as fraction */
255 	if (target < 0 || target > 1.0) {
256 	  fprintf(stderr, _("%s: error: bad target amplitude %f\n"),
257 		  progname, target);
258 	  exit(1);
259 	}
260       }
261       break;
262     case 't':
263       /* a negative threshold means don't use threshold (use 2*stddev) */
264       threshold = strtod(optarg, NULL);
265       break;
266     case 'g':
267       gain = strtod(optarg, &p);
268 
269       /* check if "dB" is given after number */
270       while(isspace(*p))
271 	p++;
272       if (strncaseeq(p, "db", 2)) {
273 	dBdiff = gain;
274 	gain = DBTOFRAC(dBdiff);
275 	gain_in_decibels = TRUE;
276       }
277 
278       do_compute_levels = FALSE;
279       batch_mode = TRUE;
280       if (gain < 0) {
281 	fprintf(stderr, _("%s: invalid argument to -g option\n"), progname);
282 	usage_short();
283 	exit(1);
284       }
285       break;
286     case 'n':
287       do_print_only = TRUE;
288       do_apply_gain = FALSE;
289       break;
290     case 'b':
291       batch_mode = TRUE;
292       break;
293     case 'm':
294       mix_mode = TRUE;
295       break;
296     case 'c':
297       fprintf(stderr, _("%s: Warning: the -c option is deprecated, and may be removed in v1.0\n"),
298 	      progname);
299       break;
300     case 'l':
301       lmtr_lvl = strtod(optarg, &p);
302       /* check if "dB" is given after number */
303       while(isspace(*p))
304 	p++;
305       /*fprintf(stderr, _("%s: limiting samples greater than "), progname);*/
306       if (strncaseeq(p, "db", 2)) {
307 	if (lmtr_lvl > 0)
308 	  lmtr_lvl = -lmtr_lvl;
309 	fprintf(stderr, "%f dB\n", lmtr_lvl);
310 	lmtr_lvl = DBFSTOAMP(lmtr_lvl);
311       } else {
312 	if (lmtr_lvl < 0)
313 	  lmtr_lvl = -lmtr_lvl;
314 	fprintf(stderr, "%f\n", lmtr_lvl);
315       }
316 
317       use_limiter = TRUE;
318       break;
319     case 'T':
320       adjust_thresh = strtod(optarg, &p);
321       if (adjust_thresh < 0)
322 	adjust_thresh = -adjust_thresh;
323       /*
324       fprintf(stderr, _("%s: ignoring adjustments less than %fdB\n"),
325 	      progname, adjust_thresh);
326       */
327       break;
328     case 'w':
329       output_bitwidth = strtol(optarg, NULL, 0);
330       break;
331     case OPT_CLIPPING:
332       use_limiter = FALSE;
333       break;
334     case OPT_PEAK:
335       use_peak = TRUE;
336       use_limiter = FALSE;
337       break;
338     case OPT_FRACTIONS:
339       use_fractions = TRUE;
340       break;
341     case OPT_ID3_COMPAT:
342       id3_compat = TRUE;
343       break;
344     case OPT_ID3_UNSYNC:
345       id3_unsync = TRUE;
346       break;
347     case OPT_NO_PROGRESS:
348       show_progress = FALSE;
349       break;
350     case OPT_QUERY:
351       /*fprintf(stderr, _("%s: Warning: the --query option is deprecated, and may be removed in v1.0\n"),
352 	progname);*/
353       do_query = TRUE;
354       break;
355     case OPT_FRONTEND:
356       frontend = TRUE;
357       verbose = VERBOSE_QUIET;
358       break;
359     case 'v':
360       verbose++;
361       break;
362     case 'q':
363       verbose = VERBOSE_QUIET;
364       break;
365     case 'V':
366       printf("normalize %s\n", version);
367       printf(_("\
368 Copyright (C) 2005 Chris Vaill\n\
369 This is free software; see the source for copying conditions.  There is NO\n\
370 warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
371 "));
372       printf(_("This copy of normalize is compiled with the following libraries:\n"));
373 #if USE_MAD
374       printf("  MAD");
375 #endif
376 #if USE_AUDIOFILE
377       printf("  audiofile");
378 #endif
379       printf("\n");
380       exit(0);
381     case 'h':
382       usage();
383       exit(0);
384     default:
385       usage_short();
386       exit(1);
387     }
388   }
389   if (output_bitwidth < 0 || output_bitwidth > 32) {
390     fprintf(stderr, _("%s: error: output bitwidth must be between 1 and 32\n"),
391  	    progname);
392     exit(1);
393   }
394   if (mix_mode && batch_mode) {
395     fprintf(stderr,
396 	    _("%s: error: the -m and -b options are mutually exclusive\n"),
397 	    progname);
398     exit(1);
399   }
400   if (use_peak && (mix_mode || batch_mode)) {
401     fprintf(stderr,
402 	    _("%s: error: -m and -b can't be used with the --peak option\n"),
403 	    progname);
404     exit(1);
405   }
406   if (optind >= argc) {
407     usage_short();
408     exit(1);
409   }
410 
411 
412   /*
413    * get sizes of all files, for progress calculation
414    */
415   nfiles = 0;
416   progress_info.batch_size = 0;
417   fnames = (char **)xmalloc((argc - optind) * sizeof(char *));
418   progress_info.file_sizes = (off_t *)xmalloc((argc - optind) * sizeof(off_t));
419   for (i = optind; i < argc; i++) {
420 #if 0 /* FIXME: read from stdin currently not supported */
421     if (strcmp(argv[i], "-") == 0) {
422       if (do_apply_gain) {
423 	fprintf(stderr, _("%s: Warning: stdin specified on command line, not adjusting files\n"), progname);
424 	do_apply_gain = FALSE;
425 	do_print_only = TRUE;
426       }
427       fnames[nfiles++] = argv[i];
428     } else
429 #endif
430     if (stat(argv[i], &st) == -1) {
431       fprintf(stderr, _("%s: file %s: %s\n"),
432 	      progname, argv[i], strerror(errno));
433     } else {
434       /* we want the size of the file in kilobytes, rounding up */
435       progress_info.file_sizes[nfiles] = (st.st_size + 1023) / 1024;
436       /* add the size of the file, in kb */
437       progress_info.batch_size += progress_info.file_sizes[nfiles];
438       fnames[nfiles] = argv[i];
439       nfiles++;
440     }
441   }
442   if (nfiles == 0) {
443     fprintf(stderr, _("%s: no files!\n"), progname);
444     return 1;
445   }
446 
447   /* allocate space to store levels and peaks */
448   sis = (struct signal_info *)xmalloc(nfiles * sizeof(struct signal_info));
449   for (i = 0; i < nfiles; i++) {
450     sis[i].file_size = progress_info.file_sizes[i];
451     sis[i].orig_index = i;
452   }
453 
454   if (frontend) {
455     /* frontend mode: print "NUMFILES <number>" */
456     printf("NUMFILES %d\n", nfiles);
457     /* frontend mode: print "FILE <number> <filename>" for each file */
458     for (i = 0; i < nfiles; i++)
459       printf("FILE %d %s\n", i, fnames[i]);
460   }
461 
462   /*
463    * Compute the levels
464    */
465   if (do_compute_levels) {
466     compute_levels(sis, fnames, nfiles);
467 
468     /* anything that came back with a level of -1 was bad, so remove it */
469     for (i = 0; i < nfiles; i++) {
470       if (sis[i].level < 0) {
471 	nfiles--;
472 	memmove(sis + i, sis + i + 1,
473 		(nfiles - i) * sizeof(struct signal_info));
474 	memmove(fnames + i, fnames + i + 1,
475 		(nfiles - i) * sizeof(char *));
476 	memmove(progress_info.file_sizes + i, progress_info.file_sizes + i + 1,
477 		(nfiles - i) * sizeof(off_t));
478       }
479     }
480 
481     if (batch_mode || mix_mode) {
482       level = average_levels(sis, nfiles, threshold);
483 
484       /* For mix mode, we set the target to the average level */
485       if (mix_mode)
486 	target = level;
487 
488       /* For batch mode, we use one gain for all files */
489       if (batch_mode)
490 	gain = target / level;
491 
492       /* frontend mode: print "AVERAGE_LEVEL <level>" */
493       if (frontend)
494 	printf("AVERAGE_LEVEL %f\n", AMPTODBFS(level));
495 
496       if (do_print_only) {
497 	if (!mix_mode) { /* in mix mode we print everything at the end */
498 	  if (use_fractions) {
499 	    printf(_("%-12.6f average level\n"), level);
500 	  } else {
501 	    sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(level));
502 	    printf(_("%-12s average level\n"), cbuf);
503 	  }
504 	}
505       } else if (verbose >= VERBOSE_INFO) {
506 	if (use_fractions)
507 	  printf(_("Average level: %0.4f\n"), level);
508 	else
509 	  printf(_("Average level: %0.4fdBFS\n"), AMPTODBFS(level));
510       }
511     }
512 
513   } /* end of if (do_compute_levels) */
514 
515 
516   /*
517    * FIXME: this comment belongs somewhere else now...
518    *
519    * Check if we need to apply the gain --
520    *
521    *   If a file would be adjusted by an unnoticeable amount, we don't
522    *   want to bother doing the adjustment.  The smallest noticeable
523    *   difference varies with the absolute intensity and the pitch,
524    *   but I don't think it's a stretch to say that a 0.25 dB
525    *   difference is unnoticeable for most signals.
526    *
527    *   By default then, we allow amplitudes that are +/-0.125 dB from
528    *   the target to pass without adjustment (mainly so that the
529    *   normalize operation is idempotent, i.e. normalizing files for
530    *   the second time has no effect).
531    *
532    *   Why 0.125 dB?  If we allow amplitudes that are 0.125 dB above
533    *   and below the target, the total possible range is 0.25 dB,
534    *   which shouldn't be noticeable.
535    */
536 
537   if (batch_mode) {
538     /* if gain_in_decibels, then dBdiff is the original specified gain */
539     if (!gain_in_decibels)
540       dBdiff = FRACTODB(gain);
541   }
542 
543 
544   /*
545    * Apply the gain
546    */
547   if (do_apply_gain) {
548 
549     /* print adjust message for batch mode */
550     if (batch_mode && verbose >= VERBOSE_PROGRESS) {
551       /* if !do_compute_levels, -g was specified, so we force the adjust */
552       if (do_compute_levels && fabs(dBdiff) < adjust_thresh) {
553 	fprintf(stderr, _("Files are already normalized, not adjusting..."));
554       } else {
555 	if (!do_compute_levels) { /* if -g */
556 	  if (gain_in_decibels)
557 	    fprintf(stderr, _("Applying adjustment of %fdB...\n"), dBdiff);
558 	  else
559 	    fprintf(stderr, _("Applying adjustment of %f...\n"), gain);
560 	} else if (do_apply_gain) {
561 	  fprintf(stderr, _("Applying adjustment of %0.2fdB...\n"), dBdiff);
562 	}
563       }
564     }
565 
566     progress_info.batch_start = time(NULL);
567     progress_info.finished_size = 0;
568 
569     for (i = 0; i < nfiles; i++) {
570 
571       if (!batch_mode) {
572 	if (use_peak)
573 	  gain = 1.0 / sis[i].peak;
574 	else
575 	  gain = target / sis[i].level;
576       }
577 
578       /* frontend mode: print "ADJUSTING <number> <gain>" */
579       if (frontend)
580 	printf("ADJUSTING %d %f\n", sis[i].orig_index, FRACTODB(gain));
581 
582       progress_info.file_start = time(NULL);
583       progress_info.on_file = i;
584 
585       psi = do_compute_levels ? &sis[i] : NULL;
586       ret = apply_gain(fnames[i], gain, psi);
587       if (ret == -1) {
588 	fprintf(stderr, _("%s: error applying adjustment to %s: %s\n"),
589 		progname, fnames[i], strerror(errno));
590       } else {
591 	if (ret == 0) {
592 	  /* gain was not applied */
593 	  if (!batch_mode) {
594 	    if (verbose >= VERBOSE_PROGRESS)
595 	      fprintf(stderr, _("%s already normalized, not adjusting..."),
596 		      fnames[i]);
597 	  }
598 	} else {
599 	  /* gain was applied */
600 	  file_needs_adjust = TRUE;
601 	}
602 	/* frontend mode: print "ADJUSTED <number> 1|0" */
603 	if (frontend)
604 	  printf("ADJUSTED %d %d\n", sis[i].orig_index, ret);
605       }
606 
607       progress_info.finished_size += progress_info.file_sizes[i];
608 
609       if (verbose >= VERBOSE_PROGRESS && !batch_mode)
610 	fputc('\n', stderr);
611     }
612 
613     /* we're done with the second progress meter, so go to next line */
614     if (verbose >= VERBOSE_PROGRESS && batch_mode)
615       fputc('\n', stderr);
616 
617   } else {
618 
619     if (batch_mode && do_print_only) {
620 
621       /* if we're not applying the gain, just print it out, and we're done */
622       if (use_fractions) {
623 	printf(_("%-12f volume adjustment\n"), gain);
624       } else {
625 	sprintf(cbuf, "%fdB", FRACTODB(gain));
626 	printf(_("%-12s volume adjustment\n"), cbuf);
627       }
628 
629     } else if (mix_mode && do_print_only) {
630 
631       /*
632        * In mix mode, we don't have all the information until the end,
633        * so we have to print it all here.
634        */
635       /* clear the progress meter first */
636       if (verbose >= VERBOSE_PROGRESS && show_progress)
637 	fprintf(stderr,
638 		"\r                                     "
639 		"                                     \r");
640       for (i = 0; i < nfiles; i++) {
641 	if (use_fractions) {
642 	  sprintf(cbuf, "%0.6f", sis[i].level);
643 	  printf("%-12s ", cbuf);
644 	  sprintf(cbuf, "%0.6f", sis[i].peak);
645 	  printf("%-12s ", cbuf);
646 	  sprintf(cbuf, "%0.6f", target / sis[i].level);
647 	  printf("%-10s ", cbuf);
648 	} else {
649 	  sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(sis[i].level));
650 	  printf("%-12s ", cbuf);
651 	  sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(sis[i].peak));
652 	  printf("%-12s ", cbuf);
653 	  sprintf(cbuf, "%0.4fdB", AMPTODBFS(target / sis[i].level));
654 	  printf("%-10s ", cbuf);
655 	}
656 	printf("%s\n", fnames[i]);
657       }
658       if (use_fractions) {
659 	printf(_("%-12.6f average level\n"), level);
660       } else {
661 	sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(level));
662 	printf(_("%-12s average level\n"), cbuf);
663       }
664 
665     } /* end of if (batch_mode && do_print_only) */
666 
667     /*
668      * Since we're not applying any gain, we haven't computed
669      * file_needs_adjust yet, so we do it now.
670      */
671     for (i = 0; i < nfiles; i++) {
672       if (use_peak)
673 	gain = 1.0 / sis[i].peak;
674       else
675 	gain = target / sis[i].level;
676       dBdiff = FRACTODB(gain);
677 
678       if (fabs(dBdiff) >= adjust_thresh) {
679 	file_needs_adjust = TRUE;
680 	break;
681       }
682     }
683 
684   } /* end of if (do_apply_gain) */
685 
686   free(sis);
687   free(progress_info.file_sizes);
688   free(fnames);
689 
690   /*
691    * frontend mode:
692    *
693    *   print "ADJUST_NEEDED 1" if a file was adjusted, or if the -n
694    *   option was given and a file would need adjustment.
695    *
696    *   print "ADJUST_NEEDED 0" if the -n option was not given and no
697    *   file was adjusted, or if -n was given and no file would need
698    *   adjustment.
699    */
700   if (frontend)
701     printf("ADJUST_NEEDED %d\n", file_needs_adjust ? 1 : 0);
702 
703   /* for --query option */
704   /* NOTE: the --query option is broken and obsolete and will go away */
705   if (do_query)
706     return file_needs_adjust ? 0 : 2;
707 
708   return 0;
709 }
710 
711 /*
712  * Compute the RMS levels of the files.
713  */
714 void
compute_levels(struct signal_info * sis,char ** fnames,int nfiles)715 compute_levels(struct signal_info *sis, char **fnames, int nfiles)
716 {
717   double power;
718   int i;
719   char cbuf[32];
720   /*struct wavfmt fmt = { 1, 2, 44100, 176400, 0, 16 };*/
721 
722   if (verbose >= VERBOSE_PROGRESS) {
723     fprintf(stderr, _("Computing levels...\n"));
724 
725     if (do_print_only) {
726       if (batch_mode)
727 	fprintf(stderr, _("  level        peak\n"));
728       else
729 	fprintf(stderr, _("  level        peak         gain\n"));
730     }
731   }
732 
733   progress_info.batch_start = time(NULL);
734   progress_info.finished_size = 0;
735 
736   for (i = 0; i < nfiles; i++) {
737 
738     /* frontend mode: print "ANALYZING <number>" for each file index */
739     if (frontend)
740       printf("ANALYZING %d\n", i);
741 
742     sis[i].level = 0;
743 
744 #if 0 /* FIXME: reinstate stdin reading */
745     if (strcmp(fnames[i], "-") == 0) {
746       progress_info.file_start = time(NULL);
747       progress_info.on_file = i;
748       errno = 0;
749 
750       /* for a stream, format info is passed through sis[i].fmt */
751       sis[i].channels = 2;
752       sis[i].bits_per_sample = 16;
753       sis[i].samples_per_sec = 44100;
754       power = signal_max_power_stream(stdin, NULL, &sis[i]);
755       fnames[i] = "STDIN";
756 
757     } else {
758 #endif
759 
760       progress_info.file_start = time(NULL);
761       progress_info.on_file = i;
762       errno = 0;
763 
764       power = signal_max_power(fnames[i], &sis[i]);
765 
766 #if 0 /* FIXME */
767     }
768 #endif
769     if (power < 0) {
770       fprintf(stderr, _("%s: error reading %s"), progname, fnames[i]);
771       if (errno)
772 	fprintf(stderr, ": %s\n", strerror(errno));
773       else
774 	fprintf(stderr, "\n");
775       sis[i].level = -1;
776       goto error_update_progress;
777     }
778     /* frontend mode: print "LEVEL <number> <level>" for each file index */
779     if (frontend)
780       printf("LEVEL %d %f\n", i, AMPTODBFS(sis[i].level));
781     if (power < EPSILON) {
782       if (verbose >= VERBOSE_PROGRESS) {
783 	if (show_progress)
784 	  fprintf(stderr,
785 		  "\r                                     "
786 		  "                                     \r");
787 	fprintf(stderr,
788 		_("File %s has zero power, ignoring...\n"), fnames[i]);
789       }
790       sis[i].level = -1;
791       goto error_update_progress;
792     }
793 
794     if (do_print_only) {
795 
796       /* in mix mode we don't have enough info to print gain yet */
797       if (!mix_mode) {
798 
799 	/* clear the progress meter first */
800 	if (verbose >= VERBOSE_PROGRESS && show_progress)
801 	  fprintf(stderr,
802 		  "\r                                     "
803 		  "                                     \r");
804 
805 	if (use_fractions) {
806 	  sprintf(cbuf, "%0.6f", sis[i].level);
807 	  printf("%-12s ", cbuf);
808 	  sprintf(cbuf, "%0.6f", sis[i].peak);
809 	  printf("%-12s ", cbuf);
810 	} else {
811 	  sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(sis[i].level));
812 	  printf("%-12s ", cbuf);
813 	  sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(sis[i].peak));
814 	  printf("%-12s ", cbuf);
815 	}
816 	if (!batch_mode) {
817 	  if (use_fractions)
818 	    sprintf(cbuf, "%0.6f", target / sis[i].level);
819 	  else
820 	    sprintf(cbuf, "%0.4fdB", AMPTODBFS(target / sis[i].level));
821 	  printf("%-10s ", cbuf);
822 	}
823 	printf("%s\n", fnames[i]);
824       }
825 
826     } else if (verbose >= VERBOSE_INFO) {
827       if (show_progress)
828 	fprintf(stderr,
829 		"\r                                     "
830 		"                                     \r");
831       if (use_fractions)
832 	fprintf(stderr, _("Level for %s: %0.4f (%0.4f peak)\n"),
833 		fnames[i], sis[i].level, sis[i].peak);
834       else
835 	fprintf(stderr, _("Level for %s: %0.4fdBFS (%0.4fdBFS peak)\n"),
836 		fnames[i], AMPTODBFS(sis[i].level), AMPTODBFS(sis[i].peak));
837     }
838 
839   error_update_progress:
840     progress_info.finished_size += progress_info.file_sizes[i];
841   }
842 
843   /* we're done with the level calculation progress meter, so go to
844      next line */
845   if (verbose == VERBOSE_PROGRESS && !do_print_only)
846     fputc('\n', stderr);
847 }
848 
849 /*
850  * For batch mode, we take the levels for all the input files, throw
851  * out any that appear to be statistical aberrations, and average the
852  * rest together to get one level and one gain for the whole batch.
853  */
854 double
average_levels(struct signal_info * sis,int nlevels,double threshold)855 average_levels(struct signal_info *sis, int nlevels, double threshold)
856 {
857   int i, files_to_avg;
858   double sum, level_difference, std_dev, variance;
859   double level, mean_level;
860   char *badlevels;
861 
862   /* badlevels is a boolean array marking the level values to be thrown out */
863   badlevels = (char *)xmalloc(nlevels * sizeof(char));
864   memset(badlevels, 0, nlevels * sizeof(char));
865 
866   /* get mean level */
867   sum = 0;
868   for (i = 0; i < nlevels; i++)
869     sum += sis[i].level;
870   mean_level = sum / nlevels;
871 
872   /* if no threshold is specified, use 2 * standard dev */
873   if (threshold < 0.0) {
874 
875     /*
876      * We want the standard dev of the levels, but we need it in decibels.
877      * Therefore, if u is the mean, the variance is
878      *                  (1/N)summation((20*log10(x/u))^2)
879      *       instead of (1/N)summation((x-u)^2),
880      * which it would be if we needed straight variance "by the numbers".
881      */
882 
883     /* get variance */
884     sum = 0;
885     for (i = 0; i < nlevels; i++) {
886       double tmp = FRACTODB(sis[i].level / mean_level);
887       sum += tmp * tmp;
888     }
889     variance = sum / nlevels;
890 
891     /* get standard deviation */
892     if (variance < EPSILON)
893       std_dev = 0.0;
894     else
895       std_dev = sqrt(variance);
896     if (verbose >= VERBOSE_INFO)
897       printf(_("Standard deviation is %0.2f dB\n"), std_dev);
898 
899     threshold = 2 * std_dev;
900   }
901 
902   /*
903    * Throw out level values that seem to be aberrations
904    * (so that one "quiet song" doesn't throw off the average)
905    * We define an aberration as a level that is > 2*stddev dB from the mean.
906    */
907   if (threshold > EPSILON && nlevels > 1) {
908     for (i = 0; i < nlevels; i++) {
909 
910       /* Find how different from average the i'th file's level is.
911        * The "level" here is the signal's maximum sustained amplitude,
912        * from which we can compute the difference in decibels. */
913       level_difference = fabs(FRACTODB(mean_level / sis[i].level));
914 
915       /* mark as bad any level that is > threshold different than the mean */
916       if (level_difference > threshold) {
917 
918 	/* frontend mode: print "AVERAGE_EXCLUDES <number> <difference>" */
919 	if (frontend)
920 	  printf("AVERAGE_EXCLUDES %d %f\n",
921 		 sis[i].orig_index, level_difference);
922 
923 	if (verbose >= VERBOSE_INFO) {
924 	  if (use_fractions) {
925 	    printf(_("Throwing out level of %0.4f (different by %0.2fdB)\n"),
926 		   sis[i].level, level_difference);
927 	  } else {
928 	    printf(_("Throwing out level of %0.4fdBFS (different by %0.2fdB)\n"),
929 		   AMPTODBFS(sis[i].level), level_difference);
930 	  }
931 	}
932 	badlevels[i] = TRUE;
933       }
934     }
935   }
936 
937   /* throw out the levels marked as bad */
938   files_to_avg = 0;
939   sum = 0;
940   for (i = 0; i < nlevels; i++)
941     if (!badlevels[i]) {
942       sum += sis[i].level;
943       files_to_avg++;
944     }
945 
946   if (files_to_avg == 0) {
947     fprintf(stderr, _("%s: all files ignored, try using -t 100\n"), progname);
948     exit(1);
949   }
950 
951   free(badlevels);
952 
953   level = sum / files_to_avg;
954 
955   return level;
956 }
957 
958 
959 void
progress_callback(char * prefix,float fraction_completed)960 progress_callback(char *prefix, float fraction_completed)
961 {
962   /* the field lengths used by the sprintf() calls below are carefully
963    * chosen so that buf will never overflow */
964   char buf[128];
965   time_t now, time_spent;
966   unsigned int file_eta_hr, file_eta_min, file_eta_sec;
967   off_t kb_done;
968   float batch_fraction = 0;
969   unsigned int batch_eta_hr, batch_eta_min, batch_eta_sec;
970 
971   if (!show_progress)
972     return;
973 
974   now = time(NULL);
975 
976   if (fraction_completed > 1.0)
977     fraction_completed = 1.0;
978 
979   /* figure out the ETA for this file */
980   file_eta_hr = file_eta_sec = file_eta_min = 0;
981   if (fraction_completed > 0.0) {
982     time_spent = now - progress_info.file_start;
983     if (fraction_completed == 0.0)
984       file_eta_sec = 0;
985     else
986       file_eta_sec = (unsigned int)((float)time_spent / fraction_completed
987 				    - (float)time_spent + 0.5);
988 
989     file_eta_min = file_eta_sec / 60;
990     file_eta_sec = file_eta_sec % 60;
991     file_eta_hr = file_eta_min / 60;
992     file_eta_min = file_eta_min % 60;
993     if (file_eta_hr > 99)
994       file_eta_hr = 99;
995   }
996 
997 
998   /* figure out the ETA for the whole batch */
999   batch_eta_hr = batch_eta_min = batch_eta_sec = 0;
1000   if (progress_info.batch_size != 0) {
1001     kb_done = progress_info.finished_size
1002       + fraction_completed * progress_info.file_sizes[progress_info.on_file];
1003     batch_fraction = (float)kb_done / (float)progress_info.batch_size;
1004     time_spent = now - progress_info.batch_start;
1005     if (kb_done == 0)
1006       batch_eta_sec = 0;
1007     else
1008       batch_eta_sec = (unsigned int)((float)time_spent / batch_fraction
1009 				     - (float)time_spent + 0.5);
1010 
1011     batch_eta_min = batch_eta_sec / 60;
1012     batch_eta_sec = batch_eta_sec % 60;
1013     batch_eta_hr = batch_eta_min / 60;
1014     batch_eta_min = batch_eta_min % 60;
1015     if (batch_eta_hr > 99) {
1016       batch_eta_hr = 99;
1017       batch_eta_min = 59;
1018       batch_eta_sec = 59;
1019     }
1020   }
1021 
1022 
1023   /* if progress on current file is zero, don't do file ETA */
1024   if (fraction_completed <= 0.0) {
1025     if (progress_info.batch_size == 0) {
1026       /* if we don't have batch info, don't compute batch ETA either */
1027       sprintf(buf, _(" %-17s  --%% done, ETA --:--:-- (batch  --%% done, ETA --:--:--)"),
1028 	      prefix);
1029     } else {
1030       sprintf(buf, _(" %-17s  --%% done, ETA --:--:-- (batch %3.0f%% done, ETA %02d:%02d:%02d)"),
1031 	      prefix, batch_fraction * 100,
1032 	      batch_eta_hr, batch_eta_min, batch_eta_sec);
1033     }
1034 
1035   } else {
1036 
1037     sprintf(buf, _(" %-17s %3.0f%% done, ETA %02d:%02d:%02d (batch %3.0f%% done, ETA %02d:%02d:%02d)"),
1038 	    prefix, fraction_completed * 100,
1039 	    file_eta_hr, file_eta_min, file_eta_sec,
1040 	    batch_fraction * 100,
1041 	    batch_eta_hr, batch_eta_min, batch_eta_sec);
1042 
1043   }
1044 
1045   fprintf(stderr, "%s \r", buf);
1046 }
1047 
1048 /*
1049  * Return nonzero if the two strings are equal, ignoring case, up to
1050  * the first n characters
1051  */
1052 int
strncaseeq(const char * s1,const char * s2,size_t n)1053 strncaseeq(const char *s1, const char *s2, size_t n)
1054 {
1055   for ( ; n > 0; n--) {
1056     if (tolower(*s1++) != tolower(*s2++))
1057       return 0;
1058   }
1059 
1060   return 1;
1061 }
1062 
1063 /*
1064  * Like the SUSv2 basename, except guaranteed non-destructive, and
1065  * doesn't correctly handle pathnames ending in '/'.
1066  */
1067 char *
basename(char * path)1068 basename(char *path)
1069 {
1070   char *p;
1071   p = strrchr(path, SLASH_CHAR);
1072   if (p)
1073     p++;
1074   else
1075     p = path;
1076   return p;
1077 }
1078 
1079 void *
xmalloc(size_t size)1080 xmalloc(size_t size)
1081 {
1082   void *ptr = malloc(size);
1083   if (ptr == NULL) {
1084     fprintf(stderr, _("%s: unable to malloc\n"), progname);
1085     exit(1);
1086   }
1087   return ptr;
1088 }
1089