/* ** CHMAP -- Channel Map; remap Midi channels ** psl 10/85, revised 12/85 */ #include #include #define MAXCHAN 16 #define MAXMAP 16 int map[MAXCHAN][MAXMAP]; int maplen[MAXCHAN]; main(argc, argv) char *argv[]; { register int i, chan, stat; int new[MAXCHAN], old[MAXCHAN], newlen, oldlen; int chin[MAXCHAN], oflg; long now; MCMD *mp; oflg = 0; while (--argc > 0) { if (chanarg(argv[argc], new, &newlen, old, &oldlen) == -1) syntax(argv[0]); if (newlen == oldlen) { for (i = 0; i < newlen; i++) if (addmap(new[i], old[i]) == -1) syntax(argv[0]); } else if (newlen == 1) { for (i = 0; i < oldlen; i++) if (addmap(new[0], old[i]) == -1) syntax(argv[0]); } else if (oldlen == 1) { for (i = 0; i < newlen; i++) if (addmap(new[i], old[0]) == -1) syntax(argv[0]); } else syntax(argv[0]); oflg++; } for (now = 0L; mp = getmcmd(stdin, now); now = mp->when) { if (mp->len < 2 || mp->len > 4) { if (oflg) putmcmd(stdout, mp); } else { chan = (mp->cmd[0] & M_CHAN_MASK); if (oflg) { stat = (mp->cmd[0] & M_CMD_MASK); for (i = 0; i < maplen[chan]; i++) { mp->cmd[0] = stat | map[chan][i]; putmcmd(stdout, mp); } } else chin[chan]++; } } if (!oflg) { for (i = 0; i < MAXCHAN; i++) if (chin[i]) fprintf(stderr, "%d event%s from chan %d\n", chin[i], chin[i] == 1? "" : "s", i + 1); } } syntax(a0) char *a0; { fprintf(stderr, "Usage: %s [NEW=OLD] ... file2\n", a0); fprintf(stderr, "where NEW and OLD are comma separated lists"); fprintf(stderr, " of channel numbers,\nusing '-' for ranges."); fprintf(stderr, " Channel numbers are decimal numbers"); fprintf(stderr, " in the range 1-16.\n"); fprintf(stderr, "NEW and OLD must either contain the same number"); fprintf(stderr, " of channels (one to one),\n"); fprintf(stderr, "or NEW must be a single channel (many to one),\n"); fprintf(stderr, "or OLD must be a single channel (one to many).\n"); fprintf(stderr, "E.g. %s 1-3=1 4=2 copies channel 1 to", a0); fprintf(stderr, " 1, 2, and 3, and channel 2 to 4.\n"); fprintf(stderr, "Note: only channels mentioned are output.\n"); fprintf(stderr, "If no channel arguments are given,"); fprintf(stderr, " print statistics on channel usage.\n"); exit(2); } /* ** Add ochan->nchan to the map for ochan. */ addmap(nchan, ochan) { if (maplen[ochan] >= MAXMAP) { fprintf(stderr, "Too many destinations for %d\n", ochan); return(-1); } map[ochan][maplen[ochan]++] = nchan; return(0); } /* ** Interpret channel arg of the form list=list ** where "list" is of the form understood by chanlist(). ** Fill in two ordered lists of channels, "new" and "old", ** and put their lengths in "newlenp" and "oldlenp". ** Return 0 for success, -1 for syntax error. */ chanarg(arg, new, newlenp, old, oldlenp) char *arg; int new[], *newlenp, old[], *oldlenp; { register char *cp; for (cp = arg; *cp && *cp != '='; cp++); if (*cp != '=') return(-1); *cp++ = '\0'; if ((*newlenp = chanlist(arg, new)) == -1) return(-1); if ((*oldlenp = chanlist(cp, old)) == -1) return(-1); return(0); } /* ** Interpret channel list of the form: #,#-#,... ** # is a decimal number in the range 1 to 16, and "3-5" == "3,4,5". ** Save an ordered list of channels specified in "chans" array. ** Return the number of channels specified, -1 for error. */ chanlist(list, chans) char *list; int chans[MAXCHAN]; { register char *cp; register int i, j, n; n = 0; for (cp = list; *cp; ) { i = j = atoi(cp) - 1; while ('0' <= *cp && *cp <= '9') cp++; if (*cp == '-') { j = atoi(++cp) - 1; while ('0' <= *cp && *cp <= '9') cp++; } if (i < 0 || i >= MAXCHAN || j < 0 || j >= MAXCHAN) return(-1); if (i <= j) for (; i <= j; chans[n++] = i++); else for (; i >= j; chans[n++] = i--); if (*cp++ != ',') break; } return(n); }