File Coverage

blib/lib/Data/iRealPro/Input/Text.pm
Criterion Covered Total %
statement 71 76 93.4
branch 18 32 56.2
condition 4 5 80.0
subroutine 11 11 100.0
pod 0 4 0.0
total 104 128 81.2


line stmt bran cond sub pod time code
1             #! perl
2              
3             # Data::iRealPro::Input::Text -- parse iRealPro data (text format)
4              
5             # Author : Johan Vromans
6             # Created On : Tue Sep 6 14:58:26 2016
7             # Last Modified By: Johan Vromans
8             # Last Modified On: Wed Oct 31 22:31:44 2018
9             # Update Count : 95
10             # Status : Unknown, Use with caution!
11              
12             ################ Common stuff ################
13              
14 10     10   969 use strict;
  10         21  
  10         333  
15 10     10   57 use warnings;
  10         21  
  10         261  
16 10     10   52 use Carp;
  10         28  
  10         527  
17 10     10   58 use utf8;
  10         19  
  10         70  
18              
19             package Data::iRealPro::Input::Text;
20              
21 10     10   432 use Data::iRealPro::URI;
  10         19  
  10         253  
22 10     10   77 use Data::iRealPro::Playlist;
  10         20  
  10         213  
23 10     10   62 use Data::iRealPro::Song;
  10         22  
  10         11641  
24              
25             my %keymap =
26             ( 'C' => 0,
27             'C#' => 1, 'Db' => 1,
28             'D' => 2,
29             'D#' => 3, 'Eb' => 3,
30             'E ' => 4,
31             'F' => 5,
32             'F#' => 6, 'Gb' => 6,
33             'G' => 7,
34             'G#' => 8, 'Ab' => 8,
35             'A' => 9,
36             'A#' => 10, 'Bb' => 10,
37             'B' => 11,
38              
39             'A-' => 0,
40             'A#-' => 1, 'Bb-' => 1,
41             'B-' => 2,
42             'C-' => 3,
43             'C#-' => 4, 'Db-' => 4,
44             'D-' => 5,
45             'D#-' => 6, 'Eb-' => 6,
46             'E-' => 7,
47             'F-' => 8,
48             'F#-' => 9, 'Gb-' => 9,
49             'G-' => 10,
50             'G#-' => 11, 'Ab-' => 11,
51             );
52              
53             sub encode {
54 7     7 0 24 my ( $self, $data ) = @_;
55 7         25 my $variant = "irealpro";
56 7   100     51 $self->{transpose} //= 0;
57              
58 7         13 my $plname;
59 7 100       38 if ( $data =~ /^Playlist:\s*(.*)/m ) {
60 1 50       13 $plname = $1 unless $1 eq "";
61             }
62              
63 7         16 my @songs;
64 7         34 while ( $data =~ /\A(Song(?: (\d+))?:.*?)^(Song(?: \d+)?:.*)/ms ) {
65 0 0       0 warn("Expecting song ", 1+@songs, " but got $2\n")
66             unless $2 == 1 + @songs;
67 0         0 push( @songs, encode_song( $self, $1 ) );
68 0         0 $data = $3;
69             }
70 7 50       48 if ( $data =~ /^Song(?: (\d+))?:.*/ ) {
71 7 50 66     49 warn("Expecting song number ", 1+@songs, " but got number $1\n")
72             if $1 && $1 != 1 + @songs;
73 7         33 push( @songs, encode_song( $self, $data ) );
74             }
75              
76             # Build a playlist for the songs...
77 7 100       95 my $pl = Data::iRealPro::Playlist->new
78             ( variant => $variant,
79             songs => \@songs,
80             $plname ? ( name => $plname ) : (),
81             );
82              
83             # Build a URI for the playlist...
84             my $uri = Data::iRealPro::URI->new
85             ( variant => $variant,
86             playlist => $pl,
87             transpose => $self->{transpose},
88 7         88 );
89              
90             # And deliver.
91 7         29 return $uri;
92             }
93              
94             sub encode_song {
95 7     7 0 23 my ( $self, $data ) = @_;
96 7         18 my $variant = "irealpro";
97 7         66 my $tv =
98             { variant => $variant,
99             composer => "Composer",
100             key => 'C',
101             style => "Rock Ballad",
102             actual_key => 0,
103             actual_repeats => 0,
104             actual_style => "",
105             actual_tempo => 0,
106             };
107              
108 7 100       34 if ( $data =~ /^Playlist:\s*(.*)/m ) {
109 1 50       6 $tv->{pl_name} = $1 unless $1 eq "";
110             }
111              
112 7 50       69 if ( $data =~ /^Song(?:\s+\d+)?:\s+(.*)\s+\((.*?)\)/m ) {
113 7         30 $tv->{title} = $1;
114 7         63 my @t = split( ' ', $2 );
115 7 50       57 @t[0,1] = @t[1,0] if @t == 2;
116 7         40 $tv->{composer} = "@t";
117             }
118              
119 7 50       64 if ( $data =~ /Style:\s+([^;(\n]*)(?:\s+\(([^)\n]+)\))?(?:;|$)/m ) {
120 7         25 $tv->{style} = $1;
121 7         20 $tv->{actual_style} = $2;
122             }
123              
124 7 50       52 if ( $data =~ /; key:\s+([^;\n]+)/ ) {
125 7         23 $tv->{key} = $1;
126             }
127 7 50       33 if ( $data =~ /; actual\s+key:\s+([^;\n]+)/ ) {
128 0         0 $tv->{actual_key} = $keymap{$1};
129             }
130             else {
131 7         28 $tv->{actual_key} = $keymap{$tv->{key}};
132             }
133              
134 7 50       40 if ( $data =~ /; tempo:\s+(\d+)/ ) {
135 7         26 $tv->{actual_tempo} = $1;
136             }
137 7 50       28 if ( $data =~ /; repeats?:\s+(\d+)/ ) {
138 0         0 $tv->{actual_repeats} = $1;
139             }
140              
141 7         44 $data =~ s/^.*?\n\n//s;
142              
143             # Build the song...
144             my $song = Data::iRealPro::Song->new
145             ( variant => $variant,
146             title => $tv->{title},
147             composer => $tv->{composer},
148             style => $tv->{style},
149             key => $tv->{key},
150             actual_key => $tv->{actual_key},
151             actual_tempo => $tv->{actual_tempo},
152             actual_style => $tv->{actual_style},
153             actual_repeats => $tv->{actual_repeats},
154             transpose => $self->{transpose},
155 7         98 _transpose => ( $tv->{actual_key} - $keymap{$tv->{key}} ) % 12,
156             );
157 7         31 $song->{data} = yfitaen($data);
158              
159             # And deliver.
160 7         46 return $song;
161             }
162              
163             sub yfitaen {
164 7     7 0 20 my ( $t ) = @_;
165 7         40 my @a = split( /(\<.*?\>)/, $t );
166 7         21 $t = "";
167 7         31 while ( @a > 1 ) {
168 2         15 $t .= yfitaen1(shift(@a)) . shift(@a);
169             }
170 7 50       37 $t .= yfitaen1(shift(@a)) if @a;
171 7         44 return $t;
172             }
173              
174             sub yfitaen1 {
175 9     9 0 26 my ( $t ) = @_;
176             # Indeed, the reverse of neatify. And a bit easier.
177 9         146 $t =~ s/([[:alnum:]])\s+([[:alnum:]])/$1,$2/g;
178 9         95 $t =~ s/\s+//g;
179 9         41 $t =~ s/_/ /g;
180 9         36 return $t;
181             }
182              
183             1;