home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume6 / glib / part05 / k5single.mnu < prev    next >
Encoding:
Text File  |  1989-05-14  |  10.5 KB  |  604 lines

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