File Coverage

blib/lib/Music/VoicePhrase.pm
Criterion Covered Total %
statement 54 59 91.5
branch 5 10 50.0
condition n/a
subroutine 13 14 92.8
pod 3 3 100.0
total 75 86 87.2


line stmt bran cond sub pod time code
1             package Music::VoicePhrase;
2             our $AUTHORITY = 'cpan:GENE';
3              
4             # ABSTRACT: Construct a measured phrase of notes
5              
6             our $VERSION = '0.0114';
7              
8 2     2   483294 use v5.36;
  2         6  
9 2     2   1084 use Moo;
  2         13231  
  2         14  
10 2     2   3238 use strictures 2;
  2         2799  
  2         82  
11 2     2   664 use Carp qw(croak);
  2         4  
  2         75  
12 2     2   904 use Music::Duration::Partition ();
  2         134458  
  2         70  
13 2     2   916 use Music::Scales qw(get_scale_MIDI);
  2         8089  
  2         132  
14 2     2   865 use Music::VoiceGen ();
  2         14445  
  2         51  
15 2     2   12 use namespace::clean;
  2         2  
  2         7  
16              
17              
18             has base => (
19             is => 'rw',
20             isa => sub { croak "$_[0] is not a valid note" unless $_[0] =~ /^[A-G][#b]?$/i },
21             default => sub { 'C' },
22             );
23              
24              
25             has scale => (
26             is => 'rw',
27             isa => sub { croak "$_[0] is not a valid scale name" unless $_[0] =~ /^\w+$/ },
28             default => sub { 'major' },
29             );
30              
31              
32             has octave => (
33             is => 'rw',
34             isa => sub { croak "$_[0] is not a valid octave" unless $_[0] =~ /^[0-9]$/ },
35             default => sub { 0 },
36             );
37              
38              
39             has pitches_name => (
40             is => 'rw',
41             isa => sub { croak "$_[0] is not a valid pitches name" unless defined $_[0] },
42             default => sub { '2 octaves' },
43             );
44              
45              
46             has pitches => (
47             is => 'rw',
48             lazy => 1,
49             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
50             builder => '_build_pitches',
51             );
52              
53 1     1   3083 sub _build_pitches ($self) {
  1         4  
  1         13  
54 1         28 my @pitches = (
55             get_scale_MIDI($self->base, $self->octave, $self->scale),
56             get_scale_MIDI($self->base, $self->octave + 1, $self->scale),
57             );
58 1 50       189 say 'Built pitches: ', join ' ', @pitches if $self->verbose;
59 1         15 return \@pitches;
60             }
61              
62              
63             has intervals_name => (
64             is => 'rw',
65             isa => sub { croak "$_[0] is not a valid intervals name" unless defined $_[0] },
66             default => sub { '-3..-1,1..3' },
67             );
68              
69              
70             has intervals => (
71             is => 'rw',
72             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
73             default => sub { [-3, -2, -1, 1, 2, 3] },
74             );
75              
76             has voice => (
77             is => 'rw',
78             lazy => 1,
79             builder => '_build_voice',
80             );
81              
82 2     2   1367 sub _build_voice ($self) {
  2         2  
  2         3  
83 2         24 my $voice = Music::VoiceGen->new(
84             pitches => $self->pitches,
85             intervals => $self->intervals,
86             );
87 2 50       4371 say "Built voice: $voice" if $self->verbose;
88 2         22 return $voice;
89             }
90              
91              
92             has size => (
93             is => 'rw',
94             isa => sub { croak "$_[0] is not a valid size" unless $_[0] =~ /^[\d.]+$/ },
95             default => sub { 4 },
96             );
97              
98              
99             has pool => (
100             is => 'rw',
101             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
102             default => sub { [qw(dhn hn qn)] },
103             );
104              
105              
106             has weights => (
107             is => 'rw',
108             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
109             default => sub { [1, 2, 2] },
110             );
111              
112              
113             has groups => (
114             is => 'rw',
115             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
116             default => sub { [0, 0, 0] },
117             );
118              
119             has _rhythm => (
120             is => 'rw',
121             lazy => 1,
122             builder => '_build__rhythm',
123             );
124              
125 2     2   2452 sub _build__rhythm ($self) {
  2         3  
  2         2  
126 2         24 my $mdp = Music::Duration::Partition->new(
127             size => $self->size,
128             pool => $self->pool,
129             weights => $self->weights,
130             groups => $self->groups,
131             );
132 2 50       2647 say "Built rhythm generator: $mdp" if $self->verbose;
133 2         31 return $mdp;
134             }
135              
136              
137             has motif_num => (
138             is => 'rw',
139             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
140             default => sub { 4 },
141             );
142              
143              
144             has motifs => (
145             is => 'rw',
146             lazy => 1,
147             builder => 'build_motifs',
148             );
149              
150              
151             has voices => (
152             is => 'rw',
153             lazy => 1,
154             builder => 'build_voices',
155             );
156              
157              
158             has patch => (
159             is => 'rw',
160             isa => sub { croak "$_[0] is not a valid patch" unless $_[0] =~ /^[0-9]+$/ },
161             default => sub { 0 },
162             );
163              
164              
165             has queue => (
166             is => 'rw',
167             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
168             default => sub { [] },
169             );
170              
171              
172             has index => (
173             is => 'rw',
174             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
175             default => sub { 0 },
176             );
177              
178              
179             has note => (
180             is => 'rw',
181             isa => sub { croak "$_[0] is not a valid note" unless ref $_[0] eq 'HASH' },
182             default => sub { +{} },
183             );
184              
185              
186             has onsets => (
187             is => 'rw',
188             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
189             default => sub { [] },
190             );
191              
192              
193             has channel => (
194             is => 'rw',
195             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
196             default => sub { 0 },
197             );
198              
199              
200             has verbose => (
201             is => 'rw',
202             isa => sub { croak "$_[0] is not a boolean" unless $_[0] =~ /^[01]$/ },
203             default => sub { 0 },
204             );
205              
206              
207             # sub BUILD ($self, $args) {
208             # $self->_build_motifs;
209             # }
210              
211              
212 2     2 1 721 sub build_motifs ($self) {
  2         3  
  2         2  
213 2         23 my @motifs = $self->_rhythm->motifs($self->motif_num);
214 2 50       8106 say "Built motifs: @motifs" if $self->verbose;
215 2         28 return \@motifs;
216             }
217              
218              
219 2     2 1 457 sub build_voices ($self) {
  2         3  
  2         2  
220 2         30 my @voices = map { $self->voice->rand } $self->motifs->@*;
  24         2188  
221 2 50       225 say "Built voices: @voices" if $self->verbose;
222 2         18 return \@voices;
223             }
224              
225              
226 0     0 1   sub increment_index ($self) {
  0            
  0            
227 0           $self->index($self->index + 1);
228 0           return $self->index;
229             }
230              
231             1;
232              
233             __END__