| line |
stmt |
bran |
cond |
sub |
pod |
time |
code |
|
1
|
|
|
|
|
|
|
package Music::Scales; |
|
2
|
5
|
|
|
5
|
|
164909
|
use strict; |
|
|
5
|
|
|
|
|
15
|
|
|
|
5
|
|
|
|
|
247
|
|
|
3
|
5
|
|
|
5
|
|
6609
|
use Text::Abbrev; |
|
|
5
|
|
|
|
|
335
|
|
|
|
5
|
|
|
|
|
539
|
|
|
4
|
|
|
|
|
|
|
|
|
5
|
|
|
|
|
|
|
BEGIN { |
|
6
|
5
|
|
|
5
|
|
32
|
use Exporter (); |
|
|
5
|
|
|
|
|
15
|
|
|
|
5
|
|
|
|
|
108
|
|
|
7
|
5
|
|
|
5
|
|
106
|
use vars qw ($VERSION @ISA @EXPORT); |
|
|
5
|
|
|
|
|
9
|
|
|
|
5
|
|
|
|
|
588
|
|
|
8
|
5
|
|
|
5
|
|
12
|
$VERSION = 0.07; |
|
9
|
5
|
|
|
|
|
73
|
@ISA = qw (Exporter); |
|
10
|
5
|
|
|
|
|
13618
|
@EXPORT = qw (get_scale_notes get_scale_nums get_scale_offsets is_scale get_scale_PDL get_scale_MIDI); |
|
11
|
|
|
|
|
|
|
} |
|
12
|
|
|
|
|
|
|
|
|
13
|
|
|
|
|
|
|
|
|
14
|
|
|
|
|
|
|
=head1 NAME |
|
15
|
|
|
|
|
|
|
|
|
16
|
|
|
|
|
|
|
Scales - supply necessary notes / offsets for musical scales |
|
17
|
|
|
|
|
|
|
|
|
18
|
|
|
|
|
|
|
=head1 SYNOPSIS |
|
19
|
|
|
|
|
|
|
|
|
20
|
|
|
|
|
|
|
use Music::Scales; |
|
21
|
|
|
|
|
|
|
|
|
22
|
|
|
|
|
|
|
my @maj = get_scale_notes('Eb'); # defaults to major |
|
23
|
|
|
|
|
|
|
print join(" ",@maj); # "Eb F G Ab Bb C D" |
|
24
|
|
|
|
|
|
|
my @blues = get_scale_nums('bl'); # 'bl','blu','blue','blues' |
|
25
|
|
|
|
|
|
|
print join(" ",@blues); # "0 3 5 6 7 10" |
|
26
|
|
|
|
|
|
|
my %min = get_scale_offsets ('G','mm',1); # descending melodic minor |
|
27
|
|
|
|
|
|
|
print map {"$_=$min{$_} "} sort keys %min; # "A=0 B=-1 C=0 D=0 E=-1 F=0 G=0" |
|
28
|
|
|
|
|
|
|
|
|
29
|
|
|
|
|
|
|
|
|
30
|
|
|
|
|
|
|
=head1 DESCRIPTION |
|
31
|
|
|
|
|
|
|
|
|
32
|
|
|
|
|
|
|
Given a keynote A-G(#/b) and a scale-name, will return the scale, |
|
33
|
|
|
|
|
|
|
either as an array of notenames or as a hash of semitone-offsets for each note. |
|
34
|
|
|
|
|
|
|
|
|
35
|
|
|
|
|
|
|
=head1 METHODS |
|
36
|
|
|
|
|
|
|
|
|
37
|
|
|
|
|
|
|
=head2 get_scale_nums($scale[,$descending]) |
|
38
|
|
|
|
|
|
|
|
|
39
|
|
|
|
|
|
|
returns an array of semitone offsets for the requested scale, ascending/descending the given scale for one octave. |
|
40
|
|
|
|
|
|
|
The descending flag determines the direction of the scale, and also affects those scales (such as melodic minor) where the notes vary depending upon the direction. |
|
41
|
|
|
|
|
|
|
Scaletypes and valid values for $scale are listed below. |
|
42
|
|
|
|
|
|
|
|
|
43
|
|
|
|
|
|
|
=head2 get_scale_notes($notename[,$scale,$descending,$keypref]) |
|
44
|
|
|
|
|
|
|
|
|
45
|
|
|
|
|
|
|
returns an array of notenames, starting from the given keynote. |
|
46
|
|
|
|
|
|
|
Enharmonic equivalencies (whether to use F# or Gb, for instance) are calculated based on the keynote and the scale. Basically, it attempts to do the Right Thing if the scale is an 8-note one, |
|
47
|
|
|
|
|
|
|
(the 7th in G harmonic minor being F# rather than Gb, although G minor is a 'flat' key), but for any other scales, (Chromatic, blues etc.) it picks equivalencies based upon the keynote. |
|
48
|
|
|
|
|
|
|
This can be overidden with $keypref, setting to be either '#' or 'b' for sharps and flats respectively. Cruftiness abounds here :) |
|
49
|
|
|
|
|
|
|
|
|
50
|
|
|
|
|
|
|
=head2 get_scale_offsets($notename[,$scale,$descending,$keypref]) |
|
51
|
|
|
|
|
|
|
|
|
52
|
|
|
|
|
|
|
as get_scale_notes(), except it returns a hash of notenames with the values being a semitone offset (-1, 0 or 1) as shown in the synopsis. |
|
53
|
|
|
|
|
|
|
|
|
54
|
|
|
|
|
|
|
=head2 get_scale_MIDI($notename,$octave[,$scale,$descending]) |
|
55
|
|
|
|
|
|
|
|
|
56
|
|
|
|
|
|
|
as get_scale_notes(), but returns an array of MIDI note-numbers, given an octave number (-1..9). |
|
57
|
|
|
|
|
|
|
|
|
58
|
|
|
|
|
|
|
=head2 get_scale_PDL($notename,$octave[,$scale,$descending]) |
|
59
|
|
|
|
|
|
|
|
|
60
|
|
|
|
|
|
|
as get_scale_MIDI(), but returns an array of PDL-format notes. |
|
61
|
|
|
|
|
|
|
|
|
62
|
|
|
|
|
|
|
=head2 is_scale($scalename) |
|
63
|
|
|
|
|
|
|
|
|
64
|
|
|
|
|
|
|
returns true if $scalename is a valid scale name used in this module. |
|
65
|
|
|
|
|
|
|
|
|
66
|
|
|
|
|
|
|
=head1 SCALES |
|
67
|
|
|
|
|
|
|
|
|
68
|
|
|
|
|
|
|
Scales can be passed either by name or number. |
|
69
|
|
|
|
|
|
|
The default scale is 'major' if none / invalid is given. |
|
70
|
|
|
|
|
|
|
Text::Abbrev is used on scalenames, so they can be as abbreviated as unambiguously possible ('dor','io' etc.). |
|
71
|
|
|
|
|
|
|
Other abbreviations are shown in brackets. |
|
72
|
|
|
|
|
|
|
|
|
73
|
|
|
|
|
|
|
1 ionian / major / hypolydian |
|
74
|
|
|
|
|
|
|
2 dorian / hypmixolydian |
|
75
|
|
|
|
|
|
|
3 phrygian / hypoaeolian |
|
76
|
|
|
|
|
|
|
4 lydian / hypolocrian |
|
77
|
|
|
|
|
|
|
5 mixolydian / hypoionian |
|
78
|
|
|
|
|
|
|
6 aeolian / hypodorian / minor / m |
|
79
|
|
|
|
|
|
|
7 locrian / hypophrygian |
|
80
|
|
|
|
|
|
|
8 harmonic minor / hm |
|
81
|
|
|
|
|
|
|
9 melodic minor / mm |
|
82
|
|
|
|
|
|
|
10 blues |
|
83
|
|
|
|
|
|
|
11 pentatonic (pmajor) |
|
84
|
|
|
|
|
|
|
12 chromatic |
|
85
|
|
|
|
|
|
|
13 diminished |
|
86
|
|
|
|
|
|
|
14 wholetone |
|
87
|
|
|
|
|
|
|
15 augmented |
|
88
|
|
|
|
|
|
|
16 hungarian minor |
|
89
|
|
|
|
|
|
|
17 3 semitone |
|
90
|
|
|
|
|
|
|
18 4 semitone |
|
91
|
|
|
|
|
|
|
19 neapolitan minor (nmin) |
|
92
|
|
|
|
|
|
|
20 neapolitan major (nmaj) |
|
93
|
|
|
|
|
|
|
21 todi |
|
94
|
|
|
|
|
|
|
22 marva |
|
95
|
|
|
|
|
|
|
23 persian |
|
96
|
|
|
|
|
|
|
24 oriental |
|
97
|
|
|
|
|
|
|
25 romanian |
|
98
|
|
|
|
|
|
|
26 pelog |
|
99
|
|
|
|
|
|
|
27 iwato |
|
100
|
|
|
|
|
|
|
28 hirajoshi |
|
101
|
|
|
|
|
|
|
29 egyptian |
|
102
|
|
|
|
|
|
|
30 pentatonic minor (pminor) |
|
103
|
|
|
|
|
|
|
|
|
104
|
|
|
|
|
|
|
=head1 EXAMPLE |
|
105
|
|
|
|
|
|
|
|
|
106
|
|
|
|
|
|
|
This will print every scale in every key, adjusting the enharmonic equivalents accordingly. |
|
107
|
|
|
|
|
|
|
|
|
108
|
|
|
|
|
|
|
foreach my $note qw (C C# D D# E F F# G G# A A# B) { |
|
109
|
|
|
|
|
|
|
foreach my $mode (1..30) { |
|
110
|
|
|
|
|
|
|
my @notes = get_scale_notes($note,$mode); |
|
111
|
|
|
|
|
|
|
push @notes, get_scale_notes($note,$mode,1); # descending |
|
112
|
|
|
|
|
|
|
print join(" ",@notes),"\n"; |
|
113
|
|
|
|
|
|
|
} |
|
114
|
|
|
|
|
|
|
} |
|
115
|
|
|
|
|
|
|
|
|
116
|
|
|
|
|
|
|
|
|
117
|
|
|
|
|
|
|
=head1 TODO |
|
118
|
|
|
|
|
|
|
|
|
119
|
|
|
|
|
|
|
Add further range of scales from http://www.cs.ruu.nl/pub/MIDI/DOC/scales.zip |
|
120
|
|
|
|
|
|
|
Improve enharmonic eqivalents. |
|
121
|
|
|
|
|
|
|
Microtones |
|
122
|
|
|
|
|
|
|
Generate ragas,gamelan etc. - maybe needs an 'ethnic' subset of modules |
|
123
|
|
|
|
|
|
|
|
|
124
|
|
|
|
|
|
|
=head1 AUTHOR |
|
125
|
|
|
|
|
|
|
|
|
126
|
|
|
|
|
|
|
Ben Daglish (bdaglish@surfnet-ds.co.uk) |
|
127
|
|
|
|
|
|
|
|
|
128
|
|
|
|
|
|
|
Thanks to Steve Hay for pointing out my 'minor' mix-up and many suggestions. |
|
129
|
|
|
|
|
|
|
Thanks also to Gene Boggs for the 'is_scale' suggestion / code. |
|
130
|
|
|
|
|
|
|
|
|
131
|
|
|
|
|
|
|
=head1 BUGS |
|
132
|
|
|
|
|
|
|
|
|
133
|
|
|
|
|
|
|
A few enharmonic problems still... |
|
134
|
|
|
|
|
|
|
|
|
135
|
|
|
|
|
|
|
All feedback most welcome. |
|
136
|
|
|
|
|
|
|
|
|
137
|
|
|
|
|
|
|
=head1 COPYRIGHT |
|
138
|
|
|
|
|
|
|
|
|
139
|
|
|
|
|
|
|
Copyright (c) 2003, Ben Daglish. All Rights Reserved. |
|
140
|
|
|
|
|
|
|
This program is free software; you can redistribute |
|
141
|
|
|
|
|
|
|
it and/or modify it under the same terms as Perl itself. |
|
142
|
|
|
|
|
|
|
|
|
143
|
|
|
|
|
|
|
The full text of the license can be found in the |
|
144
|
|
|
|
|
|
|
LICENSE file included with this module. |
|
145
|
|
|
|
|
|
|
|
|
146
|
|
|
|
|
|
|
|
|
147
|
|
|
|
|
|
|
=head1 SEE ALSO |
|
148
|
|
|
|
|
|
|
|
|
149
|
|
|
|
|
|
|
PDL::Audio::Scale, perl(1). |
|
150
|
|
|
|
|
|
|
|
|
151
|
|
|
|
|
|
|
=cut |
|
152
|
|
|
|
|
|
|
|
|
153
|
|
|
|
|
|
|
my %modes = qw(ionian 1 major 1 hypolydian 1 dorian 2 hypomyxolydian 2 |
|
154
|
|
|
|
|
|
|
phrygian 3 hypoaeolian 3 lydian 4 hypolocrian 4 mixolydian 5 hypoionian 5 |
|
155
|
|
|
|
|
|
|
aeolian 6 minor 6 m 6 hypodorian 6 locrian 7 hypophrygian 7 |
|
156
|
|
|
|
|
|
|
harmonicminor 8 hm 8 melodicminor 9 mm 9 |
|
157
|
|
|
|
|
|
|
blues 10 pentatonic 11 pmaj 11 chromatic 12 diminished 13 wholetone 14 |
|
158
|
|
|
|
|
|
|
augmented 15 hungarianminor 16 3semitone 17 4semitone 18 |
|
159
|
|
|
|
|
|
|
neapolitanminor 19 nmin 19 neapolitanmajor 20 nmaj 20 |
|
160
|
|
|
|
|
|
|
todi 21 marva 22 persian 23 oriental 24 romanian 25 pelog 26 |
|
161
|
|
|
|
|
|
|
iwato 27 hirajoshi 28 egyptian 29 pminor 30 pentatonicminor 30 |
|
162
|
|
|
|
|
|
|
); |
|
163
|
|
|
|
|
|
|
|
|
164
|
|
|
|
|
|
|
my %abbrevs = abbrev(keys %modes); |
|
165
|
|
|
|
|
|
|
while (my ($k,$v) = each %abbrevs) { |
|
166
|
|
|
|
|
|
|
$modes{$k} = $modes{$v}; |
|
167
|
|
|
|
|
|
|
} |
|
168
|
|
|
|
|
|
|
|
|
169
|
|
|
|
|
|
|
my @scales=([0,2,4,5,7,9,11], # Ionian(1) |
|
170
|
|
|
|
|
|
|
[0,2,3,5,7,9,10], # Dorian (2) |
|
171
|
|
|
|
|
|
|
[0,1,3,5,7,8,10], # Phrygian (3) |
|
172
|
|
|
|
|
|
|
[0,2,4,6,7,9,11], # Lydian (4) |
|
173
|
|
|
|
|
|
|
[0,2,4,5,7,9,10], # Mixolydian (5) |
|
174
|
|
|
|
|
|
|
[0,2,3,5,7,8,10], # Aeolian (6) |
|
175
|
|
|
|
|
|
|
[0,1,3,5,6,8,10], # Locrian (7) |
|
176
|
|
|
|
|
|
|
[0,2,3,5,7,8,11], # Harmonic Minor (8) |
|
177
|
|
|
|
|
|
|
[0,2,3,5,7,9,11], # Melodic Minor (9) |
|
178
|
|
|
|
|
|
|
[0,3,5,6,7,10], # Blues (10) |
|
179
|
|
|
|
|
|
|
[0,2,4,7,9], # Pentatonic (11) |
|
180
|
|
|
|
|
|
|
[0,1,2,3,4,5,6,7,8,9,10,11],# Chromatic (12) |
|
181
|
|
|
|
|
|
|
[0,2,3,5,6,8,9,11], # Diminished (13) |
|
182
|
|
|
|
|
|
|
[0,2,4,6,8,10], # Whole tone(14) |
|
183
|
|
|
|
|
|
|
[0,3,4,7,8,11], # Augmented (15) |
|
184
|
|
|
|
|
|
|
[0,2,3,6,7,8,11], # Hungarian minor (16) |
|
185
|
|
|
|
|
|
|
[0,3,6,9], # 3 semitone (dimished arpeggio) (17) |
|
186
|
|
|
|
|
|
|
[0,4,8], # 4 semitone (augmented arpeggio) (18) |
|
187
|
|
|
|
|
|
|
[0,1,3,5,7,8,11], # Neapolitan minor (19) |
|
188
|
|
|
|
|
|
|
[0,1,3,5,7,9,11], # Neapolitan major (20) |
|
189
|
|
|
|
|
|
|
[0,1,3,6,7,8,11], # Todi (Indian) (21) |
|
190
|
|
|
|
|
|
|
[0,1,4,6,7,9,11], # Marva (Indian) (22) |
|
191
|
|
|
|
|
|
|
[0,1,4,5,6,8,11], # Persian (23) |
|
192
|
|
|
|
|
|
|
[0,1,4,5,6,9,10], # Oriental (24) |
|
193
|
|
|
|
|
|
|
[0,2,3,6,7,9,10], # Romanian (25) |
|
194
|
|
|
|
|
|
|
[0,1,3,7,10], # Pelog (Balinese) (26) |
|
195
|
|
|
|
|
|
|
[0,1,5,6,10], # Iwato (Japanese) (27) |
|
196
|
|
|
|
|
|
|
[0,2,3,7,8], # Hirajoshi (Japanese) (28) |
|
197
|
|
|
|
|
|
|
[0,2,5,7,10], # Egyptian (29) |
|
198
|
|
|
|
|
|
|
[0,3,5,7,10], # Pentatonic Minor (30) |
|
199
|
|
|
|
|
|
|
); |
|
200
|
|
|
|
|
|
|
|
|
201
|
|
|
|
|
|
|
sub get_scale_nums { |
|
202
|
14
|
|
|
14
|
1
|
19
|
my ($mode,$descending) = @_; |
|
203
|
14
|
|
|
|
|
33
|
$mode = get_mode($mode); |
|
204
|
14
|
|
|
|
|
19
|
my @dists = @{$scales[$mode-1]}; |
|
|
14
|
|
|
|
|
54
|
|
|
205
|
14
|
50
|
66
|
|
|
50
|
if ($descending && $mode == 9) { |
|
206
|
0
|
|
|
|
|
0
|
$dists[5]-- ;$dists[6]--; |
|
|
0
|
|
|
|
|
0
|
|
|
207
|
|
|
|
|
|
|
} |
|
208
|
14
|
100
|
|
|
|
68
|
($descending) ? reverse @dists : @dists; |
|
209
|
|
|
|
|
|
|
} |
|
210
|
|
|
|
|
|
|
|
|
211
|
|
|
|
|
|
|
sub get_scale_offsets { |
|
212
|
0
|
|
|
0
|
1
|
0
|
my @scale = get_scale_notes(@_); |
|
213
|
0
|
|
|
|
|
0
|
my %key_alts = qw(C 0 D 0 E 0 F 0 G 0 A 0 B 0); |
|
214
|
0
|
|
|
|
|
0
|
foreach (@scale) { |
|
215
|
0
|
0
|
|
|
|
0
|
$key_alts{$_}++ if s/#//; |
|
216
|
0
|
0
|
|
|
|
0
|
$key_alts{$_}-- if s/b//; |
|
217
|
|
|
|
|
|
|
} |
|
218
|
0
|
|
|
|
|
0
|
%key_alts; |
|
219
|
|
|
|
|
|
|
} |
|
220
|
|
|
|
|
|
|
|
|
221
|
|
|
|
|
|
|
sub get_mode { |
|
222
|
23
|
|
100
|
23
|
0
|
56
|
my $mode = shift() || 1; |
|
223
|
23
|
|
|
|
|
167
|
$mode =~ s/[^a-zA-Z0-9]//g; |
|
224
|
23
|
100
|
|
|
|
95
|
$mode = $modes{lc($mode)} unless $mode =~/^[0-9]+$/; |
|
225
|
23
|
50
|
33
|
|
|
125
|
($mode && ($mode <= @scales)) ? $mode : 1; |
|
226
|
|
|
|
|
|
|
} |
|
227
|
|
|
|
|
|
|
|
|
228
|
|
|
|
|
|
|
sub note_to_num { |
|
229
|
46
|
|
|
46
|
0
|
54
|
my $note = shift(); |
|
230
|
46
|
|
|
|
|
492
|
my %note2num = ('A','0','A#','1','BB','1','B','2','C','3','C#','4','DB','4','D','5','D#','6','EB','6','E','7','F','8','F#','9','GB','9','G','10','G#','11','AB','11'); |
|
231
|
46
|
50
|
|
|
|
117
|
return $note if ($note =~/^[0-9]+$/); |
|
232
|
46
|
50
|
|
|
|
268
|
(defined $note2num{uc($note)}) ? $note2num{uc($note)} : 0; |
|
233
|
|
|
|
|
|
|
} |
|
234
|
|
|
|
|
|
|
|
|
235
|
|
|
|
|
|
|
sub note_to_MIDI { |
|
236
|
3
|
|
|
3
|
0
|
4
|
my ($note,$octave) = @_; |
|
237
|
3
|
|
|
|
|
9
|
((note_to_num($note)+9) % 12) + (12 * ++$octave ); |
|
238
|
|
|
|
|
|
|
} |
|
239
|
|
|
|
|
|
|
|
|
240
|
|
|
|
|
|
|
sub get_scale_MIDI { |
|
241
|
3
|
|
|
3
|
1
|
14
|
my ($note,$octave,$mode,$descending) = @_; |
|
242
|
3
|
|
|
|
|
8
|
my $basenum = note_to_MIDI($note,$octave); |
|
243
|
3
|
|
|
|
|
11
|
return map {$basenum + $_} get_scale_nums($mode,$descending); |
|
|
21
|
|
|
|
|
51
|
|
|
244
|
|
|
|
|
|
|
} |
|
245
|
|
|
|
|
|
|
|
|
246
|
|
|
|
|
|
|
sub get_scale_PDL { |
|
247
|
4
|
|
|
4
|
1
|
16
|
my ($note,$octave,$mode,$descending,$keypref) = @_; |
|
248
|
4
|
|
|
|
|
11
|
scale_to_PDL($octave,get_scale_notes($note,$mode,$descending,$keypref)); |
|
249
|
|
|
|
|
|
|
} |
|
250
|
|
|
|
|
|
|
|
|
251
|
|
|
|
|
|
|
sub get_scale_notes { |
|
252
|
9
|
|
|
9
|
1
|
26
|
my ($keynote,$mode,$descending,$keypref) = @_; |
|
253
|
9
|
|
|
|
|
35
|
my @notes = ('A'..'G'); |
|
254
|
9
|
|
|
|
|
20
|
my @nums = (2,1,2,2,1,2,2); |
|
255
|
|
|
|
|
|
|
|
|
256
|
9
|
|
|
|
|
23
|
$keynote =~ s/^[a-z]/\u$&/; |
|
257
|
9
|
50
|
|
|
|
27
|
$keypref='' unless defined $keypref; |
|
258
|
9
|
|
|
|
|
29
|
my $keynum = note_to_num(uc($keynote)); |
|
259
|
9
|
|
|
|
|
25
|
$mode = get_mode($mode); |
|
260
|
9
|
|
|
|
|
21
|
my @dists = get_scale_nums($mode,$descending); |
|
261
|
9
|
100
|
|
|
|
24
|
@dists = reverse @dists if $descending; |
|
262
|
9
|
|
|
|
|
15
|
my @scale = map {($_+$keynum-$dists[0])%12} @dists; |
|
|
67
|
|
|
|
|
121
|
|
|
263
|
9
|
100
|
66
|
|
|
57
|
$keypref='b' if (!$keypref && $descending && $mode == 12); #prefer flat descending chromatic |
|
|
|
|
100
|
|
|
|
|
|
264
|
|
|
|
|
|
|
|
|
265
|
9
|
|
|
|
|
97
|
my %num2note = (0,'A',1,'A#',2,'B',3,'C',4,'C#',5,'D',6,'D#',7,'E',8,'F',9,'F#',10,'G',11,'G#'); |
|
266
|
9
|
100
|
100
|
|
|
65
|
%num2note = (0,'A',1,'Bb',2,'B',3,'C',4,'Db',5,'D',6,'Eb',7,'E',8,'F',9,'Gb',10,'G',11,'Ab') if (($keypref eq 'b') || ($keynote =~ /.b/i)); |
|
267
|
9
|
|
|
|
|
16
|
my @mscale = $keynote; |
|
268
|
9
|
100
|
|
|
|
23
|
if (@scale > 7) { # we're not bothered by niceties, so just convert |
|
269
|
2
|
|
|
|
|
5
|
@mscale = map {$num2note{$_}} @scale; |
|
|
24
|
|
|
|
|
81
|
|
|
270
|
|
|
|
|
|
|
} |
|
271
|
|
|
|
|
|
|
else { |
|
272
|
7
|
50
|
|
|
|
19
|
$keynote = $num2note{$keynote} if $keynote =~/^[0-9]+$/; |
|
273
|
7
|
|
|
|
|
9
|
my $kk = $keynote; $kk =~ s/b|\#//; $kk = ord($kk) - ord('A'); |
|
|
7
|
|
|
|
|
31
|
|
|
|
7
|
|
|
|
|
10
|
|
|
274
|
7
|
|
|
|
|
18
|
foreach(0..$kk-1) {# rotate to keynote |
|
275
|
27
|
|
|
|
|
60
|
push @notes,shift(@notes); |
|
276
|
27
|
|
|
|
|
41
|
push @nums,shift(@nums); |
|
277
|
|
|
|
|
|
|
} |
|
278
|
7
|
|
|
|
|
34
|
push @notes,shift(@notes); |
|
279
|
7
|
|
|
|
|
10
|
shift(@dists); |
|
280
|
7
|
|
|
|
|
11
|
my $cu = shift(@nums); |
|
281
|
7
|
100
|
|
|
|
20
|
$cu++ if ($keynote =~ /b/); |
|
282
|
7
|
100
|
|
|
|
19
|
$cu-- if ($keynote =~ /#/); |
|
283
|
7
|
|
|
|
|
12
|
foreach (@dists) { |
|
284
|
36
|
|
|
|
|
43
|
my $m = $_ - $cu; |
|
285
|
36
|
|
|
|
|
42
|
my $ns = shift(@nums); |
|
286
|
36
|
|
|
|
|
42
|
push @nums,$ns; |
|
287
|
36
|
|
|
|
|
47
|
my $n = shift(@notes); |
|
288
|
36
|
|
|
|
|
45
|
push @notes,$n; |
|
289
|
36
|
|
100
|
|
|
198
|
while (abs($m) > 2 || (@scale < 7 && abs($m) >= $ns)) { # step up/down notes, 'reducing' flats/sharps |
|
|
|
|
33
|
|
|
|
|
|
290
|
6
|
|
|
|
|
8
|
$n = shift(@notes); push @notes,$n; |
|
|
6
|
|
|
|
|
7
|
|
|
291
|
6
|
50
|
|
|
|
12
|
if ($m > 0) {$m -= $ns;$cu += $ns } |
|
|
6
|
0
|
|
|
|
5
|
|
|
|
6
|
|
|
|
|
8
|
|
|
|
0
|
|
|
|
|
0
|
|
|
292
|
0
|
|
|
|
|
0
|
elsif ($m < 0){$m += $ns;$cu -= $ns} |
|
293
|
6
|
|
|
|
|
6
|
$ns = shift(@nums); push @nums,$ns; |
|
|
6
|
|
|
|
|
31
|
|
|
294
|
|
|
|
|
|
|
} |
|
295
|
36
|
100
|
|
|
|
78
|
$n .= '#' x $m if ($m > 0); |
|
296
|
36
|
100
|
|
|
|
217
|
$n .= 'b' x abs($m) if ($m < 0); |
|
297
|
36
|
|
|
|
|
51
|
push @mscale,$n; |
|
298
|
36
|
|
|
|
|
62
|
$cu += $ns; |
|
299
|
|
|
|
|
|
|
} |
|
300
|
|
|
|
|
|
|
} |
|
301
|
9
|
100
|
|
|
|
32
|
if ($descending) { |
|
302
|
2
|
|
|
|
|
3
|
@mscale = reverse @mscale; |
|
303
|
2
|
|
|
|
|
7
|
unshift @mscale,pop(@mscale); |
|
304
|
|
|
|
|
|
|
} |
|
305
|
9
|
|
|
|
|
101
|
@mscale; |
|
306
|
|
|
|
|
|
|
} |
|
307
|
|
|
|
|
|
|
|
|
308
|
|
|
|
|
|
|
|
|
309
|
|
|
|
|
|
|
sub is_scale { |
|
310
|
6
|
|
|
6
|
1
|
18
|
my $name = shift(); |
|
311
|
6
|
|
|
|
|
14
|
$name =~ s/[^a-zA-Z0-9]//g; |
|
312
|
6
|
100
|
|
|
|
41
|
return exists $modes{lc $name} ? 1 : 0; |
|
313
|
|
|
|
|
|
|
} |
|
314
|
|
|
|
|
|
|
|
|
315
|
|
|
|
|
|
|
sub scale_to_PDL { |
|
316
|
4
|
|
|
4
|
0
|
154
|
my ($octave,@scale)=@_; |
|
317
|
4
|
|
|
|
|
4
|
my @result; |
|
318
|
|
|
|
|
|
|
my $descending; |
|
319
|
4
|
|
|
|
|
9
|
my $n1 = note_to_num($scale[0]); |
|
320
|
4
|
|
|
|
|
7
|
my $n2 = note_to_num($scale[1]); |
|
321
|
4
|
100
|
100
|
|
|
21
|
if ($n2 < $n1 && ($n1-$n2 < 5)) { |
|
322
|
1
|
|
|
|
|
2
|
$descending = 1; |
|
323
|
1
|
|
|
|
|
2
|
@scale = reverse @scale; |
|
324
|
|
|
|
|
|
|
} |
|
325
|
4
|
|
|
|
|
8
|
my $last = (note_to_num($scale[0]) + 9) % 12; |
|
326
|
4
|
|
|
|
|
6
|
foreach (@scale) { |
|
327
|
22
|
|
|
|
|
40
|
my $n = (note_to_num($_) + 9) % 12; |
|
328
|
22
|
100
|
|
|
|
43
|
$octave++ if ($last > $n); #switched over octave at 'c' |
|
329
|
22
|
|
|
|
|
34
|
s/\#/s/g; |
|
330
|
22
|
|
|
|
|
28
|
s/b/f/g; |
|
331
|
22
|
|
|
|
|
38
|
push @result,lc($_).$octave; |
|
332
|
22
|
|
|
|
|
35
|
$last = $n; |
|
333
|
|
|
|
|
|
|
} |
|
334
|
4
|
100
|
|
|
|
10
|
@result = reverse @result if $descending; |
|
335
|
4
|
|
|
|
|
38
|
@result; |
|
336
|
|
|
|
|
|
|
} |
|
337
|
|
|
|
|
|
|
|
|
338
|
|
|
|
|
|
|
1; |
|
339
|
|
|
|
|
|
|
__END__ |