source: flacrip/trunk/flactrack @ 1

Last change on this file since 1 was 1, checked in by peter, 12 years ago

initial import of current flacrip files into the trunk

  • Property svn:executable set to *
File size: 3.5 KB
Line 
1#!/usr/bin/perl -w
2use strict;
3
4# extract one or more tracks from a FLAC file using its embedded cuesheet
5# save those tracks as wav or mp3 files
6# can also run them through a sox filter
7# TODO: separate sox filter for each track!
8
9use Getopt::Long;
10
11GetOptions(
12    'D=s' => \my %TRACKS,
13    't=s' => \my $TYPE,
14    'x=s' => \my $SOX_FILTER,
15);
16
17my $FLAC_FILE = shift or die "Need a flac file to decode";
18
19# default to mp3
20$TYPE ||= 'mp3';
21
22# for getting track metadata from MusicBrainz
23my %info;
24if ($TYPE eq 'mp3') {
25    require Audio::FLAC::Header;
26    require LWP;
27    require XML::XPath;
28    require XML::XPath::XMLParser;
29
30    my $flac = Audio::FLAC::Header->new($FLAC_FILE) or warn "Can't read FLAC header from $FLAC_FILE\n";
31    my $discid = $flac->tags('MBZ_DISCID') or warn "No MBZ_DISCID tag in $FLAC_FILE\n" if $flac;
32    #TODO: calculate TOC and DISCID from cuesheet if there is no MBZ_DISCID tag present
33
34    #TODO: use the functions in mbz instead of repeating them here)
35    %info = get_musicbrainz_info($discid);
36}
37
38while (my ($tracknum, $title) = each %TRACKS) {
39    if ($tracknum !~ /^\d+$/) {
40        warn "Don't know what to do with track number '$tracknum'";
41        next;
42    }
43    my $start = $tracknum . '.1';
44    my $end = $tracknum + 1 . '.1';
45    my $cmd = qq{flac -d --cue $start-$end $FLAC_FILE -o - };
46
47    if ($SOX_FILTER) {
48        $cmd .= qq{| sox -t wav - -t wav - $SOX_FILTER };
49    }
50
51    $title = quotemeta($title);
52    if ($TYPE eq 'mp3') {
53        # bitrate of 192
54        $cmd .= qq{| lame -b 192};
55        # if there is track info, add it as ID3 tags
56        if (%info) {
57            my $track = $info{TRACKS}[$tracknum];
58            $cmd .= sprintf q{ --tt %s --ta %s --tl %s --tn %d},
59                quote($$track{TITLE}),
60                quote($$track{ARTIST}),
61                quote($info{ALBUM}),
62                $tracknum;
63        }
64        $cmd .= qq{ - $title.mp3};
65    } elsif ($TYPE eq 'wav') {
66        $cmd .= qq{> $title.wav};
67    } else {
68        die "Unknown type: $TYPE\n";
69    }
70    #die $cmd;
71    system $cmd;
72
73    print "\n" if $SOX_FILTER;
74}
75
76sub quote {
77    my ($string) = @_;
78    $string =~ s/"/\\"/g;
79    return qq{"$string"};
80}
81
82
83# make the output terminal handle UTF-8 characters
84#binmode STDOUT, ':utf8';
85#my $info = get_musicbrainz_info($discid);
86#for my $key (sort keys %{ $info }) {
87#    print "$key=$$info{$key}\n";
88#}
89
90sub lookup_release {
91    my ($discid) = @_;
92    my $ua = LWP::UserAgent->new;
93
94    my $uri = URI->new('http://musicbrainz.org/ws/1/release/');
95    $uri->query_form(type => 'xml', discid => $discid);
96
97    my $res = $ua->get($uri);
98    return $res->decoded_content;
99}
100
101sub get_musicbrainz_info {
102    my ($discid) = @_;
103    my %info;
104
105    $info{MBZ_DISCID} = $discid;
106
107    my $xpath = XML::XPath->new();
108
109    $xpath->set_xml(lookup_release($discid));
110
111    # TODO: check for more than 1 release?
112
113    $info{MB_RELEASE_ID} = $xpath->findvalue('//release/@id');
114    $info{ALBUM}         = $xpath->findvalue('//release/title');
115    $info{ARTIST}        = $xpath->findvalue('//release/artist/name');
116    $info{TRACKS}        = [];
117
118    # TODO: get release date
119
120    my $tracknum = 1;
121    for my $track_node ($xpath->findnodes('//track-list/track')) {
122        $info{TRACKS}[$tracknum]{MB_TRACKID} = $xpath->findvalue('@id', $track_node);
123        $info{TRACKS}[$tracknum]{TITLE}      = $xpath->findvalue('title', $track_node);
124        $info{TRACKS}[$tracknum]{ARTIST}     = $xpath->findvalue('artist/name', $track_node) || $info{ARTIST};
125        $tracknum++;
126    }
127
128    return %info;
129}
Note: See TracBrowser for help on using the repository browser.