-
Notifications
You must be signed in to change notification settings - Fork 0
/
Scales.ml
200 lines (171 loc) · 8.35 KB
/
Scales.ml
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
(* Copyright (c) 2013 Florian Hars
Permission is hereby granted, free of charge, to any person obtaining
a copy of this software and associated documentation files (the
"Software"), to deal in the Software without restriction, including
without limitation the rights to use, copy, modify, merge, publish,
distribute, sublicense, and/or sell copies of the Software, and to
permit persons to whom the Software is furnished to do so, subject to
the following conditions:
The above copyright notice and this permission notice shall be included in all copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.
*)
let scales = [|
"Lydian", 5, [ 0; 2; 4; 6; 7; 9; 11 ];
"Ionian (Major)", 0, [ 0; 2; 4; 5; 7; 9; 11 ];
"Mixolydian", 7, [ 0; 2; 4; 5; 7; 9; 10 ];
"Dorian", 2, [ 0; 2; 3; 5; 7; 9; 10 ];
"Aeolian (Minor)", 9, [ 0; 2; 3; 5; 7; 8; 10 ];
"Phrygian", 4, [ 0; 1; 3; 5; 7; 8; 10 ];
"Locrian", 11, [ 0; 1; 3; 5; 6; 8; 10 ];
"Melodic minor (asc.)", -1, [ 0; 2; 3; 5; 7; 9; 11 ];
"Phrygian ♮6 ", -1, [ 0; 1; 3; 5; 7; 9; 10 ];
"Lydian ♯5", -1, [ 0; 2; 4; 6; 8; 9; 11 ];
"Lydian ♭7", 5, [ 0; 2; 4; 6; 7; 9; 10 ];
"Mixolydian ♭6", -1, [ 0; 2; 4; 5; 7; 8; 10 ];
"Half-diminished", -1, [ 0; 2; 3; 5; 6; 8; 10 ];
"Altered (Super Locrian)", -1, [ 0; 1; 3; 4; 6; 8; 10 ];
"Harmonic minor", -1, [ 0; 2; 3; 5; 7; 8; 11 ];
"Locrian ♮6", -1, [ 0; 1; 3; 5; 6; 9; 10 ];
"Ionian ♯5", -1, [ 0; 2; 4; 5; 8; 9; 11 ];
"Ukrainian minor", -1, [ 0; 2; 3; 6; 7; 9; 10 ];
"Phrygian dominant", -1, [ 0; 1; 4; 5; 7; 8; 10 ];
"Lydian ♯2", -1, [ 0; 3; 4; 6; 7; 9; 11 ];
"Super Locrian diminished", -1, [ 0; 1; 3; 4; 6; 8; 9 ];
"Double harmonic scale", -1, [ 0; 1; 4; 5; 7; 8; 11 ];
"Lydian ♯2 ♯6", -1, [ 0; 3; 4; 6; 7; 10; 11 ];
"Phrygian ♭4 ♭♭7", -1, [ 0; 1; 3; 4; 7; 8; 9 ];
"Hungarian minor", -1, [ 0; 2; 3; 6; 7; 8; 11 ];
"Locrian ♮6 ♯3", -1, [ 0; 1; 4; 5; 6; 9; 10 ];
"Harmonic Major ♯5 ♯2", -1, [ 0; 3; 4; 5; 8; 9; 11 ];
"Locrian ♭♭3 ♭♭7", -1, [ 0; 1; 2; 5; 6; 8; 9 ];
"Minor Pentatonic", -1, [ 0; 3; 5; 7; 10 ];
"Major Pentatonic", -1, [ 0; 2; 4; 7; 9 ];
"Egyptian, suspended", -1, [ 0; 2; 5; 7; 10 ];
"Blues minor / Man Gong", -1, [ 0; 3; 5; 8; 10 ];
"Blues major / Ritusen", -1, [ 0; 2; 5; 7; 9 ];
"In (Sakura)/ Hirajōshi", -1, [ 0; 1; 5; 7; 8 ];
"Hirajōshi, 2nd mode", -1, [ 0; 4; 6; 7; 11 ];
"Hirajōshi (Kostka)", -1, [ 0; 2; 3; 7; 8 ];
"Hirajōshi (Sachs) / Iwato", -1, [ 0; 1; 5; 6; 10 ];
"Hirajōshi, 5th mode", -1, [ 0; 4; 5; 9; 11 ];
"Blues minor", -1, [ 0; 3; 5; 6; 7; 10 ];
"Blues major", -1, [ 0; 2; 3; 4; 7; 9 ];
"Blues (heptatonic)", -1, [ 0; 2; 3; 5; 6; 9; 10 ];
"Chromatic Blues", -1, [ 0; 2; 3; 4; 5; 7; 9; 10; 11 ];
"Major bebop", -1, [ 0; 2; 4; 5; 7; 8; 9; 11 ];
"Dominant bebop (asc.)", -1, [ 0; 2; 4; 5; 7; 9; 10; 11 ];
"Dominant bebop (desc.)", -1, [ 12; 10; 9; 8; 7; 5; 3; 2 ];
"Whole tone (First mode)", -1, [ 0; 2; 4; 6; 8; 10 ];
"Sym. Diminished whole-half", -1, [ 0; 2; 3; 5; 6; 8; 9; 11 ];
"Sym. Diminished half-whole", -1, [ 0; 1; 3; 4; 6; 7; 9; 10 ];
"Third mode / 1", -1, [ 0; 2; 3; 4; 6; 7; 8; 10; 11 ];
"Third mode / 2", -1, [ 0; 1; 2; 4; 5; 6; 8; 9; 10 ];
"Third mode / 3", -1, [ 0; 1; 3; 4; 5; 7; 8; 9; 11 ];
"Fourth mode / 1", -1, [ 0; 1; 2; 5; 6; 7; 8; 11 ];
"Fourth mode / 2", -1, [ 0; 1; 4; 5; 6; 7; 10; 11 ];
"Fourth mode / 3", -1, [ 0; 3; 4; 5; 6; 9; 10; 11 ];
"Fourth mode / 4", -1, [ 0; 1; 2; 3; 6; 7; 8; 9 ];
"Fifth mode / 1", -1, [ 0; 1; 5; 6; 7; 11 ];
"Fifth mode / 2", -1, [ 0; 4; 5; 6; 10; 11 ];
"Fifth mode / 3", -1, [ 0; 1; 2; 6; 7; 8 ];
"Sixth mode / 1", -1, [ 0; 2; 4; 5; 6; 8; 10; 11 ];
"Sixth mode / 2", -1, [ 0; 2; 3; 4; 6; 8; 9; 10 ];
"Sixth mode / 3", -1, [ 0; 1; 2; 4; 6; 7; 8; 10 ];
"Sixth mode / 4", -1, [ 0; 1; 3; 5; 6; 7; 9; 11 ];
"Seventh mode / 1", -1, [ 0; 1; 2; 3; 5; 6; 7; 8; 9; 11 ];
"Seventh mode / 2", -1, [ 0; 1; 2; 4; 5; 6; 7; 8; 10; 11 ];
"Seventh mode / 3", -1, [ 0; 1; 3; 4; 5; 6; 7; 9; 10; 11 ];
"Seventh mode / 4", -1, [ 0; 2; 3; 4; 5; 6; 8; 9; 10; 11 ];
"Seventh mode / 5", -1, [ 0; 1; 2; 3; 4; 6; 7; 8; 9; 10 ];
"Melodic minor (desc.)", -1, [12; 10; 8; 7; 5; 3; 2 ];
"Aeolian ♯4", -1, [ 0; 2; 3; 6; 7; 8; 10 ];
"Neapolitan minor (asc.)", -1, [ 0; 1; 3; 5; 7; 8; 11 ];
"Neapolitan minor (desc.)", -1, [ 12; 10; 8; 7; 5; 3; 1 ];
"Neopolitan major", -1, [ 0; 1; 3; 5; 7; 9; 11 ];
"Chromatic", -1, [ 0; 1; 2; 3; 4; 5; 6; 7; 8; 9; 10; 11 ]
|]
let rec enum from_n to_n =
if from_n > to_n then []
else from_n :: enum (from_n + 1) to_n
let scale_groups = [
"Standard Modes", enum 0 6;
"Melodic Minor Modes", enum 7 13;
"Hamonic Minor Modes", enum 14 20;
"Double Harmonic Modes", enum 21 27;
"Pentatonic Modes", enum 28 37;
"Blues & Bebop", enum 38 44;
"Modes of Limited Transposition", enum 45 66;
"Other Scales", enum 67 72;
]
let keys = [| "C"; "Db"; "D"; "Eb"; "E"; "F"; "F#/Gb"; "G"; "Ab"; "A"; "Bb"; "B" |]
let guitar6 = [ 52; 57; 62; 67; 71; 76 ]
let banjo4 = [60; 67; 74; 81]
let instruments = [|
"Guitar", guitar6;
"Guitar (open D)", [50; 57; 62; 66; 69; 74];
"Guitar (open G)", [50; 55; 62; 67; 71; 74];
"Guitar (drop D)", [ 50; 57; 62; 67; 71; 76 ];
"Guitar (modal)", [ 50; 57; 62; 67; 69; 74 ];
"Guitar (NST)", [ 48; 55; 62; 69; 76; 79 ];
"Ukulele (C)", [ 67; 72; 76; 81 ];
"Ukulele (D)", [ 69; 74; 78; 83 ];
"Violin", [67; 74; 81; 88];
"Tenor Banjo", banjo4
|]
let fret_for_note str note =
let f = (note - str) mod 12 in
if f < 0 then f + 12 else f
let base_notes instrument key =
List.map (fun str -> fret_for_note str key) instrument
let transpose key scale =
List.map (fun note -> let n = (note + key) mod 12 in if n < 0 then n + 12 else n) scale
let transpose_raw key scale =
List.map (fun note -> note + key) scale
module S = Set.Make(struct type t = int let compare = compare end)
let of_list = List.fold_left (fun i s -> S.add s i) S.empty
let notes_on_string str scale =
let frets = List.fold_right
(fun note frets ->
S.add (fret_for_note str note) frets)
scale S.empty in
List.rev (S.fold (fun k l -> k :: l) frets [])
let all_notes instrument scale key =
let scale' = transpose key scale in
List.map (fun str -> notes_on_string str scale') instrument
let max_diff instrument =
let rec m_d_r acc last = function
| [] -> acc
| str::l ->
m_d_r (max acc (str - last)) str l
in
match instrument with
| [] -> -1
| [_] -> 12
| str::l ->
m_d_r (-1) str l
let rec range from width =
if width > 0 then
from :: range (from + 1) (width - 1)
else
[]
let in_range from width notes = List.filter (fun i -> S.mem (i mod 12) notes) (range from width)
let rec filter notes instrument max_diff skips accum_skip =
match instrument, skips with
| [], [] -> []
| [str], [skip] -> [in_range (accum_skip + str) (max_diff + skip) notes]
| str::(str' :: _ as strs'), skip::skips' ->
let off = (str' - str + skip) in
in_range (accum_skip + str) off notes :: filter notes strs' (max off max_diff) skips' (accum_skip + skip)
| _ -> assert false
let generate_scale instrument key scale offset skips =
let notes = of_list (transpose key scale)
and width = max_diff instrument in
let filtered = filter notes instrument width skips offset in
width, filtered