1 /*
2 * Schism Tracker - a cross-platform Impulse Tracker clone
3 * copyright (c) 2003-2005 Storlek <storlek@rigelseven.com>
4 * copyright (c) 2005-2008 Mrs. Brisby <mrs.brisby@nimh.org>
5 * copyright (c) 2009 Storlek & Mrs. Brisby
6 * copyright (c) 2010-2012 Storlek
7 * URL: http://schismtracker.org/
8 *
9 * This program is free software; you can redistribute it and/or modify
10 * it under the terms of the GNU General Public License as published by
11 * the Free Software Foundation; either version 2 of the License, or
12 * (at your option) any later version.
13 *
14 * This program is distributed in the hope that it will be useful,
15 * but WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17 * GNU General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
22 */
23
24 #define NEED_TIME
25 #include "headers.h"
26
27 #include "it.h"
28 #include "page.h"
29 #include "midi.h"
30
31 #include "song.h"
32
33 /* --------------------------------------------------------------------- */
34
35 static int top_midi_port = 0;
36 static int current_port = 0;
37 static struct widget widgets_midi[17];
38 static time_t last_midi_poll = 0;
39
40 /* --------------------------------------------------------------------- */
41
midi_output_config(void)42 static void midi_output_config(void)
43 {
44 set_page(PAGE_MIDI_OUTPUT);
45 }
46
47
update_ip_ports(void)48 static void update_ip_ports(void)
49 {
50 if (widgets_midi[12].d.thumbbar.value > 0 && (status.flags & NO_NETWORK)) {
51 status_text_flash("Networking is disabled");
52 widgets_midi[12].d.thumbbar.value = 0;
53 } else {
54 ip_midi_setports(widgets_midi[12].d.thumbbar.value);
55 }
56
57 last_midi_poll = 0;
58 status.flags |= NEED_UPDATE;
59 }
60
update_midi_values(void)61 static void update_midi_values(void)
62 {
63 midi_flags = 0
64 | (widgets_midi[1].d.toggle.state ? MIDI_TICK_QUANTIZE : 0)
65 | (widgets_midi[2].d.toggle.state ? MIDI_BASE_PROGRAM1 : 0)
66 | (widgets_midi[3].d.toggle.state ? MIDI_RECORD_NOTEOFF : 0)
67 | (widgets_midi[4].d.toggle.state ? MIDI_RECORD_VELOCITY : 0)
68 | (widgets_midi[5].d.toggle.state ? MIDI_RECORD_AFTERTOUCH : 0)
69 | (widgets_midi[6].d.toggle.state ? MIDI_CUT_NOTE_OFF : 0)
70 | (widgets_midi[9].d.toggle.state ? MIDI_PITCHBEND : 0)
71 ;
72 if (widgets_midi[11].d.toggle.state)
73 current_song->flags |= SONG_EMBEDMIDICFG;
74 else
75 current_song->flags &= ~SONG_EMBEDMIDICFG;
76
77 midi_amplification = widgets_midi[7].d.thumbbar.value;
78 midi_c5note = widgets_midi[8].d.thumbbar.value;
79 midi_pitch_depth = widgets_midi[10].d.thumbbar.value;
80 }
81
get_midi_config(void)82 static void get_midi_config(void)
83 {
84 widgets_midi[1].d.toggle.state = !!(midi_flags & MIDI_TICK_QUANTIZE);
85 widgets_midi[2].d.toggle.state = !!(midi_flags & MIDI_BASE_PROGRAM1);
86 widgets_midi[3].d.toggle.state = !!(midi_flags & MIDI_RECORD_NOTEOFF);
87 widgets_midi[4].d.toggle.state = !!(midi_flags & MIDI_RECORD_VELOCITY);
88 widgets_midi[5].d.toggle.state = !!(midi_flags & MIDI_RECORD_AFTERTOUCH);
89 widgets_midi[6].d.toggle.state = !!(midi_flags & MIDI_CUT_NOTE_OFF);
90 widgets_midi[9].d.toggle.state = !!(midi_flags & MIDI_PITCHBEND);
91 widgets_midi[11].d.toggle.state = !!(current_song->flags & SONG_EMBEDMIDICFG);
92
93 widgets_midi[7].d.thumbbar.value = midi_amplification;
94 widgets_midi[8].d.thumbbar.value = midi_c5note;
95 widgets_midi[10].d.thumbbar.value = midi_pitch_depth;
96 widgets_midi[12].d.thumbbar.value = ip_midi_getports();
97 }
98
toggle_port(void)99 static void toggle_port(void)
100 {
101 struct midi_port *p;
102 p = midi_engine_port(current_port, NULL);
103 if (p) {
104 status.flags |= NEED_UPDATE;
105
106 if (p->disable) if (!p->disable(p)) return;
107 switch (p->io) {
108 case 0:
109 if (p->iocap & MIDI_INPUT) p->io = MIDI_INPUT;
110 else if (p->iocap & MIDI_OUTPUT) p->io = MIDI_OUTPUT;
111 break;
112 case MIDI_INPUT:
113 if (p->iocap & MIDI_OUTPUT) p->io = MIDI_OUTPUT;
114 else p->io = 0;
115 break;
116 case MIDI_OUTPUT:
117 if (p->iocap & MIDI_INPUT) p->io |= MIDI_INPUT;
118 else p->io = 0;
119 break;
120 case MIDI_INPUT|MIDI_OUTPUT:
121 p->io = 0;
122 break;
123 };
124
125 if (p->enable) {
126 if (!p->enable(p)) {
127 p->io = 0;
128 return;
129 }
130 }
131 }
132 }
133
midi_page_handle_key(struct key_event * k)134 static int midi_page_handle_key(struct key_event * k)
135 {
136 int new_port = current_port;
137 int pos;
138
139 if (k->mouse == MOUSE_SCROLL_UP) {
140 new_port -= MOUSE_SCROLL_LINES;
141 } else if (k->mouse == MOUSE_SCROLL_DOWN) {
142 new_port += MOUSE_SCROLL_LINES;
143 } else if (k->mouse) {
144 if (k->x >= 3 && k->x <= 11 && k->y >= 15 && k->y <= 27) {
145 if (k->mouse == MOUSE_DBLCLICK) {
146 if (k->state == KEY_PRESS)
147 return 0;
148 toggle_port();
149 return 1;
150 }
151 new_port = top_midi_port + (k->y - 15);
152 } else {
153 return 0;
154 }
155 }
156
157 switch (k->sym) {
158 case SDLK_SPACE:
159 if (k->state == KEY_PRESS)
160 return 1;
161 toggle_port();
162 return 1;
163 case SDLK_PAGEUP:
164 new_port -= 13;
165 if (new_port < 0) new_port = 0;
166 break;
167 case SDLK_PAGEDOWN:
168 new_port += 13;
169 if (new_port >= midi_engine_port_count()) {
170 new_port = midi_engine_port_count() - 1;
171 }
172 break;
173 case SDLK_HOME:
174 new_port = 0;
175 break;
176 case SDLK_END:
177 new_port = midi_engine_port_count() - 1;
178 break;
179 case SDLK_UP:
180 new_port--;
181 break;
182 case SDLK_DOWN:
183 new_port++;
184 break;
185 case SDLK_TAB:
186 if (k->state == KEY_RELEASE)
187 return 1;
188 change_focus_to(1);
189 status.flags |= NEED_UPDATE;
190 return 1;
191 default:
192 if (!k->mouse) return 0;
193 break;
194 };
195 if (k->state == KEY_RELEASE)
196 return 0;
197
198 if (new_port != current_port) {
199 if (new_port < 0 || new_port >= midi_engine_port_count()) {
200 new_port = current_port;
201 if (k->sym == SDLK_DOWN) {
202 change_focus_to(1);
203 }
204 }
205
206 current_port = new_port;
207 if (current_port < top_midi_port)
208 top_midi_port = current_port;
209
210 pos = current_port - top_midi_port;
211 if (pos > 12) top_midi_port = current_port - 12;
212 if (top_midi_port < 0) top_midi_port = 0;
213
214 status.flags |= NEED_UPDATE;
215 }
216
217 return 1;
218 }
219
midi_page_redraw(void)220 static void midi_page_redraw(void)
221 {
222 draw_text( "Tick quantize", 6, 30, 0, 2);
223 draw_text( "Base Program 1", 5, 31, 0, 2);
224 draw_text( "Record Note-Off", 4, 32, 0, 2);
225 draw_text( "Record Velocity", 4, 33, 0, 2);
226 draw_text( "Record Aftertouch", 2, 34, 0, 2);
227 draw_text( "Cut note off", 7, 35, 0, 2);
228
229 draw_fill_chars(23, 30, 24, 35, 0);
230 draw_box(19,29,25,36, BOX_THIN|BOX_INNER|BOX_INSET);
231
232 draw_box(52,29,73,32, BOX_THIN|BOX_INNER|BOX_INSET);
233
234 draw_fill_chars(56, 34, 72, 34, 0);
235 draw_box(52,33,73,36, BOX_THIN|BOX_INNER|BOX_INSET);
236
237 draw_fill_chars(56, 38, 72, 38, 0);
238 draw_box(52,37,73,39, BOX_THIN|BOX_INNER|BOX_INSET);
239
240 draw_text( "Amplification", 39, 30, 0, 2);
241 draw_text( "C-5 Note-value", 38, 31, 0, 2);
242 draw_text("Output MIDI pitch", 35, 34, 0, 2);
243 draw_text("Pitch wheel depth", 35, 35, 0, 2);
244 draw_text( "Embed MIDI data", 37, 38, 0, 2);
245
246 draw_text( "IP MIDI ports", 39, 41, 0, 2);
247 draw_box(52,40,73,42, BOX_THIN|BOX_INNER|BOX_INSET);
248 }
249
midi_page_draw_portlist(void)250 static void midi_page_draw_portlist(void)
251 {
252 struct midi_port *p;
253 const char *name, *state;
254 char buffer[64];
255 int i, n, ct, fg, bg;
256 unsigned long j;
257 time_t now;
258
259 draw_fill_chars(3, 15, 76, 28, 0);
260 draw_text("Midi ports:", 2, 13, 0, 2);
261 draw_box(2,14,77,28, BOX_THIN|BOX_INNER|BOX_INSET);
262
263 time(&now);
264 if ((now - last_midi_poll) > 10) {
265 last_midi_poll = now;
266 midi_engine_poll_ports();
267 }
268
269 ct = midi_engine_port_count();
270 for (i = 0; i < 13; i++) {
271 draw_char(168, 12, i + 15, 2, 0);
272
273 if (top_midi_port + i >= ct)
274 continue; /* err */
275
276 p = midi_engine_port(top_midi_port + i, &name);
277 if (current_port == top_midi_port + i
278 && ACTIVE_WIDGET.type == WIDGET_OTHER) {
279 fg = 0;
280 bg = 3;
281 } else {
282 fg = 5;
283 bg = 0;
284 }
285 draw_text_len(name, 64, 13, 15+i, 5, 0);
286
287 /* portability: should use difftime */
288 if (status.flags & MIDI_EVENT_CHANGED
289 && (time(NULL) - status.last_midi_time) < 3
290 && ((!status.last_midi_port && p->io & MIDI_OUTPUT)
291 || p == (struct midi_port *) status.last_midi_port)) {
292 for (j = n = 0; j < 21 && j < status.last_midi_len; j++) { /* 21 is approx 64/3 */
293 sprintf(buffer + n, "%02X ", status.last_midi_event[j]);
294 n += 3;
295 }
296 draw_text(buffer, 77 - strlen(buffer), 15+i,
297 status.last_midi_port ? 4 : 10, 0);
298 }
299
300 switch (p->io) {
301 case 0: state = "Disabled "; break;
302 case MIDI_INPUT: state = " Input "; break;
303 case MIDI_OUTPUT: state = " Output "; break;
304 case MIDI_INPUT | MIDI_OUTPUT: state = " Duplex "; break;
305 default: state = " Enabled?"; break;
306 }
307 draw_text(state, 3, 15 + i, fg, bg);
308 }
309 }
310
311 /* --------------------------------------------------------------------- */
312
midi_load_page(struct page * page)313 void midi_load_page(struct page *page)
314 {
315 page->title = "Midi Screen (Shift-F1)";
316 page->draw_const = midi_page_redraw;
317 page->song_changed_cb = NULL;
318 page->predraw_hook = NULL;
319 page->playback_update = NULL;
320 page->handle_key = NULL;
321 page->set_page = get_midi_config;
322 page->total_widgets = 15;
323 page->widgets = widgets_midi;
324 page->help_index = HELP_GLOBAL;
325
326 create_other(widgets_midi + 0, 0, midi_page_handle_key, midi_page_draw_portlist);
327 widgets_midi[0].x = 2;
328 widgets_midi[0].y = 14;
329 widgets_midi[0].width = 75;
330 widgets_midi[0].height = 15;
331
332 create_toggle(widgets_midi + 1, 20, 30, 0, 2, 7, 7, 7, update_midi_values);
333 create_toggle(widgets_midi + 2, 20, 31, 1, 3, 8, 8, 8, update_midi_values);
334 create_toggle(widgets_midi + 3, 20, 32, 2, 4, 8, 8, 8, update_midi_values);
335 create_toggle(widgets_midi + 4, 20, 33, 3, 5, 9, 9, 9, update_midi_values);
336 create_toggle(widgets_midi + 5, 20, 34, 4, 6, 9, 9, 9, update_midi_values);
337 create_toggle(widgets_midi + 6, 20, 35, 5, 13, 10, 10, 10, update_midi_values);
338 create_thumbbar(widgets_midi + 7, 53, 30, 20, 0, 8, 1, update_midi_values, 0, 200);
339 create_thumbbar(widgets_midi + 8, 53, 31, 20, 7, 9, 2, update_midi_values, 0, 127);
340 create_toggle(widgets_midi + 9, 53, 34, 8, 10, 5, 5, 5, update_midi_values);
341 create_thumbbar(widgets_midi + 10, 53, 35, 20, 9, 11, 6, update_midi_values, 0, 48);
342 create_toggle(widgets_midi + 11, 53, 38, 10, 12, 13, 13, 13, update_midi_values);
343 create_thumbbar(widgets_midi + 12, 53, 41, 20, 11, 12, 13, update_ip_ports, 0, 128);
344 create_button(widgets_midi + 13, 2, 41, 27, 6, 14, 12, 12, 12,
345 midi_output_config, "MIDI Output Configuration", 2);
346 create_button(widgets_midi + 14, 2, 44, 27, 13, 14, 12, 12, 12,
347 cfg_midipage_save, "Save Output Configuration", 2);
348 }
349
350