home
***
CD-ROM
|
disk
|
FTP
|
other
***
search
/
The Fred Fish Collection 1.6
/
ffcollection-1-6-1993-02.iso
/
ff_disks
/
211-240
/
ff_228
/
glib
/
k5.c
< prev
next >
Wrap
C/C++ Source or Header
|
1989-06-26
|
12KB
|
601 lines
/*
* 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);
}