Guest User

Untitled

a guest
May 27th, 2018
223
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 6.51 KB | None | 0 0
  1. #!/usr/bin/env perl
  2.  
  3. use strict;
  4. use warnings;
  5. use File::Spec::Functions qw(catfile splitpath);
  6. use File::Which;
  7. use Getopt::Long qw(:config auto_help);
  8. use List::Util qw(first);
  9. use Pod::Usage;
  10. use String::ShellQuote;
  11.  
  12. my $VERSION = '0.01';
  13.  
  14. my @deps = qw(flac metaflac lame eyeD3 mp3gain);
  15. for my $dep (@deps) {
  16. die "Dependency $dep not found" if !defined which($dep);
  17. }
  18.  
  19. my %quality = (
  20. 'v2' => 'lame --preset fast standard --noreplaygain',
  21. 'v0' => 'lame --preset fast extreme --noreplaygain',
  22. 'cbr' => 'lame --preset insane --noreplaygain',
  23. );
  24.  
  25. my %flac_eyed3 = (
  26. artist => sub { return '-a', shell_quote($_[0]) },
  27. album => sub { return '-A', shell_quote($_[0]) },
  28. title => sub { return '-t', shell_quote($_[0]) },
  29. tracknumber => sub { return '-n', shell_quote($_[0]) },
  30. genre => sub { return '-G', shell_quote($_[0]) },
  31. date => sub { return '-Y', shell_quote($_[0]) },
  32. discnumber => sub { return shell_quote("--set-text-frame=TPOS:$_[0]") },
  33. );
  34.  
  35. GetOptions(
  36. 'd|debug' => \my $debug,
  37. 'R|no-replaygain' => \my $no_replaygain,
  38. #'P|no-playlist' => \my $no_playlist,
  39. 'q|quality=s@' => \(my $quality = [qw(v2 v0 cbr)]),
  40. 'v|version' => sub { print "flac2mp3 $VERSION\n"; exit },
  41. ) or pod2usage();
  42.  
  43. my @files = grep { /\.flac$/ } @ARGV;
  44. die "No FLAC files specified\n" if !@files;
  45.  
  46. for my $key (keys %quality) {
  47. delete $quality{$key} if !first { $_ eq $key } @$quality;
  48. }
  49.  
  50. for my $file (@files) {
  51. my $q_flac = shell_quote($file);
  52. my $track = (splitpath($file))[2];
  53. $track =~ s/\.flac$//;
  54. my $q_wav = shell_quote("$track.wav");
  55. my $q_mp3 = shell_quote("$track.mp3");
  56.  
  57. print "Reading tags from $track.flac\n";
  58. my @tags = split /\n/, cmd_x("metaflac --export-tags-to=- $q_flac");
  59.  
  60. print "Decoding $track.flac to WAV\n";
  61. cmd("flac --decode -o $q_wav $q_flac >/dev/null 2>&1") if !-e "$track.wav";
  62.  
  63. while (my ($dir, $encode_cmd) = each %quality) {
  64. mkdir $dir;
  65. die "Couldn't create dir $dir\n" if !-d $dir;
  66. my $mp3 = catfile($dir, "$track.mp3");
  67. print "Encoding $track.wav to $dir MP3\n";
  68. cmd("$encode_cmd $q_wav ".shell_quote($mp3)." >/dev/null 2>&1") if !-f $mp3;
  69. }
  70.  
  71. print "Deleting $track.wav\n";
  72. unlink "$track.wav";
  73.  
  74. my @tag_opts = map {
  75. my ($tag, $value) = split /=/, $_, 2;
  76. $flac_eyed3{$tag}->($value)
  77. } @tags;
  78.  
  79. my @mp3s = map { shell_quote(catfile($_, "$track.mp3")) } keys %quality;
  80. print "Tagging $track.mp3\n";
  81. cmd("eyeD3 --to-v2.3 @tag_opts @mp3s >/dev/null 2>&1");
  82. }
  83.  
  84. =pod
  85. unless ($no_playlist) {
  86. my $dir = (keys %quality)[0];
  87. my @mp3s = map {
  88. $_ = (splitpath($_))[2];
  89. s/\.flac$//;
  90. catfile($dir, "$_.mp3")
  91. } @files;
  92.  
  93. # TODO: create playlists
  94. }
  95. =cut
  96.  
  97. unless ($no_replaygain) {
  98. my $dir = (keys %quality)[0];
  99. my @mp3s = map {
  100. $_ = (splitpath($_))[2];
  101. s/\.flac$//;
  102. catfile($dir, "$_.mp3")
  103. } @files;
  104.  
  105. print "Computing ReplayGain values for album\n";
  106. my @opts = mp3gain(@mp3s);
  107.  
  108. for my $opts (@opts) {
  109. my ($file, $frames) = @$opts;
  110. $file = (splitpath($file))[2];
  111. my $q_file = shell_quote($file);
  112. my @track_mp3s = map { shell_quote(catfile($_, $file)) } keys %quality;
  113. print "Adding ReplayGain tags to $file\n";
  114. cmd("eyeD3 --to-v2.3 ".join(' ', map({ "--set-user-text-frame='$_'" } @$frames))." @track_mp3s >/dev/null 2>&1");
  115. }
  116. }
  117.  
  118. sub mp3gain {
  119. my @files = @_;
  120.  
  121. my $files = shell_quote(@files);
  122. my @tracks_raw = split /\n\n/, cmd_x("mp3gain -s s $files");
  123. my $album_raw = splice @tracks_raw, -1;
  124. my %album;
  125. $album{gain} = sprintf('%.2f dB', $album_raw =~ /^Recommended "Album" dB change for all files: (.+)$/m);
  126. $album{tracks} = [];
  127.  
  128. for my $track_raw (@tracks_raw) {
  129. my %track;
  130. my ($file) = $track_raw =~ /\A(.+)\n/m;
  131. next if $file !~ /\.mp3$/i;
  132.  
  133. ($track{gain}) = $track_raw =~ /^Recommended "Track" dB change: (.+)$/m;
  134. $track{gain} = sprintf('%.2f dB', $track{gain});
  135.  
  136. ($track{peak}) = $track_raw =~ /^Max PCM sample at current gain: (.+)$/m;
  137. $album{peak} = $track{peak} if !defined $album{peak} || $track{peak} > $album{peak};
  138. $track{peak} = sprintf('%.6f', $track{peak} / 32768);
  139.  
  140. push @{ $album{tracks} }, [$file, \%track];
  141. }
  142. $album{peak} = sprintf('%.6f', $album{peak} / 32768);
  143.  
  144. my @opts;
  145. for my $track (@{ $album{tracks} }) {
  146. my ($file, $track_values) = @$track;
  147. my @frames = (
  148. "replaygain_track_gain:$track_values->{gain}",
  149. "replaygain_track_peak:$track_values->{peak}",
  150. (@{ $album{tracks} } > 1
  151. ? ("replaygain_album_gain:$album{gain}",
  152. "replaygain_album_peak:$album{peak}")
  153. : ()
  154. )
  155. );
  156. push @opts, [$file, \@frames]
  157. }
  158.  
  159. return @opts;
  160. }
  161.  
  162. sub cmd {
  163. my (@cmd) = @_;
  164. print " @cmd\n" if $debug;
  165. system @cmd;
  166.  
  167. if (($? >> 8) != 0) {
  168. die "The following command failed:\n @cmd\n";
  169. }
  170. return;
  171. }
  172.  
  173. sub cmd_x {
  174. my (@cmd) = @_;
  175. print " @cmd\n" if $debug;
  176. my $out = qx/@cmd/;
  177.  
  178. if (($? >> 8) != 0) {
  179. die "The following command failed:\n @cmd\n";
  180. }
  181. return $out;
  182. }
  183.  
  184. =encoding utf8
  185.  
  186. =head1 NAME
  187.  
  188. flac2mp3 - Encode FLAC files into properly tagged MP3 files
  189.  
  190. =head1 SYNOPSIS
  191.  
  192. B<flac2mp3> [options] <files>
  193.  
  194. Options:
  195. -d, --debug Print the commands that will be executed
  196. -q FOO, --quality FOO Either v2, v0, or cbr (default: all)
  197. -R, --no-replaygain Don't compute and tag ReplayGain values
  198. -h, --help Print this help message
  199. -v, --version Print version
  200.  
  201. Note: Multiple -q options are allowed.
  202.  
  203. The resulting MP3 files will go into F<v2>, F<v0>, and F<cbr> directories
  204. inside the current directory.
  205.  
  206. Examples:
  207.  
  208. # encode to v2, v0, and cbr
  209. flac2mp3 My_artist-My_album/*.flac
  210.  
  211. # only encode to v0
  212. flac2mp3 -q v0 My_artist-My_album/*.flac
  213.  
  214. =head1 DESCRIPTION
  215.  
  216. This little script encodes FLAC files into MP3 files of various qualities.
  217. It also copies the FLAC tags into ID3 tags and computes ReplayGain tags.
  218.  
  219. =head1 DEPENDENCIES
  220.  
  221. The following programs are required:
  222.  
  223. =over 4
  224.  
  225. =item flac
  226.  
  227. =item metaflac
  228.  
  229. =item lame
  230.  
  231. =item eyeD3
  232.  
  233. =item mp3gain
  234.  
  235. =back
  236.  
  237. =head1 AUTHOR
  238.  
  239. Hinrik E<Ouml>rn SigurE<eth>sson, hinrik.sig@gmail.com
  240.  
  241. =head1 LICENSE AND COPYRIGHT
  242.  
  243. Copyright 2010 Hinrik E<Ouml>rn SigurE<eth>sson
  244.  
  245. This program is free software, you can redistribute it and/or modify
  246. it under the same terms as Perl itself.
  247.  
  248. =cut
Add Comment
Please, Sign In to add comment