home *** CD-ROM | disk | FTP | other *** search
/ Sound Sensations! / sound_sensations.iso / midifile / cmtcmu / record.c < prev    next >
C/C++ Source or Header  |  1990-06-28  |  19KB  |  562 lines

  1. /* record.c -- keyboard to adagio recorder
  2.  *
  3.  * the interface consists of three routines:
  4.  *        rec_init()        -- initialization
  5.  *    int rec_poll(long time) -- called during recording, returns true if
  6.  *                    recording space is exhausted
  7.  *        rec_final()        -- called to finish up
  8.  */
  9.  
  10. /*****************************************************************************
  11. *        Change Log
  12. *  Date        | Change
  13. *-----------+-----------------------------------------------------------------
  14. * 27-Feb-86 | Created changelog
  15. *        | Use pedal information when computing durations (code taken
  16. *        |  from transcribe.c)
  17. * 23-Mar-86 | Determine size of transcription when rec_init is called.
  18. * 21-May-86 | Major rewrite to use continuous controls (code taken 
  19. *        |  from transcribe.c)
  20. *****************************************************************************/
  21.  
  22. #include "cext.h"
  23. #include "stdio.h"
  24. #include "malloc.h"
  25. #include "mpu.h"
  26. #include "userio.h"
  27. #include "midicode.h"
  28. #include "record.h"
  29.         
  30. extern long space;    /* how much space is left? */
  31.  
  32. int debug_rec = false;    /* verbose debug flag for this module */
  33. int max_notes = -1;    /* -1 is flag that space must be allocated */
  34.  
  35. /****************************************************************
  36. * data structure notes: the midi stream is stored as an array 
  37. * of 4-byte records, each of which is either a time or midi
  38. * data.     Midi data always begins with a control byte (high
  39. * order bit set), and it is assumed times are positive (high
  40. * order bit clear), so the two are easy to distinguish
  41. * IF THE COMPILER PUTS THESE BITS IN THE SAME PLACE.  It looks
  42. * like the high order byte of the time lines up with the last
  43. * byte of a 4 byte array, so we will always set the high order
  44. * bit of the last array byte when the first 3 bytes are filled
  45. * with MIDI data.  This is refered to as the "tag" bit.
  46. * WARNING: Lattice C longs are UNSIGNED, therefore always
  47. * positive.  Test the high order bit with a mask.
  48. ****************************************************************/
  49.  
  50. #define MIDI_CMD_BIT        0x80
  51. #define HIGH_BIT        0x80000000
  52. #define istime(note) (!(((note)->when) & HIGH_BIT))
  53.  
  54. #define ndsw 2
  55. private char *dsw[ndsw] = { "-d", "-debug" };
  56.  
  57. typedef union note_struct {
  58.     byte n[4];
  59.     long when;
  60. } *note_type, note_node;
  61.  
  62. private note_type event_buff;    /* pointer to allocated buffer */
  63. private FILE *fp;
  64. private char file_name[100];
  65. private note_type next;    /* pointer to next entry in buffer */
  66. private note_type last;    /* pointer to last entry in buffer */
  67. private int pile_ups;    /* inner loop iteration count */
  68. private int max_pile;    /* maximum of pile_ups */
  69.  
  70. /****************************************************************************
  71. *    Routines local to this module
  72. ****************************************************************************/
  73. private void    bend_filter();
  74. private void    byteorder();
  75. private void    ctrl_filter();
  76. private int    event_bend();
  77. private void    filter();
  78. private long    getdur();
  79. private long    getnext();
  80. private char    map_ctrl();
  81. private void    output();
  82. private void    put_pitch();
  83.  
  84. /****************************************************************************
  85. *                bend_filter
  86. * Inputs:
  87. *    note_type note: the current note
  88. *    note_type last: the last recorded event
  89. *    long now: the current time
  90. * Effect:
  91. *    remove pitch bend events in same 0.01 sec time slot
  92. * Implementation:
  93. *    If the current event is a pitch bend that bends again
  94. *    in the same time slot, make it a no-op by replacing it with
  95. *    the time.
  96. ****************************************************************************/
  97.  
  98. private void bend_filter(note, last, now)
  99.     note_type note;    /* current note */
  100.     note_type last;    /* the last recorded event */
  101.     long now;        /* the current time */
  102. {
  103.     /* first see if there is another bend in this time
  104.      * slot.
  105.      */
  106.     note_type note2 = note + 1;
  107.     while (note2 < last) {
  108.     if (istime(note2) && (note2->when > now)) {
  109.         break; /* new time slot */
  110.     } else if (note->n[0] == note2->n[0]) {
  111.         note->when = now;
  112.         return; /* found another bend */
  113.     }
  114.     note2++;
  115.     }
  116. }
  117.  
  118. /****************************************************************************
  119. *                byteorder
  120. * Effect: 
  121. *    check out assumptions about byte order and placement
  122. ****************************************************************************/
  123.  
  124. private void byteorder()
  125. {
  126.     if ((sizeof(event_buff[0]) != 4) ||
  127.     (sizeof(event_buff[0].when) != 4) ||
  128.     (sizeof(event_buff[0].n[0]) != 1)) {
  129.     fprintf(stderr, "implementation error: size problem\n");
  130.     exit(1);
  131.     }
  132.     event_buff[0].n[0] = 0x12;
  133.     event_buff[0].n[1] = 0x34;
  134.     event_buff[0].n[2] = 0x56;
  135.     event_buff[0].n[3] = 0x78;
  136.     if ((event_buff[0].when != 0x78563412) &&
  137.     (event_buff[0].when != 0x12345678)) {
  138.     fprintf(stderr, "implementation error: layout problem\n");
  139.     exit(1);
  140.     }
  141. }
  142.  
  143. /****************************************************************************
  144. *                ctrl_filter
  145. * Inputs:
  146. *    note_type note: the current note
  147. *    note_type last: the last recorded event
  148. *    long now: the current time
  149. * Effect:
  150. *    remove ctrl change events in same 0.01 sec time slot
  151. * Implementation:
  152. *    If the current event is a control change that changes again
  153. *    in the same time slot, make it a no-op by replacing it with
  154. *    the time.
  155. ****************************************************************************/
  156.  
  157. private void ctrl_filter(note, last, now)
  158.     note_type note;    /* the current note */
  159.     note_type last;    /* the last recorded event */
  160.     long now;        /* the current time */
  161. {
  162.     /* see if there is another control change in this time
  163.      * slot.
  164.      */
  165.     note_type note2 = note+1;
  166.     while (note2 < last) {
  167.     if (istime(note2) && (note2->when > now)) {
  168.         break;    /* new time slot */
  169.     } else if ((note->n[0] == note2->n[0]) &&
  170.            (note->n[1] == note2->n[1])) {
  171.         note->when = now;
  172.         return; /* found another change */
  173.     }
  174.     note2++;
  175.     }
  176. }
  177.  
  178. /****************************************************************************
  179. *                event_bend
  180. * Inputs:
  181. *    note_type note: pointer to a pitch bend event
  182. * Outputs:
  183. *    returns int: an 8 bit pitch bend number
  184. ****************************************************************************/
  185.  
  186. private int event_bend(note)
  187.     note_type note;
  188. {
  189.     return (int) (((note->n[1]) >> 6) + ((note->n[2]) << 1)); 
  190. }
  191.  
  192. /****************************************************************************
  193. *                filter
  194. * Inputs:
  195. *    note_type last: the last note recorded
  196. * Effect: allow only one control change per time slot (0.01 sec)
  197. * Implementation:
  198. *    call ctrl_filter and bend_filter to overwrite control changes with
  199. *    noop data (the current time is used as a noop)
  200. ****************************************************************************/
  201.  
  202. private void filter(last)
  203.     note_type last;
  204. {
  205.     note_type note;    /* loop control variable */
  206.     long now;        /* last time seen */
  207.     int command;    /* command pointed to by note */
  208.     int chan;        /* channel pointed to by note */
  209.  
  210.     for (note = event_buff; note <= last; note++) {
  211.     if (istime(note)) {
  212.         now = note->when;
  213.     } else {
  214.         command = note->n[0] & MIDI_CODE_MASK;
  215.         chan = note->n[0] & MIDI_CHN_MASK;
  216.  
  217.         if (command == MIDI_CTRL &&
  218.         note->n[1] == SUSTAIN) {
  219.         /* do nothing */;
  220.         } else if (command == MIDI_CTRL) {
  221.         ctrl_filter(note, last, now);
  222.         } else if (command == MIDI_TOUCH) {
  223.         bend_filter(note, last, now);    /* bend and touch use the */
  224.         } else if (command == MIDI_BEND) {    /*  same filter routines  */
  225.         bend_filter(note, last, now);
  226.         }
  227.     }
  228.     }
  229. }
  230.  
  231.  
  232. /****************************************************************************
  233. *                getdur
  234. * Inputs:
  235. *    int i: index of the note
  236. *    note_type last: pointer to the last event recorded
  237. *    int ped: true if pedal is down at event i
  238. *    long now: the time at event i
  239. * Outputs:
  240. *    returns long: the duration of note i
  241. * Assumes:
  242. *    assumes i is a note
  243. * Implementation:
  244. *    This is tricky because of pedal messages.  The note is kept on by
  245. *    either the key or the pedal.  Keep 2 flags, key and ped.  Key is
  246. *    turned off when a key is released, ped goes off and on with pedal.
  247. *    Note ends when (1) both key and ped are false, (2) key is
  248. *    pressed (this event will also start another note).
  249. ****************************************************************************/
  250.  
  251. private long getdur(i, last, ped, now)
  252.     int i;
  253.     note_type last;
  254.     int ped;
  255.     long now;
  256. {
  257.     int key = true;    /* flag that says if note is on */
  258.     long start = now;
  259.     int chan = event_buff[i].n[0] & MIDI_CHN_MASK;
  260.     int pitch = event_buff[i].n[1];
  261.     note_type note = &(event_buff[i+1]);
  262.     int noteon; /* true if a noteon message received on chan */
  263.     int keyon;    /* true if noteon message had non-zero velocity */
  264.  
  265.     /* search from the next event (i+1) to the end of the buffer:
  266.      */
  267.     for (; note < last; note++) {
  268.     if (istime(note)) {
  269.         now = note->when;
  270.     } else {
  271.         noteon = keyon = false;
  272.         if ((note->n[0] & MIDI_CHN_MASK) == chan) {
  273.         noteon = ((note->n[0] & MIDI_CODE_MASK) == MIDI_ON_NOTE) &&
  274.              (note->n[1] == pitch);
  275.         keyon = noteon && (note->n[2] != 0);
  276.         if ((noteon && (note->n[2] == 0)) ||
  277.             (((note->n[0] & MIDI_CODE_MASK) == MIDI_OFF_NOTE) &&
  278.              (note->n[1] == pitch))) key = false;
  279.         if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) &&
  280.             note->n[1] == SUSTAIN && note->n[2] == 127) ped = true;
  281.         if (((note->n[0] & MIDI_CODE_MASK) == MIDI_CTRL) &&
  282.             note->n[1] == SUSTAIN && note->n[2] == 0) ped = false;
  283.  
  284.         if ((!key && !ped) || keyon)
  285.             return now - start;
  286.         }
  287.     }
  288.     }
  289.     return last->when - start;
  290. }
  291.  
  292. /****************************************************************************
  293. *                getnext
  294. * Inputs:
  295. *    int i: the index of the current note
  296. *    note_type last: pointer to last valid data
  297. *    long now: the current time
  298. * Outputs:
  299. *    returns long: the time of the next note, program, or control change
  300. *        (returns time of last event if nothing else is found)
  301. ****************************************************************************/
  302.  
  303. private long getnext(i, last, now)
  304.     int i;    /* the index of the current note */
  305.     note_type last;    /* pointer to last valid data */
  306.     long now;    /* the current time */
  307. {
  308.     i++;    /* advance to next item */
  309.     for (; event_buff + i < last; i++) {
  310.     note_type note = &(event_buff[i]);
  311.     int cmd = note->n[0] & MIDI_CODE_MASK;
  312.  
  313.     if (istime(note)) {
  314.         now = note->when;
  315.     } else if (((cmd == MIDI_ON_NOTE) &&
  316.             (note->n[2] != 0)) /* note on */ ||
  317.            (cmd == MIDI_CH_PROGRAM) /* program change */ ||
  318.            ((cmd == MIDI_CTRL) &&
  319.             (note->n[1] != SUSTAIN) /* control change */ ) ||
  320.            (cmd == MIDI_TOUCH) ||
  321.            (cmd == MIDI_BEND)) {
  322.         return now;
  323.     }
  324.     }
  325.     return last->when;
  326. }
  327.  
  328. /****************************************************************************
  329. *                map_ctrl
  330. * Inputs:
  331. *    int control: a midi control number
  332. * Outputs:
  333. *    returns char: an adagio control change command letter, NULL if
  334. *        control change is not one of PORTARATE, PORTASWITCH,
  335. *        MODWHEEL, FOOT
  336. ****************************************************************************/
  337.  
  338. private char map_ctrl(control)
  339.     int control;
  340. {
  341.     switch (control) {
  342.     case PORTARATE:        return 'J';
  343.     case PORTASWITCH:    return 'K';
  344.     case MODWHEEL:        return 'M';
  345.     case FOOT:        return 'X';
  346.     default:        return  0;
  347.     }
  348.     return NULL;    /* make Lattice C type cheker happy */
  349. }
  350.  
  351. /****************************************************************************
  352. *                output
  353. * Inputs:
  354. *    FILE *fp: an opened file pointer
  355. *    note_type last: the last data in the buffer
  356. *    boolean absflag: set to true if first line of the adagio score should
  357. *        include the absolute time
  358. * Effect: 
  359. *    write adagio file using data in event_buff
  360. * Implementation:
  361. *    NOTE: put all program changes in rests
  362. *    use N(ext) notation for all timing
  363. *    output no more than one continuous parameter change per
  364. *    clock tick for each continuous change parameter
  365. ****************************************************************************/
  366.  
  367. private void output(fp, last, absflag)
  368.     FILE *fp;
  369.     note_type last;
  370.     boolean absflag;
  371. {
  372.     int i;            /* loop counter */
  373.     int command;        /* the current command */
  374.     int chan;            /* the midi channel of the current event */
  375.     int lastchan = 0;        /* the default adagio channel (1) */
  376.     int ped = false;        /* flag maintains state of pedal */
  377.     int how_many = last - event_buff;
  378.     long now;        /* the time of the next event */
  379.     boolean bad_ctrl_flag = false;    /* set to true if unknown ctrl read */
  380.  
  381.     if (fp == NULL) {
  382.     fprintf(stderr, "internal error: output called with NULL file.\n");
  383.     exit(1);
  384.     }
  385.  
  386.     if (debug_rec)
  387.     printf("hint: if file is not being closed, decrease MAXSPACE\n");
  388.  
  389.     /* set the initial absolute time, all other times are relative */
  390.     if (absflag)
  391.     fprintf(fp, "t%ld ", event_buff[0].when);
  392.  
  393.     for (i = 0; i < how_many; i++) {
  394.     if (debug_rec) {
  395.         printf("ev %d: %x %x %x (%ld)\n", i, event_buff[i].n[0],
  396.         event_buff[i].n[1], event_buff[i].n[2], event_buff[i].when);
  397.     }
  398.  
  399.     if (istime(event_buff+i)) {
  400.         now = event_buff[i].when;
  401.         if (debug_rec) printf("i = %d, now = %ld\n", i, now);
  402.     } else {
  403.         command = event_buff[i].n[0] & MIDI_CODE_MASK;
  404.         chan = event_buff[i].n[0] & MIDI_CHN_MASK;
  405.  
  406.         if (command == MIDI_ON_NOTE && event_buff[i].n[2] != 0) {
  407.         put_pitch(fp, event_buff[i].n[1] - 12);
  408.         fprintf(fp, " u%ld l%d n%ld", getdur(i, last, ped, now),
  409.             event_buff[i].n[2], getnext(i, last, now) - now);
  410.         if (lastchan != chan) {
  411.             fprintf(fp, " v%d\n", chan + 1);
  412.             lastchan = chan;
  413.         } else fprintf(fp, "\n");
  414.         } else if (command == MIDI_CH_PROGRAM) {
  415.         fprintf(fp, "r z%d n%ld", event_buff[i].n[1] + 1,
  416.             getnext(i, last, now) - now);
  417.         if (lastchan != chan) {
  418.             fprintf(fp, " v%d\n", chan + 1);
  419.             lastchan = chan;
  420.         } else fprintf(fp, "\n");
  421.         } else if (command == MIDI_CTRL &&
  422.                event_buff[i].n[1] == SUSTAIN) {
  423.         ped = (event_buff[i].n[2] != 0);
  424.         } else if (command == MIDI_CTRL) {
  425.         char c = map_ctrl(event_buff[i].n[1]);
  426.         if (c != 0) {
  427.             fprintf(fp, "%c%d n%d\n", c,
  428.             event_buff[i].n[2], getnext(i, last, now) - now);
  429.         } else bad_ctrl_flag = true;
  430.         } else if (command == MIDI_TOUCH) {
  431.         fprintf(fp, "O%d n%d\n", event_buff[i].n[1],
  432.             getnext(i, last, now) - now);
  433.         } else if (command == MIDI_BEND) {
  434.         fprintf(fp, "Y%d n%d\n", event_bend(&event_buff[i]),
  435.             getnext(i, last, now) - now);
  436.         } else if (command != MIDI_ON_NOTE) {
  437.         fprintf(stderr, "Command 0x%x ignored\n", command);
  438.         }
  439.     }
  440.     }
  441.     if (bad_ctrl_flag)
  442.     fprintf(stderr,
  443.            "Some unrecognized control changes were omitted from file.\n");
  444. }
  445.  
  446. /****************************************************************************
  447. *                put_pitch
  448. * Inputs:
  449. *    FILE *fp: an open file
  450. *    int p: a pitch number
  451. * Effect: write out the pitch name for a given number
  452. ****************************************************************************/
  453.  
  454. private void put_pitch(fp, p)
  455.     FILE *fp;
  456.     int p;
  457. {
  458.     static char *ptos[] = {"c", "cs", "d", "ef", "e", "f", "fs", "g",
  459.                "gs", "a", "bf", "b"};
  460.     fprintf(fp, "%s%d", ptos[p % 12], p / 12);
  461. }
  462.  
  463. /**********************************************************************
  464. *            rec_final
  465. * Inputs:
  466. *    boolean absflag: output absolute time of first note if true
  467. * Effect:
  468. *    Write recorded data to a file
  469. **********************************************************************/
  470.  
  471. void rec_final(absflag)
  472.     boolean absflag;
  473. {
  474.     next->when = gettime();
  475.     last = next;
  476.     if (debug_rec) printf("max_pile_up = %d, ", max_pile);
  477.     printf("%d times and events recorded.\n", last - event_buff);
  478.     filter(last);
  479.     output(fp, last, absflag);
  480.     fclose(fp);
  481. }
  482.  
  483. /****************************************************************************
  484. *                rec_init
  485. * Inputs:
  486. *    char *file:  pointer to file name from command line (if any)
  487. *    boolean bender: true if pitch bend should be enabled
  488. * Outputs:
  489. *    returns true if initialization succeeds
  490. * Effect:
  491. *    prepares module to record midi input
  492. ****************************************************************************/
  493.  
  494. boolean rec_init(file, bender)
  495.     char *file;
  496.     boolean bender;
  497. {
  498.     /* (char *)malloc(); */ /* memory allocation */
  499.  
  500.     debug_rec = (cl_nswitch(dsw, ndsw) != NULL);
  501.  
  502.     pile_ups = 0;
  503.     max_pile = 0;
  504.  
  505.     fp = fileopen(file, "gio", "w", "Name of output file");
  506.     if (max_notes == -1) {    /* allocate space 1st time rec_init called */
  507.     max_notes = space/sizeof(note_node);
  508.     event_buff = (note_type) malloc(sizeof(note_node) * max_notes);
  509.     if (event_buff == NULL) {
  510.         fprintf(stderr, "Internal error allocating record space.");
  511.         musicterm();
  512.         exit(1);
  513.     }
  514.     byteorder();
  515.     printf("Space for %d events has been allocated.\n", max_notes);
  516.     }
  517.     next = event_buff;
  518.     last = event_buff + max_notes - 2;
  519.  
  520.     while (getkey(false) != -1) ;    /* flush old midi events */
  521.     midi_cont(bender);
  522.     return max_notes > 10;
  523. }
  524.  
  525. /****************************************************************************
  526. *                rec_poll
  527. * Inputs:
  528. *    long time: the current time
  529. * Outputs:
  530. *    returns true if there is no more memory
  531. * Effect: reads and stores any input
  532. * Assumes: rec_poll must be called frequently to get accurate results
  533. * Implementation:
  534. *    time stamps and midi events share the same buffer of 4-byte events
  535. *    save time at most once per call to rec_poll
  536. *    save time only if midi data is present
  537. ****************************************************************************/
  538.  
  539. boolean rec_poll(time)
  540.     long time;
  541. {
  542.     next->when = time;    /* this will overwrite an earlier time unless data */
  543.             /* was recorded */
  544.     if (getbuf(false, (next+1)->n)) {    /* buffer nonempty? */
  545.     next++;
  546.     next->n[3] = MIDI_CMD_BIT;    /* set tag bit */
  547.     pile_ups = 1;
  548.     while (getbuf(false, (++next)->n)) {
  549.         next->n[3] = MIDI_CMD_BIT;    /* set tag bit */
  550.         pile_ups++;
  551.         if (next >= last) {
  552.         break;
  553.         }
  554.     }
  555.     }
  556.     if (pile_ups > max_pile) max_pile = pile_ups;
  557.     if (next >= last) {
  558.     fprintf(stderr, "No more memory.\n");
  559.     return true;
  560.     } /* else */ return false;
  561. }
  562.