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