File Coverage

blib/lib/Music/Chord/Progression/T.pm
Criterion Covered Total %
statement 28 90 31.1
branch 0 20 0.0
condition n/a
subroutine 9 17 52.9
pod 2 2 100.0
total 39 129 30.2


line stmt bran cond sub pod time code
1             package Music::Chord::Progression::T;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: Generate transposed chord progressions - DEPRECATED
5              
6             our $VERSION = '0.0100_1';
7              
8 1     1   1256 use Moo;
  1         11029  
  1         6  
9 1     1   1847 use strictures 2;
  1         1607  
  1         38  
10 1     1   205 use Carp qw(croak);
  1         2  
  1         46  
11 1     1   515 use Data::Dumper::Compact qw(ddc);
  1         13294  
  1         5  
12 1     1   541 use Music::Chord::Note ();
  1         1131  
  1         28  
13 1     1   464 use Music::Chord::Namer qw(chordname);
  1         2357  
  1         84  
14 1     1   454 use lib map { "$ENV{HOME}/sandbox/$_/lib" } qw(Music-MelodicDevice-Transposition); # local author libs
  1         635  
  1         3  
  1         9  
15 1     1   582 use Music::MelodicDevice::Transposition ();
  1         69975  
  1         32  
16 1     1   7 use namespace::clean;
  1         3  
  1         9  
