#!/usr/bin/perl -w use strict; # extract one or more tracks from a FLAC file using its embedded cuesheet # save those tracks as wav or mp3 files # can also run them through a sox filter # TODO: separate sox filter for each track! use Getopt::Long; use MusicBrainz; GetOptions( 'D=s' => \my %TRACKS, 't=s' => \my $TYPE, 'x=s' => \my $SOX_FILTER, ); my $FLAC_FILE = shift or die "Need a flac file to decode"; # default to mp3 $TYPE ||= 'mp3'; # for getting track metadata from MusicBrainz my $info; if ($TYPE eq 'mp3') { require Audio::FLAC::Header; require LWP; require XML::XPath; require XML::XPath::XMLParser; my $flac = Audio::FLAC::Header->new($FLAC_FILE) or warn "Can't read FLAC header from $FLAC_FILE\n"; my $discid = $flac->tags('MBZ_DISCID') or warn "No MBZ_DISCID tag in $FLAC_FILE\n" if $flac; #TODO: calculate TOC and DISCID from cuesheet if there is no MBZ_DISCID tag present $info = get_musicbrainz_info($discid); } while (my ($tracknum, $title) = each %TRACKS) { if ($tracknum !~ /^\d+$/) { warn "Don't know what to do with track number '$tracknum'"; next; } my $start = $tracknum . '.1'; my $end = $tracknum + 1 . '.1'; my $cmd = qq{flac -d --cue $start-$end $FLAC_FILE -o - }; if ($SOX_FILTER) { $cmd .= qq{| sox -t wav - -t wav - $SOX_FILTER }; } $title = quotemeta($title); if ($TYPE eq 'mp3') { # bitrate of 192 $cmd .= qq{| lame -b 192}; # if there is track info, add it as ID3 tags if ($info) { my $track = $info->{TRACKS}[$tracknum]; $cmd .= sprintf q{ --tt %s --ta %s --tl %s --tn %d}, quote($track->{TITLE}), quote($track->{ARTIST}), quote($info->{ALBUM}), $tracknum; } $cmd .= qq{ - $title.mp3}; } elsif ($TYPE eq 'wav') { $cmd .= qq{> $title.wav}; } else { die "Unknown type: $TYPE\n"; } #die $cmd; system $cmd; print "\n" if $SOX_FILTER; } sub quote { my ($string) = @_; $string =~ s/"/\\"/g; return qq{"$string"}; }