© Pascal Willuhn, Pixelio.de
Perl-Skript lässt Digitalrekorder rückwärts laufen
tleW etrhekreV
von Michael Schilli
Erschienen im Linux-Magazin
2010/03
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!
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.
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.
| Whitepaper |
|
Daten Migration - Eine Publikation von Bloor Research
Datenmigrationsprojekte überschreiten häufig das Budget, neigen zu Verzögerung und werden unter Umständen komplett abgebrochen. Bloor Research ist eines der weltweit führenden IT-Forschungs-, Analyse- und Beratungsunternehmen und wird in dem vorliegenden White Paper die wichtigsten Aspekte dieser Problematik näher beleuchten. Ferner werden praktische Empfehlungen für erfolgreiche Migrationsprojekte gegeben, die Sie auf Ihr nächstes Projekt übertragen können.
Download PDF (Registrierung erforderlich)
|
|
Open Source Datenintegration in der Praxis: Fallstudien und Anwendungsbeispiele
Über die letzten Jahre hinweg haben sich Open Source Lösungen als fester Bestandteil des gesamten Datenintegrationsmarktes etabliert. Viele Unternehmen haben bereits das Open Source Modell für Ihre Datenintegrationsprojekte aufgegriffen. Das vorliegende White Paper illustriert anhand ausgewählter Fallstudien und Anwendungsbeispiele die Implementierung von Open Source Datenintegration in der Praxis und benennt die daraus resultierenden Vorteile.
Download PDF (Registrierung erforderlich)
|
Dieser Online-Artikel kann Links enthalten, die auf nicht mehr vorhandene Seiten verweisen. Wir ändern solche "broken links"
nur in wenigen Ausnahmefällen. Der Online-Artikel soll möglichst unverändert der gedrucken Fassung entsprechen.
|