File Coverage

blib/lib/Data/iRealPro/Input/Text.pm
Criterion Covered Total %
statement 72 77 93.5
branch 20 32 62.5
condition 5 7 71.4
subroutine 11 11 100.0
pod 0 4 0.0
total 108 131 82.4


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: Tue Nov 13 10:31:13 2018
9             # Update Count : 98
10             # Status : Unknown, Use with caution!
11              
12             ################ Common stuff ################
13              
14 11     11   960 use strict;
  11         23  
  11         333  
15 11     11   57 use warnings;
  11         22  
  11         276  
16 11     11   51 use Carp;
  11         22  
  11         574  
17 11     11   65 use utf8;
  11         20  
  11         59  
18              
19             package Data::iRealPro::Input::Text;
20              
21 11     11   469 use Data::iRealPro::URI;
  11         84  
  11         284  
22 11     11   57 use Data::iRealPro::Playlist;
  11         17  
  11         267  
23 11     11   60 use Data::iRealPro::Song;
  11         17  
  11         13028  
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 9     9 0 28 my ( $self, $data ) = @_;
55 9         24 my $variant = "irealpro";
56 9   100     62 $self->{transpose} //= 0;
57              
58 9         13 my $plname;
59 9 100       55 if ( $data =~ /^Playlist:\s*(.*)/m ) {
60 3 50       15 $plname = $1 unless $1 eq "";
61             }
62              
63 9         19 my @songs;
64 9         44 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 9 50       52 if ( $data =~ /^Song(?: (\d+))?:.*/ ) {
71 9 50 66     64 warn("Expecting song number ", 1+@songs, " but got number $1\n")
72             if $1 && $1 != 1 + @songs;
73 9         38 push( @songs, encode_song( $self, $data ) );
74             }
75              
76             # Build a playlist for the songs...
77 9 100       152 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 9         91 );
89              
90             # And deliver.
91 9         47 return $uri;
92             }
93              
94             sub encode_song {
95 9     9 0 27 my ( $self, $data ) = @_;
96 9         20 my $variant = "irealpro";
97 9         76 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 9 100       50 if ( $data =~ /^Playlist:\s*(.*)/m ) {
109 3 50       17 $tv->{pl_name} = $1 unless $1 eq "";
110             }
111              
112 9 50       85 if ( $data =~ /^Song(?:\s+\d+)?:\s+(.*)\s+\((.*?)\)/m ) {
113 9         38 $tv->{title} = $1;
114 9         56 my @t = split( ' ', $2 );
115 9 100       54 @t[0,1] = @t[1,0] if @t == 2;
116 9         49 $tv->{composer} = "@t";
117             }
118              
119 9 50       89 if ( $data =~ /Style:\s+([^;(\n]*)(?:\s+\(([^)\n]+)\))?(?:;|$)/m ) {
120 9         38 $tv->{style} = $1;
121 9         26 $tv->{actual_style} = $2;
122             }
123              
124 9 50       46 if ( $data =~ /; key:\s+([^;\n]+)/ ) {
125 9         27 $tv->{key} = $1;
126             }
127 9 50       40 if ( $data =~ /; actual\s+key:\s+([^;\n]+)/ ) {
128 0         0 $tv->{actual_key} = $keymap{$1};
129 0         0 $tv->{_transpose} = ( $tv->{actual_key} - $keymap{$tv->{key}} ) % 12;
130             }
131             else {
132 9         24 $tv->{actual_key} = '';
133             }
134              
135 9 50       45 if ( $data =~ /; tempo:\s+(\d+)/ ) {
136 9         26 $tv->{actual_tempo} = $1;
137             }
138 9 100       39 if ( $data =~ /; repeats?:\s+(\d+)/ ) {
139 2         6 $tv->{actual_repeats} = $1;
140             }
141              
142 9         54 $data =~ s/^.*?\n\n//s;
143              
144             # Build the song...
145             my $song = Data::iRealPro::Song->new
146             ( variant => $variant,
147             title => $tv->{title},
148             composer => $tv->{composer},
149             style => $tv->{style},
150             key => $tv->{key},
151             actual_key => $tv->{actual_key},
152             actual_tempo => $tv->{actual_tempo},
153             actual_style => $tv->{actual_style},
154             actual_repeats => $tv->{actual_repeats},
155             transpose => $self->{transpose},
156 9   50     589 _transpose => $tv->{_transpose} // 0,
157             );
158 9         38 $song->{data} = yfitaen($data);
159              
160             # And deliver.
161 9         54 return $song;
162             }
163              
164             sub yfitaen {
165 9     9 0 28 my ( $t ) = @_;
166 9         68 my @a = split( /(\<.*?\>)/, $t );
167 9         21 $t = "";
168 9         37 while ( @a > 1 ) {
169 6         17 $t .= yfitaen1(shift(@a)) . shift(@a);
170             }
171 9 50       56 $t .= yfitaen1(shift(@a)) if @a;
172 9         46 return $t;
173             }
174              
175             sub yfitaen1 {
176 15     15 0 35 my ( $t ) = @_;
177             # Indeed, the reverse of neatify. And a bit easier.
178 15         164 $t =~ s/([[:alnum:]])\s+([[:alnum:]])/$1,$2/g;
179 15         145 $t =~ s/\s+//g;
180 15         62 $t =~ s/_/ /g;
181 15         84 return $t;
182             }
183              
184             1;