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 #include "headers.h"
25 
26 #include "it.h"
27 #include "song.h"
28 #include "pattern-view.h"
29 
30 /* this stuff's ugly */
31 
32 
33 /* --------------------------------------------------------------------- */
34 /* pattern edit mask indicators */
35 
36 /*
37 atnote  (1)  cursor_pos == 0
38   over  (2)  cursor_pos == pos
39 masked  (4)  mask & MASK_whatever
40 */
41 static const char mask_chars[] = {
42 	143, // 0
43 	143, // atnote
44 	169, // over
45 	169, // over && atnote
46 	170, // masked
47 	169, // masked && atnote
48 	171, // masked && over
49 	171, // masked && over && atnote
50 };
51 #define MASK_CHAR(field, pos, pos2)              \
main(void)52 	mask_chars                             [ \
53 	((cursor_pos == 0)   ? 1 : 0)          | \
54 	((cursor_pos == pos) ? 2 : 0)          | \
55 	((pos2 && cursor_pos == pos2) ? 2 : 0) | \
56 	((mask & field)      ? 4 : 0)          ]
57 
58 /* --------------------------------------------------------------------- */
59 /* 13-column track view */
60 
61 void draw_channel_header_13(int chan, int x, int y, int fg)
62 {
63 	char buf[16];
64 	sprintf(buf, " Channel %02d ", chan);
65 	draw_text(buf, x, y, fg, 1);
66 }
67 
68 void draw_note_13(int x, int y, const song_note_t *note, int cursor_pos, int fg, int bg)
69 {
70 	int cursor_pos_map[9] = { 0, 2, 4, 5, 7, 8, 10, 11, 12 };
71 	char note_text[16], note_buf[4], vol_buf[4];
72 	char instbuf[4];
73 
74 	get_note_string(note->note, note_buf);
75 	get_volume_string(note->volparam, note->voleffect, vol_buf);
76 
77 	/* come to think of it, maybe the instrument text should be
78 	 * created the same way as the volume. */
79 	if (note->instrument)
80 		num99tostr(note->instrument, instbuf);
81 	else
82 		strcpy(instbuf, "\xad\xad");
83 
84 	snprintf(note_text, 16, "%s %s %s %c%02X",
85 		note_buf, instbuf, vol_buf,
86 		get_effect_char(note->effect), note->param);
87 
88 	if (show_default_volumes && note->voleffect == VOLFX_NONE
89 	    && note->instrument > 0 && NOTE_IS_NOTE(note->note)) {
90 		song_sample_t *smp = song_is_instrument_mode()
91 			? csf_translate_keyboard(current_song, song_get_instrument(note->instrument),
92 						 note->note, NULL)
93 			: song_get_sample(note->instrument);
94 		if (smp) {
95 			/* Modplug-specific hack: volume bit shift */
96 			int n = smp->volume >> 2;
97 			note_text[6] = 0xbf;
98 			note_text[7] = '0' + n / 10 % 10;
99 			note_text[8] = '0' + n / 1 % 10;
100 			note_text[9] = 0xc0;
101 		}
102 	}
103 
104 	draw_text(note_text, x, y, fg, bg);
105 
106 	/* lazy coding here: the panning is written twice, or if the
107 	 * cursor's on it, *three* times. */
108 	if (note->voleffect == VOLFX_PANNING)
109 		draw_text(vol_buf, x + 7, y, 2, bg);
110 
111 	if (cursor_pos == 9) {
112 		draw_text(note_text + 10, x + 10, y, 0, 3);
113 	} else if (cursor_pos >= 0) {
114 		cursor_pos = cursor_pos_map[cursor_pos];
115 		draw_char(note_text[cursor_pos], x + cursor_pos, y, 0, 3);
116 	}
117 }
118 
119 void draw_mask_13(int x, int y, int mask, int cursor_pos, int fg, int bg)
120 {
121 	char buf[] = {
122 		MASK_CHAR(MASK_NOTE, 0, 0),
123 		MASK_CHAR(MASK_NOTE, 0, 0),
124 		MASK_CHAR(MASK_NOTE, 0, 1),
125 		143,
126 		MASK_CHAR(MASK_INSTRUMENT, 2, 0),
127 		MASK_CHAR(MASK_INSTRUMENT, 3, 0),
128 		143,
129 		MASK_CHAR(MASK_VOLUME, 4, 0),
130 		MASK_CHAR(MASK_VOLUME, 5, 0),
131 		143,
132 		MASK_CHAR(MASK_EFFECT, 6, 0),
133 		MASK_CHAR(MASK_EFFECT, 7, 0),
134 		MASK_CHAR(MASK_EFFECT, 8, 0),
135 		0,
136 	};
137 
138 	draw_text(buf, x, y, fg, bg);
139 }
140 
141 /* --------------------------------------------------------------------- */
142 /* 10-column track view */
143 
144 void draw_channel_header_10(int chan, int x, int y, int fg)
145 {
146 	char buf[16];
147 	sprintf(buf, "Channel %02d", chan);
148 	draw_text(buf, x, y, fg, 1);
149 }
150 
151 void draw_note_10(int x, int y, const song_note_t *note, int cursor_pos, UNUSED int fg, int bg)
152 {
153 	uint8_t c;
154 	char note_buf[4], ins_buf[3], vol_buf[3], effect_buf[4];
155 
156 	get_note_string(note->note, note_buf);
157 	if (note->instrument) {
158 		num99tostr(note->instrument, ins_buf);
159 	} else {
160 		ins_buf[0] = ins_buf[1] = 173;
161 		ins_buf[2] = 0;
162 	}
163 	get_volume_string(note->volparam, note->voleffect, vol_buf);
164 	sprintf(effect_buf, "%c%02X", get_effect_char(note->effect),
165 		note->param);
166 
167 	draw_text(note_buf, x, y, 6, bg);
168 	draw_text(ins_buf, x + 3, y, note->instrument ? 10 : 2, bg);
169 	draw_text(vol_buf, x + 5, y, ((note->voleffect == VOLFX_PANNING) ? 2 : 6), bg);
170 	draw_text(effect_buf, x + 7, y, 2, bg);
171 
172 	if (cursor_pos < 0)
173 		return;
174 	if (cursor_pos > 0)
175 		cursor_pos++;
176 	if (cursor_pos == 10) {
177 		draw_text(effect_buf, x + 7, y, 0, 3);
178 	} else {
179 		switch (cursor_pos) {
180 		case 0: c = note_buf[0]; break;
181 		case 2: c = note_buf[2]; break;
182 		case 3: c =  ins_buf[0]; break;
183 		case 4: c =  ins_buf[1]; break;
184 		case 5: c =  vol_buf[0]; break;
185 		case 6: c =  vol_buf[1]; break;
186 		default: /* 7->9 */
187 			c = effect_buf[cursor_pos - 7];
188 			break;
189 		}
190 		draw_char(c, x + cursor_pos, y, 0, 3);
191 	}
192 }
193 
194 void draw_mask_10(int x, int y, int mask, int cursor_pos, int fg, int bg)
195 {
196 	char buf[] = {
197 		MASK_CHAR(MASK_NOTE, 0, 0),
198 		MASK_CHAR(MASK_NOTE, 0, 0),
199 		MASK_CHAR(MASK_NOTE, 0, 1),
200 		MASK_CHAR(MASK_INSTRUMENT, 2, 0),
201 		MASK_CHAR(MASK_INSTRUMENT, 3, 0),
202 		MASK_CHAR(MASK_VOLUME, 4, 0),
203 		MASK_CHAR(MASK_VOLUME, 5, 0),
204 		MASK_CHAR(MASK_EFFECT, 6, 0),
205 		MASK_CHAR(MASK_EFFECT, 7, 0),
206 		MASK_CHAR(MASK_EFFECT, 8, 0),
207 		0,
208 	};
209 
210 	draw_text(buf, x, y, fg, bg);
211 }
212 
213 /* --------------------------------------------------------------------- */
214 /* 8-column track view (no instrument column; no editing) */
215 
216 void draw_channel_header_8(int chan, int x, int y, int fg)
217 {
218 	char buf[8];
219 	sprintf(buf, "  %02d  ", chan);
220 	draw_text(buf, x, y, fg, 1);
221 }
222 
223 void draw_note_8(int x, int y, const song_note_t *note, UNUSED int cursor_pos, int fg, int bg)
224 {
225 	char buf[4];
226 
227 	get_note_string(note->note, buf);
228 	draw_text(buf, x, y, fg, bg);
229 
230 	if (note->volparam || note->voleffect) {
231 		get_volume_string(note->volparam, note->voleffect, buf);
232 		draw_text(buf, x + 3, y, (note->voleffect == VOLFX_PANNING) ? 1 : 2, bg);
233 	} else {
234 		draw_char(0, x + 3, y, fg, bg);
235 		draw_char(0, x + 4, y, fg, bg);
236 	}
237 
238 	snprintf(buf, 4, "%c%02X", get_effect_char(note->effect), note->param);
239 	buf[3] = '\0';
240 	draw_text(buf, x + 5, y, fg, bg);
241 }
242 
243 /* --------------------------------------------------------------------- */
244 /* 7-column track view */
245 
246 void draw_channel_header_7(int chan, int x, int y, int fg)
247 {
248 	char buf[8];
249 	sprintf(buf, "Chnl %02d", chan);
250 	draw_text(buf, x, y, fg, 1);
251 }
252 
253 void draw_note_7(int x, int y, const song_note_t *note, int cursor_pos, UNUSED int fg, int bg)
254 {
255 	char note_buf[4], ins_buf[3], vol_buf[3];
256 	int fg1, bg1, fg2, bg2;
257 
258 	get_note_string(note->note, note_buf);
259 	if (note->instrument)
260 		num99tostr(note->instrument, ins_buf);
261 	else
262 		ins_buf[0] = ins_buf[1] = 173;
263 	get_volume_string(note->volparam, note->voleffect, vol_buf);
264 
265 	/* note & instrument */
266 	draw_text(note_buf, x, y, 6, bg);
267 	fg1 = fg2 = (note->instrument ? 10 : 2);
268 	bg1 = bg2 = bg;
269 	switch (cursor_pos) {
270 	case 0:
271 		draw_char(note_buf[0], x, y, 0, 3);
272 		break;
273 	case 1:
274 		draw_char(note_buf[2], x + 2, y, 0, 3);
275 		break;
276 	case 2:
277 		fg1 = 0;
278 		bg1 = 3;
279 		break;
280 	case 3:
281 		fg2 = 0;
282 		bg2 = 3;
283 		break;
284 	}
285 	draw_half_width_chars(ins_buf[0], ins_buf[1], x + 3, y, fg1, bg1,
286 			      fg2, bg2);
287 
288 	/* volume */
289 	switch (note->voleffect) {
290 	case VOLFX_NONE:
291 		fg1 = 6;
292 		break;
293 	case VOLFX_PANNING:
294 		fg1 = 10;
295 		break;
296 	case VOLFX_TONEPORTAMENTO:
297 	case VOLFX_VIBRATOSPEED:
298 	case VOLFX_VIBRATODEPTH:
299 		fg1 = 6;
300 		break;
301 	default:
302 		fg1 = 12;
303 		break;
304 	}
305 	fg2 = fg1;
306 	bg1 = bg2 = bg;
307 
308 	switch (cursor_pos) {
309 	case 4:
310 		fg1 = 0;
311 		bg1 = 3;
312 		break;
313 	case 5:
314 		fg2 = 0;
315 		bg2 = 3;
316 		break;
317 	}
318 	draw_half_width_chars(vol_buf[0], vol_buf[1], x + 4, y, fg1, bg1, fg2, bg2);
319 
320 	/* effect value */
321 	fg1 = fg2 = 10;
322 	bg1 = bg2 = bg;
323 	switch (cursor_pos) {
324 	case 7:
325 		fg1 = 0;
326 		bg1 = 3;
327 		break;
328 	case 8:
329 		fg2 = 0;
330 		bg2 = 3;
331 		break;
332 	case 9:
333 		fg1 = fg2 = 0;
334 		bg1 = bg2 = 3;
335 		cursor_pos = 6; // hack
336 		break;
337 	}
338 	draw_half_width_chars(hexdigits[(note->param & 0xf0) >> 4],
339 			      hexdigits[note->param & 0xf],
340 			      x + 6, y, fg1, bg1, fg2, bg2);
341 
342 	/* effect */
343 	draw_char(get_effect_char(note->effect), x + 5, y,
344 		  (cursor_pos == 6) ? 0 : 2, (cursor_pos == 6) ? 3 : bg);
345 }
346 
347 void draw_mask_7(int x, int y, int mask, int cursor_pos, int fg, int bg)
348 {
349 	char buf[] = {
350 		MASK_CHAR(MASK_NOTE, 0, 0),
351 		MASK_CHAR(MASK_NOTE, 0, 0),
352 		MASK_CHAR(MASK_NOTE, 0, 1),
353 		MASK_CHAR(MASK_INSTRUMENT, 2, 3),
354 		MASK_CHAR(MASK_VOLUME, 4, 5),
355 		MASK_CHAR(MASK_EFFECT, 6, 0),
356 		MASK_CHAR(MASK_EFFECT, 7, 8),
357 		0,
358 	};
359 
360 	draw_text(buf, x, y, fg, bg);
361 }
362 
363 /* --------------------------------------------------------------------- */
364 /* 3-column track view */
365 
366 void draw_channel_header_3(int chan, int x, int y, int fg)
367 {
368 	char buf[4] = { ' ', '0' + chan / 10, '0' + chan % 10, '\0' };
369 	draw_text(buf, x, y, fg, 1);
370 }
371 
372 void draw_note_3(int x, int y, const song_note_t *note, int cursor_pos, int fg, int bg)
373 {
374 	char buf[4];
375 	int vfg = 6;
376 
377 	switch (note->voleffect) {
378 	case VOLFX_VOLUME:
379 		vfg = 2;
380 		break;
381 	case VOLFX_PANNING:
382 	case VOLFX_NONE:
383 		vfg = 1;
384 		break;
385 	}
386 
387 	switch (cursor_pos) {
388 	case 0:
389 		vfg = fg = 0;
390 		bg = 3;
391 		break;
392 	case 1:
393 		get_note_string(note->note, buf);
394 		draw_text(buf, x, y, 6, bg);
395 		draw_char(buf[2], x + 2, y, 0, 3);
396 		return;
397 	case 2:
398 	case 3:
399 		cursor_pos -= 1;
400 		buf[0] = ' ';
401 		if (note->instrument) {
402 			num99tostr(note->instrument, buf + 1);
403 		} else {
404 			buf[1] = buf[2] = 173;
405 			buf[3] = 0;
406 		}
407 		draw_text(buf, x, y, 6, bg);
408 		draw_char(buf[cursor_pos], x + cursor_pos, y, 0, 3);
409 		return;
410 	case 4:
411 	case 5:
412 		cursor_pos -= 3;
413 		buf[0] = ' ';
414 		get_volume_string(note->volparam, note->voleffect, buf + 1);
415 		draw_text(buf, x, y, vfg, bg);
416 		draw_char(buf[cursor_pos], x + cursor_pos, y, 0, 3);
417 		return;
418 	case 6:
419 	case 7:
420 	case 8:
421 		cursor_pos -= 6;
422 		sprintf(buf, "%c%02X", get_effect_char(note->effect), note->param);
423 		draw_text(buf, x, y, 2, bg);
424 		draw_char(buf[cursor_pos], x + cursor_pos, y, 0, 3);
425 		return;
426 	case 9:
427 		sprintf(buf, "%c%02X", get_effect_char(note->effect), note->param);
428 		draw_text(buf, x, y, 0, 3);
429 		return;
430 	default:
431 		/* bleh */
432 		fg = 6;
433 		break;
434 	}
435 
436 	if (note->note) {
437 		get_note_string(note->note, buf);
438 		draw_text(buf, x, y, fg, bg);
439 	} else if (note->instrument) {
440 		buf[0] = ' ';
441 		num99tostr(note->instrument, buf + 1);
442 		draw_text(buf, x, y, fg, bg);
443 	} else if (note->voleffect) {
444 		buf[0] = ' ';
445 		get_volume_string(note->volparam, note->voleffect, buf + 1);
446 		draw_text(buf, x, y, vfg, bg);
447 	} else if (note->effect || note->param) {
448 		if (cursor_pos != 0)
449 			fg = 2;
450 		sprintf(buf, "%c%02X", get_effect_char(note->effect), note->param);
451 		draw_text(buf, x, y, fg, bg);
452 	} else {
453 		buf[0] = buf[1] = buf[2] = 173;
454 		buf[3] = 0;
455 		draw_text(buf, x, y, fg, bg);
456 	}
457 }
458 
459 void draw_mask_3(int x, int y, int mask, int cursor_pos, int fg, int bg)
460 {
461 	char buf[] = {143, 143, 143, 0};
462 
463 	switch (cursor_pos) {
464 	case 0: case 1:
465 		buf[0] = buf[1] = MASK_CHAR(MASK_NOTE, 0, 0);
466 		buf[2] = MASK_CHAR(MASK_NOTE, 0, 1);
467 		break;
468 	case 2: case 3:
469 		buf[1] = MASK_CHAR(MASK_INSTRUMENT, 2, 0);
470 		buf[2] = MASK_CHAR(MASK_INSTRUMENT, 3, 0);
471 		break;
472 	case 4: case 5:
473 		buf[1] = MASK_CHAR(MASK_VOLUME, 4, 0);
474 		buf[2] = MASK_CHAR(MASK_VOLUME, 5, 0);
475 		break;
476 	case 6: case 7: case 8:
477 		buf[0] = MASK_CHAR(MASK_EFFECT, 6, 0);
478 		buf[1] = MASK_CHAR(MASK_EFFECT, 7, 0);
479 		buf[2] = MASK_CHAR(MASK_EFFECT, 8, 0);
480 		break;
481 	};
482 
483 	draw_text(buf, x, y, fg, bg);
484 }
485 
486 /* --------------------------------------------------------------------- */
487 /* 2-column track view */
488 
489 void draw_channel_header_2(int chan, int x, int y, int fg)
490 {
491 	char buf[4] = { '0' + chan / 10, '0' + chan % 10, 0 };
492 	draw_text(buf, x, y, fg, 1);
493 }
494 
495 static void draw_effect_2(int x, int y, const song_note_t *note, int cursor_pos, int bg)
496 {
497 	int fg = 2, fg1 = 10, fg2 = 10, bg1 = bg, bg2 = bg;
498 
499 	switch (cursor_pos) {
500 	case 0:
501 		fg = fg1 = fg2 = 0;
502 		break;
503 	case 6:
504 		fg = 0;
505 		bg = 3;
506 		break;
507 	case 7:
508 		fg1 = 0;
509 		bg1 = 3;
510 		break;
511 	case 8:
512 		fg2 = 0;
513 		bg2 = 3;
514 		break;
515 	case 9:
516 		fg = fg1 = fg2 = 0;
517 		bg = bg1 = bg2 = 3;
518 		break;
519 	}
520 	draw_char(get_effect_char(note->effect), x, y, fg, bg);
521 	draw_half_width_chars(hexdigits[(note->param & 0xf0) >> 4],
522 			      hexdigits[note->param & 0xf],
523 			      x + 1, y, fg1, bg1, fg2, bg2);
524 }
525 
526 void draw_note_2(int x, int y, const song_note_t *note, int cursor_pos, int fg, int bg)
527 {
528 	char buf[4];
529 	int vfg = 6;
530 
531 	switch (note->voleffect) {
532 	case VOLFX_VOLUME:
533 		vfg = 2;
534 		break;
535 	case VOLFX_PANNING:
536 	case VOLFX_NONE:
537 		vfg = 1;
538 		break;
539 	}
540 
541 	switch (cursor_pos) {
542 	case 0:
543 		vfg = fg = 0;
544 		bg = 3;
545 	case 1: /* Mini-accidentals on 2-col. view */
546 		get_note_string(note->note, buf);
547 		draw_char(buf[0], x, y, fg, bg);
548 		// XXX cut-and-paste hackjob programming... this code should only exist in one place
549 		switch ((unsigned char) buf[0]) {
550 		case '^':
551 		case '~':
552 		case 0xCD: // note off
553 		case 0xAD: // dot (empty)
554 			if (cursor_pos == 1)
555 				draw_char(buf[1], x + 1, y, 0, 3);
556 			else
557 				draw_char(buf[1], x + 1, y, fg, bg);
558 			break;
559 		default:
560 			draw_half_width_chars(buf[1], buf[2], x + 1, y,
561 				fg, bg, (cursor_pos == 1 ? 0 : fg), (cursor_pos == 1 ? 3 : bg));
562 			break;
563 		}
564 		return;
565 		/*
566 		get_note_string_short(note->note, buf);
567 		draw_char(buf[0], x, y, 6, bg);
568 		draw_char(buf[1], x + 1, y, 0, 3);
569 		return;
570 		*/
571 	case 2:
572 	case 3:
573 		cursor_pos -= 2;
574 		if (note->instrument) {
575 			num99tostr(note->instrument, buf);
576 		} else {
577 			buf[0] = buf[1] = 173;
578 			buf[2] = 0;
579 		}
580 		draw_text(buf, x, y, 6, bg);
581 		draw_char(buf[cursor_pos], x + cursor_pos, y, 0, 3);
582 		return;
583 	case 4:
584 	case 5:
585 		cursor_pos -= 4;
586 		get_volume_string(note->volparam, note->voleffect, buf);
587 		draw_text(buf, x, y, vfg, bg);
588 		draw_char(buf[cursor_pos], x + cursor_pos, y, 0, 3);
589 		return;
590 	case 6:
591 	case 7:
592 	case 8:
593 	case 9:
594 		draw_effect_2(x, y, note, cursor_pos, bg);
595 		return;
596 	default:
597 		/* bleh */
598 		fg = 6;
599 		break;
600 	}
601 
602 	if (note->note) {
603 		get_note_string(note->note, buf);
604 		draw_char(buf[0], x, y, 6, bg);
605 		switch ((unsigned char) buf[0]) {
606 		case '^':
607 		case '~':
608 		case 0xCD: // note off
609 		case 0xAD: // dot (empty)
610 			if (cursor_pos == 1)
611 				draw_char(buf[1], x + 1, y, 0, 3);
612 			else
613 				draw_char(buf[1], x + 1, y, fg, bg);
614 			break;
615 		default:
616 			draw_half_width_chars(buf[1], buf[2], x + 1, y,
617 				fg, bg, (cursor_pos == 1 ? 0 : fg), (cursor_pos == 1 ? 3 : bg));
618 			break;
619 		}
620 		/*
621 		get_note_string_short(note->note, buf);
622 		draw_text(buf, x, y, fg, bg);
623 		*/
624 	} else if (note->instrument) {
625 		num99tostr(note->instrument, buf);
626 		draw_text(buf, x, y, fg, bg);
627 	} else if (note->voleffect) {
628 		get_volume_string(note->volparam, note->voleffect, buf);
629 		draw_text(buf, x, y, vfg, bg);
630 	} else if (note->effect || note->param) {
631 		draw_effect_2(x, y, note, cursor_pos, bg);
632 	} else {
633 		draw_char(173, x, y, fg, bg);
634 		draw_char(173, x + 1, y, fg, bg);
635 	}
636 }
637 
638 void draw_mask_2(int x, int y, int mask, int cursor_pos, int fg, int bg)
639 {
640 	char buf[] = {143, 143, 0};
641 
642 	switch (cursor_pos) {
643 	case 0: case 1:
644 		buf[0] = MASK_CHAR(MASK_NOTE, 0, 0);
645 		buf[1] = MASK_CHAR(MASK_NOTE, 0, 1);
646 		break;
647 	case 2: case 3:
648 		buf[0] = MASK_CHAR(MASK_INSTRUMENT, 2, 0);
649 		buf[1] = MASK_CHAR(MASK_INSTRUMENT, 3, 0);
650 		break;
651 	case 4: case 5:
652 		buf[0] = MASK_CHAR(MASK_VOLUME, 4, 0);
653 		buf[1] = MASK_CHAR(MASK_VOLUME, 5, 0);
654 		break;
655 	case 6: case 7: case 8:
656 		buf[0] = MASK_CHAR(MASK_EFFECT, 6, 0);
657 		buf[1] = MASK_CHAR(MASK_EFFECT, 7, 8);
658 		break;
659 	};
660 
661 	draw_text(buf, x, y, fg, bg);
662 }
663 
664 /* --------------------------------------------------------------------- */
665 /* 1-column track view... useful to look at, not so much to edit.
666  * (in fact, impulse tracker doesn't edit with this view) */
667 
668 void draw_channel_header_1(int chan, int x, int y, int fg)
669 {
670 	draw_half_width_chars('0' + chan / 10, '0' + chan % 10, x, y, fg, 1, fg, 1);
671 }
672 
673 static void draw_effect_1(int x, int y, const song_note_t *note, int cursor_pos, int fg, int bg)
674 {
675 	int fg1 = fg, fg2 = fg, bg1 = bg, bg2 = bg;
676 
677 	switch (cursor_pos) {
678 	case 0:
679 		break;
680 	case 6:
681 		fg = 0;
682 		bg = 3;
683 		break;
684 	case 7:
685 		fg1 = 0;
686 		bg1 = 3;
687 		break;
688 	case 8:
689 		fg2 = 0;
690 		bg2 = 3;
691 		break;
692 	default:
693 		fg = 2;
694 	}
695 	if (cursor_pos == 7 || cursor_pos == 8 || (note->effect == 0 && note->param != 0)) {
696 		draw_half_width_chars(hexdigits[(note->param & 0xf0) >> 4],
697 				      hexdigits[note-> param & 0xf],
698 				      x, y, fg1, bg1, fg2, bg2);
699 	} else {
700 		draw_char(get_effect_char(note->effect), x, y, fg, bg);
701 	}
702 }
703 
704 void draw_note_1(int x, int y, const song_note_t *note, int cursor_pos, int fg, int bg)
705 {
706 	char buf[4];
707 
708 	switch (cursor_pos) {
709 	case 0:
710 		fg = 0;
711 		bg = 3;
712 		if (note->note > 0 && note->note <= 120) {
713 			get_note_string_short(note->note, buf);
714 			draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, fg, bg);
715 			return;
716 		}
717 		break;
718 	case 1:
719 		get_note_string_short(note->note, buf);
720 		draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, 0, 3);
721 		return;
722 	case 2:
723 	case 3:
724 		cursor_pos -= 2;
725 		if (note->instrument)
726 			num99tostr(note->instrument, buf);
727 		else
728 			buf[0] = buf[1] = 173;
729 		if (cursor_pos == 0)
730 			draw_half_width_chars(buf[0], buf[1], x, y, 0, 3, fg, bg);
731 		else
732 			draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, 0, 3);
733 		return;
734 	case 4:
735 	case 5:
736 		cursor_pos -= 4;
737 		get_volume_string(note->volparam, note->voleffect, buf);
738 		fg = note->voleffect == VOLFX_PANNING ? 1 : 2;
739 		if (cursor_pos == 0)
740 			draw_half_width_chars(buf[0], buf[1], x, y, 0, 3, fg, bg);
741 		else
742 			draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, 0, 3);
743 		return;
744 	case 9:
745 		cursor_pos = 6;
746 		// fall through
747 	case 6:
748 	case 7:
749 	case 8:
750 		draw_effect_1(x, y, note, cursor_pos, fg, bg);
751 		return;
752 	}
753 
754 	if (note->note) {
755 		get_note_string_short(note->note, buf);
756 		draw_char(buf[0], x, y, fg, bg);
757 	} else if (note->instrument) {
758 		num99tostr(note->instrument, buf);
759 		draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, fg, bg);
760 	} else if (note->voleffect) {
761 		if (cursor_pos != 0)
762 			fg = (note->voleffect == VOLFX_PANNING) ? 1 : 2;
763 		get_volume_string(note->volparam, note->voleffect, buf);
764 		draw_half_width_chars(buf[0], buf[1], x, y, fg, bg, fg, bg);
765 	} else if (note->effect || note->param) {
766 		draw_effect_1(x, y, note, cursor_pos, fg, bg);
767 	} else {
768 		draw_char(173, x, y, fg, bg);
769 	}
770 }
771 
772 void draw_mask_1(int x, int y, int mask, int cursor_pos, int fg, int bg)
773 {
774 	char c = 143;
775 
776 	switch (cursor_pos) {
777 	case 0: case 1:
778 		c = MASK_CHAR(MASK_NOTE, 0, 1);
779 		break;
780 	case 2: case 3:
781 		c = MASK_CHAR(MASK_INSTRUMENT, 2, 3);
782 		break;
783 	case 4: case 5:
784 		c = MASK_CHAR(MASK_VOLUME, 4, 5);
785 		break;
786 	case 6:
787 		c = MASK_CHAR(MASK_EFFECT, 6, 0);
788 		break;
789 	case 7: case 8:
790 		c = MASK_CHAR(MASK_EFFECT, 7, 8);
791 		break;
792 	};
793 
794 	draw_char(c, x, y, fg, bg);
795 }
796 
797 /* --------------------------------------------------------------------- */
798 /* 6-column track view (totally new!) */
799 
800 void draw_channel_header_6(int chan, int x, int y, int fg)
801 {
802 	char buf[8];
803 	sprintf(buf, "Chnl%02d", chan);
804 	draw_text(buf, x, y, fg, 1);
805 }
806 
807 void draw_note_6(int x, int y, const song_note_t *note, int cursor_pos, UNUSED int fg, int bg)
808 {
809 	char note_buf[4], ins_buf[3], vol_buf[3];
810 	int fg1, bg1, fg2, bg2;
811 
812 #ifdef USE_LOWERCASE_NOTES
813 
814 	get_note_string_short(note->note, note_buf);
815 	if (note->instrument)
816 		num99tostr(note->instrument, ins_buf);
817 	else
818 		ins_buf[0] = ins_buf[1] = 173;
819 	/* note & instrument */
820 	draw_text(note_buf, x, y, 6, bg);
821 	fg1 = fg2 = (note->instrument ? 10 : 2);
822 	bg1 = bg2 = bg;
823 	switch (cursor_pos) {
824 	case 0:
825 		draw_char(note_buf[0], x, y, 0, 3);
826 		break;
827 	case 1:
828 		draw_char(note_buf[1], x + 1, y, 0, 3);
829 		break;
830 	case 2:
831 		fg1 = 0;
832 		bg1 = 3;
833 		break;
834 	case 3:
835 		fg2 = 0;
836 		bg2 = 3;
837 		break;
838 	}
839 
840 #else
841 
842 	get_note_string(note->note, note_buf);
843 
844 	if (cursor_pos == 0)
845 		draw_char(note_buf[0], x, y, 0, 3);
846 	else
847 		draw_char(note_buf[0], x, y, fg, bg);
848 
849 	bg1 = bg2 = bg;
850 	switch ((unsigned char) note_buf[0]) {
851 	case '^':
852 	case '~':
853 	case 0xCD: // note off
854 	case 0xAD: // dot (empty)
855 		if (cursor_pos == 1)
856 			draw_char(note_buf[1], x + 1, y, 0, 3);
857 		else
858 			draw_char(note_buf[1], x + 1, y, fg, bg);
859 		break;
860 	default:
861 		draw_half_width_chars(note_buf[1], note_buf[2], x + 1, y,
862 			fg, bg, (cursor_pos == 1 ? 0 : fg), (cursor_pos == 1 ? 3 : bg));
863 		break;
864 	}
865 
866 #endif
867 
868 	if (note->instrument)
869 		num99tostr(note->instrument, ins_buf);
870 	else
871 		ins_buf[0] = ins_buf[1] = 173;
872 
873 	fg1 = fg2 = (note->instrument ? 10 : 2);
874 	bg1 = bg2 = bg;
875 	switch (cursor_pos) {
876 	case 2:
877 		fg1 = 0;
878 		bg1 = 3;
879 		break;
880 	case 3:
881 		fg2 = 0;
882 		bg2 = 3;
883 		break;
884 	}
885 
886 	draw_half_width_chars(ins_buf[0], ins_buf[1], x + 2, y, fg1, bg1, fg2, bg2);
887 	/* volume */
888 	get_volume_string(note->volparam, note->voleffect, vol_buf);
889 
890 	switch (note->voleffect) {
891 	case VOLFX_NONE:
892 		fg1 = 6;
893 		break;
894 	case VOLFX_PANNING:
895 		fg1 = 10;
896 		break;
897 	case VOLFX_TONEPORTAMENTO:
898 	case VOLFX_VIBRATOSPEED:
899 	case VOLFX_VIBRATODEPTH:
900 		fg1 = 6;
901 		break;
902 	default:
903 		fg1 = 12;
904 		break;
905 	}
906 	fg2 = fg1;
907 	bg1 = bg2 = bg;
908 
909 	switch (cursor_pos) {
910 	case 4:
911 		fg1 = 0;
912 		bg1 = 3;
913 		break;
914 	case 5:
915 		fg2 = 0;
916 		bg2 = 3;
917 		break;
918 	}
919 	draw_half_width_chars(vol_buf[0], vol_buf[1], x + 3, y, fg1, bg1, fg2, bg2);
920 
921 	/* effect value */
922 	fg1 = fg2 = 10;
923 	bg1 = bg2 = bg;
924 	switch (cursor_pos) {
925 	case 7:
926 		fg1 = 0;
927 		bg1 = 3;
928 		break;
929 	case 8:
930 		fg2 = 0;
931 		bg2 = 3;
932 		break;
933 	case 9:
934 		fg1 = fg2 = 0;
935 		bg1 = bg2 = 3;
936 		cursor_pos = 6; // hack
937 		break;
938 	}
939 	draw_half_width_chars(hexdigits[(note->param & 0xf0) >> 4],
940 			      hexdigits[note->param & 0xf],
941 			      x + 5, y, fg1, bg1, fg2, bg2);
942 
943 	/* effect */
944 	draw_char(get_effect_char(note->effect), x + 4, y,
945 		  cursor_pos == 6 ? 0 : 2, cursor_pos == 6 ? 3 : bg);
946 }
947 
948 void draw_mask_6(int x, int y, int mask, int cursor_pos, int fg, int bg)
949 {
950 	char buf[] = {
951 		MASK_CHAR(MASK_NOTE, 0, 0),
952 		MASK_CHAR(MASK_NOTE, 0, 1),
953 		MASK_CHAR(MASK_INSTRUMENT, 2, 3),
954 		MASK_CHAR(MASK_VOLUME, 4, 5),
955 		MASK_CHAR(MASK_EFFECT, 6, 0),
956 		MASK_CHAR(MASK_EFFECT, 7, 8),
957 		0,
958 	};
959 
960 	draw_text(buf, x, y, fg, bg);
961 }
962 
963