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
@@ -0,0 +1,686 @@
|
|
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
|
+
class GtkRadioButtonEx < Gtk::RadioButton
|
19
|
+
type_register
|
20
|
+
def initialize
|
21
|
+
super()
|
22
|
+
end
|
23
|
+
define_signal('keybinding-event',nil,nil,nil)
|
24
|
+
end
|
25
|
+
class GtkButtonEx < Gtk::Button
|
26
|
+
type_register
|
27
|
+
def initialize
|
28
|
+
super()
|
29
|
+
end
|
30
|
+
define_signal('keybinding-event',nil,nil,nil)
|
31
|
+
end
|
32
|
+
class GtkCanvas < Gtk::DrawingArea
|
33
|
+
type_register
|
34
|
+
def initialize
|
35
|
+
super()
|
36
|
+
end
|
37
|
+
define_signal('delete-selected-event',nil,nil,nil)
|
38
|
+
define_signal('beat-up',nil,nil,nil)
|
39
|
+
define_signal('beat-dn',nil,nil,nil)
|
40
|
+
define_signal('beat-note-up',nil,nil,nil)
|
41
|
+
define_signal('beat-note-dn',nil,nil,nil)
|
42
|
+
define_signal('travel-event',nil,nil,nil)
|
43
|
+
define_signal('cycle-play-mode-bck',nil,nil,nil)
|
44
|
+
define_signal('cycle-play-mode-fwd',nil,nil,nil)
|
45
|
+
define_signal('set-start',nil,nil,nil)
|
46
|
+
define_signal('del-path-to',nil,nil,nil)
|
47
|
+
define_signal('del-path-from',nil,nil,nil)
|
48
|
+
define_signal('set-path-mode-h',nil,nil,nil)
|
49
|
+
define_signal('set-path-mode-v',nil,nil,nil)
|
50
|
+
define_signal('note-inc-up',nil,nil,nil)
|
51
|
+
define_signal('note-inc-dn',nil,nil,nil)
|
52
|
+
define_signal('path-rotate-bck',nil,nil,nil)
|
53
|
+
define_signal('path-rotate-fwd',nil,nil,nil)
|
54
|
+
end
|
55
|
+
class GtkPropEntry < Gtk::Entry
|
56
|
+
type_register
|
57
|
+
def initialize
|
58
|
+
super()
|
59
|
+
end
|
60
|
+
define_signal('keybinding-event',nil,nil,nil)
|
61
|
+
end
|
62
|
+
|
63
|
+
class UI_Elements
|
64
|
+
include Logic_Controls
|
65
|
+
# Construct a Gtk::Builder instance and load our UI description
|
66
|
+
attr_reader :menu_commands,:canvas_commands,:in_device_items,:out_device_items
|
67
|
+
def initialize
|
68
|
+
@current_file = nil
|
69
|
+
@operation_file = nil
|
70
|
+
@current_window = nil
|
71
|
+
@scale_iters = []
|
72
|
+
@in_device_items = []
|
73
|
+
@out_device_items = []
|
74
|
+
end
|
75
|
+
def build_ui
|
76
|
+
builder_file = "#{File.dirname(__FILE__)}/midinous.glade"
|
77
|
+
|
78
|
+
# Connect signal handlers to the constructed widgets
|
79
|
+
@builder = Gtk::Builder.new(:file => builder_file)
|
80
|
+
|
81
|
+
#Windows
|
82
|
+
def midinous
|
83
|
+
@builder.get_object("midinous")
|
84
|
+
end
|
85
|
+
def file_chooser
|
86
|
+
@builder.get_object("file_chooser")
|
87
|
+
end
|
88
|
+
def confirmer
|
89
|
+
@builder.get_object("confirmer")
|
90
|
+
end
|
91
|
+
|
92
|
+
#Menus
|
93
|
+
def input_menu
|
94
|
+
@builder.get_object("input_menu")
|
95
|
+
end
|
96
|
+
def output_menu
|
97
|
+
@builder.get_object("output_menu")
|
98
|
+
end
|
99
|
+
|
100
|
+
#Menu Items
|
101
|
+
def file_new
|
102
|
+
@builder.get_object("file_new")
|
103
|
+
end
|
104
|
+
def file_open
|
105
|
+
@builder.get_object("file_open")
|
106
|
+
end
|
107
|
+
def file_save
|
108
|
+
@builder.get_object("file_save")
|
109
|
+
end
|
110
|
+
def file_save_as
|
111
|
+
@builder.get_object("file_save_as")
|
112
|
+
end
|
113
|
+
def file_quit
|
114
|
+
@builder.get_object("file_quit")
|
115
|
+
end
|
116
|
+
def help_about
|
117
|
+
@builder.get_object("help_about")
|
118
|
+
end
|
119
|
+
|
120
|
+
#Drawing Areas
|
121
|
+
def canvas
|
122
|
+
@builder.get_object("canvas")
|
123
|
+
end
|
124
|
+
def canvas_viewport
|
125
|
+
@builder.get_object("canvas_viewport")
|
126
|
+
end
|
127
|
+
def canvas_scroll_window
|
128
|
+
@builder.get_object("canvas_scroll_window")
|
129
|
+
end
|
130
|
+
|
131
|
+
#Adjustments
|
132
|
+
def canvas_h_adj
|
133
|
+
@builder.get_object("canvas_scroll_h")
|
134
|
+
end
|
135
|
+
def canvas_v_adj
|
136
|
+
@builder.get_object("canvas_scroll_v")
|
137
|
+
end
|
138
|
+
def tempo_adj
|
139
|
+
@builder.get_object("tempo_adj")
|
140
|
+
end
|
141
|
+
def root_adj
|
142
|
+
@builder.get_object("root_adj")
|
143
|
+
end
|
144
|
+
|
145
|
+
#Buttons
|
146
|
+
def main_tool_1
|
147
|
+
@builder.get_object("main_tool_1")
|
148
|
+
end
|
149
|
+
def main_tool_2
|
150
|
+
@builder.get_object("main_tool_2")
|
151
|
+
end
|
152
|
+
def main_tool_3
|
153
|
+
@builder.get_object("main_tool_3")
|
154
|
+
end
|
155
|
+
def main_tool_4
|
156
|
+
@builder.get_object("main_tool_4")
|
157
|
+
end
|
158
|
+
def path_builder
|
159
|
+
@builder.get_object("path_builder")
|
160
|
+
end
|
161
|
+
def prop_mod_button
|
162
|
+
@builder.get_object("prop_mod_button")
|
163
|
+
end
|
164
|
+
def play
|
165
|
+
@builder.get_object("play")
|
166
|
+
end
|
167
|
+
def stop
|
168
|
+
@builder.get_object("stop")
|
169
|
+
end
|
170
|
+
def tempo
|
171
|
+
@builder.get_object("tempo")
|
172
|
+
end
|
173
|
+
def root_select
|
174
|
+
@builder.get_object("root_select")
|
175
|
+
end
|
176
|
+
def file_operation
|
177
|
+
@builder.get_object("file_operation")
|
178
|
+
end
|
179
|
+
def file_cancel
|
180
|
+
@builder.get_object("file_cancel")
|
181
|
+
end
|
182
|
+
def confirmer_confirm
|
183
|
+
@builder.get_object("confirmer_confirm")
|
184
|
+
end
|
185
|
+
def confirmer_cancel
|
186
|
+
@builder.get_object("confirmer_cancel")
|
187
|
+
end
|
188
|
+
|
189
|
+
#Button Areas
|
190
|
+
def logic_controls
|
191
|
+
@builder.get_object("logic_controls")
|
192
|
+
end
|
193
|
+
|
194
|
+
#Text Areas
|
195
|
+
def tool_descrip
|
196
|
+
@builder.get_object("tool_descrip")
|
197
|
+
end
|
198
|
+
def status_area
|
199
|
+
@builder.get_object("status_area")
|
200
|
+
end
|
201
|
+
def prop_mod
|
202
|
+
@builder.get_object("prop_mod")
|
203
|
+
end
|
204
|
+
def t_sig
|
205
|
+
@builder.get_object("t_sig")
|
206
|
+
end
|
207
|
+
def file_name
|
208
|
+
@builder.get_object("file_name")
|
209
|
+
end
|
210
|
+
|
211
|
+
#Labels
|
212
|
+
def perf_label
|
213
|
+
@builder.get_object("perf_label")
|
214
|
+
end
|
215
|
+
def tool_label
|
216
|
+
@builder.get_object("tool_label")
|
217
|
+
end
|
218
|
+
def tempo_label
|
219
|
+
@builder.get_object("tempo_label")
|
220
|
+
end
|
221
|
+
def property_label
|
222
|
+
@builder.get_object("property_label")
|
223
|
+
end
|
224
|
+
def modify_label
|
225
|
+
@builder.get_object("modify_label")
|
226
|
+
end
|
227
|
+
def t_sig_label
|
228
|
+
@builder.get_object("t_sig_label")
|
229
|
+
end
|
230
|
+
def confirmer_label
|
231
|
+
@builder.get_object("confirmer_label")
|
232
|
+
end
|
233
|
+
def scale_label
|
234
|
+
@builder.get_object("scale_label")
|
235
|
+
end
|
236
|
+
|
237
|
+
#Point Property Tree
|
238
|
+
def prop_list_model
|
239
|
+
@builder.get_object("prop_list_model")
|
240
|
+
end
|
241
|
+
def prop_list_view
|
242
|
+
@builder.get_object("prop_list_view")
|
243
|
+
end
|
244
|
+
def prop_list
|
245
|
+
@builder.get_object("prop_list")
|
246
|
+
end
|
247
|
+
def prop_list_col1_h
|
248
|
+
@builder.get_object("prop_list_col1_h")
|
249
|
+
end
|
250
|
+
def prop_list_col2_h
|
251
|
+
@builder.get_object("prop_list_col2_h")
|
252
|
+
end
|
253
|
+
def prop_list_col1
|
254
|
+
@builder.get_object("prop_list_col1")
|
255
|
+
end
|
256
|
+
def prop_list_col2
|
257
|
+
@builder.get_object("prop_list_col2")
|
258
|
+
end
|
259
|
+
def prop_list_selection
|
260
|
+
@builder.get_object("prop_list_selection")
|
261
|
+
end
|
262
|
+
|
263
|
+
#Scale Selection Combo Box
|
264
|
+
def scale_combo
|
265
|
+
@builder.get_object("scale_combo")
|
266
|
+
end
|
267
|
+
def scale_tree_model
|
268
|
+
@builder.get_object("scale_tree_model")
|
269
|
+
end
|
270
|
+
def scale_display
|
271
|
+
@builder.get_object("scale_display")
|
272
|
+
end
|
273
|
+
|
274
|
+
Pm.in_list.each {|i| @in_device_items << Gtk::ImageMenuItem.new(label: i.name)}
|
275
|
+
@in_device_items.each {|i| input_menu.append(i)}
|
276
|
+
input_menu.show_all
|
277
|
+
|
278
|
+
Pm.out_list.each {|o| @out_device_items << Gtk::ImageMenuItem.new(label: o.name)}
|
279
|
+
@out_device_items.each {|o| output_menu.append(o)}
|
280
|
+
output_menu.show_all
|
281
|
+
|
282
|
+
def set_device(id,type)
|
283
|
+
case type
|
284
|
+
when 'i'
|
285
|
+
Pm.sel_in(id)
|
286
|
+
when 'o'
|
287
|
+
Pm.sel_out(id)
|
288
|
+
end
|
289
|
+
regen_status
|
290
|
+
end
|
291
|
+
|
292
|
+
def regen_status
|
293
|
+
status_area.text = "Using: Output[#{Pm.out_list[Pm.out_id].name}] Input[#{Pm.in_list[Pm.in_id].name}]"
|
294
|
+
end
|
295
|
+
|
296
|
+
#Set up accelerators (keyboard shortcuts)
|
297
|
+
@menu_commands = Gtk::AccelGroup.new
|
298
|
+
@canvas_commands = Gtk::AccelGroup.new
|
299
|
+
midinous.add_accel_group(@menu_commands)
|
300
|
+
midinous.add_accel_group(@canvas_commands)
|
301
|
+
|
302
|
+
scale_cat_1 = scale_tree_model.append(nil)
|
303
|
+
scale_cat_1_sub_01 = scale_tree_model.append(scale_cat_1)
|
304
|
+
scale_cat_1_sub_02 = scale_tree_model.append(scale_cat_1)
|
305
|
+
scale_cat_1_sub_03 = scale_tree_model.append(scale_cat_1)
|
306
|
+
scale_cat_1_sub_04 = scale_tree_model.append(scale_cat_1)
|
307
|
+
scale_cat_1_sub_05 = scale_tree_model.append(scale_cat_1)
|
308
|
+
scale_cat_1_sub_06 = scale_tree_model.append(scale_cat_1)
|
309
|
+
scale_cat_2 = scale_tree_model.append(nil)
|
310
|
+
scale_cat_2_sub_01 = scale_tree_model.append(scale_cat_2)
|
311
|
+
scale_cat_2_sub_02 = scale_tree_model.append(scale_cat_2)
|
312
|
+
scale_cat_2_sub_03 = scale_tree_model.append(scale_cat_2)
|
313
|
+
scale_cat_2_sub_04 = scale_tree_model.append(scale_cat_2)
|
314
|
+
scale_cat_2_sub_05 = scale_tree_model.append(scale_cat_2)
|
315
|
+
scale_cat_2_sub_06 = scale_tree_model.append(scale_cat_2)
|
316
|
+
scale_cat_2_sub_07 = scale_tree_model.append(scale_cat_2)
|
317
|
+
scale_cat_2_sub_08 = scale_tree_model.append(scale_cat_2)
|
318
|
+
scale_cat_2_sub_09 = scale_tree_model.append(scale_cat_2)
|
319
|
+
scale_cat_3 = scale_tree_model.append(nil)
|
320
|
+
scale_cat_3_sub_01 = scale_tree_model.append(scale_cat_3)
|
321
|
+
scale_cat_3_sub_02 = scale_tree_model.append(scale_cat_3)
|
322
|
+
scale_cat_3_sub_03 = scale_tree_model.append(scale_cat_3)
|
323
|
+
scale_cat_3_sub_04 = scale_tree_model.append(scale_cat_3)
|
324
|
+
scale_cat_3_sub_05 = scale_tree_model.append(scale_cat_3)
|
325
|
+
scale_cat_3_sub_06 = scale_tree_model.append(scale_cat_3)
|
326
|
+
scale_cat_4 = scale_tree_model.append(nil)
|
327
|
+
scale_cat_4_sub_01 = scale_tree_model.append(scale_cat_4)
|
328
|
+
scale_cat_4_sub_02 = scale_tree_model.append(scale_cat_4)
|
329
|
+
scale_cat_4_sub_03 = scale_tree_model.append(scale_cat_4)
|
330
|
+
scale_cat_4_sub_04 = scale_tree_model.append(scale_cat_4)
|
331
|
+
scale_cat_4_sub_05 = scale_tree_model.append(scale_cat_4)
|
332
|
+
scale_cat_4_sub_06 = scale_tree_model.append(scale_cat_4)
|
333
|
+
scale_cat_5 = scale_tree_model.append(nil)
|
334
|
+
scale_cat_5_sub_01 = scale_tree_model.append(scale_cat_5)
|
335
|
+
scale_cat_5_sub_02 = scale_tree_model.append(scale_cat_5)
|
336
|
+
scale_cat_5_sub_03 = scale_tree_model.append(scale_cat_5)
|
337
|
+
scale_cat_5_sub_04 = scale_tree_model.append(scale_cat_5)
|
338
|
+
scale_cat_5_sub_05 = scale_tree_model.append(scale_cat_5)
|
339
|
+
|
340
|
+
scale_cat_1 [0] = "Pentatonic"
|
341
|
+
scale_cat_1_sub_01[0] = "Hirajoshi"
|
342
|
+
scale_cat_1_sub_02[0] = "Insen"
|
343
|
+
scale_cat_1_sub_03[0] = "Iwato"
|
344
|
+
scale_cat_1_sub_04[0] = "Pentatonic Major"
|
345
|
+
scale_cat_1_sub_05[0] = "Pentatonic Minor"
|
346
|
+
scale_cat_1_sub_06[0] = "Two Semitone Tritone"
|
347
|
+
scale_cat_2 [0] = "Traditional"
|
348
|
+
scale_cat_2_sub_01[0] = "Aeolian"
|
349
|
+
scale_cat_2_sub_02[0] = "Dorian"
|
350
|
+
scale_cat_2_sub_03[0] = "Harmonic Major"
|
351
|
+
scale_cat_2_sub_04[0] = "Harmonic Minor"
|
352
|
+
scale_cat_2_sub_05[0] = "Ionian"
|
353
|
+
scale_cat_2_sub_06[0] = "Locrian"
|
354
|
+
scale_cat_2_sub_07[0] = "Lydian"
|
355
|
+
scale_cat_2_sub_08[0] = "Mixolydian"
|
356
|
+
scale_cat_2_sub_09[0] = "Phrygian"
|
357
|
+
scale_cat_3 [0] = "Modified Traditional"
|
358
|
+
scale_cat_3_sub_01[0] = "Altered"
|
359
|
+
scale_cat_3_sub_02[0] = "Half Diminished"
|
360
|
+
scale_cat_3_sub_03[0] = "Locrian Major"
|
361
|
+
scale_cat_3_sub_04[0] = "Lydian Augmented"
|
362
|
+
scale_cat_3_sub_05[0] = "Melodic Minor"
|
363
|
+
scale_cat_3_sub_06[0] = "Ukrainian Dorian"
|
364
|
+
scale_cat_4 [0] = "Exotic"
|
365
|
+
scale_cat_4_sub_01[0] = "Augmented"
|
366
|
+
scale_cat_4_sub_02[0] = "Blues"
|
367
|
+
scale_cat_4_sub_03[0] = "Flamenco"
|
368
|
+
scale_cat_4_sub_04[0] = "Hungarian"
|
369
|
+
scale_cat_4_sub_05[0] = "Persian"
|
370
|
+
scale_cat_4_sub_06[0] = "Prometheus"
|
371
|
+
scale_cat_5 [0] = "Mathematical"
|
372
|
+
scale_cat_5_sub_01[0] = "Chromatic"
|
373
|
+
scale_cat_5_sub_02[0] = "Octatonic Whole"
|
374
|
+
scale_cat_5_sub_03[0] = "Octatonic Half"
|
375
|
+
scale_cat_5_sub_04[0] = "Tritone"
|
376
|
+
scale_cat_5_sub_05[0] = "Whole Tone"
|
377
|
+
|
378
|
+
@scale_iters << scale_cat_1_sub_01
|
379
|
+
@scale_iters << scale_cat_1_sub_02
|
380
|
+
@scale_iters << scale_cat_1_sub_03
|
381
|
+
@scale_iters << scale_cat_1_sub_04
|
382
|
+
@scale_iters << scale_cat_1_sub_05
|
383
|
+
@scale_iters << scale_cat_1_sub_06
|
384
|
+
@scale_iters << scale_cat_2_sub_01
|
385
|
+
@scale_iters << scale_cat_2_sub_02
|
386
|
+
@scale_iters << scale_cat_2_sub_03
|
387
|
+
@scale_iters << scale_cat_2_sub_04
|
388
|
+
@scale_iters << scale_cat_2_sub_05
|
389
|
+
@scale_iters << scale_cat_2_sub_06
|
390
|
+
@scale_iters << scale_cat_2_sub_07
|
391
|
+
@scale_iters << scale_cat_2_sub_08
|
392
|
+
@scale_iters << scale_cat_2_sub_09
|
393
|
+
@scale_iters << scale_cat_3_sub_01
|
394
|
+
@scale_iters << scale_cat_3_sub_02
|
395
|
+
@scale_iters << scale_cat_3_sub_03
|
396
|
+
@scale_iters << scale_cat_3_sub_04
|
397
|
+
@scale_iters << scale_cat_3_sub_05
|
398
|
+
@scale_iters << scale_cat_3_sub_06
|
399
|
+
@scale_iters << scale_cat_4_sub_01
|
400
|
+
@scale_iters << scale_cat_4_sub_02
|
401
|
+
@scale_iters << scale_cat_4_sub_03
|
402
|
+
@scale_iters << scale_cat_4_sub_04
|
403
|
+
@scale_iters << scale_cat_4_sub_05
|
404
|
+
@scale_iters << scale_cat_4_sub_06
|
405
|
+
@scale_iters << scale_cat_5_sub_01
|
406
|
+
@scale_iters << scale_cat_5_sub_02
|
407
|
+
@scale_iters << scale_cat_5_sub_03
|
408
|
+
@scale_iters << scale_cat_5_sub_04
|
409
|
+
@scale_iters << scale_cat_5_sub_05
|
410
|
+
|
411
|
+
scale_combo.active = 4
|
412
|
+
scale_combo.active_iter = scale_cat_5_sub_01
|
413
|
+
|
414
|
+
#Initialize the elements of the screen
|
415
|
+
midinous.add_events("key-press-mask")
|
416
|
+
canvas.add_events("button-press-mask")
|
417
|
+
canvas.add_events("button-release-mask")
|
418
|
+
canvas.add_events("pointer-motion-mask")
|
419
|
+
prop_mod.add_events("key-press-mask")
|
420
|
+
|
421
|
+
path_builder.sensitive = false
|
422
|
+
prop_mod_button.sensitive = false
|
423
|
+
stop.sensitive = false
|
424
|
+
|
425
|
+
tool_descrip.text = "Select"
|
426
|
+
t_sig.text = "4/4"
|
427
|
+
|
428
|
+
perf_label.markup = "<b>#{perf_label.text}</b>"
|
429
|
+
tempo_label.markup = "<b>#{tempo_label.text}</b>"
|
430
|
+
tool_label.markup = "<b>#{tool_label.text}</b>"
|
431
|
+
property_label.markup = "<b>#{property_label.text}</b>"
|
432
|
+
modify_label.markup = "<b>#{modify_label.text}</b>"
|
433
|
+
t_sig_label.markup = "<b>#{t_sig_label.text}</b>"
|
434
|
+
scale_label.markup = "<b>#{scale_label.text}</b>"
|
435
|
+
|
436
|
+
regen_status
|
437
|
+
|
438
|
+
#canvas.add_events(Gdk::EventMask::BUTTON_PRESS_MASK.nick) #This points to a nickname, basically a string like "button-press-mask" in this case
|
439
|
+
|
440
|
+
#Accel groups, parameter 2 is the modifier
|
441
|
+
# 0 - no modifier
|
442
|
+
# 1 - shift
|
443
|
+
# 2 - no modifier?
|
444
|
+
# 3 - shift again?
|
445
|
+
# 4 - Cntl
|
446
|
+
# 5 - Cntl+Shift
|
447
|
+
|
448
|
+
file_chooser.filter = Gtk::FileFilter.new
|
449
|
+
file_chooser.filter.add_pattern("*.nous")
|
450
|
+
file_chooser.filter.name = "nous file filter"
|
451
|
+
end
|
452
|
+
def confirm(type)
|
453
|
+
case type
|
454
|
+
when "new"
|
455
|
+
@current_window = "new_confirm"
|
456
|
+
confirmer_confirm.label = "Create New"
|
457
|
+
confirmer_label.markup = "<b> There are unsaved changes.</b> \n Do you wish to proceed? "
|
458
|
+
confirmer_cancel.visible = true
|
459
|
+
when "quit"
|
460
|
+
@current_window = "quit_confirm"
|
461
|
+
confirmer_confirm.label = "Quit"
|
462
|
+
confirmer_cancel.visible = true
|
463
|
+
confirmer_label.markup = "<b> There are unsaved changes.</b> \n Do you wish to proceed? "
|
464
|
+
when "path_warning"
|
465
|
+
@current_window = "path_warning"
|
466
|
+
confirmer_confirm.label = "OK"
|
467
|
+
confirmer_cancel.visible = false
|
468
|
+
confirmer_label.markup = "<b> WARNING:</b> Live composition detected. \n This may have affected round-robin point starting paths. "
|
469
|
+
end
|
470
|
+
confirmer.visible = true
|
471
|
+
end
|
472
|
+
def file_input_check(type)
|
473
|
+
case type
|
474
|
+
when "chooser"
|
475
|
+
unless UI::file_chooser.uri == nil
|
476
|
+
UI::file_name.text = UI::file_chooser.uri.split("/").last
|
477
|
+
else
|
478
|
+
UI::file_name.text = ""
|
479
|
+
end
|
480
|
+
when "name"
|
481
|
+
unless UI::file_name.text != "" ||
|
482
|
+
UI::file_chooser.uri != nil ||
|
483
|
+
UI::file_name.text.count(".") > 1
|
484
|
+
then
|
485
|
+
UI::file_operation.sensitive = false
|
486
|
+
else UI::file_operation.sensitive = true
|
487
|
+
end
|
488
|
+
end
|
489
|
+
end
|
490
|
+
def file_oper(type)
|
491
|
+
case type
|
492
|
+
when "open"
|
493
|
+
@current_window = "file_open"
|
494
|
+
file_chooser.title = "Open"
|
495
|
+
file_operation.label = "Open"
|
496
|
+
file_chooser.visible = true
|
497
|
+
file_name.editable = false
|
498
|
+
when "save"
|
499
|
+
@current_window = "file_save"
|
500
|
+
if @current_file == nil #If the working file does not exist yet
|
501
|
+
file_chooser.title = "Save As"
|
502
|
+
file_operation.label = "Save As"
|
503
|
+
file_name.editable = true
|
504
|
+
file_chooser.visible = true
|
505
|
+
else
|
506
|
+
save_operation #Resave the file if @current_file already exists
|
507
|
+
end
|
508
|
+
when "saveas"
|
509
|
+
@current_window = "file_save"
|
510
|
+
#If the working file does not exist yet, suggest a name
|
511
|
+
file_name.text = @current_file.split("\\").last unless @current_file == nil
|
512
|
+
file_chooser.title = "Save As"
|
513
|
+
file_operation.label = "Save As"
|
514
|
+
file_name.editable = true
|
515
|
+
file_chooser.visible = true
|
516
|
+
end
|
517
|
+
end
|
518
|
+
def confirm_act(choice)
|
519
|
+
if choice == "yes"
|
520
|
+
case @current_window
|
521
|
+
when "new_confirm"
|
522
|
+
CC.nouspoints = []
|
523
|
+
file_name.text = ""
|
524
|
+
CC.tempo = 120
|
525
|
+
CC.scale = "Chromatic"
|
526
|
+
CC.root_note = 60
|
527
|
+
CC.beats = 4
|
528
|
+
CC.beat_note = 4
|
529
|
+
|
530
|
+
CC.set_tempo(CC.tempo)
|
531
|
+
CC.set_scale(CC.scale,CC.root_note)
|
532
|
+
CC.canvas_grid_change(nil)
|
533
|
+
tempo_adj.value = CC.tempo
|
534
|
+
@scale_iters.each {|s| scale_combo.active_iter = s if s[0] == CC.scale}
|
535
|
+
root_adj.value = CC.root_note
|
536
|
+
@current_file = nil
|
537
|
+
midinous.title = "Midinous"
|
538
|
+
when "quit_confirm"
|
539
|
+
Gtk.main_quit
|
540
|
+
end
|
541
|
+
end
|
542
|
+
confirmer.visible = false
|
543
|
+
canvas.queue_draw
|
544
|
+
end
|
545
|
+
def file_oper_act(choice)
|
546
|
+
if choice == "yes"
|
547
|
+
case @current_window
|
548
|
+
when "file_open"
|
549
|
+
#Remove current points and load points from file
|
550
|
+
load_operation
|
551
|
+
when "file_save"
|
552
|
+
#Save nouspoints to a new, or existing file, window only if new
|
553
|
+
save_operation
|
554
|
+
end
|
555
|
+
end
|
556
|
+
file_chooser.visible = false
|
557
|
+
canvas.queue_draw
|
558
|
+
end
|
559
|
+
|
560
|
+
def save_operation
|
561
|
+
|
562
|
+
unless file_name.text[-5..-1] == ".nous"
|
563
|
+
@current_file = "#{file_chooser.current_folder_uri}/#{file_name.text}.nous"
|
564
|
+
|
565
|
+
else @current_file = "#{file_chooser.current_folder_uri}/#{file_name.text}"
|
566
|
+
end
|
567
|
+
|
568
|
+
operator = @current_file.sub("file:///","")
|
569
|
+
operator = operator.gsub("/","\\")
|
570
|
+
|
571
|
+
IO.binwrite(operator, "")
|
572
|
+
save = File.open(operator, "a")
|
573
|
+
issued_id = 0
|
574
|
+
CC.nouspoints.each do |n|
|
575
|
+
n.save_id = issued_id
|
576
|
+
issued_id += 1
|
577
|
+
end
|
578
|
+
CC.nouspoints.each do |n|
|
579
|
+
n.write_props(save)
|
580
|
+
save.write("\n")
|
581
|
+
end
|
582
|
+
save.write("#{CC.tempo}<~>")
|
583
|
+
save.write("#{CC.scale}<~>")
|
584
|
+
save.write("#{CC.root_note}<~>")
|
585
|
+
save.write("#{CC.beats}<~>")
|
586
|
+
save.write("#{CC.beat_note}")
|
587
|
+
midinous.title = "Midinous - #{operator}"
|
588
|
+
save.close
|
589
|
+
end
|
590
|
+
def load_operation
|
591
|
+
CC.canvas_stop
|
592
|
+
CC.nouspoints = []
|
593
|
+
@current_file = file_chooser.uri
|
594
|
+
operator = @current_file.sub("file:///","")
|
595
|
+
operator = operator.gsub("/","\\")
|
596
|
+
|
597
|
+
load = IO.binread(operator)
|
598
|
+
load = load.gsub("\r","")
|
599
|
+
load = load.split("\n")
|
600
|
+
load[0..-2].each do |point_line|
|
601
|
+
point_line = point_line.split("<~>")
|
602
|
+
CC.nouspoints << NousPoint.new(eval(point_line[1]),point_line[0].to_i)
|
603
|
+
end
|
604
|
+
CC.nouspoints.each do |n|
|
605
|
+
load.each do |point_line|
|
606
|
+
point_line = point_line.split("<~>")
|
607
|
+
if point_line[0].to_i == n.save_id
|
608
|
+
if point_line[2].match(/^([+]|-)[0-9]{1,2}$/)
|
609
|
+
n.note = point_line[2]
|
610
|
+
n.use_rel = true
|
611
|
+
elsif (point_line[2].to_i >= 0 &&
|
612
|
+
point_line[2].to_i <= 127 &&
|
613
|
+
!(point_line[2].include?("+") || point_line[2].include?("-")))
|
614
|
+
then
|
615
|
+
n.note = point_line[2].to_i
|
616
|
+
end
|
617
|
+
n.velocity = point_line[3].to_i
|
618
|
+
n.channel = point_line[4].to_i
|
619
|
+
n.duration = point_line[5].to_i
|
620
|
+
n.set_default_color(hex_to_color(point_line[6]))
|
621
|
+
n.repeat = point_line[7].to_i
|
622
|
+
n.play_modes = eval(point_line[8])
|
623
|
+
n.traveler_start = eval(point_line[9])
|
624
|
+
n.use_rel = eval(point_line[10])
|
625
|
+
n.path_mode = point_line[11]
|
626
|
+
n.path_to_rels = eval(point_line[12])
|
627
|
+
n.path_from_rels = eval(point_line[13])
|
628
|
+
n.path_to_rels.each {|ptr| n.path_to << CC.nouspoints.find {|f| ptr == f.save_id}}
|
629
|
+
n.path_from_rels.each {|pfr| n.path_from << CC.nouspoints.find {|f| pfr == f.save_id}}
|
630
|
+
end
|
631
|
+
end
|
632
|
+
end
|
633
|
+
load_last = load.last.split("<~>")
|
634
|
+
CC.tempo = load_last[0].to_f
|
635
|
+
CC.scale = load_last[1]
|
636
|
+
CC.root_note = load_last[2].to_i
|
637
|
+
CC.beats = load_last[3].to_i
|
638
|
+
CC.beat_note = load_last[4].to_i
|
639
|
+
|
640
|
+
CC.set_tempo(CC.tempo)
|
641
|
+
CC.set_scale(CC.scale,CC.root_note)
|
642
|
+
CC.canvas_grid_change(nil)
|
643
|
+
tempo_adj.value = CC.tempo
|
644
|
+
@scale_iters.each {|s| scale_combo.active_iter = s if s[0] == CC.scale}
|
645
|
+
root_adj.value = CC.root_note
|
646
|
+
|
647
|
+
midinous.title = "Midinous - #{operator}"
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
class Tool
|
652
|
+
attr_reader :tool_id
|
653
|
+
def initialize
|
654
|
+
@tool_id = 1
|
655
|
+
end
|
656
|
+
def set_tool(id)
|
657
|
+
@tool_id = id
|
658
|
+
unless @tool_id == 4
|
659
|
+
UI::path_builder.sensitive = false
|
660
|
+
end
|
661
|
+
case
|
662
|
+
when @tool_id == 1
|
663
|
+
UI::main_tool_1.active = true
|
664
|
+
UI::tool_descrip.text = "Select"
|
665
|
+
UI::canvas.queue_draw
|
666
|
+
when @tool_id == 2
|
667
|
+
UI::main_tool_2.active = true
|
668
|
+
UI::tool_descrip.text = "Place"
|
669
|
+
UI::canvas.queue_draw
|
670
|
+
when @tool_id == 3
|
671
|
+
UI::main_tool_3.active = true
|
672
|
+
UI::tool_descrip.text = "Move"
|
673
|
+
UI::canvas.queue_draw
|
674
|
+
when @tool_id == 4
|
675
|
+
UI::main_tool_4.active = true
|
676
|
+
UI::path_builder.sensitive = true
|
677
|
+
UI::tool_descrip.text = "Path"
|
678
|
+
UI::canvas.queue_draw
|
679
|
+
end
|
680
|
+
end
|
681
|
+
|
682
|
+
end
|
683
|
+
|
684
|
+
UI = UI_Elements.new() #Create a new UI_Elements object
|
685
|
+
UI::build_ui
|
686
|
+
Active_Tool = Tool.new
|
data/lib/midinous.rb
ADDED
@@ -0,0 +1,21 @@
|
|
1
|
+
# Copyright (C) 2019 James "Nornec" Ratliff
|
2
|
+
#
|
3
|
+
# Midinous is free software: you can redistribute it and/or modify
|
4
|
+
# it under the terms of the GNU General Public License as published by
|
5
|
+
# the Free Software Foundation, either version 3 of the License, or
|
6
|
+
# (at your option) any later version.
|
7
|
+
#
|
8
|
+
# Midinous is distributed in the hope that it will be useful,
|
9
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
10
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
11
|
+
# GNU General Public License for more details.
|
12
|
+
#
|
13
|
+
# You should have received a copy of the GNU General Public License
|
14
|
+
# along with Midinous. If not, see <https://www.gnu.org/licenses/>.
|
15
|
+
|
16
|
+
require "unimidi"
|
17
|
+
require "midi-eye"
|
18
|
+
require "gtk3"
|
19
|
+
require "midinous/init"
|
20
|
+
|
21
|
+
Gtk.main
|