midinous 1.0.0.beta

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,166 @@
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/proc_midi"
19
+ require "midinous/constants"
20
+ require "midinous/logic"
21
+ require "midinous/style/ui"
22
+ require "midinous/canvas"
23
+ require "midinous/key_bindings"
24
+
25
+ class Init_Prog
26
+
27
+ def initialize #Build the user interface, initiate the objects in the program
28
+ UI::canvas.set_size_request(CANVAS_SIZE,CANVAS_SIZE)
29
+ UI::canvas_h_adj.set_upper(CANVAS_SIZE)
30
+ UI::canvas_v_adj.set_upper(CANVAS_SIZE)
31
+ grid_center
32
+ initialize_provider
33
+ apply_style(UI::midinous,@provider)
34
+ apply_style(UI::prop_list_view,@provider)
35
+ apply_style(UI::file_chooser,@provider)
36
+ apply_style(UI::confirmer,@provider)
37
+ end
38
+
39
+ def grid_center #center the grid
40
+ UI::canvas_h_adj.set_value(CANVAS_SIZE/3.1)
41
+ UI::canvas_v_adj.set_value(CANVAS_SIZE/2.4)
42
+ end
43
+
44
+ def apply_style(widget, provider)
45
+ style_context = widget.style_context
46
+ style_context.add_provider(provider, Gtk::StyleProvider::PRIORITY_USER)
47
+ return unless widget.respond_to?(:children)
48
+ widget.children.each do |child|
49
+ apply_style(child, provider)
50
+ end
51
+ end
52
+
53
+ def initialize_provider
54
+ css_file = "#{File.dirname(__FILE__)}/style/midinous_themes.style"
55
+ @provider = Gtk::CssProvider.new
56
+ @provider.load_from_path(css_file)
57
+ end
58
+
59
+ end
60
+
61
+ init = Init_Prog.new
62
+ Times = Time.new
63
+ #init.grid_center # Setting Grid Center here ensures the background always gets drawn first
64
+
65
+ module Event_Router
66
+ extend Key_Bindings
67
+
68
+ #For window keep-alives
69
+ UI::midinous.signal_connect("delete-event") do
70
+ UI.confirm("quit")
71
+ true
72
+ end
73
+ UI::file_chooser.signal_connect("delete-event") do
74
+ UI::file_chooser.visible = false
75
+ true
76
+ end
77
+ UI::confirmer.signal_connect("delete-event") do
78
+ UI::confirmer.visible = false
79
+ true
80
+ end
81
+
82
+ #For key bindings
83
+ UI::midinous.signal_connect("key-press-event") { |obj, event| route_key(event) }
84
+
85
+ #For general events
86
+ UI::tempo.signal_connect("value-changed") { |obj| CC.set_tempo(obj.value) }
87
+ UI::root_select.signal_connect("value-changed") { |obj| CC.set_scale(UI::scale_combo.active_iter[0],obj.value) }
88
+
89
+ #For keys
90
+ UI::main_tool_1.signal_connect("keybinding-event") {Active_Tool.set_tool(1)}
91
+ UI::main_tool_2.signal_connect("keybinding-event") {Active_Tool.set_tool(2)}
92
+ UI::main_tool_3.signal_connect("keybinding-event") {Active_Tool.set_tool(3)}
93
+ UI::main_tool_4.signal_connect("keybinding-event") {Active_Tool.set_tool(4)}
94
+ UI::path_builder.signal_connect("keybinding-event") {CC.canvas_generic("path")}
95
+ UI::prop_mod.signal_connect("changed") {Pl.check_input(UI::prop_mod.text)}
96
+ UI::prop_mod.signal_connect("keybinding-event") {CC.canvas_generic("prop")}
97
+ UI::stop.signal_connect("keybinding-event") {CC.canvas_stop}
98
+ UI::play.signal_connect("keybinding-event") {CC.canvas_play}
99
+
100
+
101
+ #For clicks
102
+ UI::main_tool_1.signal_connect("button-press-event") {Active_Tool.set_tool(1)}
103
+ UI::main_tool_2.signal_connect("button-press-event") {Active_Tool.set_tool(2)}
104
+ UI::main_tool_3.signal_connect("button-press-event") {Active_Tool.set_tool(3)}
105
+ UI::main_tool_4.signal_connect("button-press-event") {Active_Tool.set_tool(4)}
106
+ UI::path_builder.signal_connect("button-press-event") {CC.canvas_generic("path")}
107
+ UI::prop_list_selection.signal_connect("changed") {Pl.prop_list_select(UI::prop_list_selection.selected)}
108
+ UI::prop_mod_button.signal_connect("button-press-event") {CC.canvas_generic("prop")}
109
+ UI::stop.signal_connect("button-press-event") {CC.canvas_stop}
110
+ UI::play.signal_connect("button-press-event") {CC.canvas_play}
111
+ UI::scale_combo.signal_connect("changed") {CC.set_scale(UI::scale_combo.active_iter[0],CC.root_note)}
112
+
113
+ #For menu items
114
+ UI::in_device_items.each_with_index {|i, idx| i.signal_connect("button-press-event") {UI.set_device(idx,"i")}}
115
+ UI::out_device_items.each_with_index {|o, idx| o.signal_connect("button-press-event") {UI.set_device(idx,"o")}}
116
+
117
+ #For file operations
118
+ UI::file_new.signal_connect("button-press-event") {UI.confirm("new")} #Confirm first with a dialog if there are unsaved changes.
119
+ UI::file_open.signal_connect("button-press-event") {UI.file_oper("open")} #Change the label to "Open"
120
+ UI::file_save.signal_connect("button-press-event") {UI.file_oper("save")} #Change the label to "Save", or save automatically if the working file exists.
121
+ UI::file_save_as.signal_connect("button-press-event") {UI.file_oper("saveas")} #Change the label to "Save As"
122
+ UI::file_quit.signal_connect("button-press-event") {UI.confirm("quit")} #Confirm first with a dialog if there are unsaved changes.
123
+
124
+ UI::confirmer_confirm.signal_connect("button-press-event"){UI.confirm_act("yes")}
125
+ UI::confirmer_cancel.signal_connect("button-press-event") {UI.confirm_act("no")}
126
+
127
+ UI::file_operation.signal_connect("button-press-event") {UI.file_oper_act("yes")} #If open, confirm first with a dialog if there are unsaved changes. If save/save as, overwrite confirmation should automatically appear. Otherwise, use confirmer.
128
+ UI::file_cancel.signal_connect("button-press-event") {UI.file_oper_act("no")}
129
+ UI::file_chooser.signal_connect("selection-changed") {UI.file_input_check("chooser")}
130
+ UI::file_name.signal_connect("changed") {UI.file_input_check("name")}
131
+
132
+ #For accelerators
133
+ UI::menu_commands.connect(Gdk::Keyval::KEY_n,4,0) {UI.confirm("new")}
134
+ UI::menu_commands.connect(Gdk::Keyval::KEY_o,4,0) {UI.file_oper("open")}
135
+ UI::menu_commands.connect(Gdk::Keyval::KEY_s,4,0) {UI.file_oper("save")}
136
+ UI::menu_commands.connect(Gdk::Keyval::KEY_s,5,0) {UI.file_oper("saveas")}
137
+ UI::menu_commands.connect(Gdk::Keyval::KEY_q,4,0) {UI.confirm("quit")}
138
+ UI::canvas_commands.connect(Gdk::Keyval::KEY_a,4,0) {Pl.select_all if Active_Tool.tool_id == 1}
139
+ UI::canvas_commands.connect(Gdk::Keyval::KEY_x,4,0) {Pl.copy_points("cut") if Active_Tool.tool_id == 1}
140
+ UI::canvas_commands.connect(Gdk::Keyval::KEY_c,4,0) {Pl.copy_points("copy") if Active_Tool.tool_id == 1}
141
+ UI::canvas_commands.connect(Gdk::Keyval::KEY_v,4,0) {Pl.paste_points if Active_Tool.tool_id == 1}
142
+
143
+ #Canvas Events
144
+ UI::canvas.signal_connect("button-press-event") { |obj, event| CC.canvas_press(event) }
145
+ UI::canvas.signal_connect("motion-notify-event") { |obj, event| CC.canvas_drag(obj,event) }
146
+ UI::canvas.signal_connect("button-release-event") { |obj, event| CC.canvas_release(obj,event) }
147
+ UI::canvas.signal_connect("draw") { |obj, cr| CC.canvas_draw(cr) }
148
+ UI::canvas.signal_connect("delete-selected-event") {CC.canvas_del}
149
+ UI::canvas.signal_connect("beat-up") {CC.canvas_grid_change("+")}
150
+ UI::canvas.signal_connect("beat-dn") {CC.canvas_grid_change("-")}
151
+ UI::canvas.signal_connect("beat-note-up") {CC.canvas_grid_change("++")}
152
+ UI::canvas.signal_connect("beat-note-dn") {CC.canvas_grid_change("--")}
153
+ UI::canvas.signal_connect("travel-event") {CC.canvas_travel}
154
+ UI::canvas.signal_connect("cycle-play-mode-bck") {Pl.play_mode_rotate(-1)}
155
+ UI::canvas.signal_connect("cycle-play-mode-fwd") {Pl.play_mode_rotate(1)}
156
+ UI::canvas.signal_connect("set-start") {Pl.set_start}
157
+ UI::canvas.signal_connect("del-path-to") {Pl.delete_paths_to(CC.nouspoints)}
158
+ UI::canvas.signal_connect("del-path-from") {Pl.delete_paths_from(CC.nouspoints)}
159
+ UI::canvas.signal_connect("set-path-mode-h") {Pl.set_path_mode("horz")}
160
+ UI::canvas.signal_connect("set-path-mode-v") {Pl.set_path_mode("vert")}
161
+ UI::canvas.signal_connect("note-inc-up") {Pl.inc_note(1)}
162
+ UI::canvas.signal_connect("note-inc-dn") {Pl.inc_note(-1)}
163
+ UI::canvas.signal_connect("path-rotate-bck") {Pl.play_mode_rotate_selected("-")}
164
+ UI::canvas.signal_connect("path-rotate-fwd") {Pl.play_mode_rotate_selected("+")}
165
+ end
166
+
@@ -0,0 +1,81 @@
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
+ module Key_Bindings
19
+ def route_key(event)
20
+ #puts event.keyval
21
+ unless !UI::logic_controls.focus? #Key bindings for the main canvas screen
22
+ case event.keyval
23
+ when 113 # Q
24
+ UI::main_tool_1.signal_emit("keybinding-event") if CC.dragging == false
25
+ when 119 # W
26
+ UI::main_tool_2.signal_emit("keybinding-event") if CC.dragging == false
27
+ when 101, 102 # E or F (colemak)
28
+ UI::main_tool_3.signal_emit("keybinding-event") if CC.dragging == false
29
+ when 114, 112 # R or P (colemak)
30
+ UI::main_tool_4.signal_emit("keybinding-event") if CC.dragging == false
31
+ when 65535 # del
32
+ UI::canvas.signal_emit("delete-selected-event")
33
+ when 116 # T
34
+ UI::path_builder.signal_emit("keybinding-event")
35
+ when 93 # ]
36
+ UI::canvas.signal_emit("beat-up")
37
+ when 91 # [
38
+ UI::canvas.signal_emit("beat-dn")
39
+ when 125 # }
40
+ UI::canvas.signal_emit("beat-note-up")
41
+ when 123 # {
42
+ UI::canvas.signal_emit("beat-note-dn")
43
+ when 60
44
+ UI::canvas.signal_emit("cycle-play-mode-bck")
45
+ when 62
46
+ UI::canvas.signal_emit("cycle-play-mode-fwd")
47
+ when 44 # ,
48
+ UI::canvas.signal_emit('path-rotate-bck')
49
+ when 46 # .
50
+ UI::canvas.signal_emit('path-rotate-fwd')
51
+ when 97
52
+ UI::canvas.signal_emit("set-start")
53
+ when 65367 # end
54
+ UI::canvas.signal_emit("del-path-to")
55
+ when 65360 # home
56
+ UI::canvas.signal_emit("del-path-from")
57
+ when 65365 # page up
58
+ UI::canvas.signal_emit("set-path-mode-h")
59
+ when 65366 # page down
60
+ UI::canvas.signal_emit("set-path-mode-v")
61
+ when 65451, 43 # +
62
+ UI::canvas.signal_emit("note-inc-up")
63
+ when 65453, 95 # -
64
+ UI::canvas.signal_emit("note-inc-dn")
65
+ end
66
+ if (event.keyval == 65462 || event.keyval == 32) && UI::play.sensitive? == true
67
+ UI::play.signal_emit("keybinding-event")
68
+ elsif (event.keyval == 65461 || event.keyval == 32) && UI::stop.sensitive? == true
69
+ UI::stop.signal_emit("keybinding-event")
70
+ end
71
+ end
72
+
73
+ unless !UI::prop_mod.focus? #Key bindings for the property modification text entry area
74
+ if event.keyval == 65293 && UI::prop_mod_button.sensitive? == true #Enter key
75
+ UI::prop_mod.signal_emit("keybinding-event")
76
+ end
77
+ end
78
+
79
+ end
80
+
81
+ end
@@ -0,0 +1,165 @@
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
+ module Logic_Controls #various reusable functions useful for checks and math
19
+
20
+ def set_point_speed(tempo,beats,beat_note) #Sets time between each grid point
21
+ point_speed = (tempo/60)*CC.grid_spacing #Grid points that will be hit per second
22
+ return point_speed #(will be a fraction most of the time)
23
+ end
24
+
25
+ def round_to_grid(coord) #rounds a coordinate to the nearest snappable grid point
26
+ coord.map! do |n|
27
+ temp = n % CC.grid_spacing
28
+ n -= temp if temp < (CC.grid_spacing/2)
29
+ n = n-temp+CC.grid_spacing if temp >= (CC.grid_spacing/2)
30
+ n
31
+ end
32
+ return coord
33
+ end
34
+
35
+ def sync_diff(stored_time)
36
+ new_time = Time.now.to_f*1000
37
+ return (CC.ms_per_tick - (new_time - (stored_time + CC.ms_per_tick)))
38
+ end
39
+
40
+ def relative_pos(xd,yd)
41
+ x_sign = nil
42
+ y_sign = nil
43
+ case
44
+ when xd > 0
45
+ x_sign = "+"
46
+ when xd == 0
47
+ x_sign = "0"
48
+ when xd < 0
49
+ x_sign = "-"
50
+ end
51
+ case
52
+ when yd > 0
53
+ y_sign = "+"
54
+ when yd == 0
55
+ y_sign = "0"
56
+ when yd < 0
57
+ y_sign = "-"
58
+ end
59
+
60
+ sign = [x_sign,y_sign]
61
+ case sign
62
+ when ["+","+"]
63
+ return "se"
64
+ when ["+","-"]
65
+ return "ne"
66
+ when ["-","-"]
67
+ return "nw"
68
+ when ["-","+"]
69
+ return "sw"
70
+ when ["+","0"]
71
+ return "e"
72
+ when ["-","0"]
73
+ return "w"
74
+ when ["0","+"]
75
+ return "s"
76
+ when ["0","-"]
77
+ return "n"
78
+ end
79
+ end
80
+
81
+ def draw_chevron(cr,offset,dir,p)
82
+ x = p.x
83
+ y = p.y
84
+ case dir
85
+ when "n"
86
+ cr.move_to(x, y+12+offset)
87
+ cr.line_to(x+5,y+17+offset)
88
+ cr.line_to(x+5,y+21+offset)
89
+ cr.line_to(x, y+16+offset)
90
+ cr.line_to(x-5,y+21+offset)
91
+ cr.line_to(x-5,y+17+offset)
92
+ cr.line_to(x, y+12+offset)
93
+ when "s"
94
+ cr.move_to(x, y-12-offset)
95
+ cr.line_to(x+5,y-17-offset)
96
+ cr.line_to(x+5,y-21-offset)
97
+ cr.line_to(x, y-16-offset)
98
+ cr.line_to(x-5,y-21-offset)
99
+ cr.line_to(x-5,y-17-offset)
100
+ cr.line_to(x, y-12-offset)
101
+ when "e"
102
+ cr.move_to(x-12-offset,y)
103
+ cr.line_to(x-17-offset,y+5)
104
+ cr.line_to(x-21-offset,y+5)
105
+ cr.line_to(x-16-offset,y)
106
+ cr.line_to(x-21-offset,y-5)
107
+ cr.line_to(x-17-offset,y-5)
108
+ cr.line_to(x-12-offset,y)
109
+ when "w"
110
+ cr.move_to(x+12+offset,y)
111
+ cr.line_to(x+17+offset,y+5)
112
+ cr.line_to(x+21+offset,y+5)
113
+ cr.line_to(x+16+offset,y)
114
+ cr.line_to(x+21+offset,y-5)
115
+ cr.line_to(x+17+offset,y-5)
116
+ cr.line_to(x+12+offset,y)
117
+ end
118
+ end
119
+
120
+ def round_num_to_grid(num)
121
+ temp = num % CC.grid_spacing
122
+ num -= temp if temp < (CC.grid_spacing/2)
123
+ num -= n-temp+CC.grid_spacing if temp >= (CC.grid_spacing/2)
124
+ return num
125
+ end
126
+
127
+ def color_to_hex(color)
128
+ c_str = "#"
129
+ color.each do |n|
130
+ n = "%x" % (n*127)
131
+ if n.length < 2
132
+ c_str = "#{c_str}0#{n}"
133
+ else c_str = "#{c_str}#{n}"
134
+ end
135
+ end
136
+ return c_str
137
+ end
138
+
139
+ def hex_to_color(c_hex)
140
+ color = []
141
+ color[0] = ((c_hex[1..2].hex).to_f/127)
142
+ color[1] = ((c_hex[3..4].hex).to_f/127)
143
+ color[2] = ((c_hex[5..6].hex).to_f/127)
144
+ return color
145
+ end
146
+
147
+ def check_bounds(coord,bounds) # returns true if coordinate is colliding with a point bounding box.
148
+ if coord[0].between?(bounds[0],bounds[2]) == true &&
149
+ coord[1].between?(bounds[1],bounds[3]) == true
150
+ return true
151
+ else return false
152
+ end
153
+ end
154
+
155
+ def pos_box(bounds) #turn a coordinate-bounded box with unmatching coordinates into one with positive coordinates
156
+ if bounds[0] > bounds[2] #Flip the array positions if the box is drawn backwards in any direction.
157
+ bounds[0], bounds[2] = bounds[2], bounds[0]
158
+ end
159
+ if bounds[1] > bounds[3]
160
+ bounds[1], bounds[3] = bounds[3], bounds[1]
161
+ end
162
+ return bounds
163
+ end
164
+
165
+ end