source: flacrip/trunk/flactrack @ 4

Last change on this file since 4 was 4, checked in by peter, 12 years ago
  • the MusicBrainz XML parsing returns the actual strings instead of XML::XPath::Literal elements
  • flactrack takes an --all parameter that transcodes all of the tracks for a particular flac file into a directory (directory name defaults to the same as the flac filename, but without the ".flac" extension)
  • Property svn:executable set to *
File size: 3.0 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 qw{:config no_ignore_case};
10use File::Spec::Functions qw{catfile};
11use File::Path;
12use Audio::FLAC::Header;
13use MusicBrainz;
14
15GetOptions(
16    'D=s' => \my %TRACKS,
17    't=s' => \my $TYPE,
18    'x=s' => \my $SOX_FILTER,
19    'all|a' => \my $ALL,
20    'dir|d=s' => \my $DIRECTORY,
21);
22
23my $FLAC_FILE = shift or die "Need a flac file to decode";
24
25# default to mp3
26$TYPE ||= 'mp3';
27
28# default the directory to be named like the flac file
29($DIRECTORY ||= $FLAC_FILE) =~ s/\.flac$//;
30
31my $flac = Audio::FLAC::Header->new($FLAC_FILE) or die "Can't read FLAC header from $FLAC_FILE\n";
32
33# for getting track metadata from MusicBrainz
34my $info;
35if ($ALL || $TYPE eq 'mp3') {
36    my $discid = $flac->tags('MBZ_DISCID') or warn "No MBZ_DISCID tag in $FLAC_FILE\n" if $flac;
37    #TODO: calculate TOC and DISCID from cuesheet if there is no MBZ_DISCID tag present
38
39    #TODO: also get the year from MBZ
40    $info = get_musicbrainz_info($discid);
41}
42
43if ($ALL) {
44    die "Use of --all requires a --directory\n" unless $DIRECTORY;
45    use YAML;
46    my $cuesheet = $flac->cuesheet;
47    my $count = scalar grep { /TRACK \d\d/ } @{ $flac->cuesheet };
48    print "Found $count tracks\n";
49    #TODO: default to just 01, 02, etc. if there is no $info
50    %TRACKS = map {
51        $_ => catfile($DIRECTORY, sprintf('%02d.%s', $_, to_filename($info->{TRACKS}[$_]{TITLE})))
52    } (1 .. $count);
53    print Dump(\%TRACKS);
54    mkpath($DIRECTORY);
55}
56
57while (my ($tracknum, $title) = each %TRACKS) {
58    if ($tracknum !~ /^\d+$/) {
59        warn "Don't know what to do with track number '$tracknum'";
60        next;
61    }
62    my $start = $tracknum . '.1';
63    my $end = $tracknum + 1 . '.1';
64    my $cmd = qq{flac -d --cue $start-$end $FLAC_FILE -o - };
65
66    if ($SOX_FILTER) {
67        $cmd .= qq{| sox -t wav - -t wav - $SOX_FILTER };
68    }
69
70    $title = quotemeta($title);
71    if ($TYPE eq 'mp3') {
72        # bitrate of 192
73        $cmd .= qq{| lame -b 192};
74        # if there is track info, add it as ID3 tags
75        if ($info) {
76            my $track = $info->{TRACKS}[$tracknum];
77            $cmd .= sprintf q{ --tt %s --ta %s --tl %s --tn %d},
78                quote($track->{TITLE}),
79                quote($track->{ARTIST}),
80                quote($info->{ALBUM}),
81                $tracknum;
82        }
83        $cmd .= qq{ - $title.mp3};
84    } elsif ($TYPE eq 'wav') {
85        $cmd .= qq{> $title.wav};
86    } else {
87        die "Unknown type: $TYPE\n";
88    }
89    #die $cmd;
90    system $cmd;
91
92    print "\n" if $SOX_FILTER;
93}
94
95sub quote {
96    my ($string) = @_;
97    $string =~ s/"/\\"/g;
98    return qq{"$string"};
99}
100
101sub to_filename {
102    my @strings = @_;
103    #TODO: deal with non-ascii characters (unidecode) e.g. ü --> ue
104    return map {
105        s/[^a-z0-9-_ ]+//gi;
106        s/ +/_/g;
107        lc;
108    } @strings;
109}
Note: See TracBrowser for help on using the repository browser.