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

  1. /* mted3.c   editor third module for multi */
  2. /* `MIDI Sequencing In C', Jim Conger, M&T Books, 1989 */
  3.  
  4. #include <stdio.h>  /* compiler library headers */
  5. #include <conio.h>
  6.  
  7. #include "screenf.h"
  8. #include "standard.h"
  9. #include "mpu401.h"
  10. #include "mt.h"
  11. #include "video.h"
  12. #include "mtdeclar.h"
  13.  
  14.  
  15. /* Convert measures from b_start to b_end to empty measures.  Shut down */
  16. /* any notes playing at start of block to avoid hung notes. */
  17. void
  18. empty_block(int track, int b_start, int b_end)
  19. {
  20.     int i;
  21.     struct event far *begin_block;
  22.     struct event far *end_block;
  23.     struct event far *ep1;
  24.     struct event far *ep2;
  25.  
  26.     begin_block = advance_to_measure(track, b_start);
  27.     init_note_array();
  28.     fill_note_array(g_trackarray[track].first, begin_block);
  29.     
  30.     end_block = advance_to_measure(track, b_end + 1);
  31.     end_block = end_block->next;    /* end is event after block's last m.e. */
  32.     
  33.     ep1 = begin_block->next;    /* free memory for all events in block */
  34.     while (ep1 != end_block){
  35.         ep2 = ep1;
  36.         ep1 = ep1->next;
  37. #ifdef TURBOC
  38.         farfree(ep2);
  39. #else
  40.         _ffree(ep2);
  41. #endif
  42.     }
  43.                     /* put in note offs for notes on at start */
  44.     begin_block = add_note_offs(begin_block, g_trackarray[track].midichan);
  45.     
  46.                     /* put in sacraficial event to prepare for add_measure */
  47.     begin_block = begin_block->next = eventalloc();
  48.     begin_block->b[0] = begin_block->b[1] = 0;
  49.     for (i = 0; i <= b_end - b_start; i++)      /* add back in empty meas's */
  50.         begin_block = add_measure(begin_block);
  51.  
  52.     begin_block->next = end_block;  
  53.     clean_track(track);
  54. }
  55.  
  56.  
  57. /* Copy contents of marked block repeatedly starting at the measure */
  58. /* selected.  Prompts for number of repetitions. */
  59. void    
  60. block_repeat(void)
  61. {
  62.     int i, status, reps;
  63.     struct item dest_item;
  64.     
  65.     if(g_block_on && g_block_end != -1){
  66.         writeword("Move the cursor to the starting point of the repetitions.",
  67.             1, g_text_char_v - 1, g_norm_attrib);
  68.         status = select_measure(&dest_item);
  69.         if (!status){
  70.             writerr("Block repeat was cancelled.", g_text_char_v, 
  71.                 g_norm_attrib, g_norm_attrib);
  72.             return;
  73.         }
  74.         clearline(g_text_char_v - 1, g_norm_attrib);
  75.         status = getint(g_text_char_v - 1, 
  76.             "Enter the number of times to repeat the marked block ->",
  77.             &reps, 0, 32000, g_norm_attrib, g_emph_attrib);
  78.         if (!status || !reps){
  79.             writerr("Block repeat was cancelled.", g_text_char_v, 
  80.                 g_norm_attrib, g_norm_attrib);
  81.             return;
  82.         }       
  83.  
  84.         repeat_copy(g_block_start, g_block_track, dest_item.measure, 
  85.             dest_item.track, g_block_end - g_block_start + 1, reps);
  86.         change_channel(dest_item.track, 
  87.             g_trackarray[dest_item.track].midichan);
  88.     }
  89.     else{
  90.         writerr("Mark the start end end of the source block, then repeat.",
  91.             g_text_char_v, g_norm_attrib, g_emph_attrib);
  92.     }
  93. }
  94.  
  95.  
  96. /* Copy source block repeatedly to destination track starting at dest_meas */
  97. /* Do this reps times. */
  98. void
  99. repeat_copy(int source_meas, int source_track, int dest_meas, int dest_track, 
  100.     int n_meas, int reps)
  101. {
  102.     int i, j, sm;
  103.     struct event far *source_p;
  104.     struct event far *dest_p;
  105.  
  106.     clearline(g_text_char_v - 1, g_norm_attrib);
  107.     writeword("Copying.  Hit ESC to interupt.  Now on repetition:", 1, 
  108.         g_text_char_v - 1, g_norm_attrib);
  109.  
  110.     /* build empty measures for destination, then move pointer to start */
  111.     advance_to_measure(dest_track, 1 + dest_meas + (n_meas * reps));
  112.     dest_p = advance_to_measure(dest_track, dest_meas); 
  113.  
  114.     for (i = 0; i < reps; i++){
  115.         write_int(i + 1, 60, g_text_char_v - 1, g_norm_attrib);
  116.         init_note_array();      /* prepart to track notes left on */
  117.         sm = source_meas;
  118.         for (j = 0; j < n_meas; j++){
  119.             source_p = advance_to_measure(source_track, sm++);
  120.             dest_p = merge_measure(dest_p, source_p);
  121.             if (dest_p == NULL){
  122.                 writerr("Out of memory.", g_text_char_v - 1, g_norm_attrib,
  123.                     g_emph_attrib);
  124.                 return;
  125.             }
  126.             if (kbhit()){
  127.                 if (getch() == ESC){
  128.                     add_note_offs(dest_p, g_trackarray[dest_track].midichan);
  129.                     writerr("Copy process interrupted.", g_text_char_v,
  130.                         g_norm_attrib, g_emph_attrib);
  131.                     return;
  132.                 }
  133.             }
  134.         }
  135.         add_note_offs(dest_p, g_trackarray[dest_track].midichan);
  136.     }   
  137. }
  138.  
  139.  
  140.  
  141. void
  142. transpose_block(void)   /* move all midi data within block up/down n notes */
  143. {
  144.     int *offset, x, status, b1, b2, time;
  145.     struct event far *ep;
  146.     struct event far *start_p;
  147.     struct event far *end_p;
  148.     struct event far *before_end;
  149.     offset = &x;
  150.     
  151.     status = getint(g_text_char_v - 1, 
  152.         "Enter the number of MIDI note numbers to add/subtract ->",
  153.         offset, -1 * NNOTES, NNOTES, g_norm_attrib, g_emph_attrib);
  154.     if (!status || !*offset){
  155.         writerr("Block transpose was cancelled.", g_text_char_v, 
  156.             g_norm_attrib, g_norm_attrib);
  157.         return;
  158.     }       
  159.                 /* shut all notes off at start of block */
  160.     init_note_array();
  161.     start_p = advance_to_measure(g_block_track, g_block_start);
  162.     fill_note_array(g_trackarray[g_block_track].first, start_p);
  163.     start_p = add_note_offs(start_p, g_trackarray[g_block_track].midichan);
  164.     
  165.                 /* shut all notes off at end of block */
  166.     init_note_array();
  167.     end_p = advance_to_measure(g_block_track, g_block_end + 1);
  168.     before_end = find_event_before(g_block_track, end_p);
  169.     fill_note_array(start_p, end_p);
  170.     add_note_offs(before_end, g_trackarray[g_block_track].midichan);
  171.                 /* adjust timing byte of note_offs to fall at measure end */
  172.     time = end_p->b[0];
  173.     end_p->b[0] = 0;
  174.     before_end->next->b[0] = time;
  175.     
  176.     ep = start_p->next;
  177.     while (ep != end_p){        /* transpose within block */
  178.         b1 = ep->b[1];
  179.         b2 = ep->b[2];
  180.         if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL ||
  181.             b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
  182.             b2 += *offset;
  183.             while (b2 >= NNOTES){       /* if transposition exceeds MIDI */
  184.                 b2 -= OCTIVE;           /* note range, adjust by octives */
  185.             }
  186.             while (b2 <= -1 * NNOTES){
  187.                 b2 += OCTIVE;
  188.             }
  189.         }
  190.         ep->b[2] = b2;
  191.         ep = ep->next;
  192.     }
  193.     clean_track(g_block_track);
  194. }
  195.  
  196.  
  197.  
  198. struct event far                /* find and return event right before ep */
  199. *find_event_before(int track, struct event far *ep)
  200. {
  201.     struct event far *nextp;
  202.     struct event far *lastp;
  203.     
  204.     nextp = g_trackarray[track].first;
  205.     
  206.     while (nextp != ep && nextp != NULL){
  207.         lastp = nextp;
  208.         nextp = nextp->next;
  209.     }
  210.     if (nextp != NULL)
  211.         return (lastp);
  212.     else
  213.         return (NULL);
  214. }
  215.     
  216.     
  217. /* Purge any unnecessary events from track.  Takes care of special cases */
  218. /* in merge process.  Converts explicit Note Off's to implied ones. */
  219. void
  220. clean_track(int track)
  221. {
  222.     int i, time, no_change;
  223.     unsigned int b1, b2, b3;
  224.     struct event far *ep;
  225.     struct event far *np;
  226.     struct event far *oldp;
  227.  
  228.     init_note_array();
  229.     ep = g_trackarray[track].first;
  230.     np = ep->next;
  231.     
  232.     while (1){
  233.         no_change = 1;
  234.         b1 = np->b[1];
  235.         b2 = np->b[2];
  236.         b3 = np->b[3];
  237.         if (b1 >= NOTE_OFF && b1 < NOTE_OFF + NCHANNEL){
  238.             b1 = (b1 & 0x0F) + NOTE_ON;
  239.             b3 = 0;     /* convert explicity note_offs to note on, vel = 0 */
  240.             np->b[1] = b1;
  241.             np->b[3] = 0;
  242.         }
  243.         if (b1 == ALL_END)
  244.             break;
  245.         else if (b1 >= NOTE_ON && b1 < NOTE_ON + NCHANNEL){
  246.             if (b3)                                     /* if a note on */
  247.                 g_note_array[b2]++;
  248.             else{                                       /* a note off */
  249.                 if (g_note_array[b2])                   /* if already an on */
  250.                     g_note_array[b2]--;
  251.                 else{                                   /* loose note off - */
  252.                     time = np->b[0];                    /* so delete it */
  253.                     oldp = np;
  254.                     np = np->next;
  255.                     ep->next = np;
  256. #ifdef TURBOC
  257.                     farfree(oldp);
  258. #else
  259.                     _ffree(oldp);
  260. #endif
  261.                     no_change = 0;
  262.                     while (np->b[0] == TIME_OUT) {      /* find event after */
  263.                         ep = ep->next;                  /* time_outs */
  264.                         np = np->next;
  265.                     } 
  266.                     if (np->b[0] + time < MAX_CLOCK)    /* adjust clock */
  267.                         np->b[0] += time;               /* count */
  268.                     else{
  269.                         ep = ep->next = eventalloc();   
  270.                         ep->next = np;
  271.                         ep->b[0] = TIME_OUT;
  272.                         for (i = 1; i < 4; i++){
  273.                             ep->b[i] = 0;
  274.                         }
  275.                         np->b[0] = np->b[0] + time - MAX_CLOCK;
  276.                     }
  277.                 }
  278.             }
  279.         }
  280.         if (no_change){
  281.             ep = np;
  282.             np = ep->next;
  283.         }
  284.     }
  285.     add_note_offs(ep, g_trackarray[track].midichan);
  286.  
  287.     ep = np->next;              /* points to event past ALL_END if any */
  288.     np->next = NULL;
  289.     g_trackarray[track].last = np;
  290.     
  291.     while (ep != NULL){         /* delete any events past first ALL_END */
  292.         np = ep->next;
  293. #ifdef TURBOC
  294.         farfree(oldp);
  295. #else
  296.         _ffree(ep);
  297. #endif
  298.         ep = np;
  299.     }   
  300. }
  301.  
  302.  
  303.  
  304. void
  305. block_paste(void)               /* copies marked block to targeted spot */
  306. {
  307.     int i, ans, source_track, source_measure, dest_track, dest_measure;
  308.     struct item meas_item;
  309.     struct event far *source_event;
  310.     struct event far *dest_event;
  311.  
  312.     if (!g_block_on || g_block_end == -1){
  313.         writerr("First mark the START and END of the block",
  314.             g_text_char_v, g_norm_attrib, g_emph_attrib);
  315.         return;
  316.     }
  317.     writeword(
  318.         "Move the cursor to the measure to start the pasted block"
  319.         , 1, g_text_char_v - 1, g_norm_attrib);
  320.     ans = select_measure(&meas_item);
  321.  
  322.     if (!ans)
  323.         return;
  324.     else{
  325.         clearline(g_text_char_v - 1, g_norm_attrib);
  326.         writeword("Copying.  Hit ESC to terminate.", 1, g_text_char_v - 1, 
  327.             g_norm_attrib);
  328.         
  329.         init_note_array();
  330.         source_track = g_block_track;
  331.         dest_track = meas_item.track;
  332.         source_measure = g_block_start;
  333.         dest_measure = meas_item.measure;
  334.  
  335.                         /* build empty measures as needed in dest track */
  336.         advance_to_measure(dest_track, dest_measure +
  337.             g_block_end - g_block_start + 1);
  338.         dest_event = advance_to_measure(dest_track, dest_measure);
  339.  
  340.                         /* merge each measure successively from front */
  341.         for (i = 0; i <= g_block_end - g_block_start; i++){
  342.             source_event = advance_to_measure(source_track,
  343.                 source_measure++);
  344.             if (source_event == dest_event){
  345.                 writerr("Source and destination measures cannot be the same.",
  346.                     g_text_char_v, g_norm_attrib, g_norm_attrib);
  347.                 return;
  348.             }
  349.             dest_event = merge_measure(dest_event, source_event);
  350.             if (dest_event == NULL){
  351.                 writerr("Out of memory.", g_text_char_v - 1, g_norm_attrib,
  352.                     g_emph_attrib);
  353.                 return;
  354.             }               
  355.             if (kbhit()){
  356.                 if (getch() == ESC){
  357.                     writerr("Copy process interrupted.", g_text_char_v,
  358.                         g_norm_attrib, g_emph_attrib);
  359.                     break;
  360.                 }
  361.             }
  362.         }
  363.         add_note_offs(dest_event, g_trackarray[dest_track].midichan);
  364.         clean_track(dest_track);
  365.         change_channel(dest_track, g_trackarray[dest_track].midichan);
  366.         goto_measure(g_current_measure);
  367.     }
  368. }
  369.