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

  1. /* mtsc3.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. /* Erase one note in both note and event lists */
  26. struct note_time far
  27. *delete_note(struct note_time far *first_notep, int measure, int track)
  28. {
  29.     struct note_time far *np;
  30.     struct note_pos *notepos;
  31.     int status;
  32.     
  33.     writeword(
  34.         "To Delete: Move cross hair to a note, then hit return (ESC to exit).",
  35.             1, g_graph_char_v, g_norm_attrib);
  36.     notepos = select_note(measure, FALSE);
  37.     if (notepos == NULL){
  38.         clearline(g_graph_char_v, g_norm_attrib);
  39.         return(NULL);
  40.     }
  41.     else{
  42.         np = find_note(first_notep, notepos->note, notepos->measure,
  43.             notepos->tick); 
  44.         if (np != NULL){
  45.             status = remove_event(np->on_event, track);
  46.             if (!status)
  47.                 writerr("Memory pointer error in deleting note-on event.", 
  48.                     g_graph_char_v, g_norm_attrib, g_norm_attrib);
  49.             status = remove_event(np->off_event, track);
  50.             if (!status)
  51.                 writerr("Memory pointer error in deleting note-off event.", 
  52.                     g_graph_char_v, g_norm_attrib, g_norm_attrib);
  53.                 
  54.             draw_note(np, g_back_color);    /* erase note on screen */
  55.             clearline(g_graph_char_v, g_norm_attrib);
  56.             return(remove_note(first_notep, np));
  57.         }
  58.         else{
  59.             clearline(g_graph_char_v, g_norm_attrib);
  60.             writerr("You did not select an existing note.", g_graph_char_v, 
  61.                 g_norm_attrib, g_norm_attrib);
  62.             clearline(g_graph_char_v, g_norm_attrib);
  63.             return(first_notep);
  64.         }
  65.     }
  66. }
  67.  
  68.  
  69. /* Cursor movement to select note, option to leave cross hair at point */
  70. struct note_pos 
  71. *select_note(int measure, int option)
  72. {
  73.     int c, i, vert_sum, horz_sum;
  74.     static int oldx, oldy, newx, newy, note, tick, csr_measure;
  75.     char nbuf[10];
  76.     static struct note_pos on_ev;
  77.     struct note_pos *notepos;
  78.     
  79.     notepos = &on_ev;   
  80.  
  81.     if (g_sc_refresh == 1){ /* fix cursor pos. unless screen is refreshed */
  82.                                 /* find measure, tick for center of screen */
  83.         csr_measure = measure;
  84.         newx = LEFT_BORDER - CROSS_HALF;
  85.         tick = g_first_tick;    
  86.         for (i = LEFT_BORDER; i <= g_dots_h; i += MIN_SPACE * 2){
  87.             tick += g_scale;
  88.             newx += MIN_SPACE;
  89.             if (tick >= TICK_PER_BEAT * g_meter){
  90.                 csr_measure++;
  91.                 tick = 0;
  92.             }
  93.         }
  94.         note = (g_top_note + g_bot_note)/2;
  95.     }
  96.     else if (g_sc_refresh == 2){    /* only used for add_note, 2nd pass */
  97.         tick += g_scale;
  98.         newx += MIN_SPACE;
  99.         if (tick >= TICK_PER_BEAT * g_meter){
  100.             csr_measure++;
  101.             tick = 0;
  102.         }
  103.     }
  104.     oldx = newx;
  105.  
  106.     g_sc_refresh = 0;
  107.     oldy = newy = find_note_line(note) - CROSS_HALF;
  108.     
  109.     xsprite(cross, newx, newy, g_emph_color);
  110.     clear_select_lines();
  111.     write_int(tick, g_graph_char_h - 9, g_graph_char_v - 5, g_norm_attrib);
  112.     writeword(g_notes[note].name, g_graph_char_h - 9, g_graph_char_v - 4, 
  113.         g_norm_attrib);
  114.     write_int(csr_measure + 1, g_graph_char_h - 9, g_graph_char_v - 3, 
  115.         g_norm_attrib);
  116.     
  117.     while(1){
  118.         vert_sum = horz_sum = 0;
  119.  
  120.         while(!kbhit()) 
  121.             ;                       /* wait for keypress */
  122.  
  123.         while(kbhit()){             /* sum all pending cursor keystrokes */
  124.             c = getch();
  125.             while (!c) 
  126.                 c = getch();        /* pass over null chars */
  127.             switch (c){
  128.             case ESC:           /* quit on ESC */
  129.                 xsprite(cross, oldx, oldy, g_emph_color);
  130.                 clear_select_lines();
  131.                 return(NULL);
  132.             case BACKSP:
  133.             case KLEFT:
  134.                 horz_sum--;
  135.                 break;
  136.             case KUP:
  137.                 vert_sum++;
  138.                 break;
  139.             case KDOWN:
  140.                 vert_sum--;
  141.                 break;
  142.             case KRIGHT:
  143.             case ' ':
  144.                 horz_sum++;
  145.                 break;
  146.             case TAB:
  147.             case SKRIGHT:
  148.                 horz_sum += 10;
  149.                 break;
  150.             case BTAB:
  151.             case SKLEFT:
  152.                 horz_sum -= 10;
  153.                 break;
  154.             case KPGUP:
  155.                 vert_sum += 12;
  156.                 break;
  157.             case KPGDN:
  158.                 vert_sum -= 12;
  159.                 break;
  160.             case KHOME:
  161.                 vert_sum += 48;
  162.                 break;
  163.             case KEND:
  164.                 vert_sum -= 48;
  165.                 break;
  166.             default:    /* hitting key/return to select a marked note */
  167.                 if (!option)    /* clear cross hairs if option == 0 */
  168.                     xsprite(cross, oldx, oldy, g_emph_color);
  169.                 clear_select_lines();
  170.                 notepos->measure = csr_measure;
  171.                 notepos->tick = tick;
  172.                 notepos->note = note;
  173.                 notepos->sprite_x = oldx;
  174.                 notepos->sprite_y = oldy;
  175.                 return(notepos);
  176.             }
  177.         }
  178.         
  179.         if (abs(horz_sum) > 2)          /* increase horz speedup */
  180.             horz_sum *= 2;
  181.  
  182.         while (horz_sum < 0){           /* compute new cursor location */
  183.             if (newx > LEFT_BORDER - CROSS_HALF){
  184.                 newx -= MIN_SPACE;
  185.                 tick -= g_scale;
  186.                 if (tick < 0){
  187.                     tick = (TICK_PER_BEAT * g_meter) - g_scale;
  188.                     csr_measure--;
  189.                 }
  190.             }
  191.             horz_sum++;
  192.         }
  193.         while (horz_sum > 0){
  194.             if (newx < g_dots_h - 2 * CROSS_HALF){
  195.                 newx += MIN_SPACE;
  196.                 tick += g_scale;
  197.                 if (tick > (TICK_PER_BEAT * g_meter) - 1){
  198.                     tick = 0;
  199.                     csr_measure++;
  200.                 }
  201.             }
  202.             horz_sum--;
  203.         }
  204.         while (vert_sum > 0){
  205.             if (newy >= g_top_note_line - CROSS_HALF + HALF_NOTE_DOTS)
  206.                 newy -= g_notes[note++].up_dots;
  207.             vert_sum--;
  208.         }
  209.         while (vert_sum < 0){
  210.             if (newy <= g_bot_note_line - HALF_NOTE_DOTS - CROSS_HALF)
  211.                 newy += g_notes[note--].down_dots;
  212.             vert_sum++;
  213.         }
  214.         xsprite(cross, oldx, oldy, g_emph_color);
  215.         xsprite(cross, newx, newy, g_emph_color);
  216.         clear_select_lines();
  217.         write_int(tick, g_graph_char_h - 9, g_graph_char_v - 5, g_norm_attrib);
  218.         writeword(g_notes[note].name, g_graph_char_h - 9, g_graph_char_v - 4, 
  219.             g_norm_attrib);
  220.         write_int(csr_measure + 1, g_graph_char_h - 9, g_graph_char_v - 3, g_norm_attrib);
  221.         oldx = newx;
  222.         oldy = newy;
  223.     }
  224.     return(NULL);
  225. }
  226.  
  227.  
  228.  
  229. void
  230. clear_select_lines(void)        /* blank out the note name and tick areas */
  231. {
  232.     writeword("        ", g_graph_char_h - 9, g_graph_char_v - 5, g_norm_attrib);
  233.     writeword("        ", g_graph_char_h - 9, g_graph_char_v - 4, g_norm_attrib);
  234.     writeword("        ", g_graph_char_h - 9, g_graph_char_v - 3, g_norm_attrib);
  235. }
  236.  
  237.  
  238. /* Locate a note within the note list, given that the cursor is on the */
  239. /* specified measure and tick.  Return pointer to it, or NULL if not found. */
  240. struct note_time far
  241. *find_note(struct note_time far *first_notep, int note, int measure, int tick)
  242. {
  243.     float startn, endn, noten;  /* decimal measure.xx fraction of measure */
  244.  
  245.     noten = note_to_float(measure, tick);
  246.     while (first_notep->next != NULL){
  247.         if (first_notep->note_number == note){          /* if same note */
  248.             startn = note_to_float(first_notep->on_measure, 
  249.                 first_notep->on_tick);
  250.             endn = note_to_float(first_notep->off_measure, 
  251.                 first_notep->off_tick);
  252.             if (noten >= startn && noten <= endn)
  253.                 return(first_notep);
  254.         }
  255.         first_notep = first_notep->next;  /* no match, so try next note */
  256.     }
  257.     return(NULL);
  258. }
  259.  
  260.  
  261. /* Convert note timing as measure, tick to floating point value */
  262. float
  263. note_to_float(int measure, int tick)
  264. {
  265.     float fm, ft, fn;
  266.     
  267.     fm = measure;
  268.     ft = tick;
  269.     ft = ft/(TICK_PER_BEAT * g_meter);
  270.     fn = fm + ft;
  271.     return(fn);
  272. }
  273.     
  274.  
  275. /* Removes one event from the event list.  Corrects timing bytes as needed */
  276. int
  277. remove_event(struct event far *eventp, int track)
  278. {
  279.     int ticks;
  280.     
  281.     struct event far *ep;
  282.     struct event far *lastep;
  283.     struct event far *nextep;
  284.     
  285.     lastep = ep = g_trackarray[track].first;
  286.     
  287.     while (ep != eventp && ep != NULL){
  288.         lastep = ep;
  289.         ep = ep->next;
  290.     }
  291.     
  292.     if (ep == NULL)
  293.         return(0);
  294.  
  295.     nextep = ep->next;
  296.     while (nextep->b[0] == TIME_OUT){   /* go past any linked TIME_OUT's */
  297.         nextep = nextep->next;          /* nextep is first event with a */
  298.     }                                   /* timing byte. */
  299.  
  300.     ticks = ep->b[0] + nextep->b[0];
  301.     if (ticks < MAX_CLOCK){             /* adjust next clock byte, then */
  302.         nextep->b[0] = ticks;           /* delete the marked event. */
  303.         lastep->next = ep->next;
  304. #ifdef TURBOC
  305.         farfree(ep);
  306. #else
  307.         _ffree(ep);
  308. #endif
  309.     }
  310.     else{
  311.         nextep->b[0] -= MAX_CLOCK - ep->b[0];   /* if clock is too large, */
  312.         ep->nbytes = 1;                         /* use (not) deleted event */
  313.         ep->b[0] = TIME_OUT;                    /* to hold a new TIME_OUT. */
  314.         ep->b[1] = ep->b[2] = ep->b[3] = 0;
  315.     }
  316.     return(1);
  317. }
  318.  
  319.  
  320. /* Remove one note's data from note list. */
  321. struct note_time far
  322. *remove_note(struct note_time far *first_notep, struct note_time far *notep)
  323. {
  324.     struct note_time far *np;
  325.     struct note_time far *lastnp;
  326.  
  327.     if (notep == first_notep){      /* if deleting first note */
  328.         lastnp = notep;
  329.         first_notep = first_notep->next;
  330. #ifdef TURBOC
  331.         farfree(lastnp);
  332. #else
  333.         _ffree(lastnp);
  334. #endif
  335.         return(first_notep);
  336.     }
  337.     else{
  338.         lastnp = np = first_notep;
  339.         
  340.         while (np != notep && np != NULL){
  341.             lastnp = np;
  342.             np = np->next;
  343.         }
  344.         
  345.         if (np == NULL)
  346.             return(0);
  347.         
  348.         lastnp->next = np->next;
  349. #ifdef TURBOC
  350.         farfree(np);
  351. #else
  352.         _ffree(np);
  353. #endif
  354.         return(first_notep);
  355.     }
  356. }
  357.