home *** CD-ROM | disk | FTP | other *** search
/ Club Amiga de Montreal - CAM / CAM_CD_1.iso / files / 242.lha / GenericLIBrarian / source / k5.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-04-07  |  15.1 KB  |  601 lines

  1. /*
  2.  * GLIB - a Generic LIBrarian and editor for synths
  3.  *
  4.  * Kawai K-5 Librarian - handles SINGLE and MULTI patches.
  5.  * Functions are annotated if they work for SINGLE, MULTI, or both kinds.
  6.  * Full editing not implemented - there are zillions of parameters,
  7.  * and the huge LCD on the K-5 is actually quite easy to read and use.
  8.  *
  9.  * Alan Bland - att!druwy!mab
  10.  */
  11.  
  12. #define OVERLAY2
  13.  
  14. #include "glib.h"
  15.  
  16. #define K5SINGLE        0
  17. #define K5MULTI         1
  18. #define K5MAGIC         0x5a3c
  19.  
  20. #define NERRS           5
  21.  
  22. extern char *visnum();
  23.  
  24. /* This array contains arbitrary screen labels (SINGLE) */
  25. struct labelinfo Lk5sin[] = {
  26.  3,10,"Sorry, no edit capability implemented for the K-5 yet.",
  27. 15,2,"+-------------------------+--------------+",
  28. 16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
  29. 17,2,"|",17,28,"|",17,43,"|",
  30. 18,2,"|h = left   q = quit      |Pitch",18,43,"|",
  31. 19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
  32. 20,2,"|k = up     J = Decrement |Duration      |",
  33. 21,2,"|l = right  K = Increment |Channel       |",
  34. 22,2,"|",22,28,"|",22,43,"|",
  35. 23,2,"+-------------------------+--------------+",
  36. -1,-1,NULL
  37. };
  38.  
  39. /* This array defines all the editable parameters. (SINGLE) */
  40. struct paraminfo Pk5sin[] = {
  41. "autopitch",    NULL,   -1,-1, 18, 38, visnum,          0, 127, 60, 0,
  42. "autovol",      NULL,   -1,-1, 19, 38, visnum,          0, 127, 63, 0,
  43. "autodur",      NULL,   -1,-1, 20, 38, visnum,          1,  20,  5, 0,
  44. "autochan",     NULL,   -1,-1, 21, 38, visnum,          1,  16,  1, 0,
  45.  
  46. NULL,           NULL,   -1,-1, -1, -1, visnum,          0,   0, 0, 0
  47. };
  48.  
  49. /* This array contains arbitrary screen labels (MULTI) */
  50. struct labelinfo Lk5mul[] = {
  51.  3,10,"Sorry, no edit capability implemented for the K-5 yet.",
  52. 15,2,"+-------------------------+--------------+",
  53. 16,2,"|Space = Play Note",16,28,"| Auto-Note    |",
  54. 17,2,"|",17,28,"|",17,43,"|",
  55. 18,2,"|h = left   q = quit      |Pitch",18,43,"|",
  56. 19,2,"|j = down   N = Set Name  |Volume",19,43,"|",
  57. 20,2,"|k = up     J = Decrement |Duration      |",
  58. 21,2,"|l = right  K = Increment |Channel       |",
  59. 22,2,"|",22,28,"|",22,43,"|",
  60. 23,2,"+-------------------------+--------------+",
  61. -1,-1,NULL
  62. };
  63.  
  64. /* This array defines all the editable parameters. (MULTI) */
  65. struct paraminfo Pk5mul[] = {
  66. "autopitch",    NULL,   -1,-1, 18, 38, visnum,          0, 127, 60, 0,
  67. "autovol",      NULL,   -1,-1, 19, 38, visnum,          0, 127, 63, 0,
  68. "autodur",      NULL,   -1,-1, 20, 38, visnum,          1,  20,  5, 0,
  69. "autochan",     NULL,   -1,-1, 21, 38, visnum,          1,  16,  1, 0,
  70.  
  71. NULL,           NULL,   -1,-1, -1, -1, visnum,          0,   0, 0, 0
  72. };
  73.  
  74. /*
  75.  * k5vnum
  76.  *
  77.  * Convert a voice number (0 to 47) to the string displayed in the
  78.  * librarian (A1-D12)  (SINGLE and MULTI)
  79.  */
  80. char *
  81. k5vnum(n)
  82. register int n;
  83. {
  84.         static char v[4];
  85.  
  86.         if ( n < 0 || n > 47 )
  87.                 return("??");
  88.  
  89.         sprintf(v, "%c%d", n/12 + 'A', n%12 + 1);
  90.         return(v);
  91. }
  92.  
  93. /*
  94.  * k5numv
  95.  *
  96.  * Convert an alphanumeric voice number (A1-D12) to internal
  97.  * format (0 - 47).  (SINGLE and MULTI)
  98.  */
  99. k5numv(n)
  100. register char *n;
  101. {
  102.         register int v,j;
  103.  
  104.         /* first better be [a-dA-D] */
  105.         *n = toupper(*n);
  106.         if (*n == 'A' || *n == 'B' || *n == 'C' || *n == 'D') {
  107.                 v = 12 * (*n - 'A');
  108.         } else {
  109.                 return(-1);
  110.         }
  111.  
  112.         /* followed by 1-12 */
  113.         j = atoi(++n);
  114.         if (j<1 || j>12) return(-1);
  115.         return v + j - 1;
  116. }
  117.  
  118. /*
  119.  * k5sindin
  120.  *
  121.  * Take library bank 'data' and stuff values in the P array, by using
  122.  * the setval function.
  123.  */
  124. k5sindin(data)
  125. char *data;
  126. {
  127.         /* We set the 'auto-note' channel upon entry */
  128.         setval("autochan",Channel);
  129. }
  130.  
  131. /*
  132.  * k5sindout
  133.  *
  134.  * Take (possibly changed) parameters values out of the P array and
  135.  * put them back into the library bank 'data'.
  136.  */
  137. k5sindout(data)
  138. char *data;
  139. {
  140.         /* If the autochan parameter has changed, update Channel */
  141.         Channel = getval("autochan");
  142. }
  143.  
  144. /*
  145.  * k5muldin
  146.  *
  147.  * Take library bank 'data' and stuff values in the P array, by using
  148.  * the setval function.
  149.  */
  150. k5muldin(data)
  151. char *data;
  152. {
  153.         /* We set the 'auto-note' channel upon entry */
  154.         setval("autochan",Channel);
  155. }
  156.  
  157. /*
  158.  * k5muldout
  159.  *
  160.  * Take (possibly changed) parameters values out of the P array and
  161.  * put them back into the library bank 'data'.
  162.  */
  163. k5muldout(data)
  164. char *data;
  165. {
  166.         /* If the autochan parameter has changed, update Channel */
  167.         Channel = getval("autochan");
  168. }
  169.  
  170. /*
  171.  * k5sinnof
  172.  *
  173.  * Return a pointer to the voice name buried in library bank data. (SINGLE)
  174.  */
  175. char *
  176. k5sinnof(data)
  177. register char *data;
  178. {
  179.         static char currbuff[9];
  180.         register char *p;
  181.         register int m;
  182.  
  183.         p = currbuff;
  184.         for ( m=0; m<16; m+=2 )
  185.                 *p++ = (data[m]<<4) | data[m+1];
  186.         *p = '\0';
  187.         return(currbuff);
  188. }
  189.  
  190. /*
  191.  * k5nameok
  192.  *
  193.  * Convert an ascii string to the ascii subset used for K5 names.
  194.  */
  195. char*
  196. k5nameok(name)
  197. char *name;
  198. {
  199.         static char okname[9];
  200.         register int m;
  201.  
  202.         for (m=0; m<9 && name[m]; ++m) {
  203.                 okname[m] = toupper(name[m]);
  204.                 if (!isalnum(okname[m])) {
  205.                         switch (okname[m]) {
  206.                         case '-': case ':': case '/': case '*': case '?':
  207.                         case '!': case '#': case '&': case '(': case ')':
  208.                         case '"': case '+': case '.': case '=': case ' ':
  209.                                 break;
  210.                         default:
  211.                                 okname[m] = ' ';
  212.                                 break;
  213.                         }
  214.                 }
  215.         }
  216.         okname[m] = '\0';
  217.         return okname;
  218. }
  219.  
  220. /*
  221.  * k5sinsnof
  222.  *
  223.  * Set the voice name buried in data to name. (SINGLE)
  224.  */
  225. k5sinsnof(data,name)
  226. char *data;
  227. char *name;
  228. {
  229.         register char *p;
  230.         register int m;
  231.  
  232.         for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
  233.                 data[m] = (*p & 0xf0) >> 4;
  234.                 data[m+1] = *p & 0x0f;
  235.         }
  236.         for ( ; m<17; m+=2 ) {
  237.                 data[m] = (' ' & 0xf0) >> 4;
  238.                 data[m+1] = ' ' & 0x0f;
  239.         }
  240. }
  241. /*
  242.  * k5mulnof
  243.  *
  244.  * Return a pointer to the voice name buried in library bank data. (MULTI)
  245.  */
  246. char *
  247. k5mulnof(data)
  248. char *data;
  249. {
  250.         static char currbuff[9];
  251.         register char *p;
  252.         register int m;
  253.  
  254.         p = currbuff;
  255.         for ( m=0; m<16; m+=2 )
  256.                 *p++ = (data[m+330]<<4) | data[m+331];
  257.         *p = '\0';
  258.         return(currbuff);
  259. }
  260.  
  261. /*
  262.  * k5mulsnof
  263.  *
  264.  * Set the voice name buried in data to name. (MULTI)
  265.  */
  266. k5mulsnof(data,name)
  267. char *data;
  268. char *name;
  269. {
  270.         char *p;
  271.         int m;
  272.  
  273.         for ( p=k5nameok(name),m=0; *p!='\0' && m<17; p++,m+=2 ) {
  274.                 data[m+330] = (*p & 0xf0) >> 4;
  275.                 data[m+331] = *p & 0x0f;
  276.         }
  277.         for ( ; m<17; m+=2 ) {
  278.                 data[m+330] = (' ' & 0xf0) >> 4;
  279.                 data[m+331] = ' ' & 0x0f;
  280.         }
  281. }
  282.  
  283. /*
  284.  * k5sbulk
  285.  *
  286.  * common function to send all voices to the K-5 (SINGLE and MULTI)
  287.  */
  288. k5sbulk(data, which)
  289. char *data;
  290. int which;      /* K5SINGLE or K5MULTI */
  291. {
  292.         int n, err = 0;
  293.         message("");
  294.         for (n=0; n<Nvoices; ++n) {
  295.                 for (err=0; err<NERRS; ++err) {
  296.                         if (k5sone(n, &(VOICEBYTE(data,n,0)), which ) == 0 ) {
  297.                                 windputc('+');
  298.                                 windrefresh();
  299.                                 break;
  300.                         }
  301.                         windputc('-');
  302.                         windrefresh();
  303.                 }
  304.                 if (err == NERRS) return(1);
  305.         }
  306.         return(0);
  307. }
  308.  
  309. /*
  310.  * k5sinsbulk
  311.  *
  312.  * send all voices to the K-5 (SINGLE)
  313.  */
  314. k5sinsbulk(data)
  315. char *data;
  316. {
  317.         return k5sbulk(data, K5SINGLE);
  318. }
  319.  
  320. /*
  321.  * k5mulsbulk
  322.  *
  323.  * send all voices to the K-5 (MULTI)
  324.  */
  325. k5mulsbulk(data)
  326. char *data;
  327. {
  328.         return k5sbulk(data, K5MULTI);
  329. }
  330.  
  331. /*
  332.  * k5sinsone
  333.  *
  334.  * send one voice to the K-5 (SINGLE)
  335.  */
  336. k5sinsone(iv, data)
  337. int iv;
  338. char *data;
  339. {
  340.         return k5sone(iv, data, K5SINGLE);
  341. }
  342.  
  343. /*
  344.  * k5mulsone
  345.  *
  346.  * send one voice to the K-5 (MULTI)
  347.  */
  348. k5mulsone(iv, data)
  349. {
  350.         return k5sone(iv, data, K5MULTI);
  351. }
  352.  
  353. /*
  354.  * k5sone
  355.  *
  356.  * common function to send a SINGLE or MULTI voice to the K-5.
  357.  */
  358. k5sone(iv, data, which)
  359. int iv;
  360. register char *data;
  361. int which;      /* K5SINGLE or K5MULTI */
  362. {
  363.         register int i, sum;
  364.         int length;
  365.         int c = 0, ret = 1;
  366.         long begin, toolong;
  367.  
  368.         flushmidi();
  369.  
  370.         length = (which == K5SINGLE) ? 984 : 352;
  371.  
  372.         /* calculate checksum */
  373.         for (sum=0, i=0; i<length-4; ) {
  374.                 sum += data[i++] << 4;
  375.                 sum += data[i++];
  376.                 sum += data[i++] << 12;
  377.                 sum += data[i++] << 8;
  378.         }
  379.  
  380.         sum = K5MAGIC - sum;
  381.         data[length-4] = (sum & 0x00f0) >> 4;
  382.         data[length-3] = (sum & 0x000f);
  383.         data[length-2] = (sum & 0xf000) >> 12;
  384.         data[length-1] = (sum & 0x0f00) >> 8;
  385.         
  386.         sendmidi(0xf0);
  387.         sendmidi(0x40);
  388.         sendmidi(Channel-1);
  389.         sendmidi(0x20);
  390.         sendmidi(0x00);
  391.         sendmidi(0x02);
  392.         sendmidi(which);
  393.         sendmidi(iv);
  394.  
  395.         for (i=0; i<length; i++) sendmidi(data[i]);
  396.  
  397.         sendmidi(EOX);
  398.  
  399.         /* read the ack/nack - set up for timeout */
  400.         begin = milliclock();
  401.         toolong = begin + 1000 * TIMEOUT;
  402.  
  403.         /* wait for the acknowledgement */
  404.         while ( milliclock() < toolong ) {
  405.                 if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
  406.                         break;
  407.         }
  408.         if ( c != 0xf0 ) {
  409.                 Reason = "Timeout waiting for K-5 response";
  410.                 goto getout;
  411.         }
  412.         
  413.         /* third byte after the sysex begin is the result */
  414.         for (i=0; i<3; ) {
  415.                 /* wait for midi byte or timeout */
  416.                 while ( ! STATMIDI ) {
  417.                         if ( milliclock() > toolong ) {
  418.                                 Reason = "Timeout waiting for K-5 response";
  419.                                 goto getout;
  420.                         }
  421.                 }
  422.                 /* ignore active sensing */
  423.                 if ((c = getmidi() & 0xff) != 0xfe) {
  424.                         ++i;
  425.                 }
  426.         }
  427.  
  428.         /* check the result */
  429.         switch (c) {
  430.         case 0x40:
  431.                 ret = 0;
  432.                 Reason = "";
  433.                 break;
  434.         case 0x41:
  435.                 Reason = "K-5 write error";
  436.                 break;
  437.         case 0x42:
  438.                 Reason = "K-5 write error (protected)";
  439.                 break;
  440.         case 0x43:
  441.                 Reason = "K-5 write error (no card)";
  442.                 break;
  443.         default:
  444.                 Reason = "Wierd response (is that really a K-5 you have?)";
  445.                 break;
  446.         }
  447.  
  448. getout:
  449.         return(ret);
  450. }
  451.  
  452. k5sinsedit()
  453. {
  454. }
  455.  
  456. k5mulsedit()
  457. {
  458. }
  459.  
  460. /*
  461.  * k5singbulk
  462.  *
  463.  * get all internal SINGLE voices from K-5.
  464.  */
  465. k5singbulk(data)
  466. char *data;
  467. {
  468.         return k5gbulk(data, K5SINGLE);
  469. }
  470.  
  471. /*
  472.  * k5mulgbulk
  473.  *
  474.  * get all internal MULTI voices from K-5.
  475.  */
  476. k5mulgbulk(data)
  477. char *data;
  478. {
  479.         return k5gbulk(data, K5MULTI);
  480. }
  481.  
  482. /*
  483.  * k5gbulk
  484.  *
  485.  * common routine - get all SINGLE or MULTI voices from K-5.
  486.  */
  487. k5gbulk(data, which)
  488. register char *data;
  489. int which;      /* K5SINGLE or K5MULTI */
  490. {
  491.         int c, v, sumerr = 0;
  492.         register int n, i, sum;
  493.         long begin, toolong;
  494.  
  495.         message("");
  496.         flushmidi();
  497.  
  498.         for(v = 0; v < Nvoices; v++) {
  499.  
  500. retry:          
  501.                 if (which == K5MULTI) {
  502.                         /* i don't know if this is a K-5 or Amiga problem */
  503.                         /* but multi patch download seems to need this delay */
  504.                         millisleep(500);
  505.                 }
  506.                 /* request the voice */
  507.                 sendmidi(0xf0);
  508.                 sendmidi(0x40);
  509.                 sendmidi(Channel-1);
  510.                 sendmidi(0x00);
  511.                 sendmidi(0x00);
  512.                 sendmidi(0x02);
  513.                 sendmidi(which);
  514.                 sendmidi(v);
  515.                 sendmidi(EOX);
  516.         
  517.                 /* set up for timeout */
  518.                 begin = milliclock();
  519.                 toolong = begin + 1000 * TIMEOUT;
  520.         
  521.                 /* wait for the xf0 byte starting the dump */
  522.                 while ( milliclock() < toolong ) {
  523.                         if ( STATMIDI && (c=(getmidi() & 0xff)) == 0xf0 )
  524.                                 break;
  525.                 }
  526.                 if ( c != 0xf0 ) {
  527.                         Reason = "Timeout waiting for dump from K-5";
  528.                         return 1;
  529.                 }
  530. /*printf("%02x ", c);*/
  531.                 /* skip the next 7 bytes (remainder of sysex header) */
  532.                 for (i=0; i<7; ) {
  533.                         /* wait for midi byte or timeout */
  534.                         while ( ! STATMIDI ) {
  535.                                 if ( milliclock() > toolong )
  536.                                         goto timeout;
  537.                         }
  538.                         /* ignore active sensing */
  539.                         if ((c = getmidi() & 0xff) != 0xfe) {
  540.                                 ++i;
  541. /*printf("%02x ", c);*/
  542.                         }
  543.                 }
  544.  
  545.                 /* read voice data until EOX */
  546.                 n = 0;
  547.                 while (1) {
  548.                         /* wait for midi byte or timeout */
  549.                         while ( ! STATMIDI ) {
  550.                                 if ( milliclock() > toolong )
  551.                                         goto timeout;
  552.                         }
  553.                         if ((c = getmidi() & 0xff) == 0xfe) {
  554.                                 /* ignore active sensing */
  555.                                 continue;
  556.                         } else if (c == EOX) {
  557.                                 /* finished */
  558.                                 break;
  559.                         } else {
  560.                                 /* got a data byte */
  561.                                 VOICEBYTE(data,v,n) = c;
  562.                                 ++n;
  563.                         }
  564.                 }
  565. /*printf("got block n=%d\n", n);*/
  566.                 /* verify the checksum */
  567.                 for (sum=0, i=0; i<n-4; ) {
  568.                         sum += data[i++] << 4;
  569.                         sum += data[i++];
  570.                         sum += data[i++] << 12;
  571.                         sum += data[i++] << 8;
  572.                 }
  573.  
  574.                 sum = K5MAGIC - sum;
  575.                 if ((data[n-4] == (sum & 0x00f0) >> 4) &&
  576.                     (data[n-3] == (sum & 0x000f)) &&
  577.                     (data[n-2] == (sum & 0xf000) >> 12) &&
  578.                     (data[n-1] == (sum & 0x0f00) >> 8)) {
  579.                         sumerr = 0;
  580.                         windputc('+');
  581.                 } else {
  582.                         /* retry a few times if checksum failed */
  583.                         windputc('-');
  584.                         if (sumerr++ >= NERRS) {
  585.                                 Reason = "Too many checksum errors!";
  586.                                 return(1);
  587.                         }
  588.                         goto retry;
  589.                 }
  590.                 windrefresh();
  591.  
  592.         } /* go back for another voice */
  593.         Reason = "";
  594.         return(0);
  595.  
  596. timeout:
  597.         Reason = "Timeout while reading!";
  598.         return(1);
  599. }
  600.  
  601.