File Coverage

blib/lib/Music/Interval/Barycentric.pm
Criterion Covered Total %
statement 49 49 100.0
branch n/a
condition 2 4 50.0
subroutine 12 12 100.0
pod 6 6 100.0
total 69 71 97.1


line stmt bran cond sub pod time code
1             package Music::Interval::Barycentric;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: Compute barycentric musical interval space
5              
6 1     1   756 use strict;
  1         2  
  1         29  
7 1     1   6 use warnings;
  1         3  
  1         40  
8              
9             our $VERSION = '0.0307';
10              
11 1     1   6 use List::Util qw( min );
  1         2  
  1         94  
12              
13 1     1   7 use Exporter 'import';
  1         2  
  1         82  
14              
15             our @EXPORT = qw(
16             barycenter
17             distance
18             evenness_index
19             orbit_distance
20             forte_distance
21             cyclic_permutation
22             );
23              
24 1     1   6 use constant SIZE => 3; # Default chord size
  1         2  
  1         88  
25 1     1   6 use constant SCALE => 12; # Default number of scale notes
  1         2  
  1         520  
26              
27              
28             sub barycenter {
29 13   50 13 1 616 my $size = shift || SIZE; # Default to a triad
30 13   50     51 my $scale = shift || SCALE; # Default to the common scale notes
31 13         52 return ($scale / $size) x $size;
32             }
33              
34              
35             sub distance {
36 95     95 1 157 my ($chord1, $chord2) = @_;
37 95         141 my $distance = 0;
38 95         173 for my $note (0 .. @$chord1 - 1) {
39 300         547 $distance += ($chord1->[$note] - $chord2->[$note]) ** 2;
40             }
41 95         130 $distance /= 2;
42 95         242 return sqrt $distance;
43             }
44              
45              
46             sub orbit_distance {
47 8     8 1 17 my ($chord1, $chord2) = @_;
48 8         12 my @distance = ();
49 8         19 for my $perm (cyclic_permutation(@$chord2)) {
50 25         46 push @distance, distance($chord1, $perm);
51             }
52 8         65 return min(@distance);
53             }
54              
55              
56             sub forte_distance {
57 8     8 1 16 my ($chord1, $chord2) = @_;
58 8         15 my @distance = ();
59 8         17 for my $perm (cyclic_permutation(@$chord2)) {
60 25         45 push @distance, distance($chord1, $perm);
61 25         55 push @distance, distance($chord1, [reverse @$perm]);
62             }
63 8         65 return min(@distance);
64             }
65              
66              
67             sub cyclic_permutation {
68 18     18 1 37 my @set = @_;
69 18         31 my @cycles = ();
70 18         46 for my $backward (reverse 0 .. @set - 1) {
71 56         139 for my $forward (0 .. @set - 1) {
72 176         229 push @{ $cycles[$backward] }, $set[$forward - $backward];
  176         346  
73             }
74             }
75 18         51 return @cycles;
76             }
77              
78              
79             sub evenness_index {
80 12     12 1 26 my $chord = shift;
81 12         27 my @b = barycenter( scalar @$chord );
82 12         32 my $i = distance( $chord, \@b );
83 12         84 return $i;
84             }
85              
86             1;
87              
88             __END__