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 12     12   1024 use strict;
  12         25  
  12         363  
15 12     12   63 use warnings;
  12         21  
  12         305  
16 12     12   54 use Carp;
  12         22  
  12         601  
17 12     12   76 use utf8;
  12         21  
  12         125  
18              
19             package Data::iRealPro::Input::Text;
20              
21 12     12   558 use Data::iRealPro::URI;
  12         58  
  12         308  
22 12     12   65 use Data::iRealPro::Playlist;
  12         23  
  12         304  
23 12     12   83 use Data::iRealPro::Song;
  12         22  
  12         14336  
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 10     10 0 31 my ( $self, $data ) = @_;
55 10         25 my $variant = "irealpro";
56 10   100     79 $self->{transpose} //= 0;
57              
58 10         16 my $plname;
59 10 100       53 if ( $data =~ /^Playlist:\s*(.*)/m ) {
60 3 50       14 $plname = $1 unless $1 eq "";
61             }
62              
63 10         23 my @songs;
64 10         61 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 10 50       61 if ( $data =~ /^Song(?: (\d+))?:.*/ ) {
71 10 50 66     70 warn("Expecting song number ", 1+@songs, " but got number $1\n")
72             if $1 && $1 != 1 + @songs;
73 10         54 push( @songs, encode_song( $self, $data ) );
74             }
75              
76             # Build a playlist for the songs...
77 10 100       145 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 10         115 );
89              
90             # And deliver.
91 10         40 return $uri;
92             }
93              
94             sub encode_song {
95 10     10 0 30 my ( $self, $data ) = @_;
96 10         24 my $variant = "irealpro";
97 10         129 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 10 100       59 if ( $data =~ /^Playlist:\s*(.*)/m ) {
109 3 50       18 $tv->{pl_name} = $1 unless $1 eq "";
110             }
111              
112 10 50       100 if ( $data =~ /^Song(?:\s+\d+)?:\s+(.*)\s+\((.*?)\)/m ) {
113 10         52 $tv->{title} = $1;
114 10         67 my @t = split( ' ', $2 );
115 10 100       80 @t[0,1] = @t[1,0] if @t == 2;
116 10         51 $tv->{composer} = "@t";
117             }
118              
119 10 50       84 if ( $data =~ /Style:\s+([^;(\n]*)(?:\s+\(([^)\n]+)\))?(?:;|$)/m ) {
120 10         51 $tv->{style} = $1;
121 10         35 $tv->{actual_style} = $2;
122             }
123              
124 10 50       52 if ( $data =~ /; key:\s+([^;\n]+)/ ) {
125 10         34 $tv->{key} = $1;
126             }
127 10 50       41 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 10         27 $tv->{actual_key} = '';
133             }
134              
135 10 50       50 if ( $data =~ /; tempo:\s+(\d+)/ ) {
136 10         31 $tv->{actual_tempo} = $1;
137             }
138 10 100       46 if ( $data =~ /; repeats?:\s+(\d+)/ ) {
139 3         8 $tv->{actual_repeats} = $1;
140             }
141              
142 10         58 $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 10   50     178 _transpose => $tv->{_transpose} // 0,
157             );
158 10         46 $song->{data} = yfitaen($data);
159              
160             # And deliver.
161 10         62 return $song;
162             }
163              
164             sub yfitaen {
165 10     10 0 27 my ( $t ) = @_;
166 10         77 my @a = split( /(\<.*?\>)/, $t );
167 10         28 $t = "";
168 10         40 while ( @a > 1 ) {
169 6         17 $t .= yfitaen1(shift(@a)) . shift(@a);
170             }
171 10 50       66 $t .= yfitaen1(shift(@a)) if @a;
172 10         39 return $t;
173             }
174              
175             sub yfitaen1 {
176 16     16 0 50 my ( $t ) = @_;
177             # Indeed, the reverse of neatify. And a bit easier.
178 16         197 $t =~ s/([[:alnum:]])\s+([[:alnum:]])/$1,$2/g;
179 16         173 $t =~ s/\s+//g;
180 16         98 $t =~ s/_/ /g;
181 16         67 return $t;
182             }
183              
184             1;