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

« back to all changes in this revision

Viewing changes to src/normalize-mp3.in

  • 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
#! @PERL@ -w
 
2
# -*- perl -*-
 
3
# Copyright (C) 1999--2002 Chris Vaill
 
4
# This file is part of normalize.
 
5
#
 
6
# This program is free software; you can redistribute it and/or modify
 
7
# it under the terms of the GNU General Public License as published by
 
8
# the Free Software Foundation; either version 2, or (at your option)
 
9
# any later version.
 
10
#
 
11
# This program is distributed in the hope that it will be useful,
 
12
# but WITHOUT ANY WARRANTY; without even the implied warranty of
 
13
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
14
# GNU General Public License for more details.
 
15
#
 
16
# You should have received a copy of the GNU General Public License
 
17
# along with this program; if not, write to the Free Software
 
18
# Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
 
19
 
 
20
 
 
21
#######################################################################
 
22
# These variables may be customized for local setup
 
23
#######################################################################
 
24
 
 
25
# %m becomes name of mp3 or ogg file
 
26
# %w becomes name of temporary WAV file
 
27
# %b becomes bitrate of re-encoded file, as specified by the -b option
 
28
# Example: $OGGENCODE="oggenc -Q -b %b -o %m %w"
 
29
 
 
30
$MP3DECODE  = "@MP3DECODE@";
 
31
$MP3ENCODE  = "@MP3ENCODE@";
 
32
$OGGDECODE  = "@OGGDECODE@";
 
33
$OGGENCODE  = "@OGGENCODE@";
 
34
$FLACDECODE = "@FLACDECODE@";
 
35
$FLACENCODE = "@FLACENCODE@";
 
36
 
 
37
# The %w etc. substitutions should *not* be used in the following, as
 
38
# this script knows about their options already.
 
39
$VORBISCOMMENT = "@VORBISCOMMENT@";
 
40
$METAFLAC      = "@METAFLAC@";
 
41
 
 
42
# change this if normalize is not on your path
 
43
$NORMALIZE = "normalize";
 
44
 
 
45
 
 
46
#######################################################################
 
47
# No user serviceable parts below
 
48
#######################################################################
 
49
 
 
50
use Fcntl;
 
51
 
 
52
sub usage {
 
53
    print <<EOF
 
54
Usage: $progname [OPTION]... [FILE]...
 
55
  Normalize volume of mp3, ogg, or flac files by decoding, running
 
56
  normalize, and re-encoding.  This requires as much extra disk space
 
57
  as the largest file, decoded.  Note that for batch and mix mode, all
 
58
  files must be decoded, so there must be enough disk space for the
 
59
  decoded copies of all specified files.
 
60
 
 
61
  -a AMP         \\
 
62
  -g ADJ          |
 
63
  -n              |
 
64
  -T THR          |_ These arguments are passed as arguments to normalize.
 
65
  -b              |  Run "normalize --help" for more info.
 
66
  -m              |
 
67
  -v              |
 
68
  -q             /
 
69
 
 
70
  --bitrate BR   Set bitrate of re-encoded file [default 128]
 
71
  --tmpdir TMP   Put temporary WAV files in temp directory TMP
 
72
  --notags       Do not copy ID3 or ogg tags to the output file
 
73
  --force-encode Re-encode even if file is already normalized
 
74
  --backup       Keep backups of original files, suffixed with '~'
 
75
 
 
76
  Force output format (this disables copying of comment tags):
 
77
 
 
78
  --ogg          Convert files to ogg, regardless of original format
 
79
  --mp3          Convert files to mp3, regardless of original format
 
80
  --flac         Convert files to flac, regardless of original format
 
81
 
 
82
  The following four options may be used to set the encoder and
 
83
  decoder commands for mp3 and ogg vorbis.  \%m is expanded to the
 
84
  name of the mp3 or vorbis file, \%w expands to the name of the
 
85
  temporary WAV file, and \%b expands to the bitrate, as specified by
 
86
  the --bitrate option.  The default values are shown in brackets
 
87
  below.
 
88
 
 
89
  --mp3encode=X  mp3 encoder        [$MP3ENCODE]
 
90
  --mp3decode=X  mp3 decoder        [$MP3DECODE]
 
91
  --oggencode=X  ogg vorbis encoder [$OGGENCODE]
 
92
  --oggdecode=X  ogg vorbis decoder [$OGGDECODE]
 
93
 
 
94
  -h             Display this help and exit.
 
95
  -V             Display version information and exit.
 
96
 
 
97
Report bugs to <cvaill\@cs.columbia.edu>.
 
98
EOF
 
99
}
 
