1
/* Copyright (C) 1999--2001 Chris Vaill
2
This file is part of normalize.
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)
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.
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. */
18
#define _POSIX_C_SOURCE 2
36
# define strrchr rindex
39
# define memcpy(d,s,n) bcopy((s),(d),(n))
40
# define memmove(d,s,n) bcopy((s),(d),(n))
57
# include <sys/types.h>
60
# include <sys/stat.h>
66
# include <sys/mman.h>
70
# define _(msgid) gettext (msgid)
76
# define _(msgid) (msgid)
78
#define N_(msgid) (msgid)
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 *);
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);
92
extern char version[];
94
struct progress_struct progress_info;
99
fprintf(stderr, _("Usage: %s [OPTION]... [FILE]...\n"), progname);
100
fprintf(stderr, _("Try `%s --help' for more information.\n"), progname);
107
Usage: %s [OPTION]... [FILE]...\n\
108
Normalize volume of multiple audio files\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\
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\
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\
134
-v, --verbose increase verbosity\n\
135
-w, --output-bitwidth=W force adjusted files to have W-bit samples\n\
137
-V, --version display version information and exit\n\
138
-h, --help display this help and exit\n\
140
Report bugs to <cvaill@cs.columbia.edu>.\n"), progname);
144
OPT_CLIPPING = 0x101,
146
OPT_FRACTIONS = 0x103,
147
OPT_ID3_COMPAT = 0x104,
148
OPT_ID3_UNSYNC = 0x105,
149
OPT_NO_PROGRESS = 0x106,
151
OPT_FRONTEND = 0x108,
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;
177
main(int argc, char *argv[])
179
int c, i, nfiles, ret;
180
struct signal_info *sis, *psi;
181
double level, gain = 1.0, dBdiff;
185
int file_needs_adjust = FALSE;
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},
216
/* This gives wildcard expansion on Non-POSIX shells with OS/2 */
217
_wildcard(&argc, &argv);
220
/* get program name */
221
if ((progname = strrchr(argv[0], '/')) == NULL)
225
if (strlen(progname) > 16)
229
setlocale(LC_ALL, "");
230
bindtextdomain(PACKAGE, LOCALEDIR);
235
while ((c = getopt_long(argc, argv, "hVnvqbmcT:l:g:a:t:w:", longopts, NULL)) != EOF) {
238
target = strtod(optarg, &p);
240
/* check if "dB" or "dBFS" is given after number */
243
if (strncaseeq(p, "db", 2)) {
244
/* amplitude given as dBFS */
248
fprintf(stderr, _("%s: normalizing to %f dBFS\n"), progname, target);
251
/* translate to fraction */
252
target = DBFSTOAMP(target);
256
/* amplitude given as fraction */
257
if (target < 0 || target > 1.0) {
258
fprintf(stderr, _("%s: error: bad target amplitude %f\n"),
265
/* a negative threshold means don't use threshold (use 2*stddev) */
266
threshold = strtod(optarg, NULL);
269
gain = strtod(optarg, &p);
271
/* check if "dB" is given after number */
274
if (strncaseeq(p, "db", 2)) {
276
gain = DBTOFRAC(dBdiff);
277
gain_in_decibels = TRUE;
280
do_compute_levels = FALSE;
283
fprintf(stderr, _("%s: invalid argument to -g option\n"), progname);
289
do_print_only = TRUE;
290
do_apply_gain = FALSE;
299
fprintf(stderr, _("%s: Warning: the -c option is deprecated, and may be removed in v1.0\n"),
303
lmtr_lvl = strtod(optarg, &p);
304
/* check if "dB" is given after number */
307
/*fprintf(stderr, _("%s: limiting samples greater than "), progname);*/
308
if (strncaseeq(p, "db", 2)) {
310
lmtr_lvl = -lmtr_lvl;
311
fprintf(stderr, "%f dB\n", lmtr_lvl);
312
lmtr_lvl = DBFSTOAMP(lmtr_lvl);
315
lmtr_lvl = -lmtr_lvl;
316
fprintf(stderr, "%f\n", lmtr_lvl);
322
adjust_thresh = strtod(optarg, &p);
323
if (adjust_thresh < 0)
324
adjust_thresh = -adjust_thresh;
326
fprintf(stderr, _("%s: ignoring adjustments less than %fdB\n"),
327
progname, adjust_thresh);
331
output_bitwidth = strtol(optarg, NULL, 0);
341
use_fractions = TRUE;
349
case OPT_NO_PROGRESS:
350
show_progress = FALSE;
353
/*fprintf(stderr, _("%s: Warning: the --query option is deprecated, and may be removed in v1.0\n"),
359
verbose = VERBOSE_QUIET;
365
verbose = VERBOSE_QUIET;
368
printf("normalize %s\n", version);
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\
374
printf(_("This copy of normalize is compiled with the following libraries:\n"));
379
printf(" audiofile");
391
if (output_bitwidth < 0 || output_bitwidth > 32) {
392
fprintf(stderr, _("%s: error: output bitwidth must be between 1 and 32\n"),
396
if (mix_mode && batch_mode) {
398
_("%s: error: the -m and -b options are mutually exclusive\n"),
402
if (use_peak && (mix_mode || batch_mode)) {
404
_("%s: error: -m and -b can't be used with the --peak option\n"),
408
if (optind >= argc) {
415
* get sizes of all files, for progress calculation
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) {
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;
429
fnames[nfiles++] = argv[i];
432
if (stat(argv[i], &st) == -1) {
433
fprintf(stderr, _("%s: file %s: %s\n"),
434
progname, argv[i], strerror(errno));
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];
445
fprintf(stderr, _("%s: no files!\n"), progname);
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;
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]);
467
if (do_compute_levels) {
468
compute_levels(sis, fnames, nfiles);
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) {
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));
483
if (batch_mode || mix_mode) {
484
level = average_levels(sis, nfiles, threshold);
486
/* For mix mode, we set the target to the average level */
490
/* For batch mode, we use one gain for all files */
492
gain = target / level;
494
/* frontend mode: print "AVERAGE_LEVEL <level>" */
496
printf("AVERAGE_LEVEL %f\n", AMPTODBFS(level));
499
if (!mix_mode) { /* in mix mode we print everything at the end */
501
printf(_("%-12.6f average level\n"), level);
503
sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(level));
504
printf(_("%-12s average level\n"), cbuf);
507
} else if (verbose >= VERBOSE_INFO) {
509
printf(_("Average level: %0.4f\n"), level);
511
printf(_("Average level: %0.4fdBFS\n"), AMPTODBFS(level));
515
} /* end of if (do_compute_levels) */
519
* FIXME: this comment belongs somewhere else now...
521
* Check if we need to apply the gain --
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.
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).
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.
540
/* if gain_in_decibels, then dBdiff is the original specified gain */
541
if (!gain_in_decibels)
542
dBdiff = FRACTODB(gain);
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..."));
557
if (!do_compute_levels) { /* if -g */
558
if (gain_in_decibels)
559
fprintf(stderr, _("Applying adjustment of %fdB...\n"), dBdiff);
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);
568
progress_info.batch_start = time(NULL);
569
progress_info.finished_size = 0;
571
for (i = 0; i < nfiles; i++) {
575
gain = 1.0 / sis[i].peak;
577
gain = target / sis[i].level;
580
/* frontend mode: print "ADJUSTING <number> <gain>" */
582
printf("ADJUSTING %d %f\n", sis[i].orig_index, FRACTODB(gain));
584
progress_info.file_start = time(NULL);
585
progress_info.on_file = i;
587
psi = do_compute_levels ? &sis[i] : NULL;
588
ret = apply_gain(fnames[i], gain, psi);
590
fprintf(stderr, _("%s: error applying adjustment to %s: %s\n"),
591
progname, fnames[i], strerror(errno));
594
/* gain was not applied */
596
if (verbose >= VERBOSE_PROGRESS)
597
fprintf(stderr, _("%s already normalized, not adjusting..."),
601
/* gain was applied */
602
file_needs_adjust = TRUE;
604
/* frontend mode: print "ADJUSTED <number> 1|0" */
606
printf("ADJUSTED %d %d\n", sis[i].orig_index, ret);
609
progress_info.finished_size += progress_info.file_sizes[i];
611
if (verbose >= VERBOSE_PROGRESS && !batch_mode)
615
/* we're done with the second progress meter, so go to next line */
616
if (verbose >= VERBOSE_PROGRESS && batch_mode)
621
if (batch_mode && do_print_only) {
623
/* if we're not applying the gain, just print it out, and we're done */
625
printf(_("%-12f volume adjustment\n"), gain);
627
sprintf(cbuf, "%fdB", FRACTODB(gain));
628
printf(_("%-12s volume adjustment\n"), cbuf);
631
} else if (mix_mode && do_print_only) {
634
* In mix mode, we don't have all the information until the end,
635
* so we have to print it all here.
637
/* clear the progress meter first */
638
if (verbose >= VERBOSE_PROGRESS && show_progress)
642
for (i = 0; i < nfiles; i++) {
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);
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);
658
printf("%s\n", fnames[i]);
661
printf(_("%-12.6f average level\n"), level);
663
sprintf(cbuf, "%0.4fdBFS", AMPTODBFS(level));
664
printf(_("%-12s average level\n"), cbuf);
667
} /* end of if (batch_mode && do_print_only) */
670
* Since we're not applying any gain, we haven't computed
671
* file_needs_adjust yet, so we do it now.
673
for (i = 0; i < nfiles; i++) {
675
gain = 1.0 / sis[i].peak;
677
gain = target / sis[i].level;
678
dBdiff = FRACTODB(gain);
680
if (fabs(dBdiff) >= adjust_thresh) {
681
file_needs_adjust = TRUE;
686
} /* end of if (do_apply_gain) */
689
free(progress_info.file_sizes);
695
* print "ADJUST_NEEDED 1" if a file was adjusted, or if the -n
696
* option was given and a file would need adjustment.
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
703
printf("ADJUST_NEEDED %d\n", file_needs_adjust ? 1 : 0);
705
/* for --query option */
706
/* NOTE: the --query option is broken and obsolete and will go away */
708
return file_needs_adjust ? 0 : 2;
714
* Compute the RMS levels of the files.
717
compute_levels(struct signal_info *sis, char **fnames, int nfiles)
722
/*struct wavfmt fmt = { 1, 2, 44100, 176400, 0, 16 };*/
724
if (verbose >= VERBOSE_PROGRESS) {
725
fprintf(stderr, _("Computing levels...\n"));
729
fprintf(stderr, _(" level peak\n"));
731
fprintf(stderr, _(" level peak gain\n"));
735
progress_info.batch_start = time(NULL);
736
progress_info.finished_size = 0;
738
for (i = 0; i < nfiles; i++) {
740
/* frontend mode: print "ANALYZING <number>" for each file index */
742
printf("ANALYZING %d\n", i);
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;
752
/* for a stream, format info is passed through sis[i].fmt */
754
sis[i].bits_per_sample = 16;
755
sis[i].samples_per_sec = 44100;
756
power = signal_max_power_stream(stdin, NULL, &sis[i]);
762
progress_info.file_start = time(NULL);
763
progress_info.on_file = i;
766
power = signal_max_power(fnames[i], &sis[i]);
772
fprintf(stderr, _("%s: error reading %s"), progname, fnames[i]);
774
fprintf(stderr, ": %s\n", strerror(errno));
776
fprintf(stderr, "\n");
778
goto error_update_progress;
780
/* frontend mode: print "LEVEL <number> <level>" for each file index */
782
printf("LEVEL %d %f\n", i, AMPTODBFS(sis[i].level));
783
if (power < EPSILON) {
784
if (verbose >= VERBOSE_PROGRESS) {
790
_("File %s has zero power, ignoring...\n"), fnames[i]);
793
goto error_update_progress;
798
/* in mix mode we don't have enough info to print gain yet */
801
/* clear the progress meter first */
802
if (verbose >= VERBOSE_PROGRESS && show_progress)
808
sprintf(cbuf, "%0.6f", sis[i].level);
809
printf("%-12s ", cbuf);
810
sprintf(cbuf, "%0.6f", sis[i].peak);
811
printf("%-12s ", cbuf);
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);
820
sprintf(cbuf, "%0.6f", target / sis[i].level);
822
sprintf(cbuf, "%0.4fdB", AMPTODBFS(target / sis[i].level));
823
printf("%-10s ", cbuf);
825
printf("%s\n", fnames[i]);
828
} else if (verbose >= VERBOSE_INFO) {
834
fprintf(stderr, _("Level for %s: %0.4f (%0.4f peak)\n"),
835
fnames[i], sis[i].level, sis[i].peak);
837
fprintf(stderr, _("Level for %s: %0.4fdBFS (%0.4fdBFS peak)\n"),
838
fnames[i], AMPTODBFS(sis[i].level), AMPTODBFS(sis[i].peak));
841
error_update_progress:
842
progress_info.finished_size += progress_info.file_sizes[i];
845
/* we're done with the level calculation progress meter, so go to
847
if (verbose == VERBOSE_PROGRESS && !do_print_only)
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.
857
average_levels(struct signal_info *sis, int nlevels, double threshold)
860
double sum, level_difference, std_dev, variance;
861
double level, mean_level;
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));
870
for (i = 0; i < nlevels; i++)
872
mean_level = sum / nlevels;
874
/* if no threshold is specified, use 2 * standard dev */
875
if (threshold < 0.0) {
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".
887
for (i = 0; i < nlevels; i++) {
888
double tmp = FRACTODB(sis[i].level / mean_level);
891
variance = sum / nlevels;
893
/* get standard deviation */
894
if (variance < EPSILON)
897
std_dev = sqrt(variance);
898
if (verbose >= VERBOSE_INFO)
899
printf(_("Standard deviation is %0.2f dB\n"), std_dev);
901
threshold = 2 * std_dev;
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.
909
if (threshold > EPSILON && nlevels > 1) {
910
for (i = 0; i < nlevels; i++) {
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));
917
/* mark as bad any level that is > threshold different than the mean */
918
if (level_difference > threshold) {
920
/* frontend mode: print "AVERAGE_EXCLUDES <number> <difference>" */
922
printf("AVERAGE_EXCLUDES %d %f\n",
923
sis[i].orig_index, level_difference);
925
if (verbose >= VERBOSE_INFO) {
927
printf(_("Throwing out level of %0.4f (different by %0.2fdB)\n"),
928
sis[i].level, level_difference);
930
printf(_("Throwing out level of %0.4fdBFS (different by %0.2fdB)\n"),
931
AMPTODBFS(sis[i].level), level_difference);
939
/* throw out the levels marked as bad */
942
for (i = 0; i < nlevels; i++)
948
if (files_to_avg == 0) {
949
fprintf(stderr, _("%s: all files ignored, try using -t 100\n"), progname);
955
level = sum / files_to_avg;
962
progress_callback(char *prefix, float fraction_completed)
964
/* the field lengths used by the sprintf() calls below are carefully
965
* chosen so that buf will never overflow */
967
time_t now, time_spent;
968
unsigned int file_eta_hr, file_eta_min, file_eta_sec;
970
float batch_fraction;
971
unsigned int batch_eta_hr, batch_eta_min, batch_eta_sec;
978
if (fraction_completed > 1.0)
979
fraction_completed = 1.0;
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)
988
file_eta_sec = (unsigned int)((float)time_spent / fraction_completed
989
- (float)time_spent + 0.5);
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)
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);
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)
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 --:--:--)"),
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);
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);
1041
fprintf(stderr, "%s \r", buf);
1045
* Return nonzero if the two strings are equal, ignoring case, up to
1046
* the first n characters
1049
strncaseeq(const char *s1, const char *s2, size_t n)
1051
for ( ; n > 0; n--) {
1052
if (tolower(*s1++) != tolower(*s2++))
1060
xmalloc(size_t size)
1062
void *ptr = malloc(size);
1064
fprintf(stderr, _("%s: unable to malloc\n"), progname);