home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / mt / mtrc4.c < prev    next >
C/C++ Source or Header  |  1990-03-06  |  11KB  |  398 lines

  1. /* mtrc4.c */
  2. /* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
  3.  
  4. /* #define TURBOC 1   Define if using TURBOC, leave out for Microsoft */
  5.  
  6. #include <stdio.h>
  7. #include <conio.h>
  8. #include <string.h>
  9.  
  10. #ifdef TURBOC
  11.     #include <alloc.h>
  12. #else
  13.     #include <malloc.h>
  14. #endif
  15.  
  16. #include "screenf.h"
  17. #include "standard.h"
  18. #include "mpu401.h"
  19. #include "mt.h"
  20. #include "video.h"
  21. #include "mtdeclar.h"
  22.  
  23.  
  24. /* allocate a block of far memory big enough to hold one event. */
  25. /* returns pointer to memory area. */
  26. struct event far 
  27. *eventalloc(void)
  28. {   
  29. #ifdef TURBOC
  30.     return((struct event far *)farmalloc(sizeof(struct event)));
  31. #else
  32.     return((struct event far *)_fmalloc(sizeof(struct event)));
  33. #endif
  34. }
  35.  
  36.     
  37. /* store an event in far memory , return pointer to next event. */
  38. /* node is the last (empty) event created. */
  39. struct event far
  40. *store(struct event far *node, int nbytes, int b0, int b1, int b2, int b3)
  41. {
  42.     node->next = eventalloc();
  43.     (node->next)->next = NULL;  /* null pointer in next node to mark end */
  44.     node->nbytes = nbytes;
  45.     node->b[0] = b0;
  46.     node->b[1] = b1;
  47.     node->b[2] = b2;
  48.     node->b[3] = b3;
  49.     return(node->next);
  50. }
  51.  
  52.  
  53. /* This block contains the communications functions to/from the MPU-401 */
  54. /* At the lowest level these use the MIO401.ASM assembly language calls. */
  55. /* Only get401(), sendcmd401(), repeat_cmd401() and putdata401() are used */
  56. /* outside of this block.  The remainder handle data buffering. */
  57.  
  58. #define BUFSIZE     100
  59. int cmdbuf[BUFSIZE];        /* global buffer for pending MPU commands */
  60. int cmdbufp = 0;            /* next free position in cmdbuf */
  61.  
  62.  /* get a possibly pushed back command from MPU or cmdbuf */
  63. int
  64. getnext401(void)
  65. {
  66.     return((cmdbufp > 0) ? cmdbuf[--cmdbufp] : getdata());
  67. }
  68.  
  69.  
  70. void
  71. ungetnext401(int n)                     /* push a command back on input */
  72. {
  73.     if (cmdbufp > BUFSIZE)
  74.         printf("\nungetnext401 ran out of buffer space.");
  75.     else
  76.         cmdbuf[cmdbufp++] = n;
  77. }
  78.  
  79.  
  80. int
  81. get401(void)        /* get next byte from mpu401 (or pending buffer) */     
  82. {                   /* try forever, stop on keypress */
  83.     int i;
  84.     
  85.     while (1){
  86.         if (kbhit())
  87.             return(-1);
  88.         i = getnext401();
  89.         if (g_trace_on){
  90.             if (i != -1)
  91.                 printf(" rc=%0x", i);
  92.         }
  93.         if (i != -1) 
  94.             return(i);
  95.     }
  96.     return(-1);
  97. }
  98.  
  99.  
  100. void
  101. putdata401(int n)       /* send data byte to MPU, print it if trace is on */
  102. {
  103.     putdata(n);
  104.     if (g_trace_on)
  105.         printf(" td=%0x", n);
  106. }
  107.  
  108.  
  109. int                 /* send a command, check for ACK, if not save MPU data */
  110. sendcmd401(int n)   /* until it stops sending */
  111. {
  112.     int ans;
  113.  
  114.     if (g_trace_on)
  115.         printf(" tc=%0x", n);
  116.     ans = putcmd(n);
  117.     if (ans == ACK){
  118.         if (g_trace_on)
  119.             fputs("(ACK)", stdout);
  120.         return(ans);
  121.     }
  122.     else if (ans != -1){
  123.         if (g_trace_on)
  124.             fputs("(No ACK)", stdout);
  125.         ungetnext401(ans);      /* put pending data on stack */
  126.         while (1){              /* check for more incoming data */
  127.             ans = getdata();
  128.             if (ans == ACK || ans == -1)
  129.                 return(ans);
  130.             else
  131.                 ungetnext401(ans);
  132.         }
  133.     }
  134.     return(ans);
  135. }
  136.  
  137.  
  138. int
  139. repeat_cmd401(int n)    /* determined command send -  max tries = 10 */
  140. {
  141.     int i, j, m;
  142.     char buf[SCRNWIDE], nbuf[10];
  143.     
  144.     for (i = 0; i < 10; i++){
  145.         m = sendcmd401(n);
  146.         if (m != -1)
  147.             return(m);
  148.         if ((m = getdata()) != -1)      /* check for ack */
  149.             return(m) ;
  150.     }
  151.     if (!g_trace_on)
  152.     {
  153.         strcpy(buf, "Error in sending command ");
  154.         itoa(n, nbuf, 16);
  155.         strcat(buf, nbuf);
  156.         strcat(buf, " hex. (repeat_cmd401)");
  157.         writeword(buf, 1, g_text_char_v, g_emph_attrib);
  158.     }
  159.     return(-1);
  160. }
  161.  
  162. /* end of MPU communications function block */
  163.  
  164. /* Move all track counters to given measure.  Returns measure number of */
  165. /* the highest measure reached before running off end of longest track. */
  166. int
  167. goto_measure(int meas)
  168. {
  169.     int end_meas, count, i;
  170.     struct event far *ep;
  171.     struct event far *lep;
  172.     struct event far *startp;
  173.     
  174.     end_meas = 0;
  175.     for (i = 0; i < NTRACK; i++){
  176.         startp = ep = g_trackarray[i].first;
  177.         lep = g_trackarray[i].last;
  178.         count = 0;
  179.         while (count != meas){
  180.             if (ep == lep){                 /* if reached end of track */
  181.                 break;
  182.             }
  183.             if ((ep->b[1]) == MES_END){     /* found measure end mark */
  184.                 if (ep != startp){          /* don't count first event */
  185.                     count++;
  186.                 }
  187.             }
  188.             ep = ep->next;
  189.         }
  190.         if (count > end_meas)
  191.             end_meas = count;
  192.         g_trackarray[i].current = ep;
  193.     }
  194.     return(end_meas);
  195. }
  196.  
  197.  
  198. /* adjust all MIDI data on track to channel specified */
  199. void
  200. change_channel(int track, int channel)
  201. {
  202.     unsigned int data, root;
  203.     struct event far *ep;
  204.  
  205.     ep = g_trackarray[track].first;
  206.     
  207.     while (ep->next != NULL){
  208.         data = ep->b[1];                /* get second byte of data */
  209.                                         /* check if it is a MIDI message */
  210.         if (data >= 0x90 && data <= 0xEF){   
  211.             root = data - (data % 0x10);
  212.             ep->b[1] = root + channel;
  213.         }
  214.         ep = ep->next;
  215.     }
  216. }
  217.  
  218.  
  219. /* put default values in track data array.  Allocate first event for each */
  220. /* track and set it to a MES_END.  Called on startup from main(). */
  221. void
  222. init_tracks(void)
  223. {
  224.     int i, j;
  225.     struct event far *ep;
  226.     
  227.     for (i = 0; i < NTRACK; i++){
  228.         strcpy(g_trackarray[i].name, "<      >");
  229.         g_trackarray[i].midichan = i;
  230.         g_trackarray[i].numevents = 1;
  231.         g_trackarray[i].active = 0;
  232.         g_trackarray[i].midivol = 100;
  233.         ep = eventalloc();
  234.         g_trackarray[i].first = ep;
  235.         g_trackarray[i].current = ep;
  236.         g_trackarray[i].last = ep;
  237.  
  238.         ep->next = NULL;            /* starting event is a mes_end */
  239.         ep->nbytes = 2;
  240.         ep->b[1] = MES_END;
  241.         ep->b[0] = ep->b[2] = ep->b[3] = 0;
  242.     }
  243.     g_trackarray[0].active = 1;     /* start with track 1 active */
  244. }
  245.  
  246.  
  247. /* Find the number of K bytes free in memory on startup.  Allocates 10K */
  248. /* blocks until not further space.  Can leave smaller space unnoticed. */
  249. int
  250. free_memory(void)
  251. {
  252.     void far *node[64];
  253.     int i, j;
  254.     
  255.     i = 0;
  256.     do{
  257. #ifdef TURBOC
  258.         node[i] = farmalloc(1024 * 10); /* allocate one 10 K byte */
  259. #else
  260.         node[i] = _fmalloc(1024 * 10);  /* allocate one 10 K byte */
  261. #endif
  262.     }while (node[i++] != NULL);
  263.     
  264.     for (j = 0; j < i; j++){            /* free memory for use */
  265. #ifdef TURBOC
  266.         farfree(node[j]);
  267. #else
  268.         _ffree(node[j]);
  269. #endif
  270.     }
  271.     return(10 * i);
  272. }
  273.  
  274.  
  275. /* returns the number of K bytes used by all track data. */
  276. int
  277. used_memory(void)
  278. {
  279.     int i;
  280.     long bytes, ln;
  281.     
  282.     bytes = 0;
  283.     for (i = 0; i < NTRACK; i++){
  284.         ln = g_trackarray[i].numevents;
  285.         bytes += ln * (sizeof(struct event) + FMALLOC_BYTES);
  286.     }
  287.     i = bytes/1024;         /* convert to integer K bytes */
  288.     return(i);
  289. }
  290.  
  291.  
  292. /* Display track data until esc key is pressed.  This is a menu item on */
  293. /* both the Record and MLE screens. */
  294. void
  295. data_dump(void)
  296. {
  297.     int i, j, k;
  298.     struct event far *ep[NTRACK];
  299.     
  300.     for (i = 0; i < NTRACK; i++){
  301.         ep[i] = g_trackarray[i].current;
  302.     }
  303.     
  304.     while (1){
  305.         clearscreen(g_norm_attrib);
  306.         fputs("MIDI data in hex for tracks 1-8:\n\n", stdout);
  307.         for (i = 0; i < 20; i++){
  308.             for (j = 0; j < NTRACK; j++){
  309.                 for (k = 0; k < 4; k++){
  310.                     if (ep[j] != NULL)
  311.                         printf("%02x", ep[j]->b[k]);
  312.                     else
  313.                         fputs("  ", stdout);
  314.                 }
  315.                 fputs("-", stdout);
  316.                 if (ep[j] != NULL)
  317.                     ep[j] = ep[j]->next;
  318.             }
  319.             fputs("\n",stdout);
  320.         }
  321.         while(kbhit())
  322.             getch();
  323.         fputs("\nHit space to continue, ESC to quit.", stdout);
  324.         while(!kbhit())
  325.             ;
  326.         if (getch() == ESC)
  327.             return;
  328.     }
  329. }
  330.  
  331.  
  332. /* Erases all track data forward of the current measure number.  Prompts */
  333. /* for track number.  Sticks new track terminator event at end. */
  334. void
  335. clear_forward(void)
  336. {
  337.     int ans, track;
  338.     char nbuf[10], buf[SCRNWIDE];
  339.     struct event far *ep;
  340.     struct event far *np;
  341.     
  342.     ans = getint(g_text_char_v - 1, 
  343.         "Enter the track number to clear forward ->",
  344.         &track, 1, 8, g_norm_attrib, g_emph_attrib);
  345.     if (ans){
  346.         strcpy(buf, "Clear track number ");
  347.         itoa(track, nbuf, 10);
  348.         strcat(buf, nbuf);
  349.         strcat(buf, " from current measure to end? (Y/N)->");
  350.         writeword(buf, 1, g_text_char_v - 1, g_norm_attrib);
  351.         ans = getche();                 
  352.         if (toupper(ans) == 'Y'){
  353.             track--;
  354.             ep = advance_to_measure(track, g_current_measure);
  355.             np = ep->next;              /* point to event past meas end */
  356.             clear_events(np);
  357.             np = ep->next = eventalloc();
  358.             np->next = NULL;            /* add track terminator to end */
  359.             np->nbytes = 2;
  360.             np->b[1] = ALL_END;
  361.             np->b[0] = np->b[2] = np->b[3] = 0;
  362.             clean_track(track);
  363.             g_trackarray[track].current = advance_to_measure(track,
  364.                 g_current_measure);
  365.         }
  366.     }
  367. }
  368.  
  369.  
  370. /* Does the work of clearing all events from start to end of event list */
  371. /* from memory.  */
  372. void
  373. clear_events(struct event far *start)
  374. {
  375.     struct event far *nextevent;
  376.     
  377.     while (start != NULL){
  378.         nextevent = start->next;
  379. #if TURBOC
  380.         farfree(start);
  381. #else
  382.         _ffree(start);
  383. #endif
  384.         start = nextevent;
  385.     }
  386. }
  387.  
  388.  
  389. void
  390. wait_for_key(void)                      /* pause until a key is pressed */
  391. {
  392.     while (kbhit())     /* clear key buffer */
  393.         getch();
  394.     while (!kbhit())    /* wait for key */
  395.         ;
  396.     getch();
  397. }
  398.