File Coverage

blib/lib/Music/PitchNum/ABC.pm
Criterion Covered Total %
statement 36 36 100.0
branch 20 22 90.9
condition n/a
subroutine 7 7 100.0
pod 2 2 100.0
total 65 67 97.0


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 the
4             # format is Case Sensitive, and the accidentals very different from those seen
5             # 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   14615 use 5.010000;
  2         8  
  2         84  
12 2     2   10 use Moo::Role;
  2         3  
  2         14  
13 2     2   1397 use POSIX qw/floor/;
  2         7626  
  2         15  
14 2     2   1449 use Scalar::Util qw/looks_like_number/;
  2         3  
  2         868  
15              
16             our $VERSION = '0.06';
17              
18             # for pitchnum (TODO make these attributes or otherwise f(x) calls?)
19             my %NOTE2NUM = (
20             C => 0,
21             D => 2,
22             E => 4,
23             F => 5,
24             G => 7,
25             A => 9,
26             B => 11,
27             );
28             # ASPN-style note-fu for pitchname (ABC accidental form)
29             my %NUM2NOTE = (
30             0 => 'C',
31             1 => '^C',
32             2 => 'D',
33             3 => '^D',
34             4 => 'E',
35             5 => 'F',
36             6 => '^F',
37             7 => 'G',
38             8 => '^G',
39             9 => 'A',
40             10 => '^A',
41             11 => 'B',
42             );
43              
44             ##############################################################################
45             #
46             # METHODS
47              
48             sub pitchname {
49 10     10 1 17128 my ( $self, $number ) = @_;
50 10 100       47 die "need a number for pitchname\n" if !looks_like_number $number;
51              
52 9         48 my $octave = floor( $number / 12 ) - 1;
53 9         25 my $note = $NUM2NOTE{ $number % 12 };
54              
55 9 100       28 $note = lc $note if $octave > 4;
56 9 100       25 $note .= (q{'}) x ( $octave - 5 ) if $octave > 5;
57 9 100       31 $note .= (q{,}) x ( 4 - $octave ) if $octave < 4;
58              
59 9         46 return $note;
60             }
61              
62             sub pitchnum {
63 11     11 1 23 my ( $self, $name ) = @_;
64              
65             # already a pitch number, but nix the decimal foo
66 11 50       53 return int $name if looks_like_number $name;
67              
68 11         12 my $pitchnum;
69              
70 11 50       79 if ( $name =~
71             m/ (? (?: [_]{1,2} | [\^]{1,2} ) )? (?: (?[A-G])(?[,]+)? | (?[a-g])(?[']+)? ) /x
72             ) {
73 11     1   77 my $octave = $+{octave};
  1         700  
  1         522  
  1         218  
74 11         58 my $chrome = $+{chrome};
75 11         46 my $note = $+{note};
76              
77 11 100       57 $pitchnum = $NOTE2NUM{ uc $note } + 12 * ( $note =~ m/[A-G]/ ? 5 : 6 );
78              
79 11 100       28 if ( defined $octave ) {
80 5 100       19 $pitchnum += 12 * length($octave) * ( $octave =~ m/[,]/ ? -1 : 1 );
81             }
82              
83 11 100       25 if ( defined $chrome ) {
84 4 100       40 $pitchnum += length($chrome) * ( $chrome =~ m/[_]/ ? -1 : 1 );
85             }
86             }
87              
88 11         50 return $pitchnum;
89             }
90              
91             1;
92             __END__