100
 
 
101
 
 
102
# same effect as a backtick, but shell metacharacters are not expanded
 
103
sub backtick_noshell {
 
104
    my @args = @_;
 
105
    my $retval = "";
 
106
    defined(my $pid = open(BABY, "-|")) || die "Can't fork: $!, stopped";
 
107
    if ($pid) {
 
108
        local $SIG{INT} = 'IGNORE';
 
109
        while (<BABY>) {
 
110
            $retval .= $_;
 
111
        }
 
112
        close BABY;
 
113
    } else {
 
114
        exec(@args) || die "Can't exec $args[0], stopped";
 
115
    }
 
116
    $retval;
 
117
}
 
118
 
 
119
 
 
120
sub read_tags {
 
121
    my ($fname) = @_;
 
122
    my ($retval, $vorbis_tag, $id3v1_tag, $id3v2_tag, $id3v2_sz);
 
123
 
 
124
    if ($fname =~ /\.ogg$/i) {
 
125
        $vorbis_tag = backtick_noshell($VORBISCOMMENT, $fname);
 
126
        defined($vorbis_tag) || die "Can't run vorbiscomment: $!, stopped";
 
127
        $retval = [ 'ogg', $vorbis_tag ];
 
128
 
 
129
    } elsif ($fname =~ /\.mp3$/i) {
 
130
        open(IN, $fname) || die "Can't read $fname: $!, stopped";
 
131
        # read ID3v2 tag, if it's there
 
132
        # FIXME: doesn't work for ID3v2.4.0 appended tags
 
133
        read(IN, $id3v2_tag, 3);
 
134
        if ($id3v2_tag eq "ID3") {
 
135
            read(IN, $id3v2_tag, 7, 3);
 
136
            # figure tag size
 
137
            my ($x1, $x2, $x3, $x4) = unpack("x6 C C C C", $id3v2_tag);
 
138
            my $tagsz = $x1;
 
139
            $tagsz <<= 7;
 
140
            $tagsz += $x2;
 
141
            $tagsz <<= 7;
 
142
            $tagsz += $x3;
 
143
            $tagsz <<= 7;
 
144
            $tagsz += $x4;
 
145
            read(IN, $id3v2_tag, $tagsz, 10);
 
146
            $id3v2_sz = $tagsz + 10;
 
147
        } else {
 
148
            undef $id3v2_tag;
 
149
            $id3v2_sz = 0;
 
150
        }
 
151
        # read ID3v1 tag, if it's there
 
152
        seek(IN, -128, 2);
 
153
        read(IN, $id3v1_tag, 3);
 
154
        if ($id3v1_tag eq "TAG") {
 
155
            read(IN, $id3v1_tag, 125, 3);
 
156
        } else {
 
157
            undef $id3v1_tag;
 
158
        }
 
159
        close(IN);
 
160
 
 
161
        $retval = [ 'id3', $id3v1_tag, $id3v2_tag, $id3v2_sz ];
 
162
    } else {
 
163
        $retval = [ 'none' ];
 
164
    }
 
165
 
 
166
    $retval;
 
167
}
 
