#!/usr/local/bin/perl -w ########################################### # flipit - Record and Play Backwards # Mike Schilli, 2009 (m@perlmeister.com) ########################################### use strict; use POE; use POE::Wheel::Run; use Curses::UI::POE; use File::Temp qw(tempfile); use Sysadm::Install qw(:all); use POSIX; our $HEAP; my $CUI = Curses::UI::POE->new( -color_support => 1, inline_states => { _start => sub { $HEAP = $_[HEAP]; }, play_ended => \&footer_update, }); my $WIN = $CUI->add("win_id", "Window"); my $FOOT = $WIN->add(qw( bottom Label -y -1 -paddingspaces 1 -fg white -bg blue)); footer_update(); $CUI->set_binding(sub { exit 0; }, "q"); $CUI->set_binding( \&play_flipped, "p"); $CUI->set_binding( \&record, "r" ); $CUI->set_binding( \&record_stop, "s" ); $CUI->mainloop; ########################################### sub record { ########################################### if(defined $HEAP->{recorder}->{wheel}) { return; # Still recording } my($fh, $tempfile) = tempfile( SUFFIX => ".ogg", UNLINK => 1); my $wheel = POE::Wheel::Run->new( Program => "rec", ProgramArgs => [$tempfile], StderrEvent => 'ignore', ); $HEAP->{recorder} = { wheel => $wheel, file => $tempfile, }; $FOOT->text("Recording ... " . "([s] to stop, [p] to play)"); $FOOT->draw(); } ########################################### sub record_stop { ########################################### my $wheel = $HEAP->{recorder}->{wheel}; return if !defined $wheel; $wheel->kill(SIGTERM); delete $HEAP->{recorder}->{wheel}; footer_update(); } ########################################### sub footer_update { ########################################### my $text = "[r] to record"; if(defined $HEAP->{recorder}->{file}) { $text .= ", [p] to play"; } $text .= ", [q] to quit"; $FOOT->text($text); $FOOT->draw(); } ########################################### sub play_flipped { ########################################### if(defined $HEAP->{recorder}->{wheel}) { # Active recording? Stop it. record_stop( $HEAP ); } $FOOT->text("Playing ..."); $FOOT->draw(); my $recorded = $HEAP->{recorder}->{file}; return if ! defined $recorded; my $wheel = POE::Wheel::Run->new( Program => \&sox_play, ProgramArgs => [$recorded], StderrEvent => 'ignore', CloseEvent => 'play_ended', ); $HEAP->{players}->{$wheel->ID} = $wheel; } ########################################### sub sox_play { ########################################### my($recording) = @_; my($fh, $tmpfile) = tempfile(SUFFIX => ".ogg"); tap "sox", $recording, $tmpfile, "reverse"; tap "play", $tmpfile; unlink $tmpfile; }