Open Source im professionellen Einsatz
Linux-Magazin 03/2010
© Pascal Willuhn, Pixelio.de

© Pascal Willuhn, Pixelio.de

Perl-Skript lässt Digitalrekorder rückwärts laufen

tleW etrhekreV

Der Titel des Beatles-Songs "Revolution 9" soll nach einer Verschwörungstheorie rückwärts gespielt einen Hinweis offenbaren, dass das Management die Band gezwungen habe, den toten Paul McCartney durch einen Doppelgänger zu ersetzen. Perl macht klar: alles Schwindel!

851

Neulich lauschte ich im Internetradio dem Song "Work It" von Missy Elliot und stellte fest, dass ich Teile des Refrains trotz ordentlicher Englischkenntnisse seit seinem Erscheinen im Jahre 2002 noch nie recht verstanden hatte. Wikipedia löste das Rätsel: Die feiste Hip-Hopperin spielt einfach Gesangssequenzen rückwärts ein [2].

Wie die Alten sungen

Dies so genannte Backmasking [3] war schon in meiner Jugendzeit ein beliebter Zeitvertreib. Denn damals gab es noch keine Killerspiele und als das pädagogisch wertvolle Holzspielzeug seine Spannung verlor, blieb uns nur, von gutgläubigen Erwachsenen aus der Apotheke geholte Chemikalien zu lautstarken Sprengsätzen zu vermengen. Außerdem hatte es uns ein Kassettenrekorder angetan, den man durch gezielte Manipulation des Antriebs dazu brachte, aufgenommene Bänder verkehrt herum abzuspielen. Man sprach "Redro Kernettesack!" aufs Band und aus dem Lautsprecher kam in unvorstellbarem Akzent, irgendwo zwischen osteuropäisch und außerirdisch: "Kkkassettnrekorrdeeer!" Stundenlanger Spaß für die ganze Familie!

Das Skript in Listing 1 produziert nach dem Aufruf in einem Terminal die Fußzeile in Abbildung 1 und lädt dazu ein, die Taste [R] (für Record) zu drücken, um eine ins Mikrofon gesprochene Nachricht aufzunehmen. Während der Aufnahme erscheint das Menü in Abbildung 2, das darauf hinweist, dass [S] (für Stopp) die Aufnahme beendet und [P] (für Play) die aufgenommene Ogg-Datei verkehrt herum abspielt. Während der Wiedergabe erscheint der Text in Abbildung 3, der sofort wieder dem Menü in Abbildung 1 Platz macht, sobald keine Sounddaten mehr vorliegen.

Abbildung 1: Zum Programmbeginn: Die Taste [R] startet eine Aufnahme.

Abbildung 2: Während der Aufnahme: [S] beendet die Aufnahme, [P] spielt sie gleich rückwärts ab.

Abbildung 3: Mit dem Tool Sox kehrt »flipit« die Aufnahme um und spielt das Original rückwärts ab.

Die minimalistische grafische Oberfläche erzeugt das Modul Curses::UI::POE, das die Grafikroutinen der Curses-Library mit der Multitasking-Umgebung POE verbandelt. Denn während das Skript langwierige Vorgänge wie die Aufnahme einer Sounddatei, deren Umkehrung oder das Abspielen steuert, soll das GUI blitzschnell auf User-Eingaben reagieren.

Listing 1:
»flipit«