168
 
 
169
 
 
170
sub write_tags {
 
171
    my ($fname, $tag) = @_;
 
172
 
 
173
    if ($fname =~ /\.ogg$/i) {
 
174
        if ($tag->[0] eq 'ogg' && $tag->[1]) {
 
175
            my @args = ($VORBISCOMMENT, "-a", $fname);
 
176
            defined(my $pid = open(BABY, "|-"))
 
177
                || die "Can't fork: $!, stopped";
 
178
            if ($pid) {
 
179
                local $SIG{INT} = 'IGNORE';
 
180
                print BABY $tag->[1];
 
181
                close BABY;
 
182
                $? == 0 || die "Error running vorbiscomment, stopped";
 
183
            } else {
 
184
                exec(@args) || die "Can't run vorbiscomment: $!, stopped";
 
185
            }
 
186
 
 
187
        }
 
188
 
 
189
    } elsif ($fname =~ /\.mp3$/i) {
 
190
        if ($tag->[0] eq 'id3' && $tag->[1]) {
 
191
            my $id3v1_tag = $tag->[1];
 
192
            open(OUT, ">>".$fname)
 
193
                || die "Can't append tag to $fname: $!, stopped";
 
194
            syswrite(OUT, $id3v1_tag, 128);
 
195
            close(OUT);
 
196
        }
 
197
        if ($tag->[0] eq 'id3' && $tag->[2]) {
 
198
            my ($buf, $tmpfile);
 
199
            my $id3v2_tag = $tag->[2];
 
200
            my $id3v2_sz = $tag->[3];
 
201
            my $n = $$;
 
202
            while (1) {
 
203
                $tmpfile = $tmpdir.$progname."-".$n.".tag";
 
204
                if (sysopen(OUT, $tmpfile, O_WRONLY|O_CREAT|O_EXCL)) {
 
205
                    last;
 
206
                }
 
207
                $! == EEXIST || die "Can't write $tmpfile: $!, stopped";
 
208
                $n++;
 
209
            }
 
210
            syswrite(OUT, $id3v2_tag, $id3v2_sz);
 
211
            open(IN, $fname) || die "Can't read $fname: $!, stopped";
 
212
            while ($ret = sysread(IN, $buf, 4096)) {
 
213
                syswrite(OUT, $buf, $ret);
 
214
            }
 
215
            close(IN);
 
216
            close(OUT);
 
217
            unlink $fname;
 
218
            rename($tmpfile, $fname)
 
219
                || die "Can't rename temp file, leaving in $tmpfile, stopped";
 
220
        }
 
221
    }
 
222
}
 
223
 
 
224
sub find_prog {
 
225
    my ($prog) = @_;
 
226
    my $retval = undef;
 
227
    my $fullpath;
 
228
 
 
229
    @_ = split(/:/, $ENV{PATH});
 
230
    for (@_) {
 
231
        ($_ .= "/") unless (/\/$/);
 
232
        $fullpath = $_.$prog;
 
233
        if (-x $fullpath) {
 
234
            $retval = $fullpath;
 
235
            last;
 
236
        }
 
237
    }
 
238
 
 
239
    $retval;
 
240
}
 
241
 
 
242
sub find_mp3decode {
 
243
    my ($path);
 
244
    $path = find_prog("madplay");
 
245
    if ($path) { $path .= " -q -o %w %m"; }
 
246
    unless ($path) {
 
247
        $path = find_prog("mpg123");
 
248
        if ($path) { $path .= " -q -w %w %m"; }
 
249
    }
 
250
    if ($path) { $MP3DECODE = $path; }
 
251
}
 
252
 
 
253
sub find_mp3encode {
 
254
    my ($path);
 
255
    $path = find_prog("lame");
 
256
    unless ($path) {
 
257
        $path = find_prog("notlame");
 
258
    }
 
259
    if ($path) { $path .= " --quiet -h -b %b %w %m"; }
 
260
    unless ($path) {
 
261
        $path = find_prog("bladeenc");
 
262
        if ($path) { $path .= " -quiet %w %m"; }
 
263
    }
 
264
    if ($path) { $MP3ENCODE = $path; }
 
265
}
 
266
 
 
267
sub find_oggdecode {
 
268
    my ($path);
 
269
    $path = find_prog("oggdec");
 
270
    if ($path) { $path .= " -Q -o %w %m"; }
 
271
    unless ($path) {
 
272
        $path = find_prog("ogg123");
 
273
        if ($path) { $path .= " -q -d wav -f %w %m"; }
 
274
    }
 
275
    if ($path) { $OGGDECODE = $path; }
 
276
}
 
277
 
 
278
sub find_oggencode {
 
279
    my ($path);
 
280
    $path = find_prog("oggenc");
 
281
    if ($path) {
 
282
        $path .= " -Q -b %b -o %m %w";
 
283
        $OGGENCODE = $path;
 
284
    }
 
285
}
 
286
 
 
287
sub find_vorbiscomment {
 
288
    my ($path);
 
289
    $path = find_prog("vorbiscomment");
 
290
    if ($path) { $VORBISCOMMENT = $path; }
 
291
}
 
292
 
 
293
sub find_flacdecode {
 
294
    my ($path);
 
295
    $path = find_prog("flac");
 
296
    if ($path) {
 
297
        $path .= " -s -d -o %w %m";
 
298
        $FLAC = $path;
 
299
    }
 
300
}
 
