#!/usr/bin/perl -w use strict; use Getopt::Std 'getopts'; # The "size*" fields may be followed by a byte to get to an even alignment; # it is not included into size! (Not applicable to these formats) my $wav_header = < $prefix, buf => $in} unless $read == $header_size; if ($opt{I} and $in =~ /^ID3(..)(.)([\x00-\x7f]{4})/s) { my $f = 0 + ord $2; # Make into integer my $s = 0; for my $c (split //, $3) { $s <<= 7; $s |= ord $c; } $s += (($f & 0x10) ? 20 : 10); $read = sysread $fh, $in, $s, $header_size or die "can't read the header"; return {buf => $in} unless $read == $s; $prefix = substr $in, 0, $s; $in = substr $in, $s; } my %vals; @vals{@wav_fields} = unpack $wav_header, $in or return {buf => $in}; return {prefix => $prefix, buf => $in} unless $vals{header} eq 'RIFF'; if ($vals{size1} == 0x20) { # Format above expects 0x1e... my $in2; $read = sysread $fh, $in2, 2 or die "can't read rest of the header"; $in .= $in2; return {prefix => $prefix, buf => $in} unless $read == 2; my %vals1; @vals1{@wav_fields} = unpack $wav_header, substr $in, 2 or return {buf => $in}; @vals{'type2', 'sizedata'} = @vals1{'type2', 'sizedata'}; } if ($vals{type2} eq 'fact') { my $h2_size = length pack "V a4 V", (0) x 20; # No Optional part my $in2; $read = sysread $fh, $in2, $h2_size or die "can't read rest of the header"; $in .= $in2; return {prefix => $prefix, buf => $in} unless $read == $h2_size; @vals{qw[type12 size12]} = @vals{qw[type2 sizedata]}; @vals{qw[Unknown5 type2 sizedata]} = unpack "V a4 V", $in2; } die <{type2}; return; } (my $o = $f) =~ s/\.wav$/.mp3/i or die "`$f' is not with extension .wav"; unless (defined $rc->{type2}) { close IN or die; die "File `$f': no valid RIFF header" unless $opt{F}; rename $f, $o or die "rename `$f' => `$o': $!"; return; } open OUT, ">$o" or die; binmode OUT; syswrite OUT, $rc->{prefix} if length $rc->{prefix}; my ($in, $c); while ($c = sysread IN, $in, 1<<20) { syswrite OUT, $in or die; } close IN or die "close for read: $!"; close OUT or die "close for write: $!"; unlink $f or die "unlink: $!" if $opt{d}; } if ($opt{R}) { require File::Find; File::Find::find({wanted => sub {return unless -f and ($opt{M} ? /\.mp3$/i : /\.wav$/i); process_file $_}, no_chdir => 1}, @ARGV); } else { for my $f (@ARGV) { process_file $f; } }