midinous 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
data/README.md ADDED
@@ -0,0 +1,31 @@
1
+ # Midinous: Grid-based Generative Music Software
2
+
3
+ Midinous combines generative features with a grid-based GUI to offer a supplemental unique compositional experience
4
+
5
+ ## Requirements
6
+
7
+ * [GTK3](http://www.gtk.org/) 3.3.6 or later
8
+ * Midinous is designed to run on 64-bit architectures
9
+ * You must have 64-bit Ruby version 2.5.5 installed with the devkit and MSYS2
10
+
11
+ ## Install
12
+
13
+ gem install midinous
14
+
15
+ ## Tutorials, examples:
16
+
17
+ * doc/Hotkeys.txt: Useful hotkeys used within the program
18
+ * saves/sample.nous: Example Midinous project having every basic feature. Experiment from this starting point!
19
+
20
+ ## License
21
+
22
+ Copyright (C) 2019 James "Nornec" Ratliff
23
+
24
+ Midinous is free software: you can redistribute it and/or modify
25
+ it under the terms of the GNU General Public License as published by
26
+ the Free Software Foundation, either version 3 of the License, or
27
+ (at your option) any later version.
28
+
29
+ ## Project Websites
30
+
31
+ * https://github.com/Nornec/Midinous
@@ -0,0 +1,30 @@
1
+ [ -- decrement grid size/change time signature divisor -1
2
+ ] -- increment grid size/ change time signature divisor +1
3
+ { -- decrement time signature denominator (slows down play) - min 2
4
+ } -- increment time signature denominator (speeds up play) - max 16
5
+ delete -- deletes selected point(s)
6
+ home -- deletes paths entering selected point(s)
7
+ end -- deletes paths leaving selected point(s)
8
+ Page Up -- change path direction
9
+ Page Down -- change path direction
10
+ A -- Make starting point (need at least 1 to begin play)
11
+ T -- Built path - build a path between one or more points
12
+ Q -- Select Tool - Box select or single select points
13
+ W -- Point Place Tool - Places a point
14
+ E -- Move Tool - moves selected points based on a stencil
15
+ R -- Path Tool - Select source point, select target points, push build path or hit 'T'
16
+ < and > -- Cycle Play Mode - between robin, portal (random, split, if more than one path is leaving a point)
17
+ , and . -- Cycle starting path if more than one path is leaving a point
18
+ + and - -- add or subtract 1 from the currently selected points' note
19
+ Num 6 -- play
20
+ Num 5 -- stop
21
+ space -- toggle play/stop
22
+ Ctrl+A -- select all
23
+ Ctrl+C -- copy selected points
24
+ Ctrl+X -- cut selected points
25
+ Ctrl+V -- paste copied/cut points
26
+ Ctrl+O -- Open
27
+ Ctrl+S -- Save
28
+ Shift+Ctrl+S -- Save As
29
+ Ctrl+N -- New
30
+ Ctrl+Q -- Quit
@@ -0,0 +1,64 @@
1
+ Note Octave
2
+ -2 -1 0 1 2 3 4 5 6 7 8
3
+ C 0 12 24 36 48 60 72 84 96 108 120
4
+ C# 1 13 25 37 49 61 73 85 97 109 121
5
+ D 2 14 26 38 50 62 74 86 98 110 122
6
+ D# 3 15 27 39 51 63 75 87 99 111 123
7
+ E 4 16 28 40 52 64 76 88 100 112 124
8
+ F 5 17 29 41 53 65 77 89 101 113 125
9
+ F# 6 18 30 42 54 66 78 90 102 114 126
10
+ G 7 19 31 43 55 67 79 91 103 115 127
11
+ G# 8 20 32 44 56 68 80 92 104 116 -
12
+ A 9 21 33 45 57 69 81 93 105 117 -
13
+ A# 10 22 34 46 58 70 82 94 106 118 -
14
+ B 11 23 35 47 59 71 83 95 107 119 -
15
+
16
+ Note Octave
17
+ -2 -1 0 1 2 3 4 5 6 7 8
18
+ C 00 0C 18 24 30 3C 48 54 60 6C 78
19
+ C# 01 0D 19 25 31 3D 49 55 61 6D 79
20
+ D 02 0E 1A 26 32 3E 4A 56 62 6E 7A
21
+ D# 03 0F 1B 27 33 3F 4B 57 63 6F 7B
22
+ E 04 10 1C 28 34 40 4C 58 64 70 7C
23
+ F 05 11 1D 29 35 41 4D 59 65 71 7D
24
+ F# 06 12 1E 2A 36 42 4E 5A 66 72 7E
25
+ G 07 13 1F 2B 37 43 4F 5B 67 73 7F
26
+ G# 08 14 20 2C 38 44 50 5C 68 74 -
27
+ A 09 15 21 2D 39 45 51 5D 69 75 -
28
+ A# 0A 16 22 2E 3A 46 52 5E 6A 76 -
29
+ B 0B 17 23 2F 3B 47 53 5F 6B 77 -
30
+
31
+ W = whole tone, H = Half tone
32
+ Scales and their relative intervals
33
+ Aeolian R-W-H-W-W-H-W-W
34
+ Altered R-H-W-H-W-W-W-W
35
+ Augmented R-3H-H-3H-H-3H-H
36
+ Blues R-3H-W-H-H-3H-W
37
+ Chromatic R-H-H-H-H-H-H-H-H-H-H-H-H
38
+ Dorian R-W-H-W-W-W-H-W
39
+ Flamenco R-H-3H-H-W-H-3H-H
40
+ Half Diminished R-W-H-W-H-W-W-W
41
+ Harmonic major R-W-W-H-W-H-3H-H
42
+ Harmonic minor R-W-H-W-W-H-3H-H
43
+ Hirajoshi R-2W-W-H-2W-H
44
+ Hungarian R-W-H-3H-H-H-3H-H
45
+ Insen R-H-2W-W-2W-W
46
+ Ionian R-W-W-H-W-W-W-H
47
+ Iwato R-H-2W-H-2W-W
48
+ Locrian R-H-W-W-H-W-W-W
49
+ Locrian Major R-W-W-H-H-W-W-W
50
+ Lydian R-W-W-W-H-W-W-H
51
+ Lydian Augmented R-W-W-W-W-H-W-H
52
+ Pentatonic Major R-W-W-3H-W-3H
53
+ Pentatonic Minor R-3H-W-W-3H-W
54
+ Melodic minor R-W-H-W-W-W-W-H
55
+ Mixolydian R-W-W-H-W-W-H-W
56
+ Octatonic Whole R-W-H-W-H-W-H-W-H
57
+ Octatonic Half R-H-W-H-W-H-W-H-W
58
+ Persian R-H-3H-H-H-W-3H-H
59
+ Phrygian R-H-W-W-W-H-W-W
60
+ Prometheus R-W-W-W-3H-H-W
61
+ Tritone R-H-3H-W-H-3H-W
62
+ Two-semitone Tritone R-H-H-4H-H-H
63
+ Ukrainian Dorian R-W-H-3H-H-W-H-W
64
+ Whole Tone R-W-W-W-W-W-W
@@ -0,0 +1,388 @@
1
+ # Copyright (C) 2019 James "Nornec" Ratliff
2
+ #
3
+ # This file is part of Midinous
4
+ #
5
+ # Midinous is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Midinous is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Midinous. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ require "midinous/points"
19
+
20
+ class Canvas_Control
21
+ include Logic_Controls
22
+ attr_accessor :nouspoints, :travelers, :beats, :beat_note, :scale, :root_note,
23
+ :tempo, :repeaters, :queued_note_plays, :queued_note_stops
24
+ attr_reader :grid_spacing, :midi_sync, :ms_per_tick, :dragging, :start_time,
25
+ :mouse_last_pos, :scale_posns
26
+ def initialize
27
+ @mouse_last_pos = nil
28
+ @sel_box = nil
29
+ @selecting = false
30
+ @sel_white = [0.8,0.8,0.8,0.1] #selection box colors
31
+ @sel_blue = [0,0.5,1,0.5] #selection box colors
32
+ @point_origin = nil
33
+ @path_origin = nil
34
+ @point_move = nil
35
+ @dragging = false
36
+ @diff = [0,0]
37
+ @nouspoints = []
38
+ @travelers = []
39
+ @starters = []
40
+ @repeaters = []
41
+ @scale = "Chromatic"
42
+ @root_note = 60
43
+ @scale_notes = []
44
+ @scale_posns = []
45
+ set_scale(@scale,@root_note)
46
+ @tempo = 120.000
47
+ @midi_sync = 0.000
48
+ @path_sourced = false
49
+ @attempt_path = false
50
+ @ms_per_tick = 125.000 #default tempo of 120bpm
51
+ @beats = 4 #number of beats in a whole note -- should be reasonably between 1 and 16
52
+ @beat_note = 4 #as a fraction of a whole note -- should be between 2 and 16 via powers of 2
53
+ @grid_spacing = 35
54
+ @queued_note_plays = []
55
+ @queued_note_stops = []
56
+ end
57
+
58
+ def set_tempo(tempo)
59
+ @tempo = tempo
60
+ @ms_per_tick = (1000 * (15 / @tempo)) / (@beat_note / 4)
61
+ end
62
+ def set_scale(scale_text,root)
63
+ @scale = scale_text
64
+ @root_note = root
65
+ scale = SCALES[scale_text]
66
+ slen = scale.length
67
+ @scale_notes = []
68
+ @scale_notes << root
69
+
70
+ c = 0
71
+ note = root
72
+ while note < 127
73
+ note += scale[c]
74
+ @scale_notes << note unless note > 127
75
+ c = (c + 1) % slen
76
+ end
77
+
78
+ c = 0
79
+ note = root
80
+ while note > 0
81
+ note -= scale.reverse[c]
82
+ @scale_notes << note unless note < 0
83
+ c = (c + 1) % slen
84
+ end
85
+ @scale_notes.sort!
86
+
87
+ (0..127).each do |num|
88
+ @scale_posns[num] = false
89
+ @scale_posns[num] = true if @scale_notes.find {|f| f == num} != nil
90
+ end
91
+ end
92
+
93
+ def canvas_generic(string) #Used as a pseudo-handler between classes
94
+ case string
95
+ when "path"
96
+ if !@nouspoints.empty? && @nouspoints.find_all(&:pathable).any?
97
+ @nouspoints = Pl.add_path(@nouspoints)
98
+ @nouspoints, @path_sourced = Pl.cancel_path(@nouspoints)
99
+ UI::canvas.queue_draw
100
+ end
101
+ when "prop"
102
+ @nouspoints = Pl.modify_properties(@nouspoints)
103
+ Pl.populate_prop(@nouspoints)
104
+ UI::canvas.queue_draw
105
+ end
106
+ end
107
+
108
+ def canvas_play
109
+
110
+ if @nouspoints.find(&:traveler_start)
111
+ @playing = true
112
+ @nouspoints.find_all {|n| n.path_to.length > 1}.each {|p| p.path_to.each {|e| p.path_to_memory << e}}
113
+ UI::play.sensitive = false
114
+ UI::stop.sensitive = true
115
+ end
116
+
117
+ @nouspoints.find_all(&:traveler_start).each do |n|
118
+ @starters << Starter.new(nil,n,nil)
119
+ UI::canvas.queue_draw
120
+ @queued_note_plays.each {|o| o.play}
121
+ signal_chain(n,n.note)
122
+ end
123
+ @stored_time = Time.now.to_f*1000
124
+ canvas_timeout(@ms_per_tick) #Start sequence
125
+ end
126
+
127
+ def canvas_timeout(ms)
128
+ GLib::Timeout.add(ms) do
129
+ UI::canvas.signal_emit('travel-event') unless !@playing
130
+ false
131
+ end
132
+ end
133
+
134
+ def canvas_travel
135
+ @queued_note_plays = []
136
+ canvas_stop if !@playing ||
137
+ (@travelers.length == 0 &&
138
+ @starters.length == 0 &&
139
+ @repeaters.length == 0)
140
+
141
+ @starters.each {|s| s.travel}
142
+ @travelers.each {|t| t.travel}
143
+ @travelers.find_all(&:reached).each do |t|
144
+ signal_chain(t.dest,t.played_note) #Pass the last played note here. Gather the played note from the first traveler creation
145
+ t.reached = false
146
+ end
147
+ @repeaters.each {|r| r.repeat}
148
+
149
+ @queued_note_stops.each {|n| n.stop}
150
+ @queued_note_plays.each {|n| n.play}
151
+ @starters.reject!(&:remove)
152
+ @travelers.reject!(&:remove)
153
+ @repeaters.reject!(&:remove)
154
+ @queued_note_stops = []
155
+
156
+ canvas_timeout(sync_diff(@stored_time))
157
+ @stored_time += @ms_per_tick
158
+ UI::canvas.queue_draw
159
+ end
160
+
161
+ def canvas_stop
162
+ @playing = false
163
+ @starters = []
164
+ @repeaters = []
165
+ @queued_note_plays = []
166
+ @queued_note_stops = []
167
+ @nouspoints.find_all {|n| n.path_to.length > 1}.each {|p| p.reset_path_to}
168
+ UI::canvas.queue_draw
169
+ @nouspoints.each do |n|
170
+ n.playing = false
171
+ n.repeating = false
172
+ Pm.note_rlse(n.channel,n.note) unless n.note.to_s.include?("+") || n.note.to_s.include?("-")
173
+ end
174
+ @travelers.each do |t|
175
+ Pm.note_rlse(t.dest.channel,t.played_note) unless t.played_note == nil
176
+ end
177
+ @travelers = []
178
+ UI::stop.sensitive = false
179
+ UI::play.sensitive = true
180
+ end
181
+
182
+ def signal_chain(point,pn) #pn = played note
183
+ case point.play_modes[0]
184
+ when "robin"
185
+ p = point.path_to.first
186
+ if p
187
+ @travelers << Traveler.new(point,p,pn)
188
+ point.path_to.rotate!
189
+ end
190
+ when "split"
191
+ point.path_to.each {|p| @travelers << Traveler.new(point,p,pn)}
192
+ when "portal"
193
+ point.path_to.each do |p|
194
+ @starters << Starter.new(point,p,pn)
195
+ UI::canvas.queue_draw
196
+ #@queued_note_plays.each {|o| o.play}
197
+ signal_chain(p,pn)
198
+ end
199
+ when "random"
200
+ p = point.path_to.sample
201
+ if p
202
+ @travelers << Traveler.new(point,p,pn)
203
+ point.path_to.rotate!(rand(point.path_to.length))
204
+ end
205
+ end
206
+ end
207
+
208
+ def canvas_grid_change(dir)
209
+ prev_beat_note = @beat_note
210
+ case dir
211
+ when "+"
212
+ @beats += 1
213
+ @beats = 16 if @beats > 16
214
+ when "-"
215
+ @beats -= 1
216
+ @beats = 1 if @beats < 1
217
+ when "++"
218
+ @beat_note *= 2
219
+ @beat_note = 16 if @beat_note > 16
220
+ when "--"
221
+ @beat_note /= 2
222
+ @beat_note = 2 if @beat_note < 2
223
+ end
224
+ if @beat_note != prev_beat_note
225
+ case dir
226
+ when "++"
227
+ @ms_per_tick /= 2
228
+ when "--"
229
+ @ms_per_tick *= 2
230
+ end
231
+ end
232
+ UI::t_sig.text = "#{@beats}/#{@beat_note}"
233
+ UI::canvas.queue_draw
234
+ end
235
+
236
+ def canvas_press(event)
237
+ UI::logic_controls.focus = true
238
+ case Active_Tool.tool_id
239
+ when 1
240
+ @sel_box = [event.x,event.y,event.x,event.y]
241
+ @selecting = true
242
+ when 2
243
+ @point_origin = [event.x,event.y]
244
+ when 3
245
+ @point_move = [event.x,event.y,event.x,event.y]
246
+ when 4
247
+ @path_origin = [event.x,event.y]
248
+ end
249
+ end
250
+ def canvas_drag(obj,event)
251
+ @dragging = false
252
+ @mouse_last_pos = [event.x,event.y]
253
+ case
254
+ when (@selecting && @sel_box)
255
+ @dragging = true
256
+ @sel_box[2] = event.x
257
+ @sel_box[3] = event.y
258
+ obj.queue_draw
259
+ when (@point_origin)
260
+ @dragging = true
261
+ @point_origin[0] = event.x
262
+ @point_origin[1] = event.y
263
+ when (@point_move)
264
+ @dragging = true
265
+ # difference in movement of the point, cumulative until mouse released
266
+ @diff = round_to_grid([(event.x - @point_move[0]) , (event.y - @point_move[1])])
267
+ @point_move[2] = event.x
268
+ @point_move[3] = event.y
269
+ obj.queue_draw
270
+ end
271
+ end
272
+ def canvas_release(obj,event)
273
+ @dragging = false
274
+ case Active_Tool.tool_id
275
+ when 1
276
+ unless !@sel_box
277
+ @sel_box = pos_box(@sel_box)
278
+ @nouspoints = Pl.select_points(@sel_box,@nouspoints)
279
+ @sel_box = nil
280
+ @selecting = false
281
+ end
282
+ when 2 #Add a point where/when the tool is released
283
+ unless !@point_origin
284
+ @nouspoints = Pl.add_point(round_to_grid(@point_origin),@nouspoints)
285
+ @point_origin = nil
286
+ end
287
+ when 3 #move point(s) designated by the move stencil
288
+ @nouspoints = Pl.move_points(@diff,@nouspoints)
289
+ @point_move = nil
290
+ @diff = [0,0]
291
+ when 4 #select singular point
292
+ @nouspoints, @path_sourced = Pl.select_path_point(@path_origin,@nouspoints,@path_sourced)
293
+ end
294
+ obj.queue_draw
295
+ end
296
+
297
+ def canvas_del
298
+ @nouspoints = Pl.delete_points(@nouspoints)
299
+ UI::canvas.queue_draw
300
+ end
301
+
302
+ def canvas_bg_draw(cr)
303
+ # fill background with black
304
+ cr.set_source_rgb(BLACK)
305
+ cr.paint
306
+ cr.set_source_rgb(BLUGR)
307
+ x = @grid_spacing
308
+ while x < CANVAS_SIZE
309
+ y = @grid_spacing
310
+ while y < CANVAS_SIZE
311
+ cr.circle(x,y,1)
312
+ cr.fill
313
+ y += @grid_spacing
314
+ end
315
+ x += @grid_spacing
316
+ end
317
+ #Handle measure drawing via notches on paths instead of this, maybe
318
+ cr.set_source_rgba(DGREY)
319
+ x = @grid_spacing
320
+ y = CANVAS_SIZE - @grid_spacing
321
+ while x < CANVAS_SIZE
322
+ cr.move_to(x,@grid_spacing)
323
+ cr.line_to(x,CANVAS_SIZE-@grid_spacing)
324
+ cr.set_line_width(1)
325
+ cr.stroke
326
+ x += @grid_spacing*@beats
327
+ end
328
+ y = @grid_spacing
329
+ x = CANVAS_SIZE - @grid_spacing
330
+ while y < CANVAS_SIZE
331
+ cr.move_to(@grid_spacing,y)
332
+ cr.line_to(CANVAS_SIZE-@grid_spacing,y)
333
+ cr.set_line_width(1)
334
+ cr.stroke
335
+ y += @grid_spacing*@beats
336
+ end
337
+ end
338
+
339
+ def canvas_draw(cr)
340
+ canvas_bg_draw(cr)
341
+ case #These draw events are for in-progress/temporary activities
342
+ when(@sel_box)
343
+ width = @sel_box[2] - @sel_box[0]
344
+ height = @sel_box[3] - @sel_box[1]
345
+
346
+ cr.set_source_rgba(@sel_blue)
347
+ cr.rectangle(@sel_box[0],@sel_box[1],width,height)
348
+ cr.set_line_width(2)
349
+ cr.stroke
350
+ when(@point_move)
351
+ start_coord = [@point_move[0],@point_move[1]]
352
+ end_coord = [@point_move[2],@point_move[3]]
353
+ start_coord = round_to_grid(start_coord)
354
+ end_coord = round_to_grid(end_coord)
355
+
356
+ cr.move_to(start_coord[0],start_coord[1])
357
+ cr.set_source_rgba(RED)
358
+ cr.line_to(end_coord[0],end_coord[1])
359
+ cr.set_line_width(2)
360
+ cr.stroke
361
+ cr.rounded_rectangle(end_coord[0]-10,end_coord[1]-10,20,20,2,2)
362
+ cr.set_line_width(2)
363
+ cr.stroke
364
+ end
365
+
366
+ #Set the scene if the current tool does not permit a style
367
+ case Active_Tool.tool_id
368
+ when 1
369
+ @nouspoints, @path_sourced = Pl.cancel_path(@nouspoints)
370
+ when 2
371
+ @nouspoints, @path_sourced = Pl.cancel_path(@nouspoints)
372
+ when 3
373
+ @nouspoints, @path_sourced = Pl.cancel_path(@nouspoints)
374
+ when 4
375
+ @nouspoints = Pl.cancel_selected(@nouspoints)
376
+ end
377
+
378
+ #Draw all the points and paths last
379
+ #Paths are behind points, so draw them first
380
+ @nouspoints.each { |n| n.path_draw(cr) }
381
+ @nouspoints.each { |n| n.caret_draw(cr)}
382
+ @nouspoints.each { |n| n.draw(cr) }
383
+
384
+
385
+ end
386
+ end
387
+
388
+ CC = Canvas_Control.new
@@ -0,0 +1,108 @@
1
+ # Copyright (C) 2019 James "Nornec" Ratliff
2
+ #
3
+ # This file is part of Midinous
4
+ #
5
+ # Midinous is free software: you can redistribute it and/or modify
6
+ # it under the terms of the GNU General Public License as published by
7
+ # the Free Software Foundation, either version 3 of the License, or
8
+ # (at your option) any later version.
9
+ #
10
+ # Midinous is distributed in the hope that it will be useful,
11
+ # but WITHOUT ANY WARRANTY; without even the implied warranty of
12
+ # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
13
+ # GNU General Public License for more details.
14
+ #
15
+ # You should have received a copy of the GNU General Public License
16
+ # along with Midinous. If not, see <https://www.gnu.org/licenses/>.
17
+
18
+ CANVAS_SIZE = 4400
19
+ PI = 3.14159265358979
20
+ RED = [0.8,0.0,0.0]
21
+ GREEN = [0.0,0.6,0.0]
22
+ LGRN = [0.4,0.6,0.4]
23
+ BLUE = [0.0,0.0,0.6]
24
+ GREY = [0.6,0.6,0.6]
25
+ WHITE = [1.0,1.0,1.0]
26
+ ORNGE = [1.0,0.5,0.5]
27
+ CYAN = [0.0,0.5,1.0]
28
+ VLET = [0.6,0.2,0.8]
29
+ BLACK = [0.1,0.1,0.1]
30
+ BLUGR = [0.2,0.4,0.7]
31
+ DGREY = [0.5,0.5,0.5,0.3]
32
+
33
+ SCALES = {
34
+ "Aeolian" => [2,1,2,2,1,2,2],
35
+ "Altered" => [1,2,1,2,2,2,2],
36
+ "Augmented" => [3,1,3,1,3,1],
37
+ "Blues" => [3,2,1,1,3,2],
38
+ "Chromatic" => [1,1,1,1,1,1,1,1,1,1,1,1],
39
+ "Dorian" => [2,1,2,2,2,1,2],
40
+ "Flamenco" => [1,3,1,2,1,3,1],
41
+ "Half Diminished" => [2,1,2,1,2,2,2],
42
+ "Harmonic Major" => [2,2,1,2,1,3,1],
43
+ "Harmonic Minor" => [2,1,2,2,1,3,1],
44
+ "Hirajoshi" => [4,2,1,4,1],
45
+ "Hungarian" => [2,1,3,1,1,3,1],
46
+ "Insen" => [1,4,2,4,2],
47
+ "Ionian" => [2,2,1,2,2,2,1],
48
+ "Iwato" => [1,4,1,4,2],
49
+ "Locrian" => [1,2,2,1,2,2,2],
50
+ "Locrian Major" => [2,2,1,1,2,2,2],
51
+ "Lydian" => [2,2,2,1,2,2,1],
52
+ "Lydian Augmented" => [2,2,2,2,1,2,1],
53
+ "Pentatonic Major" => [2,2,3,2,3],
54
+ "Pentatonic Minor" => [3,2,2,3,2],
55
+ "Melodic Minor" => [2,1,2,2,2,2,1],
56
+ "Mixolydian" => [2,2,1,2,2,1,2],
57
+ "Octatonic Whole" => [2,1,2,1,2,1,2,1],
58
+ "Octatonic Half" => [1,2,1,2,1,2,1,2],
59
+ "Persian" => [1,3,1,1,2,3,1],
60
+ "Phrygian" => [1,2,2,2,1,2,2],
61
+ "Prometheus" => [2,2,2,3,1,2],
62
+ "Tritone" => [1,3,2,1,3,2],
63
+ "Two Semitone Tritone" => [1,1,4,1,1],
64
+ "Ukrainian Dorian" => [2,1,3,1,2,1,2],
65
+ "Whole Tone" => [2,2,2,2,2,2]
66
+ }
67
+
68
+ =begin
69
+
70
+ Pentatonic
71
+ "Hirajoshi"
72
+ "Insen"
73
+ "Iwato"
74
+ "Pentatonic Major"
75
+ "Pentatonic Minor"
76
+ "Two Semitone Tritone"
77
+ Traditional
78
+ "Aeolian"
79
+ "Dorian"
80
+ "Harmonic Major"
81
+ "Harmonic Minor"
82
+ "Ionian"
83
+ "Locrian"
84
+ "Lydian"
85
+ "Mixolydian"
86
+ "Phrygian"
87
+ Modified Traditional
88
+ "Altered"
89
+ "Half Diminished"
90
+ "Locrian Major"
91
+ "Lydian Augmented"
92
+ "Melodic Minor"
93
+ "Ukrainian Dorian"
94
+ Exotic
95
+ "Augmented"
96
+ "Blues"
97
+ "Flamenco"
98
+ "Hungarian"
99
+ "Persian"
100
+ "Prometheus"
101
+ Mathematical
102
+ "Chromatic"
103
+ "Octatonic Whole"
104
+ "Octatonic Half"
105
+ "Tritone"
106
+ "Whole Tone"
107
+
108
+ =end