#!/usr/bin/perl use warnings; use strict; use Curses::UI; use Audio::CD 0.05; # setup root window my $cui = new Curses::UI ( -clear_on_exit => 1, -debug => $debug, ); # initialize cd player my $cd = Audio::CD->init; # check for cd in drive until ( $cd->stat->present ) { my $value = $cui->dialog( -message => 'Please load cd in drive', -buttons => [ 'ok', 'cancel' ], -buttonalignment => 'middle', ); exit unless ($value); $cui->status( 'Loading cd...please wait' ); } my ($tracklist_win, $tracklist_content,); my ($cddb_data, $cddb_tracks, %cddb, $min, $sec,); my $track = $cd->stat->current_track; my $total_tracks = $cd->stat->total_tracks; my @all_tracks = ($cd->stat->first_track..$cd->stat->total_tracks); # get the length of each track my @times; my $track_length = $cd->stat->tracks; foreach my $length (@$track_length) { my ($min, $sec) = $length->length; push (@times, sprintf "%d:%02d", $min, $sec); } # setup the status bar window my $statusbar_win = $cui->add( 'statusbar_win', 'Window', -height => 4, -y => -1, ); # add the initial status my $modeline = get_mode(); my $status = $statusbar_win->add( 'status_text', 'TextViewer', -padtop => 2, -width => 25, -text => "$modeline: Track $track", ); # add the timer window my $timer = $statusbar_win->add( 'timer', 'Label', -padtop => 2, -width => 15, -x => -1, -ipadleft => -1, ); get_timer($track); # setup the progressbar window my $progress = progress(); # setup the screen updater process $cui->set_timer( 'track_check', \&poll_track, 1 ); sub poll_track { my $cur_track = $cd->stat->current_track; # increment the timer ($min, $sec) = get_timer($cur_track); # increment the progressbar my $pos = $min * 60 + $sec; $statusbar_win->getobj('progress')->pos($pos); $progress->draw; # update the modeline if it has changed my $cur_modeline = get_mode(); if ($cur_modeline ne $modeline || $cur_track != $track) { $modeline = $cur_modeline; $statusbar_win->getobj('status_text')->text("$modeline: Track $cur_track"); $statusbar_win->draw; } # update the tracklist and progressbar when a new track starts if ($cur_track != $track) { $track = $cur_track; add_tracklist(); progress(); } } # add keybindings $cui->set_binding( \&cddb, "\cL" ); $cui->set_binding( \&select_handler, "343" ); # "enter" key $cui->set_binding( \&select_handler, "p" ); $cui->set_binding( \&exit, "q" ); $cui->set_binding( \&stop, "s" ); $cui->set_binding( \&next_track, ">" ); $cui->set_binding( \&prev_track, "<" ); $cui->set_binding( \&advance, "." ); $cui->set_binding( \&reverse, "," ); $cui->set_binding( \&help, "H" ); # fire it up add_tracklist(); $cui->mainloop(); ################################################################################### # UI subs sub add_title { my $text; if ( $cddb{artist} ) { # this will exist if a successful cddb lookup has occurred $text = "$cddb{artist} - $cddb{album}"; } else { $text = "Unknown Disc"; } } sub add_tracklist { if ($tracklist_win) { $cui->delete('tracklist_win'); # delete any existing tracklists in case it is being updated } # determine the disc's title my $text; if ( $cddb{artist} ) { $text = "$cddb{artist} - $cddb{album}"; } else { $text = "Unknown Disc"; } # setup the tracklist window $tracklist_win = $cui->add( 'tracklist_win', 'Window', -title => $text, -titlereverse => 0, -border => 1, -y => 1, -padbottom => 5, ); my %track_labels = track_labels($cddb_tracks); $tracklist_content = $tracklist_win->add( 'tracklist', 'Listbox', -values => \@all_tracks, -labels => \%track_labels, -vscrollbar => 'right', -selected => $track-1, -onchange => \&select_handler, -ipad => 1, ); $tracklist_win->focus(); } sub get_timer { my $cur_track = shift; if ($modeline eq 'Stopped') { ($min, $sec) = (0, 0); } else { ($min, $sec) = $cd->stat->track_time; } $sec = sprintf "%02d", $sec; $statusbar_win->getobj('timer')->text("[$min:$sec/$times[$cur_track-1]]"); $timer->draw; return $min, $sec; } sub progress { $statusbar_win->delete('progress'); my ($tmin, $tsec) = split /:/, $times[$track-1]; # track time $progress = $statusbar_win->add( 'progress', 'Progressbar', -border => 0, -nopercentage => 1, -max => $tmin * 60 + $tsec, -pos => $min * 60 + $sec, ); } sub no_match { $cui->dialog( -message => "No match found!" ); } ############################################################################ # CD subs sub cddb { $cddb_data = $cd->cddb->lookup unless ($cddb_data); $cddb{artist} = $cddb_data->artist; $cddb{album} = $cddb_data->title; $cddb_tracks = $cddb_data->tracks($cd->stat); unless ( $cddb{artist} ) { no_match(); } else { add_title(); add_tracklist(); } } sub track_labels { my %track_info; if (my $track_titles = shift) { # passed an array ref containing track titles from a successful cddb lookup foreach my $number (@all_tracks) { # $number is the track number ( 1... ), track_titles and times are zero referenced $track_info{$number} = sprintf( "%-5d%-65s%5s", ($number, $$track_titles[$number-1]->name, $times[$number-1]) ); } } else { foreach my $number (@all_tracks) { $track_info{$number} = sprintf( "%-5d%70s", ($number, $times[$number-1]) ); } } return %track_info; } sub get_mode { my $modeline; my $mode = $cd->stat->mode; if ($mode == 0) { $modeline = "Playing"; } elsif ($mode == 1) { $modeline = "Paused"; } else { $modeline = "Stopped"; } } sub stop { $cd->stop; } sub next_track { my $cur_track = $cd->stat->current_track; # method not available in Audio::CD 0.04 $cd->play_track($cur_track, $total_tracks) unless ( ++$cur_track > $total_tracks ); } sub prev_track { my $cur_track = $cd->stat->current_track; $cd->play_track($cur_track, $total_tracks) unless ( --$cur_track < 1 ); } sub advance { $cd->advance(0, 5); } sub reverse { $cd->advance(0, -5); } sub select_handler { my $sel = $tracklist_content->get_active_value(); my $cur_track = $cd->stat->current_track; if ($sel == $cur_track) { my $mode = $cd->stat->mode; if ($mode == 0) { $cd->pause; } elsif ($mode == 1 ) { $cd->resume; } else { $cd->play($sel); } } else { $cd->play($sel); } } sub exit { exit; } ############################################################################# sub help {#{{{ $cui->set_binding( \&return, "343" ); # want "enter" to select ok instead of track my $help_win = $cui->add( 'help_win', 'Window', -width => 35, -height => 15, -title => 'nccd help', -titlereverse => 0, -centered => 1, -border => 1, ); my $help = $help_win->add( 'help', 'TextViewer', -y => 1, -height => 10, -text => "[ ctrl-l ]\tcddb lookup\n" . "[ enter ]\tplay\n" . "[ p ]\t\tplay/pause\n" . "[ s ]\t\tstop\n" . "[ > ]\t\tskip forward\n" . "[ < ]\t\tskip back\n" . "[ . ]\t\tadvance 5 sec\n" . "[ , ]\t\treverse 5 sec\n" . "[ q ]\t\tquit\n" . "[ H ]\t\thelp\n", ); my $buttons = $help_win->add( undef, 'Buttonbox', -y => -1, -buttons => [ { -label => "< OK >", -onpress => \&return, } ] ); $help_win->focus(); $buttons->focus(); } sub return { $cui->set_binding( \&select_handler, "343" ); # return "enter" keybinding back to original $cui->delete('help_win'); return; }#}}}