1#!/usr/local/bin/perl 2# 3# mp3burn $Revision: 0.13 $ $Date: 2008/10/04 10:23:21 $ 4# based upon mp3burn-0.1 - see http://sourceforge.net/projects/mp3burn/ 5# 6#Copyright 2000 Ryan Richter <bobort@bigfoot.com> 7#With help from Dan Lark <dlark@pcisys.net> 8#Copyright 2003 Alexander Wirt <formorer@formorer.de> 9# 10#You may fold, spindle, and mutilate this software under the terms of the GPL 11# 12# $Log: mp3burn,v $ 13# Revision 0.13 2008/10/04 10:23:21 formorer 14# Fix swab detection 15# 16# Revision 0.12 2006/09/24 09:38:28 formorer 17# Add swap support for ppc 18# 19# Revision 0.11 2005/02/09 21:10:51 formorer 20# Added swab detection for amd64 21# 22# Revision 0.10 2004/07/08 20:33:50 formorer 23# - Fixed some small typo - thanks to sdelafond@lika.fr.st 24# 25# Revision 0.9 2004/06/20 15:22:18 formorer 26# Added Support for length detection of FLAC files. 27# (There must be someone outside really using them ;)) 28# 29# Revision 0.8 2004/06/05 06:40:34 formorer 30# I'm bored from any locale problems or changes in the output of ogginfo... 31# So I decided to switch to Ogg::Vorbis::Header and it work like a charme.. 32# Here it is. 33# 34# Revision 0.7 2004/06/05 05:56:18 formorer 35# the decection of the correct mp3decoder is now much smarter :) 36# 37# Revision 0.6 2004/04/28 08:06:37 formorer 38# Fixed Flac Detection - Thanks to: Georg Wittmann <debian-bug@pbrz.de> 39# 40# Revision 0.5 2004/04/14 10:06:39 formorer 41# Fixed get_atip function, so that $cdrecord_opts are recognized 42# 43# Revision 0.4 2004/01/02 09:12:48 formorer 44# Fixed Podparsing 45# 46# Revision 0.3.1.1 2004/01/01 21:43:57 formorer 47# Initial Import 48# 49###################### 50 51 52=head1 NAME 53 54mp3burn - burn audio CDs from MP3, Ogg Vorbis, or FLAC files 55 56=cut 57 58use MP3::Info; 59use File::Basename; 60use Pod::Usage; 61use String::ShellQuote; 62use Getopt::Long; 63use Ogg::Vorbis::Header; 64 65sub get_audio_info { 66 my ($filename) =@_; 67 my $hash = {}; 68 my $fileinfo=`file -b "$filename"`; 69 if ($fileinfo =~ m/FLAC/i) { 70 #If the FLAC decoder is not installed we just exit 71 $flac = `which flac`; 72 chomp $flac; 73 if (! -x $flac) { print "FLAC decoder is not available\n"; return; } 74 75 # FLAC file 76 # we don't know the length, so just set it to 1 second 77 $hash->{DECODER}=["flac", "-d", "-F", "-s", "-c"]; 78 eval "require Audio::FLAC"; 79 if ($@) { 80 if ($DEBUG) { print "No Audio::FLAC available\n"; } 81 $hash->{SECS} = 1; 82 } else { 83 require Audio::FLAC; 84 my $flac = Audio::FLAC->new("$filename"); 85 $hash->{SECS} = $flac->{trackTotalLengthSeconds}; 86 if ($DEBUG) { print "Flac Length: $hash->{SECS}\n"; } 87 88 } 89 90 } elsif ($fileinfo =~ m/Ogg data/i) { 91 # Ogg/Vorbis processing 92 $hash->{DECODER}=["ogg123", "-d", "raw", "-f", "-", "-q"]; 93 my $ogginfo = Ogg::Vorbis::Header->new("$filename"); 94 if (! defined $ogginfo) { 95 undef $hash; 96 next; 97 } 98 99 $hash->{SECS} = $ogginfo->info('length'); 100 $hash->{MODE} = $ogginfo->info('channels'); 101 $hash->{FREQUENCY} = $ogginfo->info('rate'); 102 if ($DEBUG) { 103 print "ogg parsing:\n"; 104 print "\tchannels=$hash->{MODE}\n"; 105 print "\trate=$hash->{FREQUENCY}\n"; 106 print "\tlength=$hash->{SECS}\n"; 107 } 108 } elsif ($hash = MP3::Info::get_mp3info($filename)) { 109 if ($mp3decoder) { 110 $hash->{DECODER} = ["$mp3decoder", "--rate", "44100", "--stereo", "-s", "-q"]; 111 } else { 112 if ($hash->{FREQUENCY} != 44.1) { 113 print "*** unable to continue ***\n"; 114 print " mpg321 cannot handle files with sample rates != 44.1kHz\n"; 115 print " sample rate is $hash->{FREQUENCY} for file: $filename\n"; 116 print " please either burn without this file or see the mp3burn manpage\n"; 117 print " about using -M or setting \$mp3decoder in \~/.mp3burnrc\n"; 118 &Cleanup; 119 exit 1; 120 } 121 $hash->{DECODER} = ["mpg321", "--rate", "44100", "--stereo", "-s", "-q"]; 122 } 123 } 124 # else we don't know what type of file this is... 125 $hash; 126} 127 128 129sub get_ATIP_info () { 130 #die "No CDR device information is available. Please specify the device." unless ($1); 131 #eject doesn't work with the atip switch... also it would be counterproductive to eject 132 #the cd before burning... so just remove it 133 134 $atipoptions = $cdrecord_opts; 135 $atipoptions =~ s/-eject//; 136 137 if ($DEBUG) { print "Call cdrecord with: cdrecord -atip $atipoptions. \n"; } 138 open(CDINFO,"cdrecord -atip $atipoptions 2>&1 |"); #Use cdrecord -atip to get ATIP info 139 while (<CDINFO>) { 140 if (/cdrecord: No CD\/DVD-Recorder device specified/) { 141 print "No CDR device specified. It must be specified via on of the following:\n"; 142 print "\tdev=\$device in \~/.mp3burnrc\n"; 143 print "\t-o \"dev=\$device\" on the command-line\n"; 144 print "\tthe value of \$CDR_DEVICE in the environment\n"; 145 print "\tin the file /etc/default/cdrecord (man cdrecord)\n"; 146 exit 1; 147 } 148 next unless (/out:.+\((\d+):(\d+)/); #The lead out time is what we want 149 $min=$1; $sec=$2; 150 } 151 close CDINFO; 152 die "No CD-R in CD Writer." unless ($sec && $min); 153 printf "ATIP reports available time: [%d:%.2d]\n",$min,$sec; 154} 155 156 157sub Cleanup { 158 159 # kill off any children that might still be around 160 if (@children) { 161 print "cleaning up children: @children\n"; 162 kill 'TERM', @children; 163 } 164 165 # remove any fifos we created 166 if (@fifo) { 167 unlink @fifo; 168 } 169} 170 171=head1 SYNOPSIS 172 173B<mp3burn> [OPTION] [mp3,ogg, and flac files] 174 175=cut 176 177 178#Very much better and more intuitivly to work :) 179Getopt::Long::Configure ("bundling"); 180$files = GetOptions('help|h' => \$help, #Help function 181 'swap|m' => \$swap, #Manual swap 182 'playlist|p=s' => \$playlist, #Load a playliste 183 'tmpdir|t=s' => \$tempdir, #tempdir 184 'check|c=s' => \$check, #timecheck 185 'cdrecord|o=s' => \$manual, #cdrecord 186 'dummy|d' => \$dummy, #debugfunction 187 'atip|a' => \$atip, #show atip infos 188 'encoder|M=s' => \$encoder, #external mp3 encoder 189 'debug|D' => \$DEBUG); #debugging 190 191 192 193=head1 DESCRIPTION 194 195B<mp3burn> 196is a simple command line tool for making audio CDs from 197MP3s without filling up your disk with .wav files. It uses 198Perl(1), ogg123(1), mpg321(1) or mpg123(1), cdrecord(1), 199flac(1), and the L<MP3::Info(3)> Perl module. 200 201=cut 202 203=head1 OPTIONS 204 205=over 4 206 207=cut 208 209=item B<-h, --help> 210 211Prints out a brief help 212 213=item B<-m, --swap> 214 215Manual C<cdrecord -swab> option mode. 216Use this to disable the automatic detection for swab mode in case it is 217not working correctly on your system. (Also, please send email to 218<formorer@formorer.de> or file a bug against the L<mp3burn> package if you 219encounter this problem.) 220 221=cut 222 223$manual_cdrecord_opts = $swap; 224 225=item B<-p, --playlist> ".m3u playlist" 226 227Use a playlist to specify audio files to burn. 228Instead of (or in addition to) listing mp3/ogg/flac files, 229supply a .m3u playlist (e.g., from xmms) that contains the 230audio files for your CD. 231 232Note: If you specify both a playlist and audio files, the 233files specified on the command-line will be appended to the list 234of audio files listed in the playlist. If a file referenced 235in a playlist cannot be read, it will be skipped. Be wary of 236playlist editors that use relative paths - mp3burn cannot know 237what path the playlist editor assumed. 238 239=cut 240 241 242=item B<-t, --tmpdir> "tmpdir" 243 244Put temporary files in F<tmpdir>. 245Default is to use the current directory. 246 247=cut 248 249if ($tempdir) { 250 $tmpdir=$tempdir ."/"; 251 die "Cannot write to temp. dir -> $tmpdir" unless ( -d $tmpdir && -w $tmpdir); 252} 253 254 255 256 257if (-r "$ENV{'HOME'}/.mp3burnrc") { #process ~/.mp3burnrc 258 if ((stat("$ENV{'HOME'}/.mp3burnrc"))[2] & 02) { 259 die "$ENV{'HOME'}/.mp3burnrc should not be world-writable"; 260 } 261 open(RC, "$ENV{'HOME'}/.mp3burnrc"); 262 $oldRS = $/; 263 undef $/; 264 $rc = <RC>; 265 close(RC); 266 unless(defined eval $rc) { 267 die "Error in .mp3burnrc:\n$@"; 268 } 269 $/ = $oldRS; 270} 271 272#cdrecord_opts must be determined before -c or -a options are processed. 273#The value of $CDR_DEVICE must be explicitly added to $cdrecord_opts 274#in order to get past our checks. Other cdrecord env vars need not be processed by us. 275if(exists $ENV{'CDR_DEVICE'}) { 276 $cdrecord_opts .= " dev=" . $ENV{'CDR_DEVICE'} . " "; 277 if ($DEBUG) { 278 print "adding the value of environment variable CDR_DEVICE to the cdrecord_opts\n"; 279 } 280} 281 282$cdrecord_opts = $manual if $manual; # -o overrides .mp3burnrc 283 284=item B<-c, --check> "MMM:SS" | ATIP 285 286Time check: compute the total length of files to be burned 287and warn if greater than I<MMM:SS> minutes and seconds. If 288the value ATIP is supplied, the total length is checked 289against the length available on the CDR[W] as reported by 290ATIP. 291 292Note that FLAC-encoded files are assumed to be 1 second long 293(until there is an easy way to get the file duration). You 294will need to calculate burn-length on your own with FLAC files. 295 296=cut 297 298if ($check) { 299 die "Time check not available without MP3::Info module" if $no_mp3info; 300 if ($check =~ /ATIP/i) { #If the user trusts ATIP info use that for our time check 301 get_ATIP_info(); 302 } else { #Otherwise a time is supplied 303 die "Time check needs to be in the form of MMM:SS or 'ATIP'" 304 unless ($check =~ /\d{0,3}\:\d{2}$/); 305 ($min,$sec)=split(/\:/,$check); 306 } 307} 308 309# this is no longer necessarily a condition to die... 310#if ($cdrecord_opts eq '') { 311# die "Need to specify cdrecord options through -o or .mp3burnrc\n" . 312# "Usage: mp3burn [-c MMM:SS] [-d] [-t tmpdir] [-o cdrecord_opts] [mp3 files]\n"; 313#} 314 315 316=item B<-d, --dummy> 317 318Perform a "dummy" run: do everything except actually burn the CD 319(uses L<cdrecord(1)> C<-dummy> option). 320 321=cut 322 323if ($dummy) { 324 $cdrecord_opts .= " -dummy"; 325} 326 327 328=item B<-o, --cdrecord> "cdrecord_opts" 329 330Specify the command line options for cdrecord. 331The quotes are required to prevent B<mp3burn> from parsing cdrecord(1) options. 332Overrides options specified in F<~/.mp3burnrc>. 333 334Example: B<-o> "-v dev=1,0 speed=4 -swab" 335 336=item B<Note:> 337 338The options I<-pad> and I<-audio> are added automatically, since they are 339always necessary. The script also tries to detect if I<-swab> is needed (for 340example on x86 and other little-Endian platforms). cdrecord is supposed 341to take care of any byte-ordering requirements specific to your burner. 342(If you end up with a CD that merely sounds like static, you most likely 343need to toggle use of I<-swab>.) You should also consider using I<-v> so 344that you can watch the burn in progress. This goes for F<~/.mp3burnrc> also. 345 346=cut 347 348$cdrecord_opts .= " -tao -pad -audio"; 349 350unless ($manual_cdrecord_opts) { 351 # if the datastream is in little-endian order, we need to 352 # add the swab flag to cdrecord if it's not already present 353 354 if (!($cdrecord_opts =~ /.*-swab.*/)) { 355 # assert: swab wasn't set 356 # check to see if it's needed 357 chop ($arch = `/usr/bin/uname -m`); 358 if ($DEBUG) { print "arch=$arch\n"; } 359 360 if ($arch =~ /i[3456]86/ || $arch =~ /amd64/ || $arch =~ /ppc/ ) { # ia32 - we need to swab 361 $cdrecord_opts .= " -swab"; 362 if ($DEBUG) { print "-swab flag automatically added\n"; } 363 } #elsif () {} # what other arch's need this? 364 } 365} 366 367=item B<-a, --atip> 368 369Lookup the ATIP info for the device in the cdburner 370(using L<cdrecord(1)> C<-atip>) and then exits. This 371option can only be used (successfully) in conjuction with B<-o>. 372 373=cut 374 375# process -a (ATIP) flag 376if ($atip) { # We just want to see how much time the disk has 377 if ($check || $dummy || $tempdir) { 378 #The -a option is mutually exclusive of all but the -o 379 #"cdrecord options" switch 380 $errmsg = "The '-a' ATIP check cannot be used with any other switches\n"; 381 $errmsg .= "You may use '-c ATIP' to automatically use disk ATIP info, however."; 382 die $errmsg; 383 } else { 384 get_ATIP_info(); #Let's get the ATIP info and bail 385 exit 0; 386 } 387} 388 389 390unless ($playlist) { 391 # display usage if there is no playlist and no audio filename args or if -h is ommitted 392 if (! @ARGV || $help) { 393 pod2usage(1); 394 } 395} 396 397# check to see if mpg123 is present 398# 399# since this package depends on mpg321, we can count on 400# /usr/bin/mpg123 being a link to /etc/alternatives and then mpg321 401# by default - for the time being check for the debian install of 402# mpg123 in mpg123-oss <grumble> 403 404 405=item B<-M, --encoder> "MP3 decoder" 406 407Use an MP3 decoder other than the default, which is mpg321. This is 408imperative when burning tracks that have sample rates other than 44.1kHz, 409and the current version of mpg321 will not decode these files. Specify 410the name of the decoder to be used, e.g. F<mpg123-oss-3dnow>; you can 411also specify this in your .mp3burnrc file with B<$mp3decoder 412=> F<mp3decoder>. I<(Note: Currently, the MP3 decoder must be 413able to accept mpg123-style command-line arguments.)> 414 415=cut 416 417$mp3decoder = $encoder if $encoder; # -M overrides .mp3burnrc 418if ($mp3decoder) { 419 $mp3decoder = `which $mp3decoder`; 420 chop $mp3decoder; 421 die "Cannot locate MP3 decoder -> $encoder" unless (-x $mp3decoder); 422} 423#No mp3decoder choosed ? We use our default 424 425if (! $mp3decoder) { $mp3decoder = "mpg123"; } 426if (! `which $mp3decoder`) { 427 print "$mp3decoder not found...\n"; 428 print "Try mpg123: "; 429 if (`which mpg123`) { 430 print "found\n"; 431 $mp3decoder = `which mpg123`; 432 } else { 433 print "not found\n"; 434 print "Try mpg321: "; 435 if (`which mpg321`){ 436 print "found\n"; 437 $mp3decoder = `which mpg321`; 438 } else { 439 print "not found\n"; 440 die "No mpg123 compatible player found"; 441 } 442 print "Using $mp3decoder as mp3 decoder\n"; 443 } 444} else { 445 $mp3decoder = `which $mp3decoder`; 446} 447chop $mp3decoder; 448 449# process the playlist - push these files onto ARGV 450if ($playlist) { 451 shift 452 my @playlist_files; 453 open (PL, $playlist) || die "cannot open playlist $playlist"; 454 455 while (<PL>) { 456 # skip over comments/headers, others lines should be filenames 457 next if ($_ =~ /^#/); 458 chomp; 459 if (-r $_) { 460 unshift (@playlist_files, $_); 461 } else { 462 print "file not found - skipping playlist file $_"; 463 } 464 } 465 close (PL); 466 467 foreach $element (@playlist_files) { 468 quotemeta($element); 469 unshift (@ARGV, $element); 470 } 471} 472 473############################################# 474# loop over the audio filenames in ARGV 475############################################# 476for ($i = 0; $i <= $#ARGV; $i++) { 477 die "$ARGV[$i] does not exist or invalid audio file" unless (-f $ARGV[$i]); #Check to see if file exists 478 if (-l $ARGV[$i]) { #mp3info doesn't work on symlinks 479 $file = readlink $ARGV[$i]; 480 } else { 481 $file = $ARGV[$i]; 482 } 483 484 # 2002/11/10 <tmancill@debian.org> 485 # moved get_audio_info up to avoid creating FIFO when we don't 486 # have a valid audio file to work with 487 $info = get_audio_info $file; #Let's get the mp3's time 488 unless ($info) { 489 print "skipping file: $file - not a valid MP3, OGG, or FLAC file, or decoder is not installed!\n"; 490 next; 491 } 492 493 494 if ($DEBUG) { 495 print "creating FIFO for audio file: $file\n"; 496 } 497 498 $fifo[$i] = $tmpdir . basename $ARGV[$i]; #set the names of the fifos 499 $fifo[$i] =~ s/$/.cdr/i; #foo.mp3 -> foo.mp3.cdr 500 501 if ($sec) { 502 $totsecs += $info->{SECS} + 2; # total time + 2 for padding 503 } 504 system "mkfifo", $fifo[$i]; #Make our fifos (optionally to the tempdir) 505 # 2000/11/21 <tmancill@debian.org> 506 # beef up the fork() code - example taken from camel book 507 FORK: 508 if ($pid = fork) { 509 # we're in the parent here, child pid in $pid 510 # we could use a list, but we're lazy and know how many procs 511 # there will be, so use an array 512 push @children, $pid; 513 } elsif (defined $pid) { 514 # if $pid is defined, it's == 0 515 #start decoder processes 516 517 if ($DEBUG) { 518 print "Decoder: @{$info->{DECODER}} File: $ARGV[$i]\n"; 519 } 520 close(STDOUT); 521 open(STDOUT, ">$fifo[$i]"); #this to avoid using the shell 522 exec(@{$info->{DECODER}}, $ARGV[$i]); 523 die "Failed to exec \`".join(" ",@{$info->{DECODER}})."\': $!"; 524 } elsif ($! =~ /No more process/) { 525 # EAGAIN, supposedly recoverable fork error 526 sleep 5; 527 redo FORK; 528 } else { 529 # weird fork error 530 die "Can't fork: $!\n"; 531 } 532} 533 534#If we have no valid files left we should die 535 536die "No valid files to burn left. Exiting\n" unless @fifo; 537 538$totmin=int $totsecs/60; 539$totsec=$totsecs % 60; 540if (($totsecs > (($min*60)+$sec)) && $sec) { 541 printf "The max time allocated was [$min:%02d].\n", $sec; 542 printf "The total time came to [$totmin:%02d]\n", $totsec; 543 print "Do you wish to continue? (Y/N) "; 544 while (1) { 545 $key=uc(getc); 546 if ($key eq 'N') { 547 unlink @fifo; 548 print "cleaning up children: @children\n"; 549 kill 'TERM', @children; 550 exit 1; 551 } 552 last if ($key eq 'Y'); 553 } 554} 555if ($sec){ 556 printf "\nTotal time is [$totmin:%02d] of [$min:%02d] available calculated\n\n", $totsec; 557 sleep 3; 558} 559 560# prepare the command line 561# We use now the shellquote module for escaping the filenames 562$cdrecordcmd = "cdrecord " . join (" ", split(/\s+/, $cdrecord_opts)) . " " . shell_quote @fifo; 563 564if ($DEBUG) { 565 print "invoking cdrecord with:\n"; 566 print "$cdrecordcmd\n"; 567} 568 569# burn! 570$rc = system "$cdrecordcmd"; 571 572# check the return code from cdrecord 573if ($rc != 0) { 574 # cdrecord exited non-zero 575 print "warning: cdrecord exited non-zero!\n"; 576} 577 578&Cleanup; 579 580exit 0; 581 582 583=head1 RETURN VALUE 584 585B<mp3burn> returns 0 on success. 586 587=head1 DIAGNOSTICS 588 589=item Error in .mp3burnrc: 590 591Perl(1) cannot parse the F<.mp3burnrc> file. 592The following example occurs when a double quote is not terminated: 593 594 bash-2.05$ sudo mp3burn -d ~/bell.ogg 595 String found where operator expected at (eval 10) line 7, at end of line 596 (Missing operator before ?) 597 Error in .mp3burnrc: 598 Can't find string terminator '"' anywhere before EOF at (eval 10) line 7. 599 bash-2.05$ 600 601You will experience this error if you define both $cdrecord_opts and 602$mp3decoder without terminating the variable assignments with the ';' 603character: 604 605 $ mp3burn -d -t /tmp Theodor_Storm_Aquis_submersus_1.mp3 606 Scalar found where operator expected at (eval 10) line 2, near ""-v speed=2 dev=0,3,0" 607 $mp3decoder" 608 (Missing operator before 609 $mp3decoder?) 610 Error in .mp3burnrc: 611 syntax error at (eval 10) line 2, near ""-v speed=2 dev=0,3,0" 612 $mp3decoder" 613 614=back 615 616=head1 EXAMPLES 617 618Write an Ogg Vorbis file from a CD-R drive, F</dev/scd0>, 619mounted at F</mnt/scd0/> to a 620CD-RW drive, F</dev/scd1>, called C<0,1,0> in cdrecord(1) SCSI notation. 621Ensure that file is no longer than 50 minutes. 622L<sudo(1)> is used to get root permissions for cdrecord(1). 623 624 % sudo mp3burn -c 050:00 -o "-v speed=2 dev=0,1,0" /mnt/scd0/bell.ogg 625 626Create a F<~/.mp3burnrc> that prints a message before writing and uses 627a different MP3 decoder than the default of mpg321. 628 629 # This is an example. 630 $cdrecord_opts="-v speed=2 dev=0,1,0"; 631 $mp3decoder = "mpg123-oss-3dnow"; 632 633 print "Nine seconds to slap a CD-R in the drive!\n" ; 634 635 # 636 # See mp3burn(3). 637 # 638 639Specify an mp3decoder other than mpg321. 640 641 $ sudo mp3burn -M mpg123-esd ./rush/*mp3 642 643=head1 FILES 644 645=over 4 646 647=item F<~/.mp3burnrc> 648 649In this file, you may permanently specify the cdrecord options and 650MP3 decoder you want to use. The format is: 651 652 $cdrecord_opts = "cdrecord options"; 653 $mp3decoder = "some mp3 decoder"; 654 655You may place comments in this file by beginning a line with C<#>. 656 657=item B<Note:> 658 659The values of $cdrecord_opts and $mp3decoder in F<~/.mp3burnrc> are ignored 660if the C<-o> or C<-<>command-line options are used, respectively. 661 662=back 663 664=head1 CAVEATS 665 666Has not been tested extensively with Ogg Vorbis files. 667Ogg Vorbis files must be in CD-DA format: 668i.e. 44100 samples/channel x 16 bits/sample x 2 channels. 669 670=head1 BUGS 671 672If you execute B<mp3burn> with root permissions, 673the F<~/.mp3burnrc> will also be executed with root permissions. 674 675=head1 NOTES 676 677There are a number of GUI frontends for B<mp3burn>: 678 679=over 680 681=item Xmp3Burn 682 683http://perso.wanadoo.es/ja_recio/xmp3burn/xmp3burn.html 684 685=item Kmp3burn 686 687http://computer.freepage.de/kmp3burn/index.htm 688 689=item GtkMp3Burn 690 691http://gtkmp3burn.sourceforge.net/ 692 693=back 694 695=head1 SEE ALSO 696 697cdrecord(1), mpg321(1), ogg123(1), ogginfo(1), flac(1), L<MP3::Info(3)> 698The B<mp3burn> web page is http://mp3burn.sourceforge.net/. 699The Ogg Vorbis web page is http://www.xiph.org/ogg/vorbis/. 700The FLAC web page is http://flac.sourceforge.net/. 701 702=head1 AUTHOR 703 704Copyright (c) 2000 Ryan Richter. 705Copyright (c) 2003 Alexander Wirt 706 707This script was written by Ryan Richter <bobort@bigfoot.com> with much code 708contributed by Dan Lark <dlark@spinn.net>. 709 710I would like to thank Dan Lark <dlark@spinn.net> for 711contributing the ideas and code for most of the new features, 712and Tony Mancill <tony@mancill.com> for making Debian packages 713and helping with debugging. 714 715Later in 2003 Alexander Wirt continued to write this program. 716 717This program is licensed under the GNU General Public License. 718You may fold, spindle, and mutilate this software under the terms of the GPL. 719 720=head1 HISTORY 721 722=over 723 724=item 20031014 <formorer@formorer.de> 725 726Switches from standard getopt to GetOpts::Long 727 728Updated Manpage for the new option format 729 730=item 20031012 <formorer@formorer.de> 731 732Updated mp3burn to use pod2usage 733 734Added -h switch for getting help 735 736Fixed a bug with the output of file in conduction with FLAC files 737 738Added a gracefully exit if there are no valid files left 739 740Use String::Shellquote to avoid problems with the shell 741 742=item 20030203 <tmancill@debian.org> 743 744hacked in support for FLAC, as per suggested by <ldm@apartia.org> 745 746=item 20021110 <tmancill@debian.org> 747 748updated to work with new ogginfo output format in vorbis-tools 1.0; 749modified slightly to not create FIFOs for invalid MP3/OGG files 750 751=item 20020728 <tmancill@debian.org> 752 753added I<-M $mp3decoder> switch to support MP3 decoders other than 754mpg321 and mpg123-oss 755 756=item 20010917 <tmancill@debian.org> 757 758added check to automatically add -swab on ia32 platform 759 760L<MP3::Info(3)> replaces MPEG::MP3Info 761 762=item B<mp3burn> 0.02 10/28/00 763 764Changes since 0.01: 765 766Bugfixes: 767 768Spaces, quotes, and other shell metacharacters in filenames 769should no longer problematic, since we use Shell:QuoteString 770to avoid problems with that (Feedback for that is wished). 771 772Mono MP3s and MP3s not sampled at 44.1kHz are no longer 773problematic. 774 775New Features: 776 777Editing the executable is no longer necessary; cdrecord 778options can be specified on the command line or in F<~/.mp3burnrc>. 779 780Temp dir for FIFOs may be set to other than the current dir. 781 782Dummy runs now supported from the command line. 783 784A time check is now available: B<mp3burn> can abort if total 785time exceeds a threshold. Requires L<MPEG::MP3Info>. 786 787Playlist support. 788 789=back 790 791=cut 792 793