midinous 1.0.0.beta

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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