Skeeve •---->


Anmeldedatum: 20.04.2006 Beiträge: 1067
|
Verfasst am: 10.01.2007 - 23:20 Titel: mp3-analyze |
|
|
Habt Ihr Euch je gefragt, was in einem mp3 an Musikdaten steckt? Nicht viel! Hier ist ein kleines (Perl-)Script, das ich verzapft habe, mit dem man mp3 Dateien analysieren und sogar (unter Verlust von id3 Tags, aber sei's drum) zusammenfügen kann. Das Zusammenfügen habe ich gerade eben noch aufgrund von diesem Post bei ApfelTalk eingebaut.
Gespeichert wird das script wie üblich, d.h. in einen TextEditor kopieren, abspeichern als reine Textdatei unter dem Namen "mp3-analyze". Anschließend im Terminal Code: | chmod +x mp3-analyze | eingeben.
Aufgerufen wird das Script dann mit:
Code: | ./mp3-analyze -help
# Gibt eine Hilfe (englisch) aus
./mp3-analyze -man
# Gibt eine länger Hilfe (manual englisch) aus
./mp3-analyze -verbose filename1.mp3 filename2.mp3 ...
# Mehr Informationen ausgeben
./mp3-analyze -extract soundfile.mp3 filename1.mp3 filename2.mp3 ...
# führt filename1.mp3 filename2.mp3 ...
# zusammen zu soundfile.mp3 |
Hier das Script:
Code: | #!/usr/bin/perl
#
# (C) 2007 by mp3-analyze.question.skeeve et xoxy.net
#
# Documentation used: http://mpgedit.org/mpgedit/mpeg_format/mpeghdr.htm
#
use strict;
use warnings;
use Getopt::Long;
use Pod::Usage;
my $BUFSIZE= 0x4000;
###### MPEG information setup ##############################################{{{
my @version=(
'MPEG Version 2.5 (unofficial)',
'reserved 1',
'MPEG Version 2 (ISO/IEC 13818-3)',
'MPEG Version 1 (ISO/IEC 11172-3)',
);
my @layer=(
'reserved 0',
'Layer III',
'Layer II',
'Layer I',
);
my @bitrate= (
[ # V2.5
[ # reserved
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer III
'free', 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 'bad f',
],
[ # Layer II
'free', 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 'bad f',
],
[ # Layer I
'free', 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 'bad f',
],
],
[ # reserved
[ # reserved
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer III
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer II
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer I
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
],
[ # V2
[ # reserved
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer III
'free', 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 'bad f',
],
[ # Layer II
'free', 8, 16, 24, 32, 40, 48, 56, 64, 80, 96, 112, 128, 144, 160, 'bad f',
],
[ # Layer I
'free', 32, 48, 56, 64, 80, 96, 112, 128, 144, 160, 176, 192, 224, 256, 'bad f',
],
],
[ # V1
[ # reserved
'bad 0', 'bad 1', 'bad 2', 'bad 3', 'bad 4', 'bad 5', 'bad 6', 'bad 7', 'bad 8', 'bad 9', 'bad a', 'bad b', 'bad c', 'bad d', 'bad e', 'bad f',
],
[ # Layer III
'free', 32, 40, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 'bad f',
],
[ # Layer II
'free', 32, 48, 56, 64, 80, 96, 112, 128, 160, 192, 224, 256, 320, 384, 'bad f',
],
[ # Layer I
'free', 32, 64, 96, 128, 160, 192, 224, 256, 288, 320, 352, 384, 416, 448, 'bad f',
],
],
);
my @samplingrate=(
[ # V2.5
11025, 12000, 8000, 'reserved 3',
],
[ # reserved
'reserved 0', 'reserved 1', 'reserved 2', 'reserved 3',
],
[ # V2
22050, 24000, 16000, 'reserved 3',
],
[ # V1
44100, 48000, 32000, 'reserved 3',
],
);
my @channelmode= (
'Stereo',
'Joint stereo (Stereo)',
'Dual channel (2 mono channels)',
'Single channel (Mono)',
);
my @modeextension= (
[ # reserved
'bad 0', 'bad 1', 'bad 2', 'bad 3',
],
[ # Layer III
'Stereo: Intensity off, MS off',
'Stereo: Intensity on, MS off',
'Stereo: Intensity off, MS on',
'Stereo: Intensity on, MS on',
],
[ # Layer II
'bands 4 to 31',
'bands 8 to 31',
'bands 12 to 31',
'bands 16 to 31',
],
[ # Layer I
'bands 4 to 31',
'bands 8 to 31',
'bands 12 to 31',
'bands 16 to 31',
],
);
my @emphasis= (
'none',
'50/15 ms',
'reserved 3',
'CCIT J.17',
);
my @protected= (
'not protected',
'protected',
);
my @padding= (
'not padded',
'padded',
);
my @copyright= (
'Audio is not copyrighted',
'Audio is copyrighted',
);
my @original= (
'Copy of original media',
'Original media',
);
###### END: MPEG information setup #########################################}}}
###### POD #################################################################{{{
=head1 NAME
B<mp3-analyze> examins all frames inside an MP3 file
=head1 SYNOPSIS
mp3-analyze filename...
=head1 DESCRIPTION
B<mp3-analyze> scans mp3 files for frame headers and prints the average bitrate.
In verbose mode all available information found in frames is printed
=head1 OPTIONS
=over 5
=item B<-verbode> | B<-v>
verbose output
=item B<-extract> I<filename>
=item B<-x> I<filename>
extract all frames and put them into I<filename>
=item B<-help> | B<-h>
show a short help
=item B<-man> | B<-m>
show a short manual.
=back
=cut
###### END: POD ############################################################}}}
##### commandline option variables #########################################{{{
my (
$verbose,
$extract,
);
##### end commandline option variables #####################################}}}
##### commandline options ##################################################{{{
# defaults
&help unless GetOptions(
"extract|x=s" => \$extract,
"verbose|v!" => \$verbose,
"help|h" => \&help,
"man" => \&man,
);
sub help { exit pod2usage( verbose => 1 ); };
sub man { exit pod2usage( verbose => 2 ); };
##### end commandline options ##############################################}}}
my $sound;
if ( $extract ) {
open $sound, '>', $extract
or die "Can't create '$extract': $!\n";
}
foreach my $filename (@ARGV) {
my (
$buf, # buffer
$mp3, # filedescriptor
$lobr, # lowest and
$hibr, # higest bitrate
$lnloseq, # longest sequence of lowest bitrate
$shloseq, # shortest sequence of lowest bitrate
$prevbr, # previous bitrate
$seq, # count length of sequence
$losam, # lowest and
$hisam, # higest samplingrate
$sumbr, # sum of bitrates
$sumsam, # sum of samplingrates
$frame, # framecount
$rb,
$length,
);
if ( not open $mp3, '<', $filename ) {
warn "$filename: $!\n";
next;
}
print "$filename\n";
$length= 0;
$prevbr= 0;
while ( 0 < ($rb= read($mp3, $buf, $BUFSIZE)) ) {
$length+= $rb;
while ($buf=~ s/^.*?\xff//) {
$length-= length $buf;
my $index= $length;
$rb+= read($mp3, $buf, $BUFSIZE-length($buf), length($buf));
$length+= length $buf;
next if 0xe0 > ord $buf;
my(
$dummy,
$version, # MPEG Audio version ID
$layer, # Layer description
$protected, # Protection bit
$bitrateIndex, # Bitrate index
$samplingrateIndex, # Sampling rate frequency index
$padding, # Padding bit
$private, # Private bit
$channelmode, # Channel Mode
$modeextension, # Mode extension
$copyright, # Copyright
$original, # Original
$emphasis, # Emphasis AAA BB CC D EEEE FF G H II JJ K L MM
)= map oct( "0b$_" ), unpack 'A3 A2 A2 A1 A4 A2 A1 A1 A2 A2 A1 A1 A2', unpack 'B*', substr($buf,0,3);
my $bitrate= $bitrate[ $version ][ $layer ][ $bitrateIndex ];
my $samplingrate= $samplingrate[ $version ][ $samplingrateIndex ];
my $warn= '';
$warn.= "Bitrate '$bitrate' isn't numeric\n" unless $bitrate=~ /^\d+$/;
$warn.= "Samplingrate '$samplingrate' isn't numeric\n" unless $samplingrate=~ /^\d+$/;
my $FrameLengthInBytes= '?';
if ( $warn eq '' ) {
$FrameLengthInBytes= int(
$layer == 3 ?
(12000 * $bitrate / $samplingrate + $padding) * 4
:
144000 * $bitrate / $samplingrate + $padding
);
};
$sumbr+= $bitrate;
$sumsam+= $samplingrate;
if ( $frame++ ) {
if ( $bitrate < $lobr ) {
$lobr= $bitrate;
$lnloseq= $shloseq= undef;
}
$losam= $samplingrate if $samplingrate < $losam;
$hibr= $bitrate if $bitrate > $hibr;
$hisam= $samplingrate if $samplingrate > $hisam;
}
else {
$hibr= $lobr= $bitrate;
$hisam= $losam= $samplingrate;
}
if ( $prevbr == $bitrate ) {
++$seq;
}
else {
if ( $prevbr == $lobr ) {
$shloseq= $seq if not defined($shloseq) or $seq < $shloseq;
$lnloseq= $seq if not defined($lnloseq) or $seq > $lnloseq;
}
$prevbr= $bitrate;
$seq= 1;
}
if ( $verbose ) {
printf
"Frame . . . . . . . . .: %d".
"\nIndex . . . . . . . . .: %x".
"\nFrame length . . . . .: %x",
$frame,
$index-1,
$FrameLengthInBytes;
print
"\nMPEG Audio version ID .: ", $version[ $version ],
"\nLayer description . . .: ", $layer[ $layer ],
"\nProtection . . . . . .: ", $protected[ $protected ],
"\nBitrate . . . . . . . .: ", $bitrate,' kbps',
"\nSampling rate frequency: ", $samplingrate,
"\nPadding . . . . . . . .: ", $padding[ $padding ],
"\nPrivate bit: . . . . .: ", $private,
"\nChannel Mode . . . . .: ", $channelmode[ $channelmode ],
"\nMode extension . . . .: ", $modeextension[ $modeextension ],
"\nCopyright . . . . . . .: ", $copyright, $copyright[ $copyright ],
"\nOriginal . . . . . . .: ", $original[ $original ],
"\nEmphasis . . . . . . .: ", $emphasis[ $emphasis ],
"\n\n";
}
die $warn if $warn;
if ($sound) {
print $sound "\xff",substr($buf, 0, $FrameLengthInBytes-1);
}
$buf= substr($buf, $FrameLengthInBytes-1);
last if length $buf == 0;
if ( ord($buf) != 255 ) {
die sprintf "unexpected data at position %x, Frame %d\n", $index+$FrameLengthInBytes-1, $frame;
}
}
}
$shloseq= $seq unless defined $shloseq;
$lnloseq= $seq unless defined $lnloseq;
print
"Frames . . . . . . . . .: ",$frame,
"\nLowest samplingrate . .: ",$losam,
"\nHighest samplingrate . .: ",$hisam,
"\nAverage samplingrate . .: ",$sumsam/$frame,
"\nLowest bitrate . . . . .: ",$lobr,
"\nHighest bitrate . . . . .: ",$hibr,
"\nAverage bitrate . . . . .: ",$sumbr/$frame,
"\nShortest sequence of low : ",$shloseq,
"\nLongest sequence of low : ",$lnloseq,
"\n\n";
close $mp3;
}
close $sound if $sound;
|
_________________ "All problems are solved in slightly less than half an hour" (Chumbawamba, "Hey Hey We're The Junkies") |
|