~ubuntu-branches/ubuntu/trusty/normalize-audio/trusty-proposed

« back to all changes in this revision

Viewing changes to src/normalize.c

  • Committer: Bazaar Package Importer
  • Author(s): Eduardo Marcel Macan
  • Date: 2004-06-28 23:01:43 UTC
  • Revision ID: james.westby@ubuntu.com-20040628230143-59fd3lt4hqbc7ay4
Tags: upstream-0.7.6
ImportĀ upstreamĀ versionĀ 0.7.6

Show diffs side-by-side

added added

removed removed

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