midinous 1.0.0.beta
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/COPYING.L +674 -0
- data/README.md +31 -0
- data/lib/doc/Hotkeys.txt +30 -0
- data/lib/doc/Notes and Scales.txt +64 -0
- data/lib/midinous/canvas.rb +388 -0
- data/lib/midinous/constants.rb +108 -0
- data/lib/midinous/init.rb +166 -0
- data/lib/midinous/key_bindings.rb +81 -0
- data/lib/midinous/logic.rb +165 -0
- data/lib/midinous/points.rb +1060 -0
- data/lib/midinous/proc_midi.rb +100 -0
- data/lib/midinous/style/midinous.glade +928 -0
- data/lib/midinous/style/midinous_themes.style +4022 -0
- data/lib/midinous/style/ui.rb +686 -0
- data/lib/midinous.rb +21 -0
- data/lib/saves/sample.nous +9 -0
- metadata +102 -0
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
|
data/lib/doc/Hotkeys.txt
ADDED
@@ -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
|