001 #!/usr/local/bin/perl -w
002 use strict;
003 use POE;
004 use POE::Wheel::Run;
005 use Curses::UI::POE;
006 use File::Temp qw(tempfile);
007 use Sysadm::Install qw(:all);
008 use POSIX;
009
010 our $HEAP;
011
012 my $CUI = Curses::UI::POE->new(
013 -color_support => 1,
014 inline_states => {
015    _start => sub {
016       $HEAP = $_[HEAP];
017    },
018    play_ended => &footer_update,
019 });
020
021 my $WIN = $CUI->add("win_id", "Window");
022
023 my $FOOT = $WIN->add(qw( bottom Label
024 -y -1 -paddingspaces 1
025 -fg white -bg blue));
026
027 footer_update();
028
029 $CUI->set_binding(sub { exit 0; }, "q");
030 $CUI->set_binding( &play_flipped, "p");
031 $CUI->set_binding( &record, "r" );
032 $CUI->set_binding( &record_stop, "s" );
033
034 $CUI->mainloop;
035
036 ###########################################
037 sub record {
038 ###########################################
039   if(defined $HEAP->{recorder}->{wheel}) {
040      return; # Still recording
041   }
042
043    my($fh, $tempfile) = tempfile(
044    SUFFIX => ".ogg", UNLINK => 1);
045
046    my $wheel =
047    POE::Wheel::Run->new(
048    Program => "rec",
049    ProgramArgs => [$tempfile],
050    StderrEvent => 'ignore',
051    );
052
053    $HEAP->{recorder} = {
054    wheel => $wheel,
055   file => $tempfile,
056 };
057
058 $FOOT->text("Recording ... " .
059 "([s] to stop, [p] to play)");
060 $FOOT->draw();
061 }
062
063 ###########################################
064 sub record_stop {
065 ###########################################
066    my $wheel = $HEAP->{recorder}->{wheel};
067
068    return if !defined $wheel;
069
070    $wheel->kill(SIGTERM);
071    delete $HEAP->{recorder}->{wheel};
072    footer_update();
073 }
074
075 ###########################################
076 sub footer_update {
077 ###########################################
078    my $text = "[r] to record";
079
080   if(defined $HEAP->{recorder}->{file}) {
081      $text .= ", [p] to play";
082    }
083
084    $text .= ", [q] to quit";
085
086    $FOOT->text($text);
087    $FOOT->draw();
088 }
089
090 ###########################################
091 sub play_flipped {
092 ###########################################
093    if(defined $HEAP->{recorder}->{wheel}) {
094       # Active recording? Stop it.
095       record_stop( $HEAP );
096    }
097
098    $FOOT->text("Playing ...");
099    $FOOT->draw();
100
101    my $recorded = $HEAP->{recorder}->{file};
102
103    return if ! defined $recorded;
104
105    my $wheel =
106    POE::Wheel::Run->new(
107       Program => &sox_play,
108       ProgramArgs => [$recorded],
109       StderrEvent => 'ignore',
110       CloseEvent => 'play_ended',
111    );
112
113    $HEAP->{players}->{$wheel->ID} = $wheel;
114 }
115
116 ###########################################
117 sub sox_play {
118 ###########################################
119    my($recording) = @_;
120
121    my($fh, $tmpfile) =
122    tempfile(SUFFIX => ".ogg");
123
124    tap "sox", $recording,
125    $tmpfile, "reverse";
126    tap "play", $tmpfile;
127
128    unlink $tmpfile;
129 }

Curses tanzt mit POE

Erfahrene Leser dieser Rubrik wissen, dass die kooperative Multitasking-Umgebung POE dafür die nötigen Voraussetzungen mitbringt. Sie verfolgt einen asynchronen Ansatz, der Anfängern oft Kopfzerbrechen bereitet. Wer aber den Bogen raus hat, kann mit ihr schnell robuste Applikationen bauen.

Der Konstruktoraufruf in Zeile 13 schaltet mit »color_support« Terminalfarben ein und bestimmt zwei POE-typische Zustände. Den ersten - »_start« - springt POE sofort nach dem Start des POE-Kernels an. Zeile 16 nutzt ihn nur dazu, eine Referenz auf die ebenfalls POE-typische Datenstruktur eines Session-Heap in der globalen Variablen »$HEAP« abzulegen, damit der als Variablenspeicher genutzte Hash auch außerhalb der POE-Welt zugänglich ist. Den zweiten Zustand - »play_ended« - springt POE an, falls ein aufgenommener Sound erfolgreich rückwärts abgespielt wurde. Für diesen Fall definiert Zeile 18 den Handler »footer_update()«, der den Text auf dem Fußbalken dem Status des Apparats anpasst.

Linux-Magazin kaufen

Einzelne Ausgabe
 
Abonnements
 
TABLET & SMARTPHONE APPS
Bald erhältlich
Get it on Google Play

Deutschland

Ähnliche Artikel

  • Episodenfilm

    Ein Perl-Skript mit GTK-2-Oberfläche merkt sich, wie weit sein Anwender gespeicherte Videos angesehen hat, und fährt auf Wunsch an der Stelle der letzten Unterbrechung wieder fort.

  • Am Fließband

    Beim halbautomatischen Umwandeln von gedruckten Zeitschriftenartikeln ins PDF-Format hilft das heute vorgestellte Perl-Skript. Den Ablauf triggert ein Taster am Scanner.

  • Das Log als Ohrwurm

    Statt eingehende Requests nur in der Logdatei des Webservers zu verfolgen, macht ein Soundserver sie für den Systemadministrator hörbar. Nun kann man die Surfer nebenbei belauschen.

  • Netz-Journal

    Was der Rechner im eigenen Netz treibt, offenbart ein Aufruf von »netstat«. Mit ein paar Perl-Modulen lässt sich daraus ein Tool entwickeln, das die Daten dynamisch anzeigt, ganz nach dem Vorbild von Top.

  • Schöner schicken

    Eigentlich brauchen lokale Mailclients nur während des Sendens einen sicheren Weg zum SMTP-Server. Ein in Perl selbst gebauter Daemon bohrt darum nur temporär einen SSH-Tunnel.

     

comments powered by Disqus

Ausgabe 08/2016

Artikelserien und interessante Workshops aus dem Magazin können Sie hier als Bundle erwerben.