home *** CD-ROM | disk | FTP | other *** search
/ C++ Games Programming / CPPGAMES.ISO / mt / mtsc2.c < prev    next >
C/C++ Source or Header  |  1989-01-13  |  10KB  |  332 lines

  1. /* mtsc2.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 <stdlib.h>
  9.  
  10. #ifdef TURBOC
  11.     #include <alloc.h>
  12. #else
  13.     #include <malloc.h>
  14. #endif
  15.  
  16. #include "standard.h"
  17. #include "screenf.h"
  18. #include "mpu401.h"
  19. #include "mt.h"
  20. #include "video.h"
  21. #include "mtsc.h"
  22. #include "mtdeclar.h"
  23.  
  24.  
  25. /* Draw the note edit area box on the graphics screen. */
  26. void
  27. init_screen_box(int beat, int measure)
  28. {
  29.     int x1, x2, y1, y2;
  30.     
  31.     x1 = LEFT_BORDER;
  32.     y1 = g_top_note_line - HALF_NOTE_DOTS;
  33.     x2 = g_dots_h - 1;
  34.     y2 = g_bot_note_line + HALF_NOTE_DOTS;
  35.         
  36.     draw_rectangle(FALSE, x1, y1, x2, y2, g_line_color);
  37.     draw_rectangle(TRUE, x1 + 1, y1 + 1, x2 - 1, y2 - 1, g_back_color);
  38.     top_scale(beat, x1, y1, x2, y2, measure);
  39.     dotted_lines(x1, y1, x2, y2, 8, 20, g_line_color);      
  40.     g_sc_refresh = 1;
  41. }
  42.  
  43.  
  44. /* put top scale on screen, initialize globals for side boundaries */
  45. void
  46. top_scale(int beat, int leftside, int topline, int rightside, int botline, 
  47.     int measure)
  48. {
  49.     int i, tick, xpos;
  50.     char nbuf[10];
  51.     
  52.     g_first_measure = measure;
  53.     tick = 0;
  54.     xpos = leftside;
  55.     
  56.     clearline(2, g_norm_attrib);
  57.     writeword("Beat:", 1, 2, g_norm_attrib);
  58.  
  59.     /* put in tick marks at the top of the NLE edit box */ 
  60.     for (i = leftside; i < rightside; i += MIN_SPACE){
  61.         if (tick % TICK_PER_BEAT == 0){
  62.             drawline(xpos, topline, xpos, botline, g_line_color);
  63.             write_int(beat + 1, 1 + (xpos/g_let_dots_h), 2, g_emph_attrib);
  64.             if (beat < g_meter - 1)
  65.                 beat++;
  66.             else{
  67.                 beat = 0;
  68.                 tick = 0;
  69.                 measure++;
  70.             }
  71.         }
  72.         else if (tick % (TICK_PER_BEAT/2) == 0)
  73.             drawline(xpos, topline - 6, xpos, topline, g_line_color);
  74.         else if (tick % (TICK_PER_BEAT/4) == 0)
  75.             drawline(xpos, topline - 4, xpos, topline, g_line_color);
  76.         else if (tick % (TICK_PER_BEAT/8) == 0)
  77.             drawline(xpos, topline - 2, xpos, topline, g_line_color);
  78.         else
  79.             drawline(xpos, topline - 1, xpos, topline, g_line_color);
  80.         tick += g_scale;
  81.         xpos += MIN_SPACE;
  82.     }
  83. }
  84.  
  85.  
  86. /* Write top note name on screen and initialize global for bottom note */
  87. void
  88. name_top_note(int oct_shown)
  89. {                               
  90.     int ypos;
  91.     char buf[10];
  92.     
  93.     g_bot_note = g_top_note - (oct_shown * 12) + 1;
  94.     
  95.     writeword("       ", 72, g_graph_char_v - 2, g_norm_attrib);
  96.     writeword(g_notes[g_top_note].name, 72, g_graph_char_v - 2, 
  97.         g_norm_attrib);
  98. }
  99.  
  100.  
  101. void
  102. name_measure(int measure)       /* put measure number at top left corner */
  103. {
  104.     char buf[20], nbuf[10];
  105.     
  106.     strcpy(buf, "Meas:   ");
  107.     itoa(measure + 1, nbuf, 10);
  108.     strcat(buf, nbuf);
  109.     strcat(buf, "   ");
  110.     writeword(buf, 1, 1, g_norm_attrib);
  111. }
  112.  
  113.  
  114.  
  115. /* puts dotted lines in rectangular region */
  116. void
  117. dotted_lines(int topx, int topy, int botx, int boty, int vspace, int hspace, 
  118.     int color)
  119. {
  120.     int x, y;
  121.     
  122.     
  123.     for (y = topy + (vspace/2) ; y < boty; y += vspace){
  124.         for (x = topx; x < botx; x += hspace){
  125.             dotplot(x, y, color);
  126.         }
  127.     }
  128. }
  129.             
  130.  
  131. /* Convert track data from event list to temporary form used for editing. */
  132. /* The note_time structure makes it easier to locate and draw single notes. */
  133. struct note_time far
  134. *build_note_list(int track)
  135. {
  136.     int measure, tick, i, b0, b1, b2, b3;
  137.     struct event far *ep;
  138.     struct note_time far *notep;
  139.     struct note_time far *first_notep;
  140.     struct on_event on_array[NNOTES];
  141.     
  142.     for (i = 0; i < NNOTES; i++){   /* keeps track of pending note_ons */
  143.         on_array[i].event = NULL;
  144.     }
  145.     
  146.     ep = g_trackarray[track].first;
  147.     if (ep->b[1] == MES_END)        /* skip start of track marker */
  148.         ep = ep->next;
  149.     
  150.     notep = first_notep = 
  151. #ifdef TURBOC
  152.         (struct note_time far *)farmalloc(sizeof(struct note_time));
  153. #else
  154.         (struct note_time far *)_fmalloc(sizeof(struct note_time));
  155. #endif
  156.     notep->on_event = NULL;
  157.     notep->off_event = NULL;
  158.     notep->on_measure = notep->off_measure = 0;
  159.     notep->on_tick = notep->off_tick = 0;
  160.     notep->note_number = 0;     
  161.     notep->next = NULL;
  162.     
  163.     measure = tick = 0;
  164.     while (ep != NULL){
  165.         b0 = ep->b[0];
  166.         b1 = ep->b[1];
  167.         b2 = ep->b[2];
  168.         b3 = ep->b[3];
  169.         if (b1 == MES_END){
  170.             measure++;
  171.             tick = 0;
  172.         }
  173.         else if (b1 == ALL_END)
  174.             break;
  175.         else if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL ||
  176.             b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
  177.             tick += b0;
  178.                         /* if already have note on, and this is note off */
  179.             if (on_array[b2].event != NULL && 
  180.                 (b3 == 0 || (b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL))){
  181.                 notep->on_event = on_array[b2].event;
  182.                 notep->on_measure = on_array[b2].measure;
  183.                 notep->on_tick = on_array[b2].tick;
  184.                 notep->note_number = b2;
  185.                 notep->off_event = ep;
  186.                 notep->off_measure = measure;
  187.                 notep->off_tick = tick;
  188.                 notep = notep->next = (struct note_time far *)
  189. #ifdef TURBOC
  190.                     farmalloc(sizeof(struct note_time));
  191. #else
  192.                     _fmalloc(sizeof(struct note_time));
  193. #endif
  194.                 if (notep == NULL){
  195.                     free_note_list(first_notep);
  196.                     return(NULL);
  197.                 }
  198.                 notep->next = NULL;
  199.                 on_array[b2].event = NULL;
  200.             }
  201.             else if (b3 != 0){              /* if not a loose note off */
  202.                 on_array[b2].event = ep;
  203.                 on_array[b2].measure = measure;
  204.                 on_array[b2].tick = tick;
  205.                 on_array[b2].vel = b3;
  206.             }
  207.         }
  208.         else if (b0 == TIME_OUT){
  209.             tick += MAX_CLOCK;
  210.         }
  211.         else{
  212.             tick += b0;     /* all data except note on/off ignored */
  213.         }                   /* but timing value added to running count. */
  214.  
  215.         if (kbhit()){       /* quit if ESC key hit */
  216.             if (getch() == ESC){
  217.                 free_note_list(first_notep);
  218.                 return(NULL);
  219.             }
  220.         }                   
  221.         ep = ep->next;
  222.     }
  223.     return(first_notep);
  224. }
  225.  
  226.  
  227. /* Free memory used for temporary note list.  Used on exit from NLE. */
  228. void
  229. free_note_list(struct note_time far *np)
  230. {
  231.     struct note_time far *nextp;
  232.     
  233.     while (np != NULL){
  234.         nextp = np->next;
  235. #if TURBOC
  236.         farfree(np);
  237. #else
  238.         _ffree(np);
  239. #endif
  240.         np = nextp;
  241.     }
  242. }
  243.  
  244.  
  245. /* Display all notes within screen boundaries as horiz. lines */
  246. void
  247. disp_notes(struct note_time far *first_notep, int first_measure, int beat)
  248. {
  249.     int start_x, end_x;
  250.     struct note_time far *np;
  251.  
  252.     g_first_tick = beat * TICK_PER_BEAT;
  253.     
  254.     np = first_notep;
  255.     do {                /* check if within 10 measures to avoid overflow */
  256.         if (abs(np->on_measure - first_measure) < 10 &&
  257.             abs(np->off_measure - first_measure) < 10){
  258.                 draw_note(np, g_emph_color);
  259.         }       
  260.         np = np->next;
  261.     } while (np != NULL);
  262. }
  263.  
  264.  
  265.  
  266. /* put line on screen for note duration */
  267. void
  268. draw_note(struct note_time far *np, int color)
  269. {
  270.     int ypos, start_x, end_x;
  271.  
  272.     start_x = LEFT_BORDER + ((((np->on_measure - g_first_measure) * 
  273.         TICK_PER_BEAT * g_meter) + np->on_tick - g_first_tick) * 
  274.         MIN_SPACE)/g_scale;
  275.     
  276.     end_x = LEFT_BORDER + ((((np->off_measure - g_first_measure) * 
  277.         TICK_PER_BEAT * g_meter) + np->off_tick - g_first_tick) * 
  278.         MIN_SPACE)/g_scale;
  279.     
  280.     if ((start_x >= LEFT_BORDER + MIN_SPACE) && 
  281.         (start_x < g_dots_h) || 
  282.         (end_x >= LEFT_BORDER + MIN_SPACE) && 
  283.         (end_x < g_dots_h)){
  284.     
  285.         if (np->note_number > g_top_note || np->note_number < g_bot_note)
  286.             return;
  287.         
  288.         if (start_x < LEFT_BORDER + MIN_SPACE)
  289.             start_x = LEFT_BORDER + MIN_SPACE;
  290.         if (end_x > g_dots_h - 1)
  291.             end_x = g_dots_h - 1;
  292.         
  293.         ypos = find_note_line(np->note_number);
  294.         drawline(start_x, ypos, end_x, ypos, color);
  295.     }
  296. }
  297.  
  298.  
  299. void
  300. mark_middle_c(int first)  /* put little m on middle C key on keyboard image */
  301. {
  302.     static int ypos = 0;    /* static to save last value of ypos */
  303.     
  304.     if (ypos && !first)     /* erase old m, unless first time or off scale */
  305.         xsprite(little_m, 40, ypos - 3, g_line_color);
  306.     
  307.     ypos = find_note_line(60);                  /* Middle C is note 60 */
  308.  
  309.     if (ypos)
  310.         xsprite(little_m, 40, ypos - 3, g_line_color);
  311. }
  312.  
  313.  
  314. /* Returns the screen line number for note.  Returns 0 if note is outside */
  315. /* of range displayed on screen. */
  316. int
  317. find_note_line(int note_no)
  318. {
  319.     int ypos, note;
  320.     
  321.     if (note_no > g_top_note || note_no < g_bot_note)
  322.         return(0);
  323.     
  324.     ypos = g_top_note_line;
  325.     note = g_top_note;
  326.     
  327.     while (note > note_no)
  328.         ypos += g_notes[note--].down_dots;
  329.     
  330.     return(ypos);
  331. }
  332.