Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #!/usr/bin/env perl
- use strict;
- use warnings;
- use File::Spec::Functions qw(catfile splitpath);
- use File::Which;
- use Getopt::Long qw(:config auto_help);
- use List::Util qw(first);
- use Pod::Usage;
- use String::ShellQuote;
- my $VERSION = '0.01';
- my @deps = qw(flac metaflac lame eyeD3 mp3gain);
- for my $dep (@deps) {
- die "Dependency $dep not found" if !defined which($dep);
- }
- my %quality = (
- 'v2' => 'lame --preset fast standard --noreplaygain',
- 'v0' => 'lame --preset fast extreme --noreplaygain',
- 'cbr' => 'lame --preset insane --noreplaygain',
- );
- my %flac_eyed3 = (
- artist => sub { return '-a', shell_quote($_[0]) },
- album => sub { return '-A', shell_quote($_[0]) },
- title => sub { return '-t', shell_quote($_[0]) },
- tracknumber => sub { return '-n', shell_quote($_[0]) },
- genre => sub { return '-G', shell_quote($_[0]) },
- date => sub { return '-Y', shell_quote($_[0]) },
- discnumber => sub { return shell_quote("--set-text-frame=TPOS:$_[0]") },
- );
- GetOptions(
- 'd|debug' => \my $debug,
- 'R|no-replaygain' => \my $no_replaygain,
- #'P|no-playlist' => \my $no_playlist,
- 'q|quality=s@' => \(my $quality = [qw(v2 v0 cbr)]),
- 'v|version' => sub { print "flac2mp3 $VERSION\n"; exit },
- ) or pod2usage();
- my @files = grep { /\.flac$/ } @ARGV;
- die "No FLAC files specified\n" if !@files;
- for my $key (keys %quality) {
- delete $quality{$key} if !first { $_ eq $key } @$quality;
- }
- for my $file (@files) {
- my $q_flac = shell_quote($file);
- my $track = (splitpath($file))[2];
- $track =~ s/\.flac$//;
- my $q_wav = shell_quote("$track.wav");
- my $q_mp3 = shell_quote("$track.mp3");
- print "Reading tags from $track.flac\n";
- my @tags = split /\n/, cmd_x("metaflac --export-tags-to=- $q_flac");
- print "Decoding $track.flac to WAV\n";
- cmd("flac --decode -o $q_wav $q_flac >/dev/null 2>&1") if !-e "$track.wav";
- while (my ($dir, $encode_cmd) = each %quality) {
- mkdir $dir;
- die "Couldn't create dir $dir\n" if !-d $dir;
- my $mp3 = catfile($dir, "$track.mp3");
- print "Encoding $track.wav to $dir MP3\n";
- cmd("$encode_cmd $q_wav ".shell_quote($mp3)." >/dev/null 2>&1") if !-f $mp3;
- }
- print "Deleting $track.wav\n";
- unlink "$track.wav";
- my @tag_opts = map {
- my ($tag, $value) = split /=/, $_, 2;
- $flac_eyed3{$tag}->($value)
- } @tags;
- my @mp3s = map { shell_quote(catfile($_, "$track.mp3")) } keys %quality;
- print "Tagging $track.mp3\n";
- cmd("eyeD3 --to-v2.3 @tag_opts @mp3s >/dev/null 2>&1");
- }
- =pod
- unless ($no_playlist) {
- my $dir = (keys %quality)[0];
- my @mp3s = map {
- $_ = (splitpath($_))[2];
- s/\.flac$//;
- catfile($dir, "$_.mp3")
- } @files;
- # TODO: create playlists
- }
- =cut
- unless ($no_replaygain) {
- my $dir = (keys %quality)[0];
- my @mp3s = map {
- $_ = (splitpath($_))[2];
- s/\.flac$//;
- catfile($dir, "$_.mp3")
- } @files;
- print "Computing ReplayGain values for album\n";
- my @opts = mp3gain(@mp3s);
- for my $opts (@opts) {
- my ($file, $frames) = @$opts;
- $file = (splitpath($file))[2];
- my $q_file = shell_quote($file);
- my @track_mp3s = map { shell_quote(catfile($_, $file)) } keys %quality;
- print "Adding ReplayGain tags to $file\n";
- cmd("eyeD3 --to-v2.3 ".join(' ', map({ "--set-user-text-frame='$_'" } @$frames))." @track_mp3s >/dev/null 2>&1");
- }
- }
- sub mp3gain {
- my @files = @_;
- my $files = shell_quote(@files);
- my @tracks_raw = split /\n\n/, cmd_x("mp3gain -s s $files");
- my $album_raw = splice @tracks_raw, -1;
- my %album;
- $album{gain} = sprintf('%.2f dB', $album_raw =~ /^Recommended "Album" dB change for all files: (.+)$/m);
- $album{tracks} = [];
- for my $track_raw (@tracks_raw) {
- my %track;
- my ($file) = $track_raw =~ /\A(.+)\n/m;
- next if $file !~ /\.mp3$/i;
- ($track{gain}) = $track_raw =~ /^Recommended "Track" dB change: (.+)$/m;
- $track{gain} = sprintf('%.2f dB', $track{gain});
- ($track{peak}) = $track_raw =~ /^Max PCM sample at current gain: (.+)$/m;
- $album{peak} = $track{peak} if !defined $album{peak} || $track{peak} > $album{peak};
- $track{peak} = sprintf('%.6f', $track{peak} / 32768);
- push @{ $album{tracks} }, [$file, \%track];
- }
- $album{peak} = sprintf('%.6f', $album{peak} / 32768);
- my @opts;
- for my $track (@{ $album{tracks} }) {
- my ($file, $track_values) = @$track;
- my @frames = (
- "replaygain_track_gain:$track_values->{gain}",
- "replaygain_track_peak:$track_values->{peak}",
- (@{ $album{tracks} } > 1
- ? ("replaygain_album_gain:$album{gain}",
- "replaygain_album_peak:$album{peak}")
- : ()
- )
- );
- push @opts, [$file, \@frames]
- }
- return @opts;
- }
- sub cmd {
- my (@cmd) = @_;
- print " @cmd\n" if $debug;
- system @cmd;
- if (($? >> 8) != 0) {
- die "The following command failed:\n @cmd\n";
- }
- return;
- }
- sub cmd_x {
- my (@cmd) = @_;
- print " @cmd\n" if $debug;
- my $out = qx/@cmd/;
- if (($? >> 8) != 0) {
- die "The following command failed:\n @cmd\n";
- }
- return $out;
- }
- =encoding utf8
- =head1 NAME
- flac2mp3 - Encode FLAC files into properly tagged MP3 files
- =head1 SYNOPSIS
- B<flac2mp3> [options] <files>
- Options:
- -d, --debug Print the commands that will be executed
- -q FOO, --quality FOO Either v2, v0, or cbr (default: all)
- -R, --no-replaygain Don't compute and tag ReplayGain values
- -h, --help Print this help message
- -v, --version Print version
- Note: Multiple -q options are allowed.
- The resulting MP3 files will go into F<v2>, F<v0>, and F<cbr> directories
- inside the current directory.
- Examples:
- # encode to v2, v0, and cbr
- flac2mp3 My_artist-My_album/*.flac
- # only encode to v0
- flac2mp3 -q v0 My_artist-My_album/*.flac
- =head1 DESCRIPTION
- This little script encodes FLAC files into MP3 files of various qualities.
- It also copies the FLAC tags into ID3 tags and computes ReplayGain tags.
- =head1 DEPENDENCIES
- The following programs are required:
- =over 4
- =item flac
- =item metaflac
- =item lame
- =item eyeD3
- =item mp3gain
- =back
- =head1 AUTHOR
- Hinrik E<Ouml>rn SigurE<eth>sson, hinrik.sig@gmail.com
- =head1 LICENSE AND COPYRIGHT
- Copyright 2010 Hinrik E<Ouml>rn SigurE<eth>sson
- This program is free software, you can redistribute it and/or modify
- it under the same terms as Perl itself.
- =cut
Add Comment
Please, Sign In to add comment