#!/usr/bin/perl
#
# mp3burn $Revision: 0.13 $ $Date: 2008/10/04 10:23:21 $ 
# based upon mp3burn-0.1 - see http://sourceforge.net/projects/mp3burn/
#
#Copyright 2000 Ryan Richter <bobort@bigfoot.com>
#With help from Dan Lark <dlark@pcisys.net>
#Copyright 2003 Alexander Wirt <formorer@formorer.de>
#
#You may fold, spindle, and mutilate this software under the terms of the GPL
#
# $Log: mp3burn,v $
# Revision 0.13  2008/10/04 10:23:21  formorer
# Fix swab detection
#
# Revision 0.12  2006/09/24 09:38:28  formorer
# Add swap support for ppc
#
# Revision 0.11  2005/02/09 21:10:51  formorer
# Added swab detection for x86_64
#
# Revision 0.10  2004/07/08 20:33:50  formorer
# - Fixed some small typo - thanks to sdelafond@lika.fr.st
#
# Revision 0.9  2004/06/20 15:22:18  formorer
# Added Support for length detection of FLAC files.
# (There must be someone outside really using them ;))
#
# Revision 0.8  2004/06/05 06:40:34  formorer
# I'm bored from any locale problems or changes in the output of ogginfo...
# So I decided to switch to Ogg::Vorbis::Header and it work like a charme..
# Here it is.
#
# Revision 0.7  2004/06/05 05:56:18  formorer
# the decection of the correct mp3decoder is now much smarter :)
#
# Revision 0.6  2004/04/28 08:06:37  formorer
# Fixed Flac Detection - Thanks to: Georg Wittmann <debian-bug@pbrz.de>
#
# Revision 0.5  2004/04/14 10:06:39  formorer
# Fixed get_atip function, so that $cdrecord_opts are recognized
#
# Revision 0.4  2004/01/02 09:12:48  formorer
# Fixed Podparsing
#
# Revision 0.3.1.1  2004/01/01 21:43:57  formorer
# Initial Import
#
######################


=head1 NAME

mp3burn - burn audio CDs from MP3, Ogg Vorbis, or FLAC files

=cut

use MP3::Info;
use File::Basename;
use Pod::Usage;
use String::ShellQuote;
use Getopt::Long;
use Ogg::Vorbis::Header;

sub get_audio_info {
    my  ($filename) =@_;
    my $hash = {};
    my $fileinfo=`file -b "$filename"`;
    if ($fileinfo =~ m/FLAC/i) {
	#If the FLAC decoder is not installed we just exit
	$flac = `which flac`;
	chomp $flac;
	if (! -x $flac) { print "FLAC decoder is not available\n"; return; }
 		
        # FLAC file
	# we don't know the length, so just set it to 1 second
	$hash->{DECODER}=["flac", "-d", "-F", "-s", "-c"];
        eval "require Audio::FLAC";
	if ($@) {
		if ($DEBUG) { print "No Audio::FLAC available\n"; }
		$hash->{SECS} = 1;
	} else {
		require Audio::FLAC;
		my $flac = Audio::FLAC->new("$filename");
		$hash->{SECS} = $flac->{trackTotalLengthSeconds};
	if ($DEBUG) { print "Flac Length: $hash->{SECS}\n"; }
	
	}
		
    } elsif ($fileinfo =~ m/Ogg data/i) {
        # Ogg/Vorbis processing
	$hash->{DECODER}=["ogg123", "-d", "raw", "-f", "-", "-q"];
	my $ogginfo = Ogg::Vorbis::Header->new("$filename");
	if (! defined $ogginfo) { 
	undef $hash;
	next; 
	}
	
	$hash->{SECS} = $ogginfo->info('length');
	$hash->{MODE} = $ogginfo->info('channels');
	$hash->{FREQUENCY} = $ogginfo->info('rate');
	if ($DEBUG) {
		print "ogg parsing:\n";
		print "\tchannels=$hash->{MODE}\n";
		print "\trate=$hash->{FREQUENCY}\n";
		print "\tlength=$hash->{SECS}\n";
	}
    } elsif ($hash = MP3::Info::get_mp3info($filename)) {
        if ($mp3decoder) {
	    $hash->{DECODER} = ["$mp3decoder", "--rate", "44100", "--stereo", "-s", "-q"];
	} else {
	    if ($hash->{FREQUENCY} != 44.1) {
	       print "*** unable to continue ***\n";
	       print "  mpg321 cannot handle files with sample rates != 44.1kHz\n";
	       print "  sample rate is $hash->{FREQUENCY} for file: $filename\n";
	       print "  please either burn without this file or see the mp3burn manpage\n";
	       print "  about using -M or setting \$mp3decoder in \~/.mp3burnrc\n";
	       &Cleanup;
	       exit 1;
	    }
  	    $hash->{DECODER} = ["mpg321", "--rate", "44100", "--stereo", "-s", "-q"];
	}    
    } 
    # else we don't know what type of file this is...
    $hash;
}


