/* ** TXGET -- Get voice(s) and/or performance(s) from DX7 or TX816 */ #include #include #include #include #d DEFCHAN 0 #d e MidiError #d EDIT -1 #d MIN 0 /* default range for voices & perfs */ #d MAX 31 #d ALL 98 int Chan = DEFCHAN; /* Midi channel to be used */ int Mfh = -1; /* file handle for Midi device */ int Iflg = 0; /* ignore wrong sys.excl. dumps */ FILE *Ofp = 0; /* default is to make a file */ int pget(), vget(); main(argc, argv) char *argv[]; { int i, n; av0 = argv[0]; if ((Mfh = open(MidiDevice, 2)) == -1) { e("%s: ", av0); perror(MidiDevice); exit(1); } for (i = 1; i < argc; i++) { if (argv[i][0] == '-') { switch (argv[i][1]) { case '-': /* use stdout */ Ofp = stdout; break; case 'c': /* set channel */ Chan = atoi(&argv[i][2]) - 1; if (Chan < 0 || 15 < Chan) use(); break; case 'i': /* ignore wrong dumps */ Iflg++; break; case 'p': /* get performance(s) */ get(argv[i], "performance", pget); break; case 'v': /* get voice(s) */ get(argv[i], "voice", vget); break; default: use(); } } else { use(); exit(2); } } exit(0); } get(arg, vorp, func) char *arg, *vorp; int (*func)(); { register char *cp; register int i, n; if (strcmp(&arg[2], "each") == 0) for (n = MIN; n <= MAX; n++) func(n); else if (strcmp(&arg[2], "all") == 0) func(ALL); else if (strcmp(&arg[2], "edit") == 0) func(EDIT); else { cp = &arg[2]; n = atoi(cp); i = n - 1; while (*cp && *cp != '-') cp++; if (*cp++ == '-') n = atoi(cp); while (i < n) func(i++); } } unsigned char Load[] = { MPU_WANT_TO_SEND_DATA, 0, /* CH_PRG | chan goes here */ 0, /* voice # goes here */ }; unsigned char Suck[] = { MPU_RESET, MPU_MIDI_THRU_OFF, MPU_SEND_SYSTEM_MESSAGE, SX_CMD, ID_YAMAHA, 0, /* (DX7_SXSS_DR<<4) | chan goes here */ 0, /* DX7_SXF_1V, DX7_SXF_32V, */ /* TX_SXF_1P, or TX_SXF_64P goes here */ SX_EOB, MPU_EXCLUSIVE_TO_HOST_ON, MPU_SEND_MEASURE_END_OFF, }; pget(n) { unsigned char buf[6 + TX64PTOTLEN + 2], *cp; int i, len, totlen, fmt; FILE *fopen(), *fp; if (!(fp = Ofp)) { if (n == ALL) sprintf(buf, "p..%d", Chan + 1); else sprintf(buf, "p.%d.%d", n + 1, Chan + 1); if (!(fp = fopen(buf, "w"))) { perror(buf); return; } } MpuSetTrack(Mfh, MPU_TR_COM); if (n == EDIT) { fmt = TX_SXF_1P; totlen = 6 + TX1PLEN + 2; } else if (n == ALL) { fmt = TX_SXF_64P; totlen = 6 + TX64PTOTLEN + 2; } else { Load[1] = CH_PRG | Chan; Load[2] = n; write(Mfh, Load, sizeof Load); fmt = TX_SXF_1P; totlen = 6 + TX1PLEN + 2; } Suck[5] = (DX7_SXSS_DR<<4) | Chan; Suck[6] = fmt; write(Mfh, Suck, sizeof Suck); MpuSetTrack(Mfh, 0); for (;;) { while (read(Mfh, buf, 1) == 1 && *buf != SX_CMD); if (read(Mfh, &buf[1], 5) != 5) { /* get header */ e("%s: EOF in header for performance %d\n", av0, n); return; } if (buf[1] == ID_YAMAHA && (buf[2] == Chan || buf[2] == 0) /* TX816 likes 0 */ && buf[3] == fmt && ((buf[4] == 0x00 && buf[5] == 0x5E) || (buf[4] == 0x20 && buf[5] == 0x00))) break; e("%s: naughty header for performance %d:", av0, n + 1); e(" %x %x %x %x %x\n", buf[1], buf[2], buf[3], buf[4], buf[5]); e("Wanted: %x, %x(or 0), %x, %x %x (or %x %x)\n", ID_YAMAHA, Chan, fmt, 0x00, 0x5E, 0x20, 0x00); if (!Iflg) { e("Giving up (try -i option?)\n"); return; } e("Scanning past wrong dump\n"); } len = totlen - 6; for (cp = &buf[6]; (i = read(Mfh, cp, len)) > 0; cp += i) if ((len -= i) <= 0) break; if (len > 0) { e("%s: expected %d bytes, got %d\n", av0, totlen, totlen - len); return; } if (write(fileno(fp), buf, totlen) != totlen) perror("write"); if (fp != Ofp) fclose(fp); } vget(n) { unsigned char buf[6 + DX732VTOTLEN + 2], *cp; int i, len, totlen, fmt; FILE *fopen(), *fp; if (!(fp = Ofp)) { if (n == ALL) sprintf(buf, "v..%d", Chan + 1); else sprintf(buf, "v.%d.%d", n + 1, Chan + 1); if (!(fp = fopen(buf, "w"))) { perror(buf); return; } } MpuSetTrack(Mfh, MPU_TR_COM); if (n == EDIT) { fmt = DX7_SXF_1V; totlen = 6 + DX7VOXLEN + 2; } else if (n == ALL) { fmt = DX7_SXF_32V; totlen = 6 + DX732VTOTLEN + 2; } else { Load[1] = CH_PRG | Chan; Load[2] = n; write(Mfh, Load, sizeof Load); fmt = DX7_SXF_1V; totlen = 6 + DX7VOXLEN + 2; } Suck[5] = (DX7_SXSS_DR<<4) | Chan; Suck[6] = fmt; write(Mfh, Suck, sizeof Suck); MpuSetTrack(Mfh, 0); for (;;) { while (read(Mfh, buf, 1) == 1 && *buf != SX_CMD); if (read(Mfh, &buf[1], 5) != 5) { /* get header */ e("%s: EOF in header for voice %d\n", av0, n); return; } if (buf[1] == ID_YAMAHA && (buf[2] == Chan || buf[2] == 0) /* TX816 likes 0 */ && buf[3] == fmt && ((buf[4] == 0x01 && buf[5] == 0x1B) || (buf[4] == 0x20 && buf[5] == 0x00))) break; e("%s: naughty header for voice %d:", av0, n + 1); e(" %x %x %x %x %x\n", buf[1], buf[2], buf[3], buf[4], buf[5]); e("Wanted: %x, %x(or 0), %x, %x %x (or %x %x)\n", ID_YAMAHA, Chan, fmt, 0x01, 0x1B, 0x20, 0x00); if (!Iflg) { e("Giving up (try -i option?)\n"); return; } e("Scanning past wrong dump\n"); } len = totlen - 6; for (cp = &buf[6]; (i = read(Mfh, cp, len)) > 0; cp += i) if ((len -= i) <= 0) break; if (len > 0) { e("%s: expected %d bytes, got %d\n", av0, totlen, totlen - len); return; } if (write(fileno(fp), buf, totlen) != totlen) perror("write"); if (fp != Ofp) fclose(fp); } use() { e("Usage: %s [--] [-c#] [-i] [POPT ...] [VOPT ...]\n", av0); e(" -- send output to stdout instead of default file(s)\n"); e(" -c# read voices from midi channel #. default is %d\n", DEFCHAN+1); e(" -i ignore other sysex dumps that may precede the one we want\n"); e("The POPTs are:\n"); e(" -p# output specified performance, (# usually in the range 1-32)\n"); e(" -p#-# output specified performances (in the style of -peach)\n"); e(" -pall output performances 1-32 as half a 64-performance dump\n"); e(" -peach output performances 1-32 as 32 1-perf dumps (-p1-32)\n"); e(" -pedit output the performance in the edit buffer (-p0)\n"); e("The VOPTs are:\n"); e(" -v# output specified voice, (# usually in the range 1-32)\n"); e(" -v#-# output specified range of voices (in the style of -veach)\n"); e(" -vall output voices 1 through 32 as a 32-voice dump\n"); e(" -veach output voices 1-32 as 32 1-voice dumps (-v1-32)\n"); e(" -vedit output the voice in the edit buffer (-v0)\n"); e("default file names are:\n"); e("\t'v.V.C'\tfor single voice bulk dumps,\n"); e("\t'v..C'\tfor 32-voice bulk dumps,\n"); e("\t'p.P.C'\tfor single performance bulk dumps,\n"); e("\t'p..C'\tfor 64-performance bulk dumps,\n"); e("where 'C' is channel, 'V' is voice number (0 for edit buffer),\n"); e("and 'P' is perf number (0 for edit buffer).\n"); exit(2); }