1 /************************************************************************
2    io_svgalib.c  -- shows midi events using svgalib
3 
4    Copyright (C) 1995-1996 Nathan I. Laredo
5 
6    This program is modifiable/redistributable under the terms
7    of the GNU General Public Licence.
8 
9    You should have received a copy of the GNU General Public License
10    along with this program; if not, write to the Free Software
11    Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
12    Send your comments and all your spare pocket change to
13    laredo@gnu.ai.mit.edu (Nathan Laredo) or to PSC 1, BOX 709, 2401
14    Kelly Drive, Lackland AFB, TX 78236-5128, USA.
15  *************************************************************************/
16 #include "playmidi.h"
17 #include <vga.h>
18 #include <vgagl.h>
19 #include <sys/time.h>
20 #include <unistd.h>
21 
22 /* following includes are for raw + nowait input mode */
23 #include <fcntl.h>
24 #include <unistd.h>
25 #include <termios.h>
26 
27 char *drum3ch[11] =
28 {
29     "STD", "RM.", "PWR", "ELE", "808",
30     "JAZ", "BRU", "ORC", "SFX", "PRG", "M32"
31 };
32 
33 #define SET(x) (x == 8 ? 1 : x >= 16 && x <= 23 ? 2 : x == 24 ? 3 : \
34 		x == 25  ? 4 : x == 32 ? 5 : x >= 40 && x <= 47 ? 6 : \
35 		x == 48 ? 7 : x == 56 ? 8 : x >= 96 && x <= 111 ? 9 : \
36 		x == 127 ? 10 : 0)
37 
38 extern int graphics, verbose, perc, ntrks;
39 extern int note_vel[16][128];
40 extern unsigned long int ticks;
41 extern char *filename, *gmvoice[256];
42 extern float skew;
43 extern void seq_reset();
44 extern struct chanstate channel[16];
45 extern struct timeval start_time;
46 char textbuf[1024], **nn;
47 int i, ytxt, mytty;
48 void *font;
49 struct termios newtty, oldtty;
50 struct timeval now_time, want_time;
51 
52 int cdeltat(t1, t2)
53 struct timeval *t1;
54 struct timeval *t2;
55 {
56     int d1, d2;
57 
58     d1 = t1->tv_sec - t2->tv_sec;
59     if ((d2 = t1->tv_usec - t2->tv_usec) < 0)
60 	(d2 += 1000000, d1 -= 1);
61     d2 /= 10000;
62     return (d2 + d1 * 100);
63 }
64 
65 void close_show(error)
66 int error;
67 {
68     vga_setmode(TEXT);
69     tcsetattr(i, TCSANOW, &oldtty);
70     exit(error);
71 }
72 
73 #define CHN		(cmd & 0xf)
74 #define NOTE		((int)data[0])
75 #define VEL		((int)data[1])
76 
77 int updatestatus()
78 {
79     char ch;
80     int d1, d2;
81 
82     want_time.tv_sec = start_time.tv_sec + (ticks / 100);
83     want_time.tv_usec = start_time.tv_usec + (ticks % 100) * 10000;
84     if (want_time.tv_usec > 1000000)
85 	(want_time.tv_usec -= 1000000, want_time.tv_sec++);
86 
87     do {
88 	if (read(mytty, &ch, 1))
89 	    switch (ch) {
90 	    case '.':
91 	    case '>':
92 		if ((skew -= 0.01) < 0.25)
93 		    skew = 0.25;
94 		sprintf(textbuf, "skew=%0.2f", skew);
95 		gl_write(512, 72, textbuf);
96 		break;
97 	    case ',':
98 	    case '<':
99 		if ((skew += 0.01) > 4)
100 		    skew = 4.0;
101 		sprintf(textbuf, "skew=%0.2f", skew);
102 		gl_write(512, 72, textbuf);
103 		break;
104 	    case 'p':
105 	    case 'P':
106 		seq_reset();
107 		return -1;
108 		break;
109 	    case 'r':
110 	    case '^':
111 		seq_reset();
112 		return 0;
113 		break;
114 	    case 3:
115 	    case 27:
116 	    case 'q':
117 	    case 'Q':
118 		close_show(0);
119 		break;
120 	    case 'n':
121 	    case 'N':
122 		seq_reset();
123 		return 1;
124 	    default:
125 		break;
126 	    }
127 	gettimeofday(&now_time, NULL);
128 	d1 = now_time.tv_sec - start_time.tv_sec;
129 	d2 = now_time.tv_usec - start_time.tv_usec;
130 	if (d2 < 0)
131 	    (d2 += 1000000, d1 -= 1);
132 	sprintf(textbuf, "%02d:%02d.%d", d1 / 60, d1 % 60, d2 / 100000);
133 	gl_write(528, 0, textbuf);
134 	d1 = cdeltat(&want_time, &now_time);
135 	if (d1 > 15)
136 	    usleep(100000);
137     } while (d1 > 10);
138     return NO_EXIT;
139 }
140 
141 void draw_note(chn, note, vel)
142 int chn, note, vel;
143 {
144     register int x, y, c, dy;
145 
146     x = 32 * chn;
147     y = 400 - note * 3;
148     c = vel / 4 + 32 * (chn % 8);
149 
150     dy = (channel[chn].bender - 8192);
151     dy *= channel[chn].bender_range;
152     dy /= 2048;
153 
154     gl_line(x, y, x + 12, y - dy, c);
155     gl_line(x + 13, y - dy, x + 23, y, c);
156 }
157 
158 void showevent(cmd, data, length)
159 int cmd;
160 unsigned char *data;
161 int length;
162 {
163     if (cmd < 8 && cmd > 0) {
164 
165 	int COLS = WIDTH / 8;
166 
167 	if (ytxt == 10)		/* clear text area */
168 	    gl_fillbox(512, 80, WIDTH - 1, HEIGHT - 1, 0);
169 	strncpy(textbuf, data, length < COLS - 66 ? length : COLS - 66);
170 	textbuf[length < COLS - 66 ? length : COLS - 66] = 0;
171 	gl_colorfont(8, 8, (cmd * 32) - 1, font);
172 	gl_write(512, ytxt * 8, textbuf);
173 	gl_colorfont(8, 8, 255, font);	/* hope this isn't slow... */
174 	if ((++ytxt) > (HEIGHT / 8) - 1)
175 	    ytxt = 10;
176     } else if (cmd & 0x80)
177 	switch (cmd & 0xf0) {
178 	case MIDI_KEY_PRESSURE:
179 	    draw_note(CHN, NOTE, VEL);
180 	    break;
181 	case MIDI_NOTEON:
182 	    draw_note(CHN, NOTE, VEL);
183 	    break;
184 	case MIDI_NOTEOFF:
185 	    draw_note(CHN, NOTE, 0);
186 	    break;
187 	case MIDI_CTL_CHANGE:
188 	    /* future expansion */
189 	    break;
190 	case MIDI_CHN_PRESSURE:
191 	    /* future expansion */
192 	    break;
193 	case MIDI_PITCH_BEND:
194 	    /* erase all notes in channel to re-draw with new bend */
195 	    gl_fillbox(32 * CHN, 8, (32 * CHN) + 24, 400, 0);
196 	    for (i = 0; i < 128; i++)
197 		if (note_vel[CHN][i])
198 		    draw_note(CHN, i, note_vel[CHN][i]);
199 	    break;
200 	case MIDI_PGM_CHANGE:
201 	    if (!ISPERC(CHN))
202 		strncpy(textbuf, gmvoice[NOTE], 3);
203 	    else
204 		strncpy(textbuf, drum3ch[SET(NOTE)], 3);
205 	    textbuf[3] = 0;
206 	    gl_write(CHN * 32, 0, textbuf);
207 	    break;
208 	case 0xf0:
209 	case 0xf7:
210 	    gl_fillbox(0, HEIGHT - 24, 511, HEIGHT - 1, 0);
211 	    sprintf(textbuf, "Sysex(%2x)", cmd);
212 	    gl_write(0, HEIGHT - 24, textbuf);
213 	    for (i = 0; i < length && i < 26; i++) {
214 		sprintf(textbuf, "%02x", data[i]);
215 		gl_write(80 + i * 16, HEIGHT - 24, textbuf);
216 	    }
217 	    for (; i < length && i < 57; i++) {		/* wrap to next line */
218 		sprintf(textbuf, "%02x", data[i]);
219 		gl_write((i - 26) * 16, HEIGHT - 16, textbuf);
220 	    }
221 	    for (; i < length && i < 88; i++) {		/* wrap to next line */
222 		sprintf(textbuf, "%02x", data[i]);
223 		gl_write((i - 57) * 16, HEIGHT - 8, textbuf);
224 	    }
225 	    break;
226 	default:
227 	    break;
228 	}
229 }
230 
231 void init_show()
232 {
233     char *tmp;
234 
235     ytxt = 10;
236     gl_clearscreen(0);
237     gl_colorfont(8, 8, 244, font);	/* hope this isn't slow... */
238     gl_write(0, 0, "ch1 ch2 ch3 ch4 ch5 ch6 ch7 ch8 ch9 "
239 	     "c10 c11 c12 c13 c14 c15 c16");
240     gl_write(512, 16, RELEASE);
241     gl_write(560, 24, "by");
242     gl_write(512, 32, "Nathan Laredo");
243     tmp = strrchr(filename, '/');
244     strncpy(textbuf, (tmp == NULL ? filename : tmp + 1), 14);
245     gl_write(512, 48, textbuf);
246     sprintf(textbuf, "%d track%c", ntrks, ntrks > 1 ? 's' : ' ');
247     gl_write(512, 56, textbuf);
248 }
249 
250 void setup_show(argc, argv)
251 int argc;
252 char **argv;
253 {
254     int vgamode, i, j;
255 
256     graphics++;			/* force -r option if not selected */
257     mytty = open("/dev/tty", O_RDONLY | O_NDELAY, 0);
258     tcgetattr(mytty, &oldtty);
259     tcgetattr(mytty, &newtty);
260     newtty.c_lflag &= ~(ICANON | ECHO | ICRNL | ISIG);
261     tcsetattr(mytty, TCSANOW, &newtty);
262     vga_init();
263     if ((vgamode = vga_getdefaultmode()) == -1)
264 	vgamode = G640x480x256;
265     if (!vga_hasmode(vgamode)) {
266 	fprintf(stderr, "\nRequested vga mode not available!\n");
267 	close_show(-1);
268     }
269     gl_setwritemode(WRITEMODE_OVERWRITE);
270     vga_setmode(vgamode);
271     gl_setcontextvga(vgamode);
272     for (i = 0; i < 32; i++) {
273 	j = i * 2;
274 	gl_setpalettecolor(i, j, 0, 0);
275 	gl_setpalettecolor(i + 32, 0, j, 0);
276 	gl_setpalettecolor(i + 64, j, j, 0);
277 	gl_setpalettecolor(i + 96, 0, 0, j);
278 	gl_setpalettecolor(i + 128, j, 0, j);
279 	gl_setpalettecolor(i + 160, 0, 0, j);
280 	gl_setpalettecolor(i + 192, 0, j, j);
281 	gl_setpalettecolor(i + 224, j, j, j);
282     }
283     font = malloc(256 * 8 * 8 * BYTESPERPIXEL);
284     gl_expandfont(8, 8, 255, gl_font8x8, font);
285     gl_setfont(8, 8, font);
286     gl_enableclipping();
287 }
288