home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / mt / mtrc3.c < prev    next >
C/C++ Source or Header  |  1989-02-04  |  11KB  |  332 lines

  1. /* mtrc3.c  -  record and play functions for recorder */
  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>  /* compiler library headers */
  7. #include <conio.h>
  8. #include <string.h>
  9. #include <stdlib.h>
  10.  
  11. #ifdef TURBOC
  12.     #include <alloc.h>
  13. #else
  14.     #include <malloc.h>
  15. #endif
  16.  
  17. #include "screenf.h"
  18. #include "standard.h"
  19. #include "mpu401.h"
  20. #include "mt.h"
  21. #include "video.h"
  22. #include "mtdeclar.h"
  23.  
  24.  
  25. /* Sends single event's data.  MIDI vol corrected if g_track_vel_used */
  26. /* is set true, meaning that at least one track has vol set to < 100 */
  27. void
  28. play_event(int track, struct event far *ep) /* ep points to event data */
  29. {
  30.     int bytes, secbyte;
  31.     
  32.     bytes = ep->nbytes;     /* use int to avoid repeatedly doing -> calcs. */
  33.     secbyte = ep->b[1];     /* ditto */
  34.     putdata401(ep->b[0]);                   /* send first byte to MPU */
  35.     if (bytes > 1){
  36.         putdata401(secbyte);                /* send second byte */
  37.         if (bytes > 2){
  38.             putdata401(ep->b[2]);           /* send third byte */
  39.                             /* if b2 = note on, adjust volume */
  40.             if (bytes > 3){
  41.                 if (secbyte >= NOTE_ON && secbyte < NOTE_ON+NTRACK
  42.                     && g_track_vel_used)    /* send fourth byte - adj. vel */
  43.                     putdata401(ep->b[3] * g_track_vel[track] / 100);
  44.                 else                
  45.                     putdata401(ep->b[3]);   /* send fourth byte, no vel adj */
  46.             }
  47.         }
  48.     }
  49. }
  50.  
  51.  
  52. /* issue MPU commands to shut down record process.  Shuts each track down */
  53. /* individually to avoid hung notes */
  54. void
  55. stop_401(int tracks_on)
  56. {
  57.     int i, cmd;
  58.     
  59.     if (tracks_on){
  60.         for (i = 0; i < NTRACK; i++){
  61.             cmd = get401();                 /* get track request from MPU */
  62.             if (cmd == ALL_END || cmd == -1)
  63.                 break;                      /* MPU sends ALL_END when done */
  64.             else if (cmd >= REQ_T1 && cmd <= REQ_T8){ 
  65.                 putdata401(0);                   /* shut each play track */
  66.                 putdata401(DATA_END);            /* down individually */
  67.             }
  68.         }
  69.     }
  70.     repeat_cmd401(MET_OFF);         /* final MPU shutdown command sequence */
  71.     repeat_cmd401(STOP_PLAY);       /* after all tracks are s/d */
  72.     repeat_cmd401(CLEAR_PMAP);
  73. }
  74.  
  75.  
  76. /* Reset and initialize MPU-401.  Returns track bit map (trackbits) */
  77. /* as an int.  Called before start of record and play process. */
  78. /* Also sets temp array ep[] so that each element points to first event */
  79. /* int the track to be played. */
  80. int                        
  81. init_401(struct event far *ep[])
  82. {
  83.     int i, status, trackbits;
  84.     
  85.     g_track_vel_used = trackbits = 0;
  86.                                         /* build track bit map */
  87.     for (i = NTRACK - 1; i >= 0; i--){
  88.         trackbits <<= 1;
  89.         if (g_trackarray[i].active && g_trackarray[i].numevents > 1)
  90.             trackbits++;
  91.         ep[i] = g_trackarray[i].current;
  92.         if (ep[i]->b[1] == MES_END) /* skip first measure end mark */
  93.             ep[i] = ep[i]->next;
  94.         
  95.         g_track_vel[i] = g_trackarray[i].midivol;   /* build velocity data */
  96.         if (g_track_vel[i] != 100)
  97.             g_track_vel_used = 1;   /* if any track vel != 0, vel correct */
  98.     }   
  99.     
  100.     status = repeat_cmd401(RESET);  /* send all initializing commands */
  101.     if (status == -1){
  102.         writerr("Unable to reset MPU-401 - play process aborted.", 
  103.             g_text_char_v - 1, g_norm_attrib, g_emph_attrib);
  104.         return(0);
  105.     }
  106.     if (g_pitchbend)                /* send setup command sequence to MPU */
  107.         repeat_cmd401(BEND_ON); 
  108.     if (g_exclusive)
  109.         repeat_cmd401(EXCL_THRU);
  110.     repeat_cmd401(SET_TEMPO);   
  111.         putdata401(g_metrate);
  112.     repeat_cmd401(METRO_MEAS); 
  113.         putdata401(g_meter);
  114.     repeat_cmd401(TB_120);      /* MT uses only 120 ticks/beat timebase */
  115.     repeat_cmd401(MIDI_METRO);  /* metro always beets every quarter note */
  116.         putdata401(24);
  117.     if (g_meton)
  118.         repeat_cmd401(MET_ON_WOUT);
  119.     repeat_cmd401(ACT_TRACK);
  120.         putdata401(trackbits);
  121.     repeat_cmd401(CLEAR_PCOUNT);
  122.     repeat_cmd401(START_PLAY);
  123.     return(trackbits);          /* return bit map of tracks set to play */
  124. }
  125.  
  126.  
  127. /* Update measure number - only if highest active track.  Used in play */
  128. /* process to avoid measure number advancing on very measure end sent */
  129. /* when multiple tracks are playing. */
  130. void
  131. maybe_measure_number(int track, int trackbits)
  132. {
  133.     int hi_act_track, i;
  134.     
  135.     for (i = 0; i < NTRACK; i++){   /* find the track # of highest track */
  136.         if (trackbits & (1 << i))   /* set to play.  Only this one trips */
  137.             hi_act_track = i;       /* update of measure # on screen. */
  138.     }
  139.     
  140.     if ((track == hi_act_track) && !g_trace_on)
  141.         write_int(++g_current_measure + 1, 53, 18, g_norm_attrib);
  142. }
  143.  
  144.  
  145. /* prompt for track number, then erase all track data.  Called from both */
  146. /* the Record and MLE screens.  Uses erase_one() to do erasing. */
  147. void
  148. erase_track(void)
  149. {
  150.     int track, ans;
  151.     char nbuf[10], buf[SCRNWIDE];
  152.     
  153.     ans = getint(g_text_char_v - 1, 
  154.         "Which track number do you wish to erase? ->", 
  155.         &track, 1, NTRACK, g_norm_attrib, g_norm_attrib);
  156.     
  157.     if (ans){
  158.         strcpy(buf, "Erase track number ");
  159.         itoa(track, nbuf, 10);
  160.         strcat(buf, nbuf);
  161.         strcat(buf, " ? (Y/N)->");
  162.         clearline(g_text_char_v - 1, g_norm_attrib);
  163.         writeword(buf, 1, g_text_char_v - 1, g_norm_attrib);
  164.         ans = getche();                 
  165.         if (toupper(ans) == 'Y')
  166.             erase_one(--track);
  167.     }
  168. }
  169.  
  170.  
  171. /* workhorse track eraser.  Updates g_trackarray[], and calls clear_events */
  172. /* to free all memory associated with track's event list */
  173. void
  174. erase_one(int track)
  175. {
  176.     clear_events(g_trackarray[track].first->next);
  177.     g_trackarray[track].current = g_trackarray[track].first;
  178.     g_trackarray[track].last = g_trackarray[track].first;
  179.     g_trackarray[track].first->next = NULL;
  180.     g_trackarray[track].current->nbytes = 2;
  181.     g_trackarray[track].current->b[0] = 0;
  182.     g_trackarray[track].current->b[1] = MES_END;
  183.     g_trackarray[track].current->b[2] = 0;
  184.     g_trackarray[track].current->b[3] = 0;
  185.     if (track == g_block_track)
  186.         g_block_on = 0;
  187. }
  188.  
  189.  
  190. /* erase all data on all tracks.  This is only called from the MT primary */
  191. /* menu as the CLEAR command. */
  192. void
  193. erase_all(void)
  194. {
  195.     int i;
  196.     
  197.     for (i = 0; i < NTRACK; i++)
  198.         erase_one(i);
  199.     g_current_measure = 0;
  200. }
  201.  
  202.  
  203. /* updates the screen data for top of record screen.  These items are */
  204. /* all elements of the mt2[] menu defined in MTSCREEN.H.   After the update */
  205. /* the normal menu functions are used to control the screen display. */
  206. void
  207. init_track_str(void)
  208. {
  209.     int i;
  210.     char buf[10];
  211.  
  212.     for (i = 0; i < NTRACK; i++){
  213.         strcpy(mt2[i].content, g_trackarray[i].name);
  214.  
  215.         itoa(g_trackarray[i].midichan + 1, buf, 10);    /* channel number */
  216.         strcpy(mt2[i + NTRACK].content, buf);
  217.  
  218.         itoa(g_trackarray[i].midivol, buf, 10);         /* MIDI volume */
  219.         strcpy(mt2[i + (5 * NTRACK)].content, buf);
  220.  
  221.         ltoa(g_trackarray[i].numevents, buf, 10);       /* event count */
  222.         strcpy(mt2[i + (6 * NTRACK)].content, buf);
  223.         
  224.         if (i != g_record_track){
  225.             strcpy(mt2[i + (2 * NTRACK)].content, "        ");
  226.             strcpy(mt2[i + (4 * NTRACK)].content, "OFF");
  227.         }
  228.         else{
  229.             strcpy(mt2[i + (2 * NTRACK)].content, "*ACTIVE*");
  230.             strcpy(mt2[i + (4 * NTRACK)].content, "ON ");
  231.             g_trackarray[i].active = 0;     /* can't play & record at once */
  232.         }
  233.         
  234.         if (g_trackarray[i].active){        /* update play status */
  235.             strcpy(mt2[i + (3 * NTRACK)].content, "ON ");
  236.         }
  237.         else{
  238.             strcpy(mt2[i + (3 * NTRACK)].content, "OFF");
  239.         }
  240.     }
  241. }
  242.  
  243.  
  244. /* update event count for each track, ret total number.  This is needed */
  245. /* to keep the calculation of the amount of memory used up-to-date */
  246. long
  247. count_events(void)
  248. {
  249.     int i;
  250.     long track_total, total;
  251.     struct event far *tp;
  252.     
  253.     total = 0;
  254.     
  255.     for (i = 0; i < NTRACK; i++){
  256.         tp = g_trackarray[i].first;
  257.         track_total = 0;
  258.         do {                        /* compute events stored in track */
  259.             tp = tp->next;
  260.             track_total++;
  261.         } while (tp != NULL);
  262.         g_trackarray[i].numevents = track_total;
  263.         total += track_total;
  264.     }
  265.     return(total);
  266. }
  267.  
  268.  
  269. /* updates all values at bottom of the recorder screen */
  270. void
  271. init_rec_val(void)
  272. {
  273.     write_int(g_metrate, SCRNWIDE - 6, 16, g_norm_attrib);
  274.     write_int(g_meter, SCRNWIDE - 6, 15, g_norm_attrib);
  275.     write_int(g_current_measure + 1, 53, 18, g_norm_attrib);
  276.     write_int(g_pct_free_memory, 53, 19, g_norm_attrib);
  277.     write_on_off(g_meton, SCRNWIDE - 6, 14);
  278.     write_on_off(g_pitchbend, SCRNWIDE - 6, 17);
  279.     write_on_off(g_exclusive, SCRNWIDE - 6, 18);
  280.     write_on_off(g_trace_on, SCRNWIDE - 6, 19);
  281. }
  282.  
  283.  
  284. void
  285. calc_pct_free(void)                     /* calculate % free memory */
  286. {
  287.     int free;
  288.     float f;
  289.  
  290.     count_events();
  291.     f = g_free_memory - used_memory();
  292.     g_pct_free_memory = 100 * f/g_free_memory;
  293. }
  294.  
  295.  
  296. void
  297. write_on_off(int param, int column, int row)  /* put an ON or OFF on screen */
  298. {
  299.     if (param)
  300.         writeword("ON ", column, row, g_emph_attrib);
  301.     else
  302.         writeword("OFF", column, row, g_norm_attrib);
  303. }
  304.  
  305.  
  306. /* Sends all notes off message on all channels.  This is a menu item on */
  307. /* on the RECORD screen. */
  308. void
  309. all_notes_off(void)
  310. {
  311.     int i;
  312.     
  313.     repeat_cmd401(UART);
  314.     for(i = 0; i < NCHANNEL; i++){
  315.         putdata401(MODE_MESSAGE + i);
  316.         putdata401(ALL_NOTES_OFF);
  317.         putdata401(0);
  318.     }
  319.     sendcmd401(RESET);
  320. }
  321.  
  322.  
  323. /* Writes a message at the top of the screen prior to the data trace output */
  324. void
  325. trace_header(void)
  326. {
  327.     clearscreen(g_norm_attrib);
  328.     writeword("Data Trace Option - all data in hex.", 1, 1, g_emph_attrib);
  329.     writeword("rc=recieved, tc=trans command, td=trans data\n\n", 1, 2, 
  330.         g_emph_attrib);
  331. }
  332.