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.
- 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
|