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

  1. /* mtrc2.c */
  2. /* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
  3.  
  4. #include <stdio.h>
  5. #include <conio.h>
  6. #include <string.h>
  7.  
  8. #include "screenf.h"
  9. #include "standard.h"
  10. #include "mpu401.h"
  11. #include "mt.h"
  12. #include "video.h"
  13. #include "mtdeclar.h"
  14.  
  15.  
  16. /* play() is called from record_menu().  Controls playing up to eight */
  17. /* tracks.  Calls play_event() to send event data.  Uses maybe_measure_ */
  18. /* number() to update measure number during playback. */
  19.  
  20. void
  21. play(void)
  22. {
  23.     int cmd, track, firstcmd, status, trackbits, stop_play, c; 
  24.     struct event far *ep[NTRACK];   /* temporary pointers to note data */
  25.  
  26.     writeword("Hit ESC or SPACEBAR to stop playback.", 1, g_text_char_v - 1, 
  27.         g_norm_attrib);
  28.     if (g_trace_on){
  29.         trace_header();
  30.         fputs("Hit ESC key to stop playback.\n\n", stdout);
  31.     }
  32.     
  33.     firstcmd = 1;
  34.     trackbits = init_401(ep);       /* reset and intialize MPU-401 */
  35.     if (trackbits == 0){
  36.         writerr("No data-containing tracks have PLAY turned ON.",
  37.             g_text_char_v - 1, g_norm_attrib, g_norm_attrib);
  38.         return;
  39.     }
  40.  
  41.     stop_play = 0;
  42.     while (1){
  43.         cmd = get401();         /* get next mpu-401 request */
  44.         if (cmd == -1){         /* initiate exit of play mode on keypress */
  45.             while (kbhit()){
  46.                 c = getch();
  47.                 if (c == ESC || c == ' '){
  48.                     if (stop_play)
  49.                         break;
  50.                     else
  51.                         stop_play = 1;
  52.                 }
  53.             }
  54.         }
  55.         else if (cmd >= REQ_T1 && cmd <= REQ_T8){       /* track req */
  56.             firstcmd = 0;
  57.             track = cmd - REQ_T1;
  58.             
  59.             if (ep[track]->b[1] == MES_END)             /* update measure # */
  60.                 maybe_measure_number(track, trackbits);
  61.  
  62.             if (stop_play){                             /* shutdown track */
  63.                 putdata401(0);                          /* wait for ALL_END */
  64.                 putdata401(DATA_END);                   /* to stop play */
  65.             }       
  66.             else{
  67.                 play_event(track, ep[track]);           /* send data bytes */
  68.             }
  69.  
  70.             /* advance track pointer to next event */
  71.  
  72.             if (ep[track]->next != NULL){
  73.                 ep[track] = ep[track]->next;
  74.                 if (ep[track]->b[1] == DATA_END)    /* track goes inactive */
  75.                     trackbits &= ~(1 << track);     /* erase from trackbits */
  76.             }
  77.         }
  78.         else if (cmd == ALL_END){
  79.             if (firstcmd)           /* don't quit if received at start */
  80.                 firstcmd = 0;
  81.             else
  82.                 break;              /* must be at end of song data */
  83.         }
  84.         else{
  85.             /* ignore anything else */
  86.         }
  87.     }
  88.     repeat_cmd401(STOP_PLAY);       /* final MPU shutdown command sequence */
  89.     repeat_cmd401(CLEAR_PMAP);
  90.     repeat_cmd401(MET_OFF);
  91.     
  92.     if (g_trace_on) 
  93.         wait_for_key();
  94.     goto_measure(g_current_measure);    /* end on even meas */
  95. }
  96.  
  97.  
  98.  
  99. /* record() is the front end to record_track().  Checks if a track is */
  100. /* active - then records one track.  */
  101. void
  102. record(void)
  103. {
  104.     if (g_record_track == -1){
  105.         writerr("No track is active for recording.",
  106.             g_text_char_v - 1, g_norm_attrib, g_emph_attrib);
  107.     }
  108.     else{                           /* start on even measure number */
  109.         g_trackarray[g_record_track].current =      
  110.             advance_to_measure(g_record_track, g_current_measure);
  111.         writeword("Hit ESC or SPACEBAR to stop recording.", 1, 
  112.             g_text_char_v - 1, g_norm_attrib);
  113.         if (g_trace_on)
  114.             trace_header();         /* if trace is on, put header on screen */
  115.  
  116.         /* go ahead and start record process */
  117.         g_trackarray[g_record_track].last = record_track(g_record_track);
  118.         
  119.         clean_track(g_record_track);    /* set all recorded data to the */
  120.         change_channel(g_record_track,  /* the track's MIDI channel */
  121.              g_trackarray[g_record_track].midichan);
  122.         goto_measure(g_current_measure);            /* end on even meas */
  123.         if (g_trace_on){
  124.             fputs("\nHit a key to return.", stdout);
  125.             wait_for_key();
  126.         }                       
  127.     }
  128.     calc_pct_free();                    /* update the free memory left */
  129. }
  130.  
  131.  
  132.  
  133. /* record_track() is the function that controls the recording process */
  134. /* Records a track while playing back any others set to PLAY.   Stops on */
  135. /* ESC or spacebar keypress. */
  136.  
  137. struct event far 
  138. *record_track(int rec_track)    /* rec_track is the track # set to record */
  139. {
  140.     int first, second, third, fourth, mstatus, track, i, status, c, trackbits;
  141.     struct event far *firstnode;
  142.     struct event far *next_to_last_node;
  143.     struct event far *nextnode;
  144.     struct event far *ep[NTRACK];   /* temp pointers to note data */
  145.  
  146.     mstatus = 0;
  147.     firstnode = g_trackarray[rec_track].current;
  148.     nextnode = firstnode->next = eventalloc();  /* create first new event */
  149.     
  150.     trackbits = init_401(ep);           /* reset and initialize MPU-401 */
  151.     repeat_cmd401(START_REC);           /* start record process */
  152.  
  153.     while (1){
  154.         first = get401();               /* get 1 byte of data from MPU-401 */
  155.         if (first == -1){               /* get401() returns -1 on keypress */
  156.             c = getch();
  157.             if (c == ESC || c == ' '){
  158.                 repeat_cmd401(STOP_REC); /* tell MPU to stop recording */
  159.                 first = 0;
  160.                 second = ALL_END;
  161.                 goto forcedstop;
  162.             }
  163.         }
  164.         next_to_last_node = nextnode;   /* keep current for returned value */
  165.  
  166.         if (first <= 0xEF){         /* timing byte */
  167.             second = get401();      /* so get second byte from MPU */
  168.             if (second <= 0x7F){    /* MIDI data, running status assumed */
  169.                 third = get401();   /* so get third byte from MPU */
  170.                 nextnode = store(nextnode, 4, first, mstatus, second, third);
  171.             }
  172.             else if (second <= 0xBF){   /* MIDI message, note on/off */
  173.                 mstatus = second;       /* after touch or control change */
  174.                 third = get401();       /* so get two more bytes */
  175.                 fourth = get401();
  176.                 nextnode = store(nextnode, 4, first, second, third, fourth);
  177.             }
  178.             else if (second <= 0xDF){   /* prog change or chan after touch */
  179.                 mstatus = second;       /* so get just one more byte */
  180.                 third = get401();
  181.                 nextnode = store(nextnode, 3, first, second, third, 0);
  182.             }
  183.             else if (second <= 0xEF){   /* pitch wheel */
  184.                 mstatus = second;       /* so get to more bytes */
  185.                 third = get401();
  186.                 fourth = get401();
  187.                 nextnode = store(nextnode, 4, first, second, third, fourth);
  188.             }
  189.             else if (second == 0xF9){   /* measure end - store it */
  190.                 if (!g_trace_on)        /* and update measure # on screen */
  191.                     write_int(++g_current_measure + 1, 53, 18, g_norm_attrib);
  192.                 nextnode = store(nextnode, 2, first, second, 0, 0);
  193.             }
  194.             else if (second == 0xFC){   /* data end - record process done */
  195. forcedstop:     store(nextnode, 2, first, second, 0, 0);    
  196.                 nextnode->next = NULL;  /* null markes end of track list */
  197.                 stop_401(trackbits);        /* allow all tracks to s/d */
  198.                 return(next_to_last_node);  /* return pointer to end */
  199.             }
  200.             else{
  201.                 clearline(g_text_char_v, g_norm_attrib);    /* show ?? data */
  202.                 csrplot(g_text_char_v, 1);                  /* but continue */
  203.                 printf("Unrecognized data %x %x", first, second);
  204.             }
  205.         }
  206.         else if (first <= 0xF7){                    /* track data request */
  207.             track = first - REQ_T1;                 /* track number */
  208.             play_event(track, ep[track]);           /* send data bytes */
  209.  
  210.             if (ep[track]->next != NULL){
  211.                                   /* advance track pointer to next event */
  212.                 ep[track] = ep[track]->next;
  213.             }
  214.         }
  215.         else {      /* first byte was not a timing byte - so decode */
  216.             switch(first){
  217.             case(TIME_OUT):
  218.                 nextnode = store(nextnode, 1, first, 0, 0, 0);
  219.                 break;
  220.             case(CONDUCT):  /* conductor (tempo change) not implemented */
  221.                 clearline(g_text_char_v, g_norm_attrib);
  222.                 writeword("Unexpected conductor data request.", 1, 
  223.                     g_text_char_v, g_norm_attrib);
  224.                 break;
  225.             case(DATA_END):
  226.                 clearline(g_text_char_v, g_norm_attrib);
  227.                 writeword("All playback tracks are finished.", 1,
  228.                     g_text_char_v, g_norm_attrib);
  229.                 break;
  230.             case(CLOCK_OUT):
  231.                 clearline(g_text_char_v, g_norm_attrib);
  232.                 writeword("Unexpected clock out signal ", 1,
  233.                     g_text_char_v, g_norm_attrib);
  234.                 break;
  235.             }
  236.         }
  237.         
  238.         if (nextnode == NULL){  /* ran out of memory for recording data */
  239.             writeword(
  240.                 "Could not allocate more memory (full?), record stopped.", 1,
  241.                 g_text_char_v, g_emph_attrib);
  242.             repeat_cmd401(STOP_REC);
  243.             stop_401(trackbits);
  244.             return(next_to_last_node);
  245.         }
  246.     }
  247.     return(next_to_last_node);
  248. }
  249.