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