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.0116';
7              
8 2     2   452992 use v5.36;
  2         6  
9 2     2   989 use Moo;
  2         13640  
  2         8  
10 2     2   5022 use strictures 2;
  2         2758  
  2         67  
11 2     2   700 use Carp qw(croak);
  2         5  
  2         76  
12 2     2   1910 use Music::Duration::Partition ();
  2         134277  
  2         73  
13 2     2   972 use Music::Scales qw(get_scale_MIDI);
  2         8520  
  2         133  
14 2     2   874 use Music::VoiceGen ();
  2         15594  
  2         78  
15 2     2   15 use namespace::clean;
  2         5  
  2         9  
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   4127 sub _build_pitches ($self) {
  1         3  
  1         1  
54 1         14 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       199 say 'Built pitches: ', join ' ', @pitches if $self->verbose;
59 1         19 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             clearer => 'clear_voice',
81             );
82              
83 2     2   1254 sub _build_voice ($self) {
  2         4  
  2         2  
84 2         26 my $voice = Music::VoiceGen->new(
85             pitches => $self->pitches,
86             intervals => $self->intervals,
87             );
88 2 50       5043 say "Built voice: $voice" if $self->verbose;
89 2         20 return $voice;
90             }
91              
92              
93             has size => (
94             is => 'rw',
95             isa => sub { croak "$_[0] is not a valid size" unless $_[0] =~ /^[\d.]+$/ },
96             default => sub { 4 },
97             );
98              
99              
100             has pool => (
101             is => 'rw',
102             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
103             default => sub { [qw(dhn hn qn)] },
104             );
105              
106              
107             has weights => (
108             is => 'rw',
109             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
110             default => sub { [1, 2, 2] },
111             );
112              
113              
114             has groups => (
115             is => 'rw',
116             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
117             default => sub { [0, 0, 0] },
118             );
119              
120             has _rhythm => (
121             is => 'rw',
122             lazy => 1,
123             builder => '_build__rhythm',
124             );
125              
126 2     2   2436 sub _build__rhythm ($self) {
  2         3  
  2         3  
127 2         23 my $mdp = Music::Duration::Partition->new(
128             size => $self->size,
129             pool => $self->pool,
130             weights => $self->weights,
131             groups => $self->groups,
132             );
133 2 50       2668 say "Built rhythm generator: $mdp" if $self->verbose;
134 2         30 return $mdp;
135             }
136              
137              
138             has motif_num => (
139             is => 'rw',
140             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
141             default => sub { 4 },
142             );
143              
144              
145             has motifs => (
146             is => 'rw',
147             lazy => 1,
148             builder => 'build_motifs',
149             clearer => 'clear_motifs',
150             );
151              
152              
153             has voices => (
154             is => 'rw',
155             lazy => 1,
156             builder => 'build_voices',
157             );
158              
159              
160             has patch => (
161             is => 'rw',
162             isa => sub { croak "$_[0] is not a valid patch" unless $_[0] =~ /^[0-9]+$/ },
163             default => sub { 0 },
164             );
165              
166              
167             has gate => (
168             is => 'rw',
169             isa => sub { croak "$_[0] is not a valid gate" unless $_[0] =~ /^[0-9.-]+$/ && $_[0] >= 0 && $_[0] <= 2 },
170             default => sub { 1 },
171             );
172              
173              
174             has queue => (
175             is => 'rw',
176             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
177             default => sub { [] },
178             );
179              
180              
181             has index => (
182             is => 'rw',
183             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
184             default => sub { 0 },
185             );
186              
187              
188             has note => (
189             is => 'rw',
190             isa => sub { croak "$_[0] is not a valid note" unless ref $_[0] eq 'HASH' },
191             default => sub { +{} },
192             );
193              
194              
195             has onsets => (
196             is => 'rw',
197             isa => sub { croak "$_[0] is not an array-ref" unless ref $_[0] eq 'ARRAY' },
198             default => sub { [] },
199             );
200              
201              
202             has channel => (
203             is => 'rw',
204             isa => sub { croak "$_[0] is not an integer" unless $_[0] =~ /^\d+$/ },
205             default => sub { 0 },
206             );
207              
208              
209             has verbose => (
210             is => 'rw',
211             isa => sub { croak "$_[0] is not a boolean" unless $_[0] =~ /^[01]$/ },
212             default => sub { 0 },
213             );
214              
215              
216             # sub BUILD ($self, $args) {
217             # $self->_build_motifs;
218             # }
219              
220              
221 2     2 1 689 sub build_motifs ($self) {
  2         3  
  2         3  
222 2         23 my @motifs = $self->_rhythm->motifs($self->motif_num);
223 2 50       7829 say "Built motifs: @motifs" if $self->verbose;
224 2         21 return \@motifs;
225             }
226              
227              
228 2     2 1 418 sub build_voices ($self) {
  2         2  
  2         3  
229 2         24 my @voices = map { $self->voice->rand } $self->motifs->@*;
  24         2537  
230 2 50       312 say "Built voices: @voices" if $self->verbose;
231 2         32 return \@voices;
232             }
233              
234              
235 0     0 1   sub increment_index ($self) {
  0            
  0            
236 0           $self->index($self->index + 1);
237 0           return $self->index;
238             }
239              
240             1;
241              
242             __END__