So
Mai
04

2008

Praktische Hashes of Arrays

Einer der recht häufig besuchten Artikel hier im Blog ist Hashes of Arrays oder Hashes of Hashes. Allem Anschein nach besteht noch immer großes Interesse an praktischen Beispielen für deren Anwendung in Perl. Dem soll nun Rechnung getragen werden.

Die Aufgabe:

Meine MP3- (und inzwischen AAC-)Sammlung ist mittlerweile recht groß. Leider sind auch die Lautstärkeschwankungen zwischen zwei Alben ziemlich ausgeprägt, so dass ich mittels aacgain eine Anpassung vornehmen möchte1.

Der Code:

Listing 1: aacgain.pl
#Code
0001#!/usr/bin/perl -w
0002# aacgain.pl benoetigt ein ausfuehrbares aacgain im pfad
0003# v1 - 02.05.2008 - initial release
0004print "### aacgain.pl ###\n";
0005use strict;
0006use DirHandle;
0007use Cwd;
0008use File::Find;
0009 
0010# Variablendeklaration
0011my ( %directories, @files, $current_directory, $options, $command );
0012 
0013&show_help
0014 if $ARGV[0] =~ /^(help|-h|h|--help|\?|-\?)/; # zeige Hilfetext wenn notwendig
0015 
0016@ARGV = qw(.)
0017 unless @ARGV; # suche im Startverzeichnis, wenn nichts anderes angegeben wurde
0018$options = '-a -k'; # Album-Modus, kein clipping, 89db (Standardeinstellung)
0019 
0020# Finde alle Songs im angegebenen Verzeichnis inkl. Unterverzeichnisse
0021find( \&find_songs, @ARGV );
0022 
0023&process_files;
0024 
0025sub find_songs {
0026 return
0027 unless /(\.m4a|\.mp3)/; # finde nur Dateien, mit entsprechender Endung
0028 $current_directory = cwd;
0029 push( @{ $directories{$current_directory} }, $_ );
0030}
0031 
0032sub process_files {
0033 foreach my $key ( keys %directories ) {
0034 @files = qw//;
0035 foreach ( @{ $directories{$key} } ) {
0036 push @files, $key . '/' . $_;
0037 }
0038 $command = 'aacgain ' . $options; # konstruiere den aacgain-Befehl
0039 foreach (@files) {
0040 $command .= ' ' . "\"$_\"";
0041 }
0042 print qx($command); # fuehre aacgain aus und zeige die Ausgabe
0043 }
0044}
0045 
0046sub show_help {
0047 print "aacgain.pl erlaubt die Mehrfachbearbeitung von MP3/AAC-Dateien.\n";
0048 print "Hierzu werden alle Unterverzeichnisse nach Dateien durchsucht.\n";
0049 print "Songs innerhalb eines Ordners werden als Album behandelt.\n";
0050 print "Syntax: perl aacgain.pl <Verzeichnisname>\n";
0051 exit;
0052}
0053 

Code herunterladen
[Downloads: 662]

Dies ist ein recht kurzes Beispiel, wie Hashes of Arrays genutzt werden können. Im Hash %directories werden die Verzeichnisse hinterlegt, in denen Songs (mit den Endungen mp3 oder m4a) gefunden wurden. Entscheidend ist Zeile 29, die Speicherung der Suchergebnisse:

Hier werden die gefundenen Songs in ein Array gepusht, welches innerhalb eines Hashes existiert. Der Key des Hashes ist der Speicherort der Musikdateien, Inhalt des Verzechnisses ist ein Array aus den gefundenen Dateinamen.

Die eigentliche Verarbeitung der Songs erfolgt in zwei foreach-Schleifen.

Für jedes Verzeichnis (=Element des Hashes) sollen die darin enthaltenen Dateien (=Elemente des Arrays) verarbeitet werden. Das Kommando hat folgende Syntax:

aacgain -a -k /path/to/song1 /path/to/song2

Um etwaige Leerzeichen im Pfad- oder Songnamen zu unterstützen werden die Dateinamen in Anführungszeichen gesetzt. Eine Rückmeldung von aacgain wird durch die qx in Verbindung mit print ermöglicht.

Damit ich das Programm auch in der nächsten Woche noch verstehen kann, gibt es eine minimale Hilfefunktion und großzügige Kommentare im Quelltext.

1 Ja, mir ist bewusst, dass man dieses Problem auch mit MacMP3Gain lösen kann, aber mit Perl macht es mehr Spaß. aacgain kann man auf dem Mac übrigens mit MacPorts einfach und schnell selbst kompilieren.

Kommentare

Textile-Hilfe