#!/usr/bin/perl -w use strict; use IPC::Open2; use IO::Prompt; use Term::ReadKey; my $FLAC_FILE = shift; my $TRACK = shift || 1; $|++; # get the track start positions from the embedded cuesheet open my $CUESHEET, "metaflac --export-cuesheet-to - $FLAC_FILE |"; my @position_for_track; my $i = 1; while (<$CUESHEET>) { if (my ($m,$s,$f) = /INDEX 01 (\d\d):(\d\d):(\d\d)/) { $position_for_track[$i] = ($m * 60) + $s + ($f / 75); $i++; } } close $CUESHEET; my $track_count = scalar @position_for_track - 1; print "$track_count tracks\n"; die "There is no track $TRACK" if $TRACK < 1 or $TRACK > $track_count; # launch the flac123 player as a daemon my $flac123_pid = open2(my $PLAYER_OUT, my $PLAYER_IN, qw{flac123 -R}); print "flac123 PID = $flac123_pid\n"; my $current_track = $TRACK; my $next_track_start = $position_for_track[$current_track + 1]; print "Track $current_track\n"; my %commands = ( z => sub { return if $current_track <= 1; $current_track--; $next_track_start = $position_for_track[$current_track + 1]; my $position = $position_for_track[$current_track]; print $PLAYER_IN "JUMP $position\n"; print "Track $current_track\n"; }, x => sub {}, c => sub {}, v => sub {}, b => sub { return if $current_track >= $track_count; $current_track++; $next_track_start = $position_for_track[$current_track + 1]; my $position = $position_for_track[$current_track]; print $PLAYER_IN "JUMP $position\n"; print "Track $current_track\n"; }, q => sub { print $PLAYER_IN "QUIT\n"; ReadMode 'restore'; exit; }, ); print $PLAYER_IN "LOAD $FLAC_FILE\n"; print $PLAYER_IN "JUMP $position_for_track[$TRACK]\n"; ReadMode 4; while (<$PLAYER_OUT>) { # do a non-blocking read to see if the user pressed a key my $cmd = ReadKey -1; if (defined $cmd && exists $commands{$cmd}) { $commands{$cmd}->(); } if (/\@F (\d+) (\d+) (\d+\.\d\d) (\d+\.\d\d)/) { my ($frame, $frames_left, $time, $time_left) = ($1, $2, $3, $4); if (defined $next_track_start && $time >= $next_track_start) { $current_track++; $next_track_start = $position_for_track[$current_track + 1]; print "Track $current_track\n"; } =begin for (my $track_number = $track_count; $track_number > 0; $track_number--) { #warn $track_number; if ($position_for_track[$track_number] <= $time) { $current_track = $track_number; #print "Track $current_track\n"; last; } } =cut } } waitpid $flac123_pid, 0; ReadMode 'restore'; =begin flac123 -R outputs @R FLAC123 flac123 tagline. Output at startup. @I ID3: Prints out the metadata information after loading the flac file. a = title (30 chars) b = artist (30 chars) c = album (30 chars) d = year (4 chars) e = comment (30 chars) f = genre (30 chars) @I filename Prints out the filename of the flac file, minus the extension. Happens after a flac file has been loaded and there is no metadata available. @F Frame decoding status updates (once per frame). Current-frame and frames-remaining are integers; current-time and time-remaining floating point numbers with two decimal places. @P {0, 1, 2} Stop/pause status. 0 - playing has stopped. When 'STOP' is entered, or the flac file is finished. 1 - Playing is paused. Enter 'PAUSE' or 'P' to continue. 2 - Playing has begun again. =cut