17              
18             with 'Music::PitchNum';
19              
20              
21             has base_note => (
22             is => 'ro',
23             isa => sub { croak "$_[0] is not a valid note" unless $_[0] =~ /^[A-G][#b]?$/ },
24             default => sub { 'C' },
25             );
26              
27              
28             has base_octave => (
29             is => 'ro',
30             isa => sub { croak "$_[0] is not a valid octave" unless $_[0] =~ /^[1-8]$/ },
31             default => sub { 4 },
32             );
33              
34              
35             has chord_quality => (
36             is => 'ro',
37             isa => sub { croak "$_[0] is not a valid quality" unless $_[0] =~ /^\w*$/ },
38             default => sub { '' },
39             );
40              
41              
42             has base_chord => (
43             is => 'lazy',
44             );
45              
46             sub _build_base_chord {
47 0     0     my ($self) = @_;
48 0           my $cn = Music::Chord::Note->new;
49 0           my @chord = $cn->chord_with_octave(
50             $self->base_note . $self->chord_quality,
51             $self->base_octave
52             );
53 0           return \@chord;
54             }
55              
56              
57             has format => (
58             is => 'ro',
59             isa => sub { croak "$_[0] is not a valid format" unless $_[0] =~ /^(?:ISO|midinum)$/ },
60             default => sub { 'ISO' },
61             );
62              
63              
64             has semitones => (
65             is => 'ro',
66             isa => sub { croak "$_[0] is not a valid number of semitones" unless $_[0] =~ /^[1-9]\d*$/ },
67             default => sub { 7 },
68             );
69              
70              
71             has max => (
72             is => 'ro',
73             isa => sub { croak "$_[0] is not a valid maximum" unless $_[0] =~ /^[1-9]\d*$/ },
74             default => sub { 4 },
75             );
76              
77              
78             has transform => (
79             is => 'ro',
80             isa => sub { croak "$_[0] is not a valid transform" unless ref $_[0] eq 'ARRAY' || $_[0] =~ /^[1-9]\d*$/ },
81             default => sub { 4 },
82             );
83              
84              
85             has mdt => (
86             is => 'lazy',
87             );
88              
89             sub _build_mdt {
90 0     0     return Music::MelodicDevice::Transposition->new;
91             }
92              
93              
94             has verbose => (
95             is => 'ro',
96             isa => sub { croak "$_[0] is not a boolean" unless $_[0] =~ /^[01]$/ },
97             default => sub { 0 },
98             );
99              
100              
101             sub generate {
102 0     0 1   my ($self) = @_;
103              
104 0           my ($pitches, $notes) = $self->_get_pitches;
105              
106 0           my @transform = $self->_build_transform;
107              
108 0 0         $self->_initial_conditions(@transform) if $self->verbose;
109              
110 0           my @generated;
111 0           my $i = 0;
112              
113 0           for my $token (@transform) {
114 0           $i++;
115              
116 0           my $transformed = $self->_build_chord($token, $pitches, $notes);
117              
118 0           my @notes = map { $self->pitchname($_) } @$transformed;
  0            
119 0           my @base = map { s/^([A-G][#b]?)\d/$1/r } @notes; # for chord-name
  0            
120              
121 0 0         push @generated, $self->format eq 'ISO' ? \@notes : $transformed;
122              
123 0 0         printf "%d. %s: %s %s %s\n",
124             $i, $token,
125             ddc($transformed), ddc(\@notes),
126             scalar chordname(@base)
127             if $self->verbose;
128              
129 0           $notes = $transformed;
130             }
131              
132 0           return \@generated;
133             }
134              
135              
136             sub circular {
137 0     0 1   my ($self) = @_;
138              
139 0           my ($pitches, $notes) = $self->_get_pitches;
140              
141 0           my @transform = $self->_build_transform;
142              
143 0 0         $self->_initial_conditions(@transform) if $self->verbose;
144              
145 0           my @generated;
146 0           my $posn = 0;
147              
148 0           for my $i (1 .. $self->max) {
149 0           my $token = $transform[ $posn % @transform ];
150              
151 0           my $transformed = $self->_build_chord($token, $pitches, $notes);
152              
153 0           my @notes = map { $self->pitchname($_) } @$transformed;
  0            
154 0           my @base = map { s/^([A-G][#b]?)\d/$1/r } @notes; # for chord-name
  0            
155              
156 0 0         push @generated, $self->format eq 'ISO' ? \@notes : $transformed;
157              
158 0 0         printf "%d. %s (%d): %s %s %s\n",
159             $i, $token, $posn % @transform,
160             ddc($transformed), ddc(\@notes),
161             scalar chordname(@base)
162             if $self->verbose;
163              
164 0           $notes = $transformed;
165              
166 0 0         $posn = int rand 2 ? $posn + 1 : $posn - 1;
167             }
168              
169 0           return \@generated;
170             }
171              
172             sub _get_pitches {
173 0     0     my ($self) = @_;
174 0           my @pitches = map { $self->pitchnum($_) } @{ $self->base_chord };
  0            
  0            
175 0           return \@pitches, [ @pitches ];
176             }
177              
178             sub _initial_conditions {
179 0     0     my ($self, @transform) = @_;
180 0           printf "Initial: %s%s %s\nTransforms: %s\n",
181             $self->base_note, $self->base_octave, $self->chord_quality,
182             join(',', @transform);
183             }
184              
185             sub _build_transform {
186 0     0     my ($self) = @_;
187              
188 0           my @transform;
189              
190 0 0         if (ref $self->transform eq 'ARRAY') {
    0          
191 0           @transform = @{ $self->transform };
  0            
192             }
193             elsif ($self->transform =~ /^\d+$/) {
194 0           @transform = ('I', map { 'T' . int(rand $self->semitones + 1) } 1 .. $self->transform - 1);
  0            
195             }
196              
197 0           return @transform;
198             }
199              
200             sub _build_chord {
201 0     0     my ($self, $token, $pitches, $notes) = @_;
202              
203 0           my $chord = [];
204              
205 0 0         if ($token =~ /^I$/) {
206 0           $chord = $pitches; # no transformation
207             }
208             else {
209 0           (my $semitones = $token) =~ s/^T(-?\d+)$/$1/;
210 0           $chord = $self->mdt->transpose($semitones, $notes);
211             }
212              
213 0           return $chord;
214             }
215              
216             1;
217              
218             __END__