home *** CD-ROM | disk | FTP | other *** search
- /*
- * GLIB - a Generic LIBrarian and editor for synths
- *
- * Kawai K-5 Librarian - handles SINGLE and MULTI patches.
- * Functions are annotated if they work for SINGLE, MULTI, or both kinds.
- * Full editing not implemented - there are zillions of parameters,
- * and the huge LCD on the K-5 is actually quite easy to read and use.
- *
- * Alan Bland - att!druwy!mab
- */
-
- #define OVERLAY2
-
- #include "glib.h"
-
- #define K5SINGLE 0
- #define K5MULTI 1
- #define K5MAGIC 0x5a3c
-
- #define NERRS 5
-
- extern char *visnum();
-
- /* This array contains arbitrary screen labels (SINGLE) */
- struct labelinfo Lk5sin[] = {
- 3,10,"Sorry, no edit capability implemented for the K-5 yet.",
- 15,2,"+-------------------------+--------------+",
- 16,2,"|Space = Play Note",16,28,"| Auto-Note |",
- 17,2,"|",17,28,"|",17,43,"|",
- 18,2,"|h = left q = quit |Pitch",18,43,"|",
- 19,2,"|j = down N = Set Name |Volume",19,43,"|",
- 20,2,"|k = up J = Decrement |Duration |",
- 21,2,"|l = right K = Increment |Channel |",
- 22,2,"|",22,28,"|",22,43,"|",
- 23,2,"+-------------------------+--------------+",
- -1,-1,NULL
- };
-
- /* This array defines all the editable parameters. (SINGLE) */
- struct paraminfo Pk5sin[] = {
- "autopitch", NULL, -1,-1, 18, 38, visnum, 0, 127, 60, 0,
- "autovol", NULL, -1,-1, 19, 38, visnum, 0, 127, 63, 0,
- "autodur", NULL, -1,-1, 20, 38, visnum, 1, 20, 5, 0,
- "autochan", NULL, -1,-1, 21, 38, visnum, 1, 16, 1, 0,
-
- NULL, NULL, -1,-1, -1, -1, visnum, 0, 0, 0, 0
- };
-
- /* This array contains arbitrary screen labels (MULTI) */
- struct labelinfo Lk5mul[] = {
- 3,10,"Sorry, no edit capability implemented for the K-5 yet.",
- 15,2,"+-------------------------+--------------+",
- 16,2,"|Space = Play Note",16,28,"| Auto-Note |",
- 17,2,"|",17,28,"|",17,43,"|",
- 18,2,"|h = left q = quit |Pitch",18,43,"|",
- 19,2,"|j = down N = Set Name |Volume",19,43,"|",
- 20,2,"|k = up J = Decrement |Duration |",
- 21,2,"|l = right K = Increment |Channel |",
- 22,2,"|",22,28,"|",22,43,"|",
- 23,2,"+-------------------------+--------------+",
- -1,-1,NULL
- };
-
- /* This array defines all the editable parameters. (MULTI) */
- struct paraminfo Pk5mul[] = {
- "autopitch", NULL, -1,-1, 18, 38, visnum, 0, 127, 60, 0,
- "autovol", NULL, -1,-1, 19, 38, visnum, 0, 127, 63, 0,
- "autodur", NULL, -1,-1, 20, 38, visnum, 1, 20, 5, 0,
- "autochan", NULL, -1,-1, 21, 38, visnum, 1, 16, 1, 0,
-
- NULL, NULL, -1,-1, -1, -1, visnum, 0, 0, 0, 0
- };
-
- /*
- * k5vnum
- *
- * Convert a voice number (0 to 47) to the string displayed in the
- * librarian (A1-D12) (SINGLE and MULTI)
- */
- char *
- k5vnum(n)
- register int n;
- {
- static char v[4];
-
- if ( n < 0 || n > 47 )
- return("??");
-
- sprintf(v, "%c%d", n/12 + 'A', n%12 + 1);
- return(v);
- }
-
- /*
- * k5numv
- *
- * Convert an alphanumeric voice number (A1-D12) to internal
- * format (0 - 47). (SINGLE and MULTI)
- */
- k5numv(n)
- register char *n;
- {
- register int v,j;
-
- /* first better be [a-dA-D] */
- *n = toupper(*n);
- if (*n == 'A' || *n == 'B' || *n == 'C' || *n == 'D') {
- v = 12 * (*n - 'A');
- } else {
- return(-1);
- }
-
- /* followed by 1-12 */
- j = atoi(++n);
- if (j<1 || j>12) return(-1);
- return v + j - 1;
- }
-
- /*
- * k5sindin
- *
- * Take library bank 'data' and stuff values in the P array, by using
- * the setval function.
- */
- k5sindin(data)
- char *data;
- {
- /* We set the 'auto-note' channel upon entry */
- setval("autochan",Channel);
- }
-
- /*
- * k5sindout
- *
- * Take (possibly changed) parameters values out of the P array and
- * put them back into the library bank 'data'.
- */
- k5sindout(data)
- char *data;
- {
- /* If the autochan parameter has changed, update Channel */
- Channel = getval("autochan");
- }
-
- /*
- * k5muldin
- *
- * Take library bank 'data' and stuff values in the P array, by using
- * the setval function.
- */
- k5muldin(data)
- char *data;
- {
- /* We set the 'auto-note' channel upon entry */
- setval("autochan",Channel);
- }
-
- /*
- * k5muldout
- *
- * Take (possibly changed) parameters values out of the P array and
- * put them back into the library bank 'data'.
- */
- k5muldout(data)
- char *data;
- {
- /* If the autochan parameter has changed, update Channel */
- Channel = getval("autochan");
- }
-
- /*
- * k5sinnof
- *
- * Return a pointer to the voice name buried in library bank data. (SINGLE)
- */
- char *
- k5sinnof(data)
- register char *data;
- {
- static char currbuff[9];
- register char *p;
- register int m;
-
- p = currbuff;
- for ( m=0; m<16; m+=2 )
- *p++ = (data[m]<<4) | data[m+1];
- *p = '\0';
- return(currbuff);
- }
-
- /*
- * k5nameok
- *
- * Convert an ascii string to the ascii subset used for K5 names.
- */
- char*
- k5nameok(name)
- char *name;
- {
- static char okname[9];
- register int m;
-
- for (m=0; m<9 && name[m]; ++m) {
- okname[m] = toupper(name[m]);
- if (!isalnum(okname[m])) {
- switch (okname[m]) {
- case '-': case ':': case '/': case '*': case '?':
- case '!': case '#': case '&': case '(': case ')':
- case '"': case '+': case '.': case '=': case ' ':
- break;
- default:
- okname[m] = ' ';
- break;
- }
- }
- }
- okname[m] = '\0';
- return okname;
- }
-
- /*
- * k5sinsnof
- *
- * Set the voice name buried in data to name. (SINGLE)
- */
- k5sinsnof(data,name)
- char *data;
- char *name;
- {
- register char *p;
- register int m;
-
- for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
- data[m] = (*p & 0xf0) >> 4;
- data[m+1] = *p & 0x0f;
- }
- for ( ; m<17; m+=2 ) {
- data[m] = (' ' & 0xf0) >> 4;
- data[m+1] = ' ' & 0x0f;
- }
- }
- /*
- * k5mulnof
- *
- * Return a pointer to the voice name buried in library bank data. (MULTI)
- */
- char *
- k5mulnof(data)
- char *data;
- {
- static char currbuff[9];
- register char *p;
- register int m;
-
- p = currbuff;
- for ( m=0; m<16; m+=2 )
- *p++ = (data[m+330]<<4) | data[m+331];
- *p = '\0';
- return(currbuff);
- }
-
- /*
- * k5mulsnof
- *
- * Set the voice name buried in data to name. (MULTI)
- */
- k5mulsnof(data,name)
- char *data;
- char *name;
- {
- char *p;
- int m;
-
- for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
- data[m+330] = (*p & 0xf0) >> 4;
- data[m+331] = *p & 0x0f;
- }
- for ( ; m<17; m+=2 ) {
- data[m+330] = (' ' & 0xf0) >> 4;
- data[m+331] = ' ' & 0x0f;
- }
- }
-
- /*
- * k5sbulk
- *
- * common function to send all voices to the K-5 (SINGLE and MULTI)
- */
- k5sbulk(data, which)
- char *data;
- int which; /* K5SINGLE or K5MULTI */
- {
- int n, err = 0;
- message("");
- for (n=0; n<Nvoices; ++n) {
- for (err=0; err<NERRS; ++err) {
- if (k5sone(n, &(VOICEBYTE(data,n,0)), which ) == 0 ) {
- windputc('+');
- windrefresh();
- break;
- }
- windputc('-');
- windrefresh();
- }
- if (err == NERRS) return(1);
- }
- return(0);
- }
-
- /*
- * k5sinsbulk
- *
- * send all voices to the K-5 (SINGLE)
- */
- k5sinsbulk(data)
- char *data;
- {
- return k5sbulk(data, K5SINGLE);
- }
-
- /*
- * k5mulsbulk
- *
- * send all voices to the K-5 (MULTI)
- */
- k5mulsbulk(data)
- char *data;
- {
- return k5sbulk(data, K5MULTI);
- }
-
- /*
- * k5sinsone
- *
- * send one voice to the K-5 (SINGLE)
- */
- k5sinsone(iv, data)
- int iv;
- char *data;
- {
- return k5sone(iv, data, K5SINGLE);
- }
-
- /*
- * k5mulsone
- *
- * send one voice to the K-5 (MULTI)
- */
- k5mulsone(iv, data)
- {
- return k5sone(iv, data, K5MULTI);
- }
-
- /*
- * k5sone
- *
- * common function to send a SINGLE or MULTI voice to the K-5.
- */
- k5sone(iv, data, which)
- int iv;
- register char *data;
- int which; /* K5SINGLE or K5MULTI */
- {
- register int i, sum;
- int length;
- int c = 0, ret = 1;
- long begin, toolong;
-
- flushmidi();
-
- length = (which == K5SINGLE) ? 984 : 352;
-
- /* calculate checksum */
- for (sum=0, i=0; i<length-4; ) {
- sum += data[i++] << 4;
- sum += data[i++];
- sum += data[i++] << 12;
- sum += data[i++] << 8;
- }
-
- sum = K5MAGIC - sum;
- data[length-4] = (sum & 0x00f0) >> 4;
- data[length-3] = (sum & 0x000f);
- data[length-2] = (sum & 0xf000) >> 12;
- data[length-1] = (sum & 0x0f00) >> 8;
-
- sendmidi(0xf0);
- sendmidi(0x40);
- sendmidi(Channel-1);
- sendmidi(0x20);
- sendmidi(0x00);
- sendmidi(0x02);
- sendmidi(which);
- sendmidi(iv);
-
- for (i=0; i<length; i++) sendmidi(data[i]);
-
- sendmidi(EOX);
-
- /* read the ack/nack - set up for timeout */
- begin = milliclock();
- toolong = begin + 1000 * TIMEOUT;
-
- /* wait for the acknowledgement */
- while ( milliclock() < toolong ) {
- if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
- break;
- }
- if ( c != 0xf0 ) {
- Reason = "Timeout waiting for K-5 response";
- goto getout;
- }
-
- /* third byte after the sysex begin is the result */
- for (i=0; i<3; ) {
- /* wait for midi byte or timeout */
- while ( ! STATMIDI ) {
- if ( milliclock() > toolong ) {
- Reason = "Timeout waiting for K-5 response";
- goto getout;
- }
- }
- /* ignore active sensing */
- if ((c = getmidi() & 0xff) != 0xfe) {
- ++i;
- }
- }
-
- /* check the result */
- switch (c) {
- case 0x40:
- ret = 0;
- Reason = "";
- break;
- case 0x41:
- Reason = "K-5 write error";
- break;
- case 0x42:
- Reason = "K-5 write error (protected)";
- break;
- case 0x43:
- Reason = "K-5 write error (no card)";
- break;
- default:
- Reason = "Wierd response (is that really a K-5 you have?)";
- break;
- }
-
- getout:
- return(ret);
- }
-
- k5sinsedit()
- {
- }
-
- k5mulsedit()
- {
- }
-
- /*
- * k5singbulk
- *
- * get all internal SINGLE voices from K-5.
- */
- k5singbulk(data)
- char *data;
- {
- return k5gbulk(data, K5SINGLE);
- }
-
- /*
- * k5mulgbulk
- *
- * get all internal MULTI voices from K-5.
- */
- k5mulgbulk(data)
- char *data;
- {
- return k5gbulk(data, K5MULTI);
- }
-
- /*
- * k5gbulk
- *
- * common routine - get all SINGLE or MULTI voices from K-5.
- */
- k5gbulk(data, which)
- register char *data;
- int which; /* K5SINGLE or K5MULTI */
- {
- int c, v, sumerr = 0;
- register int n, i, sum;
- long begin, toolong;
-
- message("");
- flushmidi();
-
- for(v = 0; v < Nvoices; v++) {
-
- retry:
- if (which == K5MULTI) {
- /* i don't know if this is a K-5 or Amiga problem */
- /* but multi patch download seems to need this delay */
- millisleep(500);
- }
- /* request the voice */
- sendmidi(0xf0);
- sendmidi(0x40);
- sendmidi(Channel-1);
- sendmidi(0x00);
- sendmidi(0x00);
- sendmidi(0x02);
- sendmidi(which);
- sendmidi(v);
- sendmidi(EOX);
-
- /* set up for timeout */
- begin = milliclock();
- toolong = begin + 1000 * TIMEOUT;
-
- /* wait for the xf0 byte starting the dump */
- while ( milliclock() < toolong ) {
- if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
- break;
- }
- if ( c != 0xf0 ) {
- Reason = "Timeout waiting for dump from K-5";
- return 1;
- }
- /*printf("%02x ", c);*/
- /* skip the next 7 bytes (remainder of sysex header) */
- for (i=0; i<7; ) {
- /* wait for midi byte or timeout */
- while ( ! STATMIDI ) {
- if ( milliclock() > toolong )
- goto timeout;
- }
- /* ignore active sensing */
- if ((c = getmidi() & 0xff) != 0xfe) {
- ++i;
- /*printf("%02x ", c);*/
- }
- }
-
- /* read voice data until EOX */
- n = 0;
- while (1) {
- /* wait for midi byte or timeout */
- while ( ! STATMIDI ) {
- if ( milliclock() > toolong )
- goto timeout;
- }
- if ((c = getmidi() & 0xff) == 0xfe) {
- /* ignore active sensing */
- continue;
- } else if (c == EOX) {
- /* finished */
- break;
- } else {
- /* got a data byte */
- VOICEBYTE(data,v,n) = c;
- ++n;
- }
- }
- /*printf("got block n=%d\n", n);*/
- /* verify the checksum */
- for (sum=0, i=0; i<n-4; ) {
- sum += data[i++] << 4;
- sum += data[i++];
- sum += data[i++] << 12;
- sum += data[i++] << 8;
- }
-
- sum = K5MAGIC - sum;
- if ((data[n-4] == (sum & 0x00f0) >> 4) &&
- (data[n-3] == (sum & 0x000f)) &&
- (data[n-2] == (sum & 0xf000) >> 12) &&
- (data[n-1] == (sum & 0x0f00) >> 8)) {
- sumerr = 0;
- windputc('+');
- } else {
- /* retry a few times if checksum failed */
- windputc('-');
- if (sumerr++ >= NERRS) {
- Reason = "Too many checksum errors!";
- return(1);
- }
- goto retry;
- }
- windrefresh();
-
- } /* go back for another voice */
- Reason = "";
- return(0);
-
- timeout:
- Reason = "Timeout while reading!";
- return(1);
- }
-
-