#!/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"};
}
