1 | #!/usr/bin/perl -w |
---|
2 | use strict; |
---|
3 | |
---|
4 | use IPC::Open2; |
---|
5 | use IO::Prompt; |
---|
6 | use Term::ReadKey; |
---|
7 | |
---|
8 | my $FLAC_FILE = shift; |
---|
9 | my $TRACK = shift || 1; |
---|
10 | |
---|
11 | $|++; |
---|
12 | |
---|
13 | # get the track start positions from the embedded cuesheet |
---|
14 | open my $CUESHEET, "metaflac --export-cuesheet-to - $FLAC_FILE |"; |
---|
15 | |
---|
16 | my @position_for_track; |
---|
17 | my $i = 1; |
---|
18 | while (<$CUESHEET>) { |
---|
19 | if (my ($m,$s,$f) = /INDEX 01 (\d\d):(\d\d):(\d\d)/) { |
---|
20 | $position_for_track[$i] = ($m * 60) + $s + ($f / 75); |
---|
21 | $i++; |
---|
22 | } |
---|
23 | } |
---|
24 | |
---|
25 | close $CUESHEET; |
---|
26 | |
---|
27 | |
---|
28 | my $track_count = scalar @position_for_track - 1; |
---|
29 | print "$track_count tracks\n"; |
---|
30 | |
---|
31 | die "There is no track $TRACK" if $TRACK < 1 or $TRACK > $track_count; |
---|
32 | |
---|
33 | |
---|
34 | # launch the flac123 player as a daemon |
---|
35 | my $flac123_pid = open2(my $PLAYER_OUT, my $PLAYER_IN, qw{flac123 -R}); |
---|
36 | |
---|
37 | print "flac123 PID = $flac123_pid\n"; |
---|
38 | |
---|
39 | my $current_track = $TRACK; |
---|
40 | my $next_track_start = $position_for_track[$current_track + 1]; |
---|
41 | |
---|
42 | print "Track $current_track\n"; |
---|
43 | |
---|
44 | my %commands = ( |
---|
45 | z => sub { |
---|
46 | return if $current_track <= 1; |
---|
47 | $current_track--; |
---|
48 | $next_track_start = $position_for_track[$current_track + 1]; |
---|
49 | my $position = $position_for_track[$current_track]; |
---|
50 | print $PLAYER_IN "JUMP $position\n"; |
---|
51 | print "Track $current_track\n"; |
---|
52 | }, |
---|
53 | x => sub {}, |
---|
54 | c => sub {}, |
---|
55 | v => sub {}, |
---|
56 | b => sub { |
---|
57 | return if $current_track >= $track_count; |
---|
58 | $current_track++; |
---|
59 | $next_track_start = $position_for_track[$current_track + 1]; |
---|
60 | my $position = $position_for_track[$current_track]; |
---|
61 | print $PLAYER_IN "JUMP $position\n"; |
---|
62 | print "Track $current_track\n"; |
---|
63 | }, |
---|
64 | q => sub { |
---|
65 | print $PLAYER_IN "QUIT\n"; |
---|
66 | ReadMode 'restore'; |
---|
67 | exit; |
---|
68 | }, |
---|
69 | ); |
---|
70 | |
---|
71 | |
---|
72 | print $PLAYER_IN "LOAD $FLAC_FILE\n"; |
---|
73 | print $PLAYER_IN "JUMP $position_for_track[$TRACK]\n"; |
---|
74 | |
---|
75 | ReadMode 4; |
---|
76 | |
---|
77 | while (<$PLAYER_OUT>) { |
---|
78 | # do a non-blocking read to see if the user pressed a key |
---|
79 | my $cmd = ReadKey -1; |
---|
80 | if (defined $cmd && exists $commands{$cmd}) { |
---|
81 | $commands{$cmd}->(); |
---|
82 | } |
---|
83 | |
---|
84 | if (/\@F (\d+) (\d+) (\d+\.\d\d) (\d+\.\d\d)/) { |
---|
85 | my ($frame, $frames_left, $time, $time_left) = ($1, $2, $3, $4); |
---|
86 | if (defined $next_track_start && $time >= $next_track_start) { |
---|
87 | $current_track++; |
---|
88 | $next_track_start = $position_for_track[$current_track + 1]; |
---|
89 | print "Track $current_track\n"; |
---|
90 | } |
---|
91 | |
---|
92 | =begin |
---|
93 | |
---|
94 | for (my $track_number = $track_count; $track_number > 0; $track_number--) { |
---|
95 | #warn $track_number; |
---|
96 | if ($position_for_track[$track_number] <= $time) { |
---|
97 | $current_track = $track_number; |
---|
98 | #print "Track $current_track\n"; |
---|
99 | last; |
---|
100 | } |
---|
101 | } |
---|
102 | |
---|
103 | =cut |
---|
104 | |
---|
105 | } |
---|
106 | } |
---|
107 | |
---|
108 | waitpid $flac123_pid, 0; |
---|
109 | |
---|
110 | ReadMode 'restore'; |
---|
111 | |
---|
112 | =begin flac123 -R outputs |
---|
113 | |
---|
114 | @R FLAC123 |
---|
115 | flac123 tagline. Output at startup. |
---|
116 | |
---|
117 | @I ID3:<a><b><c><d><e><f> |
---|
118 | Prints out the metadata information after loading the flac file. |
---|
119 | a = title (30 chars) |
---|
120 | b = artist (30 chars) |
---|
121 | c = album (30 chars) |
---|
122 | d = year (4 chars) |
---|
123 | e = comment (30 chars) |
---|
124 | f = genre (30 chars) |
---|
125 | |
---|
126 | @I filename |
---|
127 | Prints out the filename of the flac file, minus the extension. Happens after |
---|
128 | a flac file has been loaded and there is no metadata available. |
---|
129 | |
---|
130 | @F <current-frame> <frames-remaining> <current-time> <time-remaining> |
---|
131 | Frame decoding status updates (once per frame). |
---|
132 | Current-frame and frames-remaining are integers; current-time and |
---|
133 | time-remaining floating point numbers with two decimal places. |
---|
134 | |
---|
135 | @P {0, 1, 2} |
---|
136 | Stop/pause status. |
---|
137 | 0 - playing has stopped. When 'STOP' is entered, or the flac file is finished. |
---|
138 | 1 - Playing is paused. Enter 'PAUSE' or 'P' to continue. |
---|
139 | 2 - Playing has begun again. |
---|
140 | |
---|
141 | =cut |
---|