301
 
 
302
sub find_flacencode {
 
303
    my ($path);
 
304
    $path = find_prog("flac");
 
305
    if ($path) {
 
306
        $path .= " -s -o %m %w";
 
307
        $FLAC = $path;
 
308
    }
 
309
}
 
310
 
 
311
sub find_metaflac {
 
312
    my ($path);
 
313
    $path = find_prog("metaflac");
 
314
    if ($path) { $METAFLAC = $path; }
 
315
}
 
316
 
 
317
 
 
318
($progname = $0) =~ s/.*\///;
 
319
$version = "@VERSION@";
 
320
$nomoreoptions = 0;
 
321
 
 
322
# default option values
 
323
@normalize_args = ($NORMALIZE, "--frontend", "-T", "0.25");
 
324
$all_to_mp3 = 0;
 
325
$all_to_ogg = 0;
 
326
$all_to_flac = 0;
 
327
$bitrate = 128;
 
328
$do_copy_tags = 1;
 
329
$tmpdir = "";
 
330
$do_adjust = 1;
 
331
$batch_mode = 0;
 
332
$mix_mode = 0;
 
333
$force_encode = 0;
 
334
$keep_backups = 0;
 
335
# we track verbosity separately for this script
 
336
$verbose = 1;
 
337
 
 
338
 
 
339
# for any helper programs that haven't been specified statically at
 
340
# the top of this file, try to set them dynamically
 
341
find_mp3decode     unless ($MP3DECODE);
 
342
find_mp3encode     unless ($MP3ENCODE);
 
343
find_oggdecode     unless ($OGGDECODE);
 
344
find_oggencode     unless ($OGGENCODE);
 
345
find_vorbiscomment unless ($VORBISCOMMENT);
 
346
find_flacdecode    unless ($FLACDECODE);
 
347
find_flacencode    unless ($FLACENCODE);
 
348
 
 
349
@infnames = ();
 
350
 
 
351
# step through arguments
 
352
$nomoreoptions = 0;
 
353
ARG_LOOP:
 
