/* ** STATINFO -- Routines to process MIDI & MPU status/command bytes ** P. Langston 10/87 */ #include struct statstr Cvstat[] = { /* Channel Voice Messages */ { 3, RSSET, }, /* 8 CH_KEY_OFF */ { 3, RSSET, }, /* 9 CH_KEY_ON */ { 3, RSSET, }, /* A CH_POLY_KPRS */ { 3, RSSET, }, /* B CH_CTL */ { 2, RSSET, }, /* C CH_PRG */ { 2, RSSET, }, /* D CH_PRESSURE */ { 3, RSSET, }, /* E CH_P_BEND */ { 0, 0, }, /* F Sys common & real-time */ }; struct statstr Systat[] = { /* System Messages (mpu use) */ { -1, RSCLR, }, /* F0, SX_CMD */ { 1, RSCLR|UNDF, }, /* F1, undefined */ { 3, RSCLR, }, /* F2, SC_MSEL */ { 2, RSCLR, }, /* F3, SC_SSEL */ { 1, RSCLR|UNDF, }, /* F4, undefined */ { 1, RSCLR|UNDF, }, /* F5, undefined */ { 1, RSCLR, }, /* F6, SC_TSEL */ { 1, RSCLR, }, /* F7, SX_EOB */ { 1, RSNOP, }, /* F8, RT_TCIP */ { 1, RSNOP|UNDF, }, /* F9, undefined (RT_TCWME) */ { 1, RSNOP, }, /* FA, RT_SA1M */ { 1, RSNOP, }, /* FB, RT_CONT */ { 1, RSNOP, }, /* FC, RT_TCIS */ { 1, RSNOP|UNDF, }, /* FD, undefined (clock to host) */ { 1, RSNOP|UNDF, }, /* FE, undefined (active sensing) */ { 1, RSNOP, }, /* FF, RT_RESET (mpu reset) */ }; /* ** struct statstr *statinfo(status) - Return a pointer to a statstr entry ** describing the length of commands started with ``status'' and other ** miscellaneous info such as their effect on ``running status'' */ struct statstr * statinfo(status) { register int i; if ((status & M_CMD) == 0) return(0); i = (status >> 4) & 0x07; return(Cvstat[i].clen? &Cvstat[i] : &Systat[status&0x0F]); } /* ** cmdlen(status) - Return the length of a command. ** -1 system exclusive (commands terminated by SX_EOB, 0xFF) ** 0 illegal ``status'' (outside 0x80 to 0xFF range). ** 1-3 length (including status) */ cmdlen(status) { register int i; if ((status & M_CMD) == 0) return(0); i = (status >> 4) & 0x07; return(Cvstat[i].clen? Cvstat[i].clen : Systat[status&0x0F].clen); } /* ** statproc(&oldstatus, newbyte) - Process the first byte of a command, ** keeping track of running status, and return: ** -1 system exclusive (commands terminated by SX_EOB, 0xFF) ** 0 illegal ``status'' (outside 0x80 to 0xFF range). ** 1-3 actual length (including status byte, if present) ** e.g. for key-on using running status this is 2. ** For example: ** for (oldstat = 0; read(ifd, buf, 1) == 1; ) { ** n = statproc(&oldstat, buf[0]) - 1; ** if (read(ifd, buf + 1, n) == n) ** write(ofd, buf, n + 1); ** } ** In this loop each MIDI command (N.B. system exclusive is not handled) ** will be written with a single write, and the status of the current command ** will be: ((*buf & M_CMD)? *buf : oldstat). ** Note that, for MPU data, the routine would have to also pass along timing ** bytes, perhaps in this fashion: ** for (oldstat = 0; read(ifd, buf, 1) == 1; ) { ** write(ofd, buf, 1); ** if (*buf != RT_TCIP && read(ifd, buf, 1) == 1) { ** n = statproc(&oldstat, buf[0]); ** if (read(ifd, buf + 1, n - 1) == n - 1) ** write(ofd, buf, n); ** } ** } ** Neither of these deals with System Exclusive (return value -1) in which ** the command runs until the next SX_EOB (or other status byte). Nor do ** they deal with errors (return value 0) from bad data. */ statproc(statp, newbyte) int *statp; /* and return actual command length */ { /* -1 => SysEx, 0 => really bad status */ register int stat; register struct statstr *sp; stat = (newbyte & M_CMD)? newbyte : *statp; if ((stat & M_CMD) == 0) return(0); /* really bad status */ sp = &Cvstat[(stat >> 4) & 0x07]; if (sp->clen == 0) /* a system message */ sp = &Systat[stat & 0x0F]; if (sp->flgs & RSSET) *statp = stat; else if (sp->flgs & RSCLR) *statp = 0; return(sp->clen + ((newbyte & M_CMD)? 0 : -1)); /* for running stat */ }