File Coverage

blib/lib/Music/PitchNum/ABC.pm
Criterion Covered Total %
statement 37 37 100.0
branch 22 24 91.6
condition 2 2 100.0
subroutine 7 7 100.0
pod 2 2 100.0
total 70 72 97.2


line stmt bran cond sub pod time code
1             # -*- Perl -*-
2             #
3             # Pitch numbers from the ABC notation for notes, in a distinct module as
4             # the format is Case Sensitive, and the accidentals very different from
5             # those seen in other notation formats.
6             #
7             # Run perldoc(1) on this file for additional documentation.
8              
9             package Music::PitchNum::ABC;
10              
11 2     2   8685 use 5.010000;
  2         6  
12 2     2   8 use Moo::Role;
  2         2  
  2         12  
13 2     2   1031 use POSIX qw/floor/;
  2         5291  
  2         9  
14 2     2   1086 use Scalar::Util qw/looks_like_number/;
  2         3  
  2         739  
15              
16             our $VERSION = '0.09';
17              
18             my %NOTE2NUM = (
19             C => 0,
20             D => 2,
21             E => 4,
22             F => 5,
23             G => 7,
24             A => 9,
25             B => 11,
26             );
27              
28             # ABC is like ASPN only for some N+1 reason it uses a different
29             # accidental form, sigh
30             my %NUM2NOTE = (
31             0 => 'C',
32             1 => '^C',
33             2 => 'D',
34             3 => '^D',
35             4 => 'E',
36             5 => 'F',
37             6 => '^F',
38             7 => 'G',
39             8 => '^G',
40             9 => 'A',
41             10 => '^A',
42             11 => 'B',
43             );
44              
45             ##############################################################################
46             #
47             # METHODS
48              
49             sub pitchname {
50 12     12 1 11167 my ( $self, $number, %params ) = @_;
51 12 100       52 die "need a number for pitchname\n" if !looks_like_number $number;
52              
53 11   100     40 $params{ignore_octave} //= 0;
54              
55 11         21 my $note = $NUM2NOTE{ $number % 12 };
56              
57 11 100       24 if ( !$params{ignore_octave} ) {
58 9         45 my $octave = floor( $number / 12 ) - 1;
59 9 100       23 $note = lc $note if $octave > 4;
60 9 100       16 $note .= (q{'}) x ( $octave - 5 ) if $octave > 5;
61 9 100       23 $note .= (q{,}) x ( 4 - $octave ) if $octave < 4;
62             }
63              
64 11         58 return $note;
65             }
66              
67             sub pitchnum {
68 11     11 1 32 my ( $self, $name ) = @_;
69              
70             # already a pitch number, but nix the decimal foo
71 11 50       41 return int $name if looks_like_number $name;
72              
73 11         9 my $pitchnum;
74              
75 11 50       64 if ( $name =~
76             m/ (? (?: [_]{1,2} | [\^]{1,2} ) )? (?: (?[A-G])(?[,]+)? | (?[a-g])(?[']+)? ) /x
77             ) {
78 11     1   64 my $octave = $+{octave};
  1         461  
  1         328  
  1         188  
79 11         38 my $chrome = $+{chrome};
80 11         32 my $note = $+{note};
81              
82 11 100       46 $pitchnum = $NOTE2NUM{ uc $note } + 12 * ( $note =~ m/[A-G]/ ? 5 : 6 );
83              
84 11 100       18 if ( defined $octave ) {
85 5 100       15 $pitchnum += 12 * length($octave) * ( $octave =~ m/[,]/ ? -1 : 1 );
86             }
87              
88 11 100       17 if ( defined $chrome ) {
89 4 100       27 $pitchnum += length($chrome) * ( $chrome =~ m/[_]/ ? -1 : 1 );
90             }
91             }
92              
93 11         45 return $pitchnum;
94             }
95              
96             1;
97             __END__