354
while ($ARGV[0]) {
 
355
    if ($ARGV[0] =~ /^-/ && !$nomoreoptions) {
 
356
        $_ = $ARGV[0];
 
357
 
 
358
        if ($_ eq "-a" || $_ eq "--amplitude") {
 
359
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
360
            push @normalize_args, "-a", $ARGV[1];
 
361
            shift; shift; next ARG_LOOP;
 
362
        } elsif ($_ eq "--bitrate") {
 
363
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
364
            $bitrate = $ARGV[1];
 
365
            shift; shift; next ARG_LOOP;
 
366
        } elsif ($_ eq "-g" || $_ eq "--gain") {
 
367
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
368
            push @normalize_args, "-g", $ARGV[1];
 
369
            shift; shift; next ARG_LOOP;
 
370
        } elsif ($_ eq "-n" || $_ eq "--no-adjust") {
 
371
            push @normalize_args, "-n";
 
372
            $do_adjust = 0;
 
373
            shift; next ARG_LOOP;
 
374
        } elsif ($_ eq "-T" || $_ eq "--adjust-threshold") {
 
375
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
376
            push @normalize_args, "-T", $ARGV[1];
 
377
            shift; shift; next ARG_LOOP;
 
378
        } elsif ($_ eq "--fractions") {
 
379
            push @normalize_args, "--fractions";
 
380
            shift; next ARG_LOOP;
 
381
        } elsif ($_ eq "--tmp" || $_ eq "--tmpdir") {
 
382
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
383
            $tmpdir = $ARGV[1];
 
384
            unless (-d $tmpdir) { print "$progname: $tmpdir: no such directory\n"; exit 1; }
 
385
            if ($tmpdir !~ /\/$/) {
 
386
                $tmpdir = $tmpdir."/";
 
387
            }
 
388
            shift; shift; next ARG_LOOP;
 
389
        } elsif ($_ eq "-v" || $_ eq "--verbose") {
 
390
            push @normalize_args, "-v";
 
391
            $verbose = 2;
 
392
            shift; next ARG_LOOP;
 
393
        } elsif ($_ eq "-b" || $_ eq "--batch") {
 
394
            push @normalize_args, "-b";
 
395
            $batch_mode = 1;
 
396
            shift; next ARG_LOOP;
 
397
        } elsif ($_ eq "-m" || $_ eq "--mix") {
 
398
            push @normalize_args, "-m";
 
399
            $mix_mode = 1;
 
400
            shift; next ARG_LOOP;
 
401
        } elsif ($_ eq "-q" || $_ eq "--quiet") {
 
402
            push @normalize_args, "-q";
 
403
            $verbose = 0;
 
404
            shift; next ARG_LOOP;
 
405
        } elsif ($_ eq "--ogg") {
 
406
            $all_to_ogg = 1;
 
407
            $all_to_mp3 = 0;
 
408
            $all_to_flac = 0;
 
409
            shift; next ARG_LOOP;
 
410
        } elsif ($_ eq "--mp3") {
 
411
            $all_to_mp3 = 1;
 
412
            $all_to_ogg = 0;
 
413
            $all_to_flac = 0;
 
414
            shift; next ARG_LOOP;
 
415
        } elsif ($_ eq "--flac") {
 
416
            $all_to_flac = 1;
 
417
            $all_to_mp3 = 0;
 
418
            $all_to_ogg = 0;
 
419
            shift; next ARG_LOOP;
 
420
        } elsif ($_ eq "--force-encode") {
 
421
            $force_encode = 1;
 
422
            shift; next ARG_LOOP;
 
423
        } elsif ($_ eq "--backup") {
 
424
            $keep_backups = 1;
 
425
            shift; next ARG_LOOP;
 
426
        } elsif ($_ eq "--notags" || $_ eq "--noid3") {
 
427
            $do_copy_tags = 0;
 
428
            shift; next ARG_LOOP;
 
429
        } elsif ($_ eq "--mp3encode") {
 
430
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
431
            $MP3ENCODE = $ARGV[1];
 
432
            shift; shift; next ARG_LOOP;
 
433
        } elsif ($_ eq "--mp3decode") {
 
434
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
435
            $MP3DECODE = $ARGV[1];
 
436
            shift; shift; next ARG_LOOP;
 
437
        } elsif ($_ eq "--oggencode") {
 
438
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
439
            $MP3ENCODE = $ARGV[1];
 
440
            shift; shift; next ARG_LOOP;
 
441
        } elsif ($_ eq "--oggdecode") {
 
442
            if ($#ARGV < 1) { print "$progname: option $_ requires an argument\n"; exit 1; }
 
443
            $OGGDECODE = $ARGV[1];
 
444
            shift; shift; next ARG_LOOP;
 
445
        } elsif ($_ eq "-h" || $_ eq "--help") {
 
446
            usage;
 
447
            exit 0;
 
448
        } elsif ($_ eq "-V" || $_ eq "--version") {
 
449
            print "$progname (normalize) $version\n";
 
450
            exit 0;
 
451
        } elsif ($_ eq "--") {
 
452
            $nomoreoptions = 1;
 
453
            shift; next ARG_LOOP;
 
454
        } else {
 
455
            print "Unrecognized option \"",$ARGV[0],"\"\n";
 
456
            usage;
 
457
            exit 1;
 
458
        }
 
459
    }
 
460
 
 
461
    push(@infnames, shift);
 
462
}
 
463
 
 
464
unless (@infnames) {
 
465
    print STDERR "Error: no files specified\n";
 
466
    print STDERR "Usage: $progname [OPTION]... [FILE]...\n";
 
467
    print STDERR "Try `$progname --help' for more information\n";
 
468
    exit 0;
 
469
}
 
470
 
 
471
 
 
472
if ($batch_mode || $mix_mode) {
 
473
 
 
474
    #
 
475
    # decode all files
 
476
    #
 
477
    @tmpfnames = ();
 
478
    @outfnames = ();
 
479
    for($i = 0; $i <= $#infnames; $i++) {
 
480
        $input_file = $infnames[$i];
 
481
 
 
482
        $decoder = undef;
 
483
        if ($input_file =~ /\.mp3$/i) {
 
484
            $decoder = $MP3DECODE;
 
485
        } elsif ($input_file =~ /\.ogg$/i) {
 
486
            $decoder = $OGGDECODE;
 
487
        } elsif ($input_file =~ /\.flac$/i) {
 
488
            $decoder = $FLACDECODE;
 
489
        } else {
 
490
            print STDERR "$progname: $input_file has unrecognized extension\n";
 
491
            print STDERR "$progname: Recognized extensions are mp3, ogg, and flac\n";
 
492
        }
 
493
 
 
494
        unless ($decoder) {
 
495
            print STDERR "$progname: $input_file: no decoder available\n";
 
496
            splice(@infnames, $i, 1);
 
497
            $i--;
 
498
            next;
 
499
        }
 
500
 
 
501
        # construct temporary file name
 
502
        #   NOTE: There is a race condition here, similar to the C
 
503
        #   tmpnam() function.  We are ignoring it.
 
504
        ($filebase = $input_file) =~ s/^.*\///;
 
505
        $filebase = $tmpdir.$filebase;
 
506
        $n = $$;
 
507
        do {
 
508
            $tmp_file = $filebase.".".$n.".wav";
 
509
            $n++;
 
510
        } while (-e $tmp_file);
 
511
        push(@tmpfnames, $tmp_file);
 
512
        # construct output file name
 
513
        ($filebase = $input_file) =~ s/\..*?$//;
 
514
        if ($all_to_mp3) {
 
515
            $output_file = $filebase.".mp3";
 
516
        } elsif ($all_to_ogg) {
 
517
            $output_file = $filebase.".ogg";
 
518
        } else {
 
519
            $output_file = $input_file;
 
520
        }
 
521
        push(@outfnames, $output_file);
 
522
 
 
523
        # construct decode command
 
524
        @decode_args = split(/\s+/, $decoder);
 
525
        for (@decode_args) {
 
526
            s/^\%w$/$tmp_file/;
 
527
            s/^\%m$/$input_file/;
 
528
            s/^\%b$/$bitrate/;
 
529
        }
 
530
 
 
531
        # save tags
 
532
        $do_copy_tags && ($tagref = read_tags($input_file));
 
533
        push(@tags, $tagref);
 
534
 
 
535
        # run decoder
 
536
        $verbose > 0 && print STDERR "Decoding $input_file...\n";
 
537
        if ($verbose < 2) {
 
538
            open(OLDOUT, ">&STDOUT");
 
539
            open(STDOUT, ">/dev/null") || die "Can't redirect stdout, stopped";
 
540
        }
 
541
        $ret = system(@decode_args);
 
542
        if ($verbose < 2) {
 
543
            close(STDOUT);
 
544
            open(STDOUT, ">&OLDOUT");
 
545
        }
 
546
        $ret == 0 || die "Error decoding, stopped";
 
547
    }
 
548
 
 
549
 
 
550
    #
 
551
    # normalize all files
 
552
    #
 
553
    $verbose > 0 && print STDERR "Running normalize...\n";
 
554
    @args = (@normalize_args, @tmpfnames);
 
555
    $adjust_needed = $force_encode;
 
556
    defined($pid = open(NORM, "-|")) || die "Can't fork: $!, stopped";
 
557
    if ($pid) {
 
558
        local $SIG{INT} = 'IGNORE';
 
559
        $dummy = 0; # suppress warnings about single use
 
560
        while (<NORM>) {
 
561
            if (/^ADJUST_NEEDED /) {
 
562
                ($dummy, $adjust_needed_here) = split;
 
563
                $adjust_needed = $adjust_needed || $adjust_needed_here;
 
564
            } elsif (/^LEVEL /) {
 
565
                unless ($do_adjust) {
 
566
                    # with -n specified, the line following a LEVEL line
 
567
                    # is the "level peak gain" line, so print it out
 
568
                    $_ = <NORM>;
 
569
                    print;
 
570
                }
 
571
            }
 
572
        }
 
573
        close NORM;
 
574
        $? == 0 || die "Error during normalize, stopped";
 
575
    } else {
 
576
        exec(@args) || die "Can't run normalize: $!, stopped";
 
577
    }
 
578
 
 
579
 
 
580
    #
 
581
    # re-encode all files
 
582
    #
 
583
    if ($do_adjust) {
 
584
        for($i = 0; $i <= $#infnames; $i++) {
 
585
            $input_file  = $infnames[$i];
 
586
            $output_file = $outfnames[$i];
 
587
            $tmp_file    = $tmpfnames[$i];
 
588
            $tagref      = $tags[$i];
 
589
 
 
590
            # construct encode command
 
591
            $encoder = undef;
 
592
            if ($output_file =~ /\.mp3$/i) {
 
593
                $encoder = $MP3ENCODE;
 
594
            } elsif ($output_file =~ /\.ogg$/i) {
 
595
                $encoder = $OGGENCODE;
 
596
            } elsif ($output_file =~ /\.flac$/i) {
 
597
                $encoder = $FLACENCODE;
 
598
            } else {
 
599
                print STDERR "$progname: $output_file has unrecognized extension\n";
 
600
                print STDERR "$progname: Recognized extensions are mp3, ogg, and flac\n";
 
601
            }
 
602
 
 
603
            unless ($encoder) {
 
604
                print STDERR "$progname: $output_file: no decoder available\n";
 
605
                print STDERR "$progname: leaving output in $tmp_file\n";
 
606
                next;
 
607
            }
 
608
 
 
609
            @encode_args = split(/\s+/, $encoder);
 
610
            for (@encode_args) {
 
611
                s/^\%w$/$tmp_file/;
 
612
                s/^\%m$/$output_file/;
 
613
                s/^\%b$/$bitrate/;
 
614
            }
 
615
 
 
616
            if ($adjust_needed || $input_file ne $output_file) {
 
617
                if ($keep_backups) {
 
618
                    rename($input_file, $input_file."~");
 
619
                } else {
 
620
                    unlink($input_file);
 
621
                }
 
622
                # run encoder
 
623
                $verbose > 0 && print STDERR "Re-encoding $input_file...\n";
 
624
                if ($verbose < 2) {
 
625
                    open(OLDOUT, ">&STDOUT");
 
626
                    open(STDOUT, ">/dev/null")
 
627
                        || die "Can't redirect stdout, stopped";
 
628
                }
 
629
                $ret = system(@encode_args);
 
630
                if ($verbose < 2) {
 
631
                    close(STDOUT);
 
632
                    open(STDOUT, ">&OLDOUT");
 
633
                }
 
634
                $ret == 0 || die "Error encoding, stopped";
 
635
 
 
636
                # restore tags, if necessary
 
637
                $do_copy_tags && write_tags($output_file, $tagref);
 
638
            } else {
 
639
                $verbose > 0 && print "$input_file is already normalized, not re-encoding...\n";
 
640
            }
 
641
 
 
642
            # delete temp file
 
643
            unlink $tmp_file || print STDERR "Can't remove $tmp_file: $!\n";
 
644
        }
 
645
    }
 
646
 
 
647
    exit 0;
 
648
}
 
649
 
 
650
 
 
651
#
 
652
# not mix or batch mode
 
653
#
 
654
for $input_file (@infnames) {
 
655
 
 
656
    $decoder = $encoder = undef;
 
657
    if ($input_file =~ /\.mp3$/i) {
 
658
        $decoder = $MP3DECODE; $encoder = $MP3ENCODE;
 
659
    } elsif ($input_file =~ /\.ogg$/i) {
 
660
        $decoder = $OGGDECODE; $encoder = $OGGENCODE;
 
661
    } elsif ($input_file =~ /\.flac$/i) {
 
662
        $decoder = $FLACDECODE; $encoder = $FLACENCODE;
 
663
    } else {
 
664
        print STDERR "$progname: $input_file has unrecognized extension\n";
 
665
        print STDERR "$progname: Recognized extensions are mp3, ogg, and flac\n";
 
666
        next;
 
667
    }
 
668
 
 
669
    # construct temporary file name
 
670
    #   NOTE: There is a race condition here, similar to the C
 
671
    #   tmpnam() function.  We are ignoring it.
 
672
    ($filebase = $input_file) =~ s{^.*/}{};
 
673
    $filebase = $tmpdir.$filebase;
 
674
    $n = $$;
 
675
    do {
 
676
        $tmp_file = $filebase.".".$n.".wav";
 
677
        $n++;
 
678
    } while (-e $tmp_file);
 
679
    # construct output file name
 
680
    #($filebase = $input_file) =~ s{(.*/)?(.*)\..*}{$2};
 
681
    ($filebase = $input_file) =~ s{\..*?$}{};
 
682
    if ($all_to_mp3) {
 
683
        $output_file = $filebase.".mp3";
 
684
        $encoder = $MP3ENCODE;
 
685
    } elsif ($all_to_ogg) {
 
686
        $output_file = $filebase.".ogg";
 
687
        $encoder = $OGGENCODE;
 
688
    } elsif ($all_to_flac) {
 
689
        $output_file = $filebase.".flac";
 
690
        $encoder = $FLACENCODE;
 
691
    } else {
 
692
        $output_file = $input_file;
 
693
    }
 
694
 
 
695
    unless ($decoder) {
 
696
        print STDERR "$progname: $input_file: no decoder available\n";
 
697
        next;
 
698
    }
 
699
    unless ($encoder) {
 
700
        print STDERR "$progname: $output_file: no encoder available\n";
 
701
        next;
 
702
    }
 
703
 
 
704
    # construct encode and decode commands
 
705
    @decode_args = split(/\s+/, $decoder);
 
706
    for (@decode_args) {
 
707
        s/^\%w$/$tmp_file/;
 
708
        s/^\%m$/$input_file/;
 
709
        s/^\%b$/$bitrate/;
 
710
    }
 
711
    @encode_args = split(/\s+/, $encoder);
 
712
    for (@encode_args) {
 
713
        s/^\%w$/$tmp_file/;
 
714
        s/^\%m$/$output_file/;
 
715
        s/^\%b$/$bitrate/;
 
716
    }
 
717
 
 
718
    # save tags
 
719
    $do_copy_tags && ($tagref = read_tags($input_file));
 
720
 
 
721
 
 
722
    #
 
723
    # run decoder
 
724
    #
 
725
    $verbose > 0 && print STDERR "Decoding $input_file...\n";
 
726
    if ($verbose < 2) {
 
727
        open(OLDOUT, ">&STDOUT");
 
728
        open(STDOUT, ">/dev/null") || die "Can't redirect stdout, stopped";
 
729
    }
 
730
    $ret = system(@decode_args);
 
731
    if ($verbose < 2) {
 
732
        close(STDOUT);
 
733
        open(STDOUT, ">&OLDOUT");
 
734
    }
 
735
    $ret == 0 || die "Error decoding, stopped";
 
736
 
 
737
 
 
738
    #
 
739
    # run normalize
 
740
    #
 
741
    $verbose > 0 && print STDERR "Running normalize...\n";
 
742
    @args = (@normalize_args, $tmp_file);
 
743
    $adjust_needed = $force_encode;
 
744
    defined($pid = open(NORM, "-|")) || die "Can't fork: $!, stopped";
 
745
    if ($pid) {
 
746
        local $SIG{INT} = 'IGNORE';
 
747
        $dummy = 0; # suppress warnings about single use
 
748
        while (<NORM>) {
 
749
            if (/^ADJUST_NEEDED /) {
 
750
                ($dummy, $adjust_needed_here) = split;
 
751
                $adjust_needed = $adjust_needed || $adjust_needed_here;
 
752
            } elsif (/^LEVEL /) {
 
753
                unless ($do_adjust) {
 
754
                    # with -n specified, the line following a LEVEL line
 
755
                    # is the "level peak gain" line, so print it out
 
756
                    $_ = <NORM>;
 
757
                    print;
 
758
                }
 
759
            }
 
760
        }
 
761
        close NORM;
 
762
        $? == 0 || die "Error during normalize, stopped";
 
763
    } else {
 
764
        exec(@args) || die "Can't run normalize: $!, stopped";
 
765
    }
 
766
 
 
767
 
 
768
    #
 
769
    # run encoder, if necessary
 
770
    #
 
771
    if ($do_adjust) {
 
772
        if ($adjust_needed || $input_file ne $output_file) {
 
773
            if ($keep_backups) {
 
774
                rename($input_file, $input_file."~");
 
775
            } else {
 
776
                unlink($input_file);
 
777
            }
 
778
            # run encoder
 
779
            $verbose > 0 && print STDERR "Re-encoding $input_file...\n";
 
780
            if ($verbose < 2) {
 
781
                open(OLDOUT, ">&STDOUT");
 
782
                open(STDOUT, ">/dev/null")
 
783
                    || die "Can't redirect stdout, stopped";
 
784
            }
 
785
            $ret = system(@encode_args);
 
786
            if ($verbose < 2) {
 
787
                close(STDOUT);
 
788
                open(STDOUT, ">&OLDOUT");
 
789
            }
 
790
            $ret == 0 || die "Error encoding, stopped";
 
791
 
 
792
            # restore tags, if necessary
 
793
            $do_copy_tags && write_tags($output_file, $tagref);
 
794
        } else {
 
795
            $verbose > 0 && print "$input_file is already normalized, not re-encoding...\n";
 
796
        }
 
797
    }
 
798
 
 
799
    # delete temp file
 
800
    unlink $tmp_file || print STDERR "Can't remove $tmp_file: $!\n";
 
801
}