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