sub get_ATIP_info () {
	#die "No CDR device information is available. Please specify the device." unless ($1);
	#eject doesn't work with the atip switch... also it would be counterproductive to eject 
	#the cd before burning... so just remove it
	
	$atipoptions = $cdrecord_opts;
	$atipoptions =~ s/-eject//;
	
	if ($DEBUG) { print "Call cdrecord with: cdrecord -atip $atipoptions. \n"; }
	open(CDINFO,"cdrecord -atip $atipoptions 2>&1 |"); #Use cdrecord -atip to get ATIP info	
	while (<CDINFO>) {
	        if (/cdrecord: No CD\/DVD-Recorder device specified/) {
		   print "No CDR device specified. It must be specified via on of the following:\n";
		   print "\tdev=\$device in \~/.mp3burnrc\n";
		   print "\t-o \"dev=\$device\" on the command-line\n";
		   print "\tthe value of \$CDR_DEVICE in the environment\n";
		   print "\tin the file /etc/default/cdrecord (man cdrecord)\n";
		   exit 1;
		}
		next unless (/out:.+\((\d+):(\d+)/); #The lead out time is what we want
		$min=$1; $sec=$2;
	}	
	close CDINFO;
	die "No CD-R in CD Writer." unless ($sec && $min); 
	printf "ATIP reports available time: [%d:%.2d]\n",$min,$sec;
}


sub Cleanup {

   # kill off any children that might still be around
   if (@children) {
      print "cleaning up children: @children\n";
      kill 'TERM', @children;
   }
   
   # remove any fifos we created
   if (@fifo) {
      unlink @fifo;
   }
}

=head1 SYNOPSIS

B<mp3burn> [OPTION] [mp3,ogg, and flac files]

=cut


#Very much better and more intuitivly to work :)
Getopt::Long::Configure ("bundling");
$files = GetOptions('help|h' => \$help, #Help function
					'swap|m' => \$swap, #Manual swap 
					'playlist|p=s' => \$playlist, #Load a playliste
					'tmpdir|t=s' => \$tempdir, #tempdir
					'check|c=s' => \$check, #timecheck
					'cdrecord|o=s' => \$manual, #cdrecord
					'dummy|d' => \$dummy, #debugfunction
					'atip|a' => \$atip, #show atip infos
					'encoder|M=s' => \$encoder, #external mp3 encoder
					'debug|D' => \$DEBUG); #debugging



=head1 DESCRIPTION

B<mp3burn>
is a simple command line tool for making audio CDs from
MP3s without filling up your disk with .wav files.  It uses
Perl(1), ogg123(1), mpg321(1) or mpg123(1), cdrecord(1), 
flac(1), and the L<MP3::Info(3)> Perl module.

=cut

=head1 OPTIONS

=over 4

=cut

=item B<-h, --help>

Prints out a brief help

=item B<-m, --swap>

Manual C<cdrecord -swab> option mode.  
Use this to disable the automatic detection for swab mode in case it is
not working correctly on your system.  (Also, please send email to
<formorer@formorer.de> or file a bug against the L<mp3burn> package if you
encounter this problem.)

=cut

$manual_cdrecord_opts = $swap;

=item B<-p, --playlist> ".m3u playlist"

Use a playlist to specify audio files to burn.
Instead of (or in addition to) listing mp3/ogg/flac files, 
supply a .m3u playlist (e.g., from xmms) that contains the 
audio files for your CD.

Note:  If you specify both a playlist and audio files, the
files specified on the command-line will be appended to the list 
of audio files listed in the playlist.  If a file referenced
in a playlist cannot be read, it will be skipped.  Be wary of
playlist editors that use relative paths - mp3burn cannot know
what path the playlist editor assumed.
 
=cut


=item B<-t, --tmpdir> "tmpdir"

Put temporary files in F<tmpdir>.
Default is to use the current directory.

=cut

if ($tempdir) {
	$tmpdir=$tempdir ."/";
	die "Cannot write to temp. dir -> $tmpdir" unless  ( -d $tmpdir &&  -w $tmpdir);
}




if (-r "$ENV{'HOME'}/.mp3burnrc") {		#process ~/.mp3burnrc
	if ((stat("$ENV{'HOME'}/.mp3burnrc"))[2] & 02) {
		die "$ENV{'HOME'}/.mp3burnrc should not be world-writable";
	}
	open(RC, "$ENV{'HOME'}/.mp3burnrc");
	$oldRS = $/;
	undef $/;
	$rc = <RC>;
	close(RC);
	unless(defined eval $rc) {
		die "Error in .mp3burnrc:\n$@";
	}
	$/ = $oldRS;
}

#cdrecord_opts must be determined before -c or -a options are processed.
#The value of $CDR_DEVICE must be explicitly added to $cdrecord_opts
#in order to get past our checks.  Other cdrecord env vars need not be processed by us.
if(exists $ENV{'CDR_DEVICE'}) {
   $cdrecord_opts .= " dev=" . $ENV{'CDR_DEVICE'} . " ";
   if ($DEBUG) {
      print "adding the value of environment variable CDR_DEVICE to the cdrecord_opts\n";
   }
}

$cdrecord_opts = $manual if $manual; 	# -o overrides .mp3burnrc

=item B<-c, --check> "MMM:SS" | ATIP

Time check:  compute the total length of files to be burned
and warn if greater than I<MMM:SS> minutes and seconds.  If
the value ATIP is supplied, the total length is checked
against the length available on the CDR[W] as reported by
ATIP.

Note that FLAC-encoded files are assumed to be 1 second long
(until there is an easy way to get the file duration).  You
will need to calculate burn-length on your own with FLAC files.

=cut

if ($check) {
	die "Time check not available without MP3::Info module" if $no_mp3info;
	if ($check =~ /ATIP/i) { #If the user trusts ATIP info use that for our time check
		get_ATIP_info();
	} else { #Otherwise a time is supplied
		die "Time check needs to be in the form of MMM:SS or 'ATIP'" 
			unless ($check =~ /\d{0,3}\:\d{2}$/);
		($min,$sec)=split(/\:/,$check);
	}
}

# this is no longer necessarily a condition to die...
#if ($cdrecord_opts eq '') {
#	die "Need to specify cdrecord options through -o or .mp3burnrc\n" .
#		"Usage:  mp3burn [-c MMM:SS] [-d] [-t tmpdir] [-o cdrecord_opts] [mp3 files]\n";
#}


=item B<-d, --dummy>

Perform a "dummy" run: do everything except actually burn the CD
(uses L<cdrecord(1)> C<-dummy> option).

=cut

if ($dummy) {
   $cdrecord_opts .= " -dummy";
}   


=item B<-o, --cdrecord>  "cdrecord_opts"

Specify the command line options for cdrecord. 
The quotes are required to prevent B<mp3burn> from parsing cdrecord(1) options.
Overrides options specified in F<~/.mp3burnrc>.

Example: B<-o> "-v dev=1,0 speed=4 -swab"

=item B<Note:>

The options I<-pad> and I<-audio> are added automatically, since they are
always necessary.  The script also tries to detect if I<-swab>  is needed (for
example on x86 and other little-Endian platforms).  cdrecord is supposed
to take care of any byte-ordering requirements specific to your burner. 
(If you end up with a CD that merely sounds like static, you most likely
need to toggle use of I<-swab>.)  You should also consider using I<-v> so
that you can watch the burn in progress. This goes for F<~/.mp3burnrc> also.

=cut

$cdrecord_opts .= " -pad -audio";

unless ($manual_cdrecord_opts) {
   # if the datastream is in little-endian order, we need to 
   # add the swab flag to cdrecord if it's not already present

   if (!($cdrecord_opts =~ /.*-swab.*/)) {
      # assert: swab wasn't set
      # check to see if it's needed
      chop ($arch = `/bin/uname -m`);
      if ($DEBUG) { print "arch=$arch\n"; }

      if ($arch =~ /i[3456]86/ || $arch =~ /x86_64/ || $arch =~ /ppc/ ) {	# ia32 - we need to swab
	 $cdrecord_opts .= " -swab";
         if ($DEBUG) { print "-swab flag automatically added\n"; }
      } #elsif () {}			# what other arch's need this?
   }
}

=item B<-a, --atip> 

Lookup the ATIP info for the device in the cdburner 
(using L<cdrecord(1)> C<-atip>) and then exits.  This 
option can only be used (successfully) in conjuction with B<-o>.

=cut 

# process -a (ATIP) flag
if ($atip) { 	# We just want to see how much time the disk has
	if ($check || $dummy || $tempdir) {
		#The -a option is mutually exclusive of all but the -o
		#"cdrecord options" switch
		$errmsg = "The '-a' ATIP check cannot be used with any other switches\n";
		$errmsg .= "You may use '-c ATIP' to automatically use disk ATIP info, however.";
		die $errmsg;
	} else {
		get_ATIP_info(); #Let's get the ATIP info and bail
		exit 0;
	}
}


unless ($playlist) {
   # display usage if there is no playlist and no audio filename args or if -h is ommitted
   if (! @ARGV || $help) {
	pod2usage(1);
   }
}

# check to see if mpg123 is present 
#
# since this package depends on mpg321, we can count on 
# /usr/bin/mpg123 being a link to /etc/alternatives and then mpg321
# by default - for the time being check for the debian install of
# mpg123 in mpg123-oss <grumble>


=item B<-M, --encoder> "MP3 decoder"

Use an MP3 decoder other than the default, which is mpg321.  This is
imperative when burning tracks that have sample rates other than 44.1kHz,
and the current version of mpg321 will not decode these files.  Specify
the name of the decoder to be used, e.g. F<mpg123-oss-3dnow>;  you can
also specify this in  your .mp3burnrc file with B<$mp3decoder
=> F<mp3decoder>.  I<(Note:  Currently, the MP3 decoder must be
able to accept mpg123-style command-line arguments.)>

=cut

$mp3decoder = $encoder if $encoder;		# -M overrides .mp3burnrc
if ($mp3decoder) {
   $mp3decoder = `which $mp3decoder`;
   chop $mp3decoder;
   die "Cannot locate MP3 decoder -> $encoder" unless (-x $mp3decoder);
} 
#No mp3decoder choosed ? We use our default

if (! $mp3decoder) { $mp3decoder = "mpg123"; }
if (! `which $mp3decoder`) {
	print "$mp3decoder not found...\n";
	print "Try mpg123: ";
	if (`which mpg123`) {
		print "found\n";
		$mp3decoder = `which mpg123`;
	} else {
		print "not found\n";
		print "Try mpg321: ";
		if (`which mpg321`){
			print "found\n";
			$mp3decoder = `which mpg321`;
		} else {
			print "not found\n";
			die "No mpg123 compatible player found";
		}
	print "Using $mp3decoder as mp3 decoder\n";
	}
} else {
	$mp3decoder = `which $mp3decoder`;
}
chop $mp3decoder;

# process the playlist - push these files onto ARGV
if ($playlist) {
   shift 
   my @playlist_files;
   open (PL, $playlist) || die "cannot open playlist $playlist";

   while (<PL>) {
      # skip over comments/headers, others lines should be filenames
      next if ($_ =~ /^#/);
      chomp;
      if (-r $_) {
         unshift (@playlist_files, $_);
      } else {
         print "file not found - skipping playlist file $_";
      }
   }
   close (PL);
 
   foreach $element (@playlist_files) {
      quotemeta($element);
      unshift (@ARGV, $element);
   }
}

#############################################
# loop over the audio filenames in ARGV
#############################################
for ($i = 0; $i <= $#ARGV; $i++) {		
	die "$ARGV[$i] does not exist or invalid audio file" unless (-f $ARGV[$i]); #Check to see if file exists
	if (-l $ARGV[$i]) {		#mp3info doesn't work on symlinks
	    $file = readlink $ARGV[$i];
	} else {
	    $file = $ARGV[$i];
	}

	# 2002/11/10 <tmancill@debian.org>
	# moved get_audio_info up to avoid creating FIFO when we don't
	# have a valid audio file to work with
	$info = get_audio_info $file; #Let's get the mp3's time
	unless ($info) {
	   print "skipping file: $file - not a valid MP3, OGG, or FLAC file, or decoder is not installed!\n";
	   next;
	}

	
        if ($DEBUG) {
	   print "creating FIFO for audio file: $file\n";
	}

	$fifo[$i] = $tmpdir . basename $ARGV[$i];	#set the names of the fifos
	$fifo[$i] =~ s/$/.cdr/i;		#foo.mp3 -> foo.mp3.cdr

	if ($sec) {	
	    $totsecs += $info->{SECS} + 2; # total time + 2 for padding
	}
	system "mkfifo", $fifo[$i];	#Make our fifos (optionally to the tempdir)
 	# 2000/11/21 <tmancill@debian.org>
	# beef up the fork() code - example taken from camel book
	FORK:
        if ($pid = fork) {
           # we're in the parent here, child pid in $pid
           # we could use a list, but we're lazy and know how many procs
           # there will be, so use an array
           push @children, $pid;
        } elsif (defined $pid) {
           # if $pid is defined, it's == 0
           #start decoder processes
	  
	   if ($DEBUG) {
	   	print "Decoder: @{$info->{DECODER}} File: $ARGV[$i]\n";
	   }
	   close(STDOUT);
	   open(STDOUT, ">$fifo[$i]");	#this to avoid using the shell
	   exec(@{$info->{DECODER}},  $ARGV[$i]);
	   die "Failed to exec \`".join(" ",@{$info->{DECODER}})."\': $!";
	} elsif ($! =~ /No more process/) {
           # EAGAIN, supposedly recoverable fork error
           sleep 5;
           redo FORK;
        } else {
           # weird fork error
           die "Can't fork: $!\n";
        }
}

#If we have no valid files left we should die

die "No valid files to burn left. Exiting\n" unless @fifo;

$totmin=int $totsecs/60;
$totsec=$totsecs % 60;
if (($totsecs > (($min*60)+$sec)) && $sec) {
	printf "The max time allocated was [$min:%02d].\n", $sec;
	printf "The total time came to [$totmin:%02d]\n", $totsec;
	print "Do you wish to continue? (Y/N) ";
	while (1) {
		$key=uc(getc);
		if ($key eq 'N') {
			unlink @fifo;
   			print "cleaning up children: @children\n";
   			kill 'TERM', @children;
			exit 1;
		}
		last if ($key eq 'Y');
	}
}
if ($sec){
	printf "\nTotal time is [$totmin:%02d] of [$min:%02d] available calculated\n\n", $totsec;
	sleep 3;
}
 
# prepare the command line
# We use now the shellquote module for escaping the filenames 
$cdrecordcmd = "cdrecord " . join (" ", split(/\s+/, $cdrecord_opts)) . " " . shell_quote @fifo;

if ($DEBUG) { 
   print "invoking cdrecord with:\n";
   print "$cdrecordcmd\n";
}

# burn!
$rc = system "$cdrecordcmd";

# check the return code from cdrecord
if ($rc != 0) {
   # cdrecord exited non-zero
   print "warning:  cdrecord exited non-zero!\n";
}

&Cleanup;   
   
exit 0;


=head1 RETURN VALUE

B<mp3burn> returns 0 on success.

=head1 DIAGNOSTICS

=item Error in .mp3burnrc:

Perl(1) cannot parse the F<.mp3burnrc> file.
The following example occurs when a double quote is not terminated:

  bash-2.05$ sudo mp3burn -d ~/bell.ogg 
  String found where operator expected at (eval 10) line 7, at end of line
	  (Missing operator before ?)
  Error in .mp3burnrc:
  Can't find string terminator '"' anywhere before EOF at (eval 10) line 7.
  bash-2.05$ 
  
You will experience this error if you define both $cdrecord_opts and
$mp3decoder without terminating the variable assignments with the ';' 
character:

  $ mp3burn -d -t /tmp Theodor_Storm_Aquis_submersus_1.mp3 
  Scalar found where operator expected at (eval 10) line 2, near ""-v speed=2 dev=0,3,0"
  $mp3decoder"
        (Missing operator before 
  $mp3decoder?)
  Error in .mp3burnrc:
  syntax error at (eval 10) line 2, near ""-v speed=2 dev=0,3,0"
  $mp3decoder" 

=back

=head1 EXAMPLES

Write an Ogg Vorbis file from a CD-R drive, F</dev/scd0>, 
mounted at F</mnt/scd0/> to a 
CD-RW drive, F</dev/scd1>, called C<0,1,0> in cdrecord(1) SCSI notation.
Ensure that file is no longer than 50 minutes.
L<sudo(1)> is used to get root permissions for cdrecord(1).

  % sudo mp3burn -c 050:00 -o "-v speed=2 dev=0,1,0" /mnt/scd0/bell.ogg

Create a F<~/.mp3burnrc> that prints a message before writing and uses
a different MP3 decoder than the default of mpg321.

  # This is an example.
  $cdrecord_opts="-v speed=2 dev=0,1,0";
  $mp3decoder = "mpg123-oss-3dnow";

  print "Nine seconds to slap a CD-R in the drive!\n" ;

  #
  # See mp3burn(3).
  #

Specify an mp3decoder other than mpg321.

  $ sudo mp3burn -M mpg123-esd ./rush/*mp3
  
=head1 FILES

=over 4

=item F<~/.mp3burnrc>

In this file, you may permanently specify the cdrecord options and
MP3 decoder you want to use.  The format is:

  $cdrecord_opts = "cdrecord options";
  $mp3decoder = "some mp3 decoder";

You may place comments in this file by beginning a line with C<#>.

=item B<Note:>

The values of $cdrecord_opts and $mp3decoder in F<~/.mp3burnrc> are ignored 
if the C<-o> or C<-<>command-line options are used, respectively.

=back

=head1 CAVEATS

Has not been tested extensively with Ogg Vorbis files.
Ogg Vorbis files must be in CD-DA format: 
i.e. 44100 samples/channel x 16 bits/sample x 2 channels.

=head1 BUGS

If you execute B<mp3burn> with root permissions, 
the F<~/.mp3burnrc> will also be executed with root permissions.

=head1 NOTES

There are a number of GUI frontends for B<mp3burn>:

=over

=item Xmp3Burn 
  
http://perso.wanadoo.es/ja_recio/xmp3burn/xmp3burn.html

=item Kmp3burn

http://computer.freepage.de/kmp3burn/index.htm

=item GtkMp3Burn

http://gtkmp3burn.sourceforge.net/

=back

=head1 SEE ALSO

cdrecord(1), mpg321(1), ogg123(1), ogginfo(1), flac(1), L<MP3::Info(3)>
The B<mp3burn> web page is http://mp3burn.sourceforge.net/.
The Ogg Vorbis web page is http://www.xiph.org/ogg/vorbis/.
The FLAC web page is http://flac.sourceforge.net/.

=head1 AUTHOR

Copyright (c) 2000 Ryan Richter. 
Copyright (c) 2003 Alexander Wirt

This script was written by Ryan Richter <bobort@bigfoot.com> with much code
contributed by Dan Lark <dlark@spinn.net>.

I would like to thank Dan Lark <dlark@spinn.net> for
contributing the ideas and code for most of the new features,
and Tony Mancill <tony@mancill.com> for making Debian packages
and helping with debugging.

Later in 2003 Alexander Wirt continued to write this program. 

This program is licensed under the GNU General Public License.
You may fold, spindle, and mutilate this software under the terms of the GPL.

=head1 HISTORY

=over

=item  20031014 <formorer@formorer.de>

Switches from standard getopt to GetOpts::Long

Updated Manpage for the new option format

=item  20031012 <formorer@formorer.de>

Updated mp3burn to use pod2usage

Added -h switch for getting help

Fixed a bug with the output of file in conduction with FLAC files

Added a gracefully exit if there are no valid files left

Use String::Shellquote to avoid problems with the shell

=item  20030203 <tmancill@debian.org>

hacked in support for FLAC, as per suggested by <ldm@apartia.org>

=item  20021110 <tmancill@debian.org>

updated to work with new ogginfo output format in vorbis-tools 1.0; 
modified slightly to not create FIFOs for invalid MP3/OGG files

=item  20020728 <tmancill@debian.org>

added I<-M $mp3decoder> switch to support MP3 decoders other than 
mpg321 and mpg123-oss

=item  20010917	<tmancill@debian.org>	

added check to automatically add -swab on ia32 platform

L<MP3::Info(3)> replaces MPEG::MP3Info

=item B<mp3burn> 0.02 10/28/00

Changes since 0.01:

Bugfixes:

Spaces, quotes, and other shell metacharacters in filenames
should no longer problematic, since we use Shell:QuoteString 
to avoid problems with that (Feedback for that is wished).

Mono MP3s and MP3s not sampled at 44.1kHz are no longer
problematic.

New Features:

Editing the executable is no longer necessary; cdrecord
options can be specified on the command line or in F<~/.mp3burnrc>.

Temp dir for FIFOs may be set to other than the current dir.

Dummy runs now supported from the command line.

A time check is now available: B<mp3burn> can abort if total
time exceeds a threshold.  Requires L<MPEG::MP3Info>.

Playlist support.

=back

=cut

