line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
1
|
|
|
|
|
|
|
package Music::MelodicDevice::Ornamentation; |
2
|
|
|
|
|
|
|
our $AUTHORITY = 'cpan:GENE'; |
3
|
|
|
|
|
|
|
|
4
|
|
|
|
|
|
|
# ABSTRACT: Chromatic and diatonic melodic ornamentation |
5
|
|
|
|
|
|
|
|
6
|
|
|
|
|
|
|
our $VERSION = '0.0703'; |
7
|
|
|
|
|
|
|
|
8
|
1
|
|
|
1
|
|
1200
|
use strictures 2; |
|
1
|
|
|
|
|
1667
|
|
|
1
|
|
|
|
|
40
|
|
9
|
1
|
|
|
1
|
|
185
|
use Carp qw(croak); |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
52
|
|
10
|
1
|
|
|
1
|
|
558
|
use Data::Dumper::Compact qw(ddc); |
|
1
|
|
|
|
|
13378
|
|
|
1
|
|
|
|
|
4
|
|
11
|
1
|
|
|
1
|
|
638
|
use List::SomeUtils qw(first_index); |
|
1
|
|
|
|
|
12882
|
|
|
1
|
|
|
|
|
85
|
|
12
|
1
|
|
|
1
|
|
669
|
use MIDI::Simple (); |
|
1
|
|
|
|
|
21248
|
|
|
1
|
|
|
|
|
29
|
|
13
|
1
|
|
|
1
|
|
508
|
use Moo; |
|
1
|
|
|
|
|
8301
|
|
|
1
|
|
|
|
|
5
|
|
14
|
1
|
|
|
1
|
|
1926
|
use Music::Duration (); |
|
1
|
|
|
|
|
380
|
|
|
1
|
|
|
|
|
26
|
|
15
|
1
|
|
|
1
|
|
463
|
use Music::Scales qw(get_scale_MIDI is_scale); |
|
1
|
|
|
|
|
5212
|
|
|
1
|
|
|
|
|
72
|
|
16
|
1
|
|
|
1
|
|
535
|
use namespace::clean; |
|
1
|
|
|
|
|
8002
|
|
|
1
|
|
|
|
|
9
|
|
17
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
with('Music::PitchNum'); |
19
|
|
|
|
|
|
|
|
20
|
1
|
|
|
1
|
|
346
|
use constant TICKS => 96; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
51
|
|
21
|
1
|
|
|
1
|
|
6
|
use constant OCTAVES => 10; |
|
1
|
|
|
|
|
2
|
|
|
1
|
|
|
|
|
1795
|
|
22
|
|
|
|
|
|
|
|
23
|
|
|
|
|
|
|
|
24
|
|
|
|
|
|
|
has scale_note => ( |
25
|
|
|
|
|
|
|
is => 'ro', |
26
|
|
|
|
|
|
|
isa => sub { die "$_[0] is not a valid note" unless $_[0] =~ /^[A-G][#b]?$/ }, |
27
|
|
|
|
|
|
|
default => sub { 'C' }, |
28
|
|
|
|
|
|
|
); |
29
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
|
31
|
|
|
|
|
|
|
has scale_name => ( |
32
|
|
|
|
|
|
|
is => 'ro', |
33
|
|
|
|
|
|
|
isa => sub { die "$_[0] is not a valid scale name" unless is_scale($_[0]) }, |
34
|
|
|
|
|
|
|
default => sub { 'chromatic' }, |
35
|
|
|
|
|
|
|
); |
36
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
has _scale => ( |
38
|
|
|
|
|
|
|
is => 'lazy', |
39
|
|
|
|
|
|
|
init_args => undef, |
40
|
|
|
|
|
|
|
); |
41
|
|
|
|
|
|
|
|
42
|
|
|
|
|
|
|
sub _build__scale { |
43
|
3
|
|
|
3
|
|
34
|
my ($self) = @_; |
44
|
|
|
|
|
|
|
|
45
|
3
|
|
|
|
|
8
|
my @scale = map { get_scale_MIDI($self->scale_note, $_, $self->scale_name) } -1 .. OCTAVES - 1; |
|
33
|
|
|
|
|
1399
|
|
46
|
3
|
50
|
|
|
|
171
|
print 'Scale: ', ddc(\@scale) if $self->verbose; |
47
|
|
|
|
|
|
|
|
48
|
3
|
|
|
|
|
19
|
return \@scale; |
49
|
|
|
|
|
|
|
} |
50
|
|
|
|
|
|
|
|
51
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
has verbose => ( |
53
|
|
|
|
|
|
|
is => 'ro', |
54
|
|
|
|
|
|
|
isa => sub { die "$_[0] is not a valid boolean" unless $_[0] =~ /^[01]$/ }, |
55
|
|
|
|
|
|
|
default => sub { 0 }, |
56
|
|
|
|
|
|
|
); |
57
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
|
59
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
sub grace_note { |
61
|
18
|
|
|
18
|
1
|
15052
|
my ($self, $duration, $pitch, $offset) = @_; |
62
|
|
|
|
|
|
|
|
63
|
18
|
|
50
|
|
|
52
|
$offset //= 1; # Default one note above |
64
|
|
|
|
|
|
|
|
65
|
18
|
100
|
|
|
|
100
|
my $named = $pitch =~ /[A-G]/ ? 1 : 0; |
66
|
|
|
|
|
|
|
|
67
|
18
|
|
|
|
|
53
|
(my $i, $pitch) = $self->_find_pitch($pitch); |
68
|
18
|
|
|
|
|
357
|
my $grace_note = $self->_scale->[ $i + $offset ]; |
69
|
|
|
|
|
|
|
|
70
|
18
|
100
|
|
|
|
157
|
if ($named) { |
71
|
9
|
|
|
|
|
29
|
$pitch = $self->pitchname($pitch); |
72
|
9
|
|
|
|
|
182
|
$grace_note = $self->pitchname($grace_note); |
73
|
|
|
|
|
|
|
} |
74
|
|
|
|
|
|
|
|
75
|
|
|
|
|
|
|
# Compute the ornament durations |
76
|
18
|
|
|
|
|
117
|
my $x = $MIDI::Simple::Length{$duration} * TICKS; |
77
|
18
|
|
|
|
|
36
|
my $y = $MIDI::Simple::Length{yn} * TICKS; # 64th note |
78
|
18
|
|
|
|
|
140
|
my $z = sprintf '%0.f', $x - $y; |
79
|
18
|
50
|
|
|
|
63
|
print "Durations: $x, $y, $z\n" if $self->verbose; |
80
|
18
|
|
|
|
|
40
|
$y = 'd' . $y; |
81
|
18
|
|
|
|
|
38
|
$z = 'd' . $z; |
82
|
|
|
|
|
|
|
|
83
|
18
|
|
|
|
|
68
|
my @grace_note = ([$y, $grace_note], [$z, $pitch]); |
84
|
18
|
50
|
|
|
|
41
|
print 'Grace note: ', ddc(\@grace_note) if $self->verbose; |
85
|
|
|
|
|
|
|
|
86
|
18
|
|
|
|
|
71
|
return \@grace_note; |
87
|
|
|
|
|
|
|
} |
88
|
|
|
|
|
|
|
|
89
|
|
|
|
|
|
|
|
90
|
|
|
|
|
|
|
sub turn { |
91
|
12
|
|
|
12
|
1
|
13338
|
my ($self, $duration, $pitch, $offset) = @_; |
92
|
|
|
|
|
|
|
|
93
|
12
|
|
|
|
|
37
|
my $number = 4; # Number of notes in the ornament |
94
|
12
|
|
50
|
|
|
36
|
$offset //= 1; # Default one note above |
95
|
|
|
|
|
|
|
|
96
|
12
|
100
|
|
|
|
51
|
my $named = $pitch =~ /[A-G]/ ? 1 : 0; |
97
|
|
|
|
|
|
|
|
98
|
12
|
|
|
|
|
35
|
(my $i, $pitch) = $self->_find_pitch($pitch); |
99
|
12
|
|
|
|
|
239
|
my $above = $self->_scale->[ $i + $offset ]; |
100
|
12
|
|
|
|
|
255
|
my $below = $self->_scale->[ $i - $offset ]; |
101
|
|
|
|
|
|
|
|
102
|
12
|
100
|
|
|
|
92
|
if ($named) { |
103
|
6
|
|
|
|
|
17
|
$pitch = $self->pitchname($pitch); |
104
|
6
|
|
|
|
|
87
|
$above = $self->pitchname($above); |
105
|
6
|
|
|
|
|
62
|
$below = $self->pitchname($below); |
106
|
|
|
|
|
|
|
} |
107
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
# Compute the ornament durations |
109
|
12
|
|
|
|
|
75
|
my $x = $MIDI::Simple::Length{$duration} * TICKS; |
110
|
12
|
|
|
|
|
89
|
my $z = sprintf '%0.f', $x / $number; |
111
|
12
|
50
|
|
|
|
42
|
print "Durations: $x, $z\n" if $self->verbose; |
112
|
12
|
|
|
|
|
28
|
$z = 'd' . $z; |
113
|
|
|
|
|
|
|
|
114
|
12
|
|
|
|
|
58
|
my @turn = ([$z, $above], [$z, $pitch], [$z, $below], [$z, $pitch]); |
115
|
12
|
50
|
|
|
|
31
|
print 'Turn: ', ddc(\@turn) if $self->verbose; |
116
|
|
|
|
|
|
|
|
117
|
12
|
|
|
|
|
51
|
return \@turn; |
118
|
|
|
|
|
|
|
} |
119
|
|
|
|
|
|
|
|
120
|
|
|
|
|
|
|
|
121
|
|
|
|
|
|
|
sub trill { |
122
|
12
|
|
|
12
|
1
|
14335
|
my ($self, $duration, $pitch, $number, $offset) = @_; |
123
|
|
|
|
|
|
|
|
124
|
12
|
|
50
|
|
|
33
|
$number ||= 2; # Number of notes in the ornament |
125
|
12
|
|
50
|
|
|
29
|
$offset //= 1; # Default one note above |
126
|
|
|
|
|
|
|
|
127
|
12
|
100
|
|
|
|
51
|
my $named = $pitch =~ /[A-G]/ ? 1 : 0; |
128
|
|
|
|
|
|
|
|
129
|
12
|
|
|
|
|
34
|
(my $i, $pitch) = $self->_find_pitch($pitch); |
130
|
12
|
|
|
|
|
229
|
my $alt = $self->_scale->[ $i + $offset ]; |
131
|
|
|
|
|
|
|
|
132
|
12
|
100
|
|
|
|
105
|
if ($named) { |
133
|
6
|
|
|
|
|
36
|
$pitch = $self->pitchname($pitch); |
134
|
6
|
|
|
|
|
94
|
$alt = $self->pitchname($alt); |
135
|
|
|
|
|
|
|
} |
136
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
# Compute the ornament durations |
138
|
12
|
|
|
|
|
76
|
my $x = $MIDI::Simple::Length{$duration} * TICKS; |
139
|
12
|
|
|
|
|
91
|
my $z = sprintf '%0.f', ($x / $number / 2); |
140
|
12
|
50
|
|
|
|
45
|
print "Durations: $x, $z\n" if $self->verbose; |
141
|
12
|
|
|
|
|
28
|
$z = 'd' . $z; |
142
|
|
|
|
|
|
|
|
143
|
12
|
|
|
|
|
25
|
my @trill; |
144
|
|
|
|
|
|
|
|
145
|
12
|
|
|
|
|
75
|
push @trill, [$z, $pitch], [$z, $alt] for 1 .. $number; |
146
|
12
|
50
|
|
|
|
32
|
print 'Trill: ', ddc(\@trill) if $self->verbose; |
147
|
|
|
|
|
|
|
|
148
|
12
|
|
|
|
|
55
|
return \@trill; |
149
|
|
|
|
|
|
|
} |
150
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
|
152
|
|
|
|
|
|
|
sub mordent { |
153
|
12
|
|
|
12
|
1
|
12965
|
my ($self, $duration, $pitch, $offset) = @_; |
154
|
|
|
|
|
|
|
|
155
|
12
|
|
|
|
|
25
|
my $number = 4; # Finest division needed |
156
|
12
|
|
50
|
|
|
36
|
$offset //= 1; # Default one note above |
157
|
|
|
|
|
|
|
|
158
|
12
|
100
|
|
|
|
52
|
my $named = $pitch =~ /[A-G]/ ? 1 : 0; |
159
|
|
|
|
|
|
|
|
160
|
12
|
|
|
|
|
34
|
(my $i, $pitch) = $self->_find_pitch($pitch); |
161
|
12
|
|
|
|
|
221
|
my $alt = $self->_scale->[ $i + $offset ]; |
162
|
|
|
|
|
|
|
|
163
|
12
|
100
|
|
|
|
101
|
if ($named) { |
164
|
6
|
|
|
|
|
19
|
$pitch = $self->pitchname($pitch); |
165
|
6
|
|
|
|
|
89
|
$alt = $self->pitchname($alt); |
166
|
|
|
|
|
|
|
} |
167
|
|
|
|
|
|
|
|
168
|
|
|
|
|
|
|
# Compute the ornament durations |
169
|
12
|
|
|
|
|
91
|
my $x = $MIDI::Simple::Length{$duration} * TICKS; |
170
|
12
|
|
|
|
|
84
|
my $y = sprintf '%0.f', $x / $number; |
171
|
12
|
|
|
|
|
59
|
my $z = sprintf '%0.f', $x - (2 * $y); |
172
|
12
|
50
|
|
|
|
44
|
print "Durations: $x, $y, $z\n" if $self->verbose; |
173
|
12
|
|
|
|
|
27
|
$y = 'd' . $y; |
174
|
12
|
|
|
|
|
32
|
$z = 'd' . $z; |
175
|
|
|
|
|
|
|
|
176
|
12
|
|
|
|
|
24
|
my @mordent; |
177
|
|
|
|
|
|
|
|
178
|
12
|
|
|
|
|
49
|
push @mordent, [$y, $pitch], [$y, $alt], [$z, $pitch]; |
179
|
12
|
50
|
|
|
|
32
|
print 'Mordent: ', ddc(\@mordent) if $self->verbose; |
180
|
|
|
|
|
|
|
|
181
|
12
|
|
|
|
|
53
|
return \@mordent; |
182
|
|
|
|
|
|
|
} |
183
|
|
|
|
|
|
|
|
184
|
|
|
|
|
|
|
|
185
|
|
|
|
|
|
|
sub slide { |
186
|
4
|
|
|
4
|
1
|
4689
|
my ($self, $duration, $from, $to) = @_; |
187
|
|
|
|
|
|
|
|
188
|
4
|
|
|
|
|
13
|
my @scale = map { get_scale_MIDI($self->scale_note, $_, 'chromatic') } -1 .. OCTAVES - 1; |
|
44
|
|
|
|
|
2016
|
|
189
|
|
|
|
|
|
|
|
190
|
4
|
100
|
|
|
|
224
|
my $named = $from =~ /[A-G]/ ? 1 : 0; |
191
|
|
|
|
|
|
|
|
192
|
4
|
|
|
|
|
13
|
(my $i, $from) = $self->_find_pitch($from, \@scale); |
193
|
4
|
|
|
|
|
12
|
(my $j, $to) = $self->_find_pitch($to, \@scale); |
194
|
|
|
|
|
|
|
|
195
|
4
|
|
|
|
|
10
|
my ($start, $end); |
196
|
4
|
100
|
|
|
|
13
|
if ($i <= $j) { |
197
|
2
|
|
|
|
|
6
|
$start = $i; |
198
|
2
|
|
|
|
|
5
|
$end = $j; |
199
|
|
|
|
|
|
|
} |
200
|
|
|
|
|
|
|
else { |
201
|
2
|
|
|
|
|
5
|
$start = $j; |
202
|
2
|
|
|
|
|
4
|
$end = $i; |
203
|
|
|
|
|
|
|
} |
204
|
|
|
|
|
|
|
|
205
|
|
|
|
|
|
|
# Compute the ornament durations |
206
|
4
|
|
|
|
|
11
|
my $x = $MIDI::Simple::Length{$duration} * TICKS; |
207
|
4
|
|
|
|
|
9
|
my $y = $end - $start + 1; # Number of notes in the slide |
208
|
4
|
|
|
|
|
31
|
my $z = sprintf '%0.f', $x / $y; |
209
|
4
|
50
|
|
|
|
17
|
print "Durations: $x, $y, $z\n" if $self->verbose; |
210
|
4
|
|
|
|
|
10
|
$z = 'd' . $z; |
211
|
|
|
|
|
|
|
|
212
|
4
|
|
|
|
|
8
|
my @slide; |
213
|
4
|
100
|
|
|
|
11
|
if ($named) { |
214
|
2
|
|
|
|
|
7
|
@slide = map { [ $z, $self->pitchname($scale[$_]) ] } $start .. $end; |
|
8
|
|
|
|
|
98
|
|
215
|
|
|
|
|
|
|
} |
216
|
|
|
|
|
|
|
else { |
217
|
2
|
|
|
|
|
9
|
@slide = map { [ $z, $scale[$_] ] } $start .. $end; |
|
8
|
|
|
|
|
23
|
|
218
|
|
|
|
|
|
|
} |
219
|
4
|
100
|
|
|
|
58
|
@slide = reverse @slide if $j < $i; |
220
|
4
|
50
|
|
|
|
15
|
print 'Slide: ', ddc(\@slide) if $self->verbose; |
221
|
|
|
|
|
|
|
|
222
|
4
|
|
|
|
|
35
|
return \@slide; |
223
|
|
|
|
|
|
|
} |
224
|
|
|
|
|
|
|
|
225
|
|
|
|
|
|
|
sub _find_pitch { |
226
|
62
|
|
|
62
|
|
137
|
my ($self, $pitch, $scale) = @_; |
227
|
|
|
|
|
|
|
|
228
|
62
|
|
66
|
|
|
1355
|
$scale //= $self->_scale; |
229
|
|
|
|
|
|
|
|
230
|
62
|
100
|
|
|
|
642
|
$pitch = $self->pitchnum($pitch) |
231
|
|
|
|
|
|
|
if $pitch =~ /[A-G]/; |
232
|
|
|
|
|
|
|
|
233
|
62
|
|
|
3516
|
|
2058
|
my $i = first_index { $_ eq $pitch } @$scale; |
|
3516
|
|
|
|
|
5085
|
|
234
|
62
|
50
|
|
|
|
237
|
croak "Unknown pitch: $pitch" if $i < 0; |
235
|
|
|
|
|
|
|
|
236
|
62
|
|
|
|
|
195
|
return $i, $pitch; |
237
|
|
|
|
|
|
|
} |
238
|
|
|
|
|
|
|
|
239
|
|
|
|
|
|
|
1; |
240
|
|
|
|
|
|
|
|
241
|
|
|
|
|
|
|
__END__ |