File Coverage

blib/lib/Gftracks.pm
Criterion Covered Total %
statement 95 163 58.2
branch 33 66 50.0
condition 19 27 70.3
subroutine 13 23 56.5
pod 13 14 92.8
total 173 293 59.0


line stmt bran cond sub pod time code
1             #!/usr/bin/perl
2             package Gftracks;
3 6     6   193803 use warnings;
  6         15  
  6         197  
4 6     6   30 use strict;
  6         10  
  6         195  
5 6     6   3754 use Data::Dumper;
  6         37655  
  6         351  
6 6     6   38 use Exporter;
  6         7  
  6         13970  
7             our @ISA=qw / Exporter /;
8             our @EXPORT = qw / instime init deltrack printtracks shell/;
9             # Normally sec should only be used internally, but just in case,
10             # we make it possible to pull it in.
11             our @EXPORT_OK = qw /sec tidytime /;
12             our $VERSION="0.9";
13             # Returns number of secounds calculated from a grf timestamp
14              
15             sub sec{
16 44     44 0 159 my ($h,$m,$s)=split(':',$_[0]);
17 44         114 $s+=$m*60;
18 44         58 $s+=$h*3600;
19 44         210 return $s;
20             }
21              
22             =head1 NAME
23              
24             Gftracks - Perl extention for manipulation of gramofiles .tracks files
25              
26              
27             =head1 SYNOPSIS
28              
29             Usually the interactive shell will be used. The variable TRACKS shall point to
30             the .tracks file to be edited
31              
32             export TRACKS=/home/myhome/myrecord.wav.tracks
33              
34             perl -MGftracks -e shell;
35              
36              
37             Within the shell, press h for help.
38              
39             =head1 DESCRIPTION
40              
41             The .tracks file is read into an array, where the 0th element holds the
42             metadata for the file, and each of the other elements holds the information
43             for the actual track.
44              
45              
46             =head1 SUBROUTINES
47              
48             For all the subroutines the variable $tracks indicates an array build up in the
49             module.
50              
51             Those subroutines with a name starting with _ are not exported.
52              
53              
54             =head2 instime(timestamp)
55              
56             instime inserts a track at a given timestamp
57              
58             ins(\@tracks,$timestamp[,$duration]);
59             If duration is not defined, the end of the track is set to the
60             current end of the track in which the insertion is performed
61              
62             =cut
63              
64             sub instime{
65 3     3 1 33 my @tracks=@{$_[0]};
  3         8  
66 3         4 my $timestamp=$_[1];
67 3   50     15 my $duration=$_[2] || undef;
68 3 50       8 return \@tracks if $duration; # $duration still does not work
69 3         31 my $timesec=sec($timestamp);
70 3         9 foreach (1..$#tracks){
71             # Search until either, we find the track which the new is to be inserted
72             # into, or we are on the last track. (To avoid warning, the checks are done
73             # the other way around
74 7 100 66     40 next unless ($_ == $#tracks or(
      66        
75             sec($tracks[$_]{start})< $timesec)
76             and (sec($tracks[$_+1]{start})> $timesec));
77 3 100       10 if (sec($tracks[$_]{end})>$timesec){ # Unless the insert is between two tracks
78 2         6 my $new={start=>$timestamp,
79             end=>$tracks[$_]{end}};
80 2         6 splice(@tracks,$_+1,0,$new);
81 2         4 $tracks[$_]{end}=$timestamp;
82             }else{
83 1 50       5 if ($duration){
84 0         0 my $new={start=>$timestamp,
85             end=>$tracks[$_+1]{end}};
86 0         0 splice(@tracks,$_+1,0,$new);
87 0         0 $tracks[$_]{end}=$timestamp;
88             }
89             }
90 3         4 last;
91             }
92 3         8 $tracks[0]{Number_of_tracks}=$#tracks;
93 3         9 return \@tracks;
94             }
95              
96             =head2 _spliceback and _splicefwd
97              
98             _spliceback and _splicefwd splices the rest of the array when
99             a track has been deleted. They should only be used internally.
100             In both cases the arguments are a pointer to the tracks array and
101             the index that is to be deleted
102              
103             =cut
104              
105             # _spliceback removes a track by combining it with the previous track
106             sub _spliceback{
107 2     2   4 my $tracks=shift;
108 2         4 my $delno =shift;
109 2         7 $tracks->[$delno-1]{end}=$tracks->[$delno]{end};
110 2         6 splice (@$tracks,$delno,1);
111 2         7 return $tracks;
112             }
113              
114             # _spliceback removes a track by combining it with the next track
115             sub _splicefwd{
116 1     1   2 my $tracks=shift;
117 1         3 my $delno =shift;
118 1         5 $tracks->[$delno+1]{start}=$tracks->[$delno]{start};
119 1         3 splice (@$tracks,$delno,1);
120 1         4 return $tracks;
121             }
122              
123             =head2 deltrack
124              
125             deltrack (\@tracks,$index,$back)
126              
127             Deltrack removes a track by default using spliceback (unless the last track
128             is deleted).
129              
130             =cut
131              
132             sub deltrack{
133 5     5 1 2879 my $tracks=shift;
134 5         9 my $delno =shift;
135 5   100     8 my $back = $delno == $#{$tracks} || shift;
136             # $tracks->[0] must not be deleted, as it holds the meta info
137 5 100       19 return $tracks unless $delno*1;
138 4 100       27 return $tracks if $delno >$#{$tracks};
  4         16  
139 3 100       17 $tracks = $back ? _spliceback($tracks,$delno) : _splicefwd($tracks,$delno);
140 3         4 $tracks->[0]{Number_of_tracks}=$#{$tracks};
  3         9  
141 3         9 return $tracks;
142             }
143              
144             =head2 trackfile
145              
146             trackfile returns the filename as given by $ENV{TRACKS} and does some simple
147             sanity checking on it
148              
149             =cut
150              
151             sub _trackfile{
152             # Could add a function that returns a *.track file if that
153             # is the only one found in the active directory
154 0     0   0 my $file= $ENV{TRACKS};
155 0 0       0 warn("Is $file a .tracks file?") unless $file=~/.tracks$/;
156 0         0 return $file;
157              
158             }
159              
160             =head2 init
161              
162             init($filename) reads the file as specified by filename and returns the array
163             holding all the information in the .tracks-file
164              
165             =cut
166              
167             sub init{
168 7     7 1 9160 my (@lines,@tracks,$nooftracks, $comment, %data,$tracks);
169 7   33     31 my $file=$_[0] || _trackfile;
170 7         23 my $savefile=$file.".bak";
171 7 50       32 print "$file\n" if $ENV{GRFDEBUG};
172 7 50       420 open (FILE,"<$file") || die ("Cannot open $file");
173 7 50       916 open (BACKUP,">$savefile") || warn ("Cannot create backupfile, $savefile\n");
174 7         17 my $i;
175 7         170 while(){
176 252         423 print BACKUP $_;
177 252 100 100     876 if (!$nooftracks && /Number_of_tracks.(\d+)/)
178             {
179 7         22 $nooftracks=$1;
180             }
181 252         288 chomp;
182 252         426 push @lines , $_;
183 252   100     792 $tracks=$tracks || /Track ?\d/;
184 252 100       450 unless($tracks){
185 175 100       581 next if /^#/;
186 98         234 my($key,$var)=split(/=/,$_);
187 98 100       268 $data{$key}=$var if $var;
188 98         271 next;
189             }
190 77 100       184 $comment=$_ if /^#/;
191 77 100       331 if (/^Track(\d+)(start|end)=(.*)$/) {
192 42         169 $tracks[$1]{$2}=$3;
193             # The last comment is the one connected to the current track
194 42         93 $tracks[$1]{comment}=$comment;
195             # If the {end} element is not defined for current track, then
196             # we are at start and calculates the start timestamp
197 42 100       251 $tracks[$1]{starttime}=sec($3) unless ($tracks[$1]{end});
198             }
199             }
200 7         18 $tracks[0]=\%data;
201 7         59 return \@tracks;
202             }
203              
204             =head2 tidytime
205              
206             $timestamp=tidytime(timestamp)
207              
208             Does some sanitychecking of the time stamp and tidies up a bit so that the
209             returned timestamp is on the form hh:mm:ss.sss
210              
211             =cut
212              
213             sub tidytime{
214 7     7 1 15 my $zerotime="0:00:00.000";
215 7         12 my $timestamp=shift;
216 7         11 $timestamp.=' ';
217 7         34 $timestamp=~m/(\d\D)?(\d{2})\D(\d{2}(\.\d{1,3})?)?/;
218             # print "<$1|$2|$3|$4>\n";
219 7   100     31 my $sec= ($3 || '0');
220 7 100       20 $sec.='.' unless $4;
221 7 100       30 $sec='0'.$sec if $sec < 10;
222 7         17 $sec.='0'x(6-length($sec));
223 7   100     32 my $hour= ($1 || '0 ');
224 7         12 chop($hour);
225 7         41 return "$hour:$2:$sec";
226              
227             }
228              
229             =head2 Shellcommands
230              
231             =head3 shellhelp
232              
233             Prints out some basic help for the shell commands
234              
235             =cut
236              
237              
238             sub shellhelp{
239 0     0 1   print <
240             h : help
241             a : add a track at given time
242             d : delete the given track
243             n : print number of tracks
244             p : print start and end times for all tracks
245             b : alter beginning of track
246             e : alter end of track
247             s : save file
248             q : quit
249             ---------------------------------------------------------
250             time, must be given as h:mm:ss.ss
251             tracknumber
252             (c) Morten Sickel (cpan\@sickel.net) April 2005
253             The last version should be available at http://sickel.net
254             Licenced under the artistic licence
255              
256             ENDHELP
257             }
258              
259             =head3 shelladjusttime
260              
261             shelladjusttime ($tracks,$command,$end)
262              
263             adjusts the time for start or end of a track. End is either set to 'start' or
264             'end'.
265              
266             =cut
267              
268             sub shelladjusttime{
269             # adjusts the time for start or end of a track
270 0     0 1   my $tracks=shift;
271 0           my $command=shift;
272 0           my $end=shift;
273 0           $command=~/\w+\s+(\d+)\s+(.*)/;
274 0           my $time=tidytime($2);
275 0           $$tracks[$1]{$end}=$time;
276             }
277              
278             =head3 shelladd
279              
280             shelladd($tracks,$timestamp)
281             Adds track at a given time
282              
283             =cut
284              
285              
286             sub shelladd{
287              
288 0     0 1   my $tracks = shift;
289 0           my $timestamp = shift;
290 0           $timestamp=~m/^\w+\s+(.*)/;
291 0           $timestamp=$1;
292 0           $tracks=instime($tracks,$timestamp);
293            
294             }
295              
296             =head3 shelldelete
297              
298             shelldelete($tracks,$trackno)
299              
300             uses deltrack() to delete the indicated track
301              
302             =cut
303              
304              
305             sub shelldelete{
306 0     0 1   my ($tracks,$trackno)=@_;
307 0           $trackno=~m/^\w+\s+(.*)/;
308 0           $trackno=$1;
309 0           $tracks=deltrack($tracks,$trackno);
310             }
311              
312             =head3 shellprint
313             shellprint($tracks)
314             prints out the number of tracks
315              
316             =cut
317              
318             sub shellprint{
319 0     0 1   my $tracks = shift;
320 0           print $#$tracks," tracks\n";
321             }
322              
323             =head3 shellsave
324              
325             shellsave($tracks,$filename)
326             saves the information to $filename
327              
328             =cut
329              
330             sub shellsave{
331 0     0 1   my($tracks,$file)=@_;
332 0           open OUT,">$file";
333 0           print OUT printtracks($tracks);
334 0           close OUT;
335             }
336              
337             =head3 shellprinttracks
338              
339             shellprinttracks($tracks)
340              
341             prints out the beginning and end time of all the tracks
342              
343             =cut
344              
345             sub shellprinttracks{
346 0     0 1   my $tracks=shift;
347 0           my @tracks=@$tracks;
348 0           my $i;
349 0           print "track from"." "x10,"to\n";
350 0           print "-"x(6+4+10+11),"\n";
351 0           foreach $i (1..$#tracks){
352 0           print " $i"," "x(4-length($i)),$tracks[$i]->{start},
353             " - ",$tracks[$i]->{end},"\n";
354             }
355            
356              
357             }
358              
359             =head2 shell
360              
361             shell($file)
362              
363             shell will fetch the filename from _trackfile if not given.
364              
365             shell opens up a quite simple interactive shell for editing.
366              
367             The following commands are valid:
368              
369             h : help
370             a : add a track at given time
371             d : delete the given track
372             n : print number of tracks
373             p : print start and end times for all tracks
374             b : alter beginning of track
375             e : alter end of track
376             s : save file
377             q : quit
378             ---------------------------------------------------------
379             time, must be given as h:mm:ss.ss
380             tracknumber
381              
382              
383             =cut
384              
385              
386             sub shell{
387 0   0 0 1   my $file = shift || _trackfile;
388 0           $file=~tr/ //d;
389 0 0         die("Use the environment variable TRACKS to set tracks file\n")
390             unless $file;
391 0           my $tracks=init($file);
392 0 0         die('Cannot find tracks file, use the environment variable TRACKS')
393             unless $tracks;
394 0           print "press 'h' for help\n";
395 0           while(1){
396 0           print " > ";
397 0           my $command = <>;
398 0 0         last if $command=~/^q/i;
399 0 0         shellhelp if $command =~/^h/i;
400 0 0         $tracks=shelladd($tracks,$command) if $command =~/^a/;
401 0 0         shellprint($tracks) if $command=~/^n/;
402 0 0         $tracks=shelldelete($tracks,$command) if $command=~/^d/;
403 0 0         shellsave($tracks,$file) if $command=~/^s/;
404 0 0         shellprinttracks($tracks) if $command=~/^p/;
405 0 0         shelladjusttime($tracks,$command,'start') if $command=~/^b/;
406 0 0         shelladjusttime($tracks,$command,'end') if $command=~/^e/;
407             }
408             }
409              
410             =head2 printtracks
411              
412             printtracks($tracks)
413              
414             returns the information in $tracks. Suitable for saving.
415              
416             =cut
417              
418             sub printtracks{
419 0     0 1   my $tracks=shift;
420 0           my @tracks=@$tracks;
421 0           my $not="Number_of_tracks";
422 0           my $buffer="[Tracks]";
423 0           foreach (keys %{$tracks[0]}){
  0            
424 0 0         $buffer .= "$_=$$tracks[0]{$_}\n" if $_ ne $not;
425             }
426 0           $buffer.= "\n".$not."=".$$tracks[0]{$not}."\n\n";
427 0           my $i;
428 0           foreach $i (1..$#tracks){
429 0 0         $i="0".$i if $i<10;
430 6     6   40 no warnings;
  6         13  
  6         667  
431              
432 0           $buffer.= $tracks[$i]->{comment}."\n";
433 0           $buffer.= "Track${i}start=".$tracks[$i]->{start}."\n";
434 0           $buffer.= "Track${i}end=".$tracks[$i]->{end}."\n\n";
435 6     6   30 use warnings;
  6         13  
  6         433  
436             }
437 0           return $buffer;
438             }
439              
440             1;
441              
442              
443             =head1 LICENCE
444              
445             (c) Morten Sickel (cpan\@sickel.net) April 2005
446             The last version should be available at http://sickel.net
447             Licenced under the artistic licence
448              
449             =cut