home *** CD-ROM | disk | FTP | other *** search
/ Chestnut's Multimedia Mania / MM_MANIA.ISO / midi / cmtcmu / phase1.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-06-28  |  33.3 KB  |  1,137 lines

  1. /* phase1.c -- Phase 1 of adagio compilation...     */ 
  2. /*
  3.  * this module parses adagio programs and builds a linked list structure
  4.  * consisting of notes and control changes in time order.
  5.  */
  6.  
  7. /*****************************************************************************
  8. *        Change Log
  9. *  Date        | Change
  10. *-----------+-----------------------------------------------------------------
  11. * 31-Dec-85 | Created changelog
  12. * 31-Dec-85 | Add c:\ to include directives
  13. * 31-Dec-85 | Added standard command scanner, metronome variable, need to add 
  14. *        | cmdline_help procedure
  15. * 31-Dec-85 | Call intr_init
  16. * 31-Dec-85 | Set musictrace from command line via -trace
  17. * 31-Dec-85 | Added -poll
  18. *  1-Jan-86 | Put error messages out to stderr
  19. *  1-Jan-86 | Set IsAT.     Can be later overridden by -at and -xt switches,
  20. *        | currently only used for diagnostics (may be needed for
  21. *        | compatibles, who knows?  In which case remove the tests which
  22. *        | confirm the type of processor)
  23. *  1-Jan-86 | <rgd/jmn> Removed dur-adjusted message
  24. *  1-Jan-86 | Added miditrace
  25. * 18-Jan-86 | Shortened durations by 1/200 s to avoid roundoff problems --
  26. *        | see buildnote for details.
  27. *  3-Mar-86 | Allow octave and accidentals in either order after pitch name.
  28. *        | Default octave is now one that gets nearest previous pitch,
  29. *        |  the tritone (half an octave) interval is descending by default.
  30. *        | Special commands handled by table search, !Rate command added
  31. *        |  to scale all times by a percentage (50 = half speed).
  32. *  9-Mar-86 | Use space to limit amount of storage allocation.    Otherwise
  33. *        |    exhausting storage in phase1 caused phase2 to fail.
  34. * 12-Mar-86 | Broke off command line parser into adagio.c, only parser remains
  35. * 24-Mar-86 | Changed representation from note_struct to event_struct
  36. *        | Parse M, N, O, X, and Y as control change commands
  37. * 23-May-86 | Added , and ; syntax: "," means "N0\n", ";" means "\n"
  38. * 16-Jul-86 | modify to only call toupper/lower with upper/lower case as
  39. *        |  parameter to be compatible with standard C functions
  40. *  7-Aug-86 | fixed bug with default pitches and rests
  41. *****************************************************************************/
  42.  
  43. #include "cext.h"
  44. #include "stdio.h"
  45. #include "ctype.h"
  46. #include "malloc.h"
  47. #include "adagio.h"
  48. #include "cmdline.h"
  49. #include "phase1.h"
  50.  
  51. extern long space;    /* remaining free bytes */
  52.  
  53. /****************************************************************************
  54. * The following are used to simulate fixed point with the radix point
  55. * 8 bits from the right:
  56. ****************************************************************************/
  57. #define unity 256
  58. #define round(x) (((x)+128)>>8)
  59. #define precise(x) ((x)<<8)
  60.  
  61. #define nullstring(s) (s[0] == 0)
  62.  
  63. /****************************************************************************
  64. * Routines local to this module:
  65. ****************************************************************************/
  66. private         event_type ctrlalloc();
  67. private           void    do_a_rest();
  68. private           void    doabsdur();
  69. private           void    doabspitch();
  70. private           void    docomment();
  71. private           void    doctrl();
  72. private           void    dodur();
  73. private           void    doerror();
  74. private           void    doloud();
  75. private           void    donextdur();
  76. private           void    dopitch();
  77. private           void    doprogram();
  78. private           void    dorate();
  79. private           void    dospecial();
  80. private           void    dotempo();
  81. private           void    dotime();
  82. private           void    dovoice();
  83. private           void    fferror();
  84. private        boolean init();
  85. private           void    ins_event();
  86. private        boolean ins_ctrl();
  87. private        boolean ins_note();
  88. private            int issymbol();
  89. private           void    marker();
  90. private         event_type nalloc();
  91. private           void    parseend();
  92. private           void    parsefield();
  93. private        boolean parsenote();
  94. private           void    reverse();
  95. private            int scan();
  96. private            int scan1();
  97. private            int scanint();
  98.  
  99. /****************************************************************************
  100. * data structures for parser lookup tables
  101. ****************************************************************************/
  102.  
  103. struct durt {    /* duration translation table */
  104.     char symbol;
  105.     long value;
  106. };
  107. struct durt durtable[5] = {
  108.     'W', 240,
  109.     'H', 120,
  110.     'Q', 60,
  111.     'I', 30,
  112.     'S', 15
  113. };
  114.  
  115. struct loudt {    /* loudness translation table */
  116.     char symbol[4];
  117.     int value;
  118. };
  119.  
  120. struct loudt loudtable[] = {
  121.     "PPP", 20,
  122.     "PP\0", 26,
  123.     "P\0\0", 34,
  124.     "MP\0", 44,
  125.     "MF\0", 58,
  126.     "F\0\0", 75,
  127.     "FF\0", 98,
  128.     "FFF", 127
  129. };
  130.  
  131. private char *ssymbols[] = {{"TEMPO"}, {"RATE"}};
  132.             /* this was inside istempo, but */
  133.             /* I moved it here because of a compiler bug */
  134.  
  135. #define sym_tempo 0
  136. #define sym_rate 1
  137. /* number of symbols */
  138. #define sym_n 2
  139.  
  140. #define linesize 100
  141. private char line[linesize];    /* the input line */
  142. private char token[linesize];    /* a token scanned from the input line */
  143.  
  144. private boolean pitch_flag;    /* set when a pitch is indicated */
  145.     /* (if controls changes are given, only allocate a note event if
  146.      *  a pitch was specified -- i.e. when pitch_flag is set)
  147.      */
  148. private boolean rest_flag;    /* set when a rest (R) is found */
  149.     /* this flag is NOT inherited by the next line */
  150.  
  151. private boolean symbolic_dur_flag;
  152.         /* true if last dur was not absolute
  153.          * (if this is set, then the default duration is changed
  154.          *  accordingly when the tempo is changed.)
  155.          */
  156.  
  157. private boolean ctrlflag[nctrl];
  158.         /* true if control change was present
  159.          * ctrlflag[0] true if ANY control change
  160.          * was present
  161.          */
  162. private int ctrlval[nctrl];
  163.         /* the new value of the control */
  164.  
  165. private int last_prog;    /* saved value of program from previous line */
  166.     /* (this is needed to implement the rule that note
  167.      *  events are generated for rests if the program has changed.)
  168.      */
  169.  
  170. /****************************************************************************
  171. *                state variables
  172. * Because each line of an Adagio score inherits properties from the previous
  173. * line, it makes sense to implement the parser as a collection of routines
  174. * that make small changes to some global state.     For example, pitch is a
  175. * global variable.  When the field G4 is encountered, the dopitch routine
  176. * assigns the pitch number for G4 to the variable pitch.  After all fields
  177. * are processed, these variables describe the current note and contain the
  178. * default parameters for the next note as well.
  179. *
  180. * Global variables that are used in this way by the parsing rountines are:
  181. ****************************************************************************/
  182. private int
  183.     linex,    /* index of the next character to be scanned */
  184.     lineno,    /* current line number */
  185.     fieldx,    /* index of the current character within a field */
  186.     pitch,    /* pitch of note */
  187.     loud,    /* loudness of note */
  188.     voice,    /* voice (midi channel) of note */
  189.     program;    /* midi program (timbre control) of note */
  190.  
  191. private boolean ndurp;        /* set when a next (N) is indicated */
  192.     /* (next time defaults to the current time plus duration unless
  193.      *  overridden by a next (N) command whose presence is signalled
  194.      *  by ndurp.)
  195.      */
  196.  
  197. private long
  198.     thetime,    /* the starting time of the note */
  199.     rate,    /* time rate -- scales time and duration, default = 100 */
  200.     ntime,    /* the starting time of the next note */
  201.     dur,    /* the duration of the note */
  202.     tempo,    /* the current tempo */
  203.     start;    /* the reference time (time of last !tempo or !rate cmd) */
  204.  
  205. private int pitchtable[7] = { 57, 59, 48, 50, 52, 53, 55 };
  206.  
  207. extern char score_na[name_length];
  208.  
  209. private int note_count = 0;    /* the number of notes translated */
  210. private int ctrl_count = 0;    /* ditto for control commands */
  211.  
  212. private int debug = false;    /* controls verbose printout */
  213.  
  214. /****************************************************************************
  215. *                ctrlalloc
  216. * Outputs: returns an event_type for representing a control change
  217. *       returns NULL if space is unavailable
  218. * Effect: allocates ctrlsize bytes
  219. * Assumes: space tells how many bytes are available
  220. ****************************************************************************/
  221. private event_type ctrlalloc()
  222. {    
  223.    /* (char *)malloc(); */
  224.     event_type result;
  225.     space -= ctrlsize;
  226.     if (space > 0) {
  227.     result = (event_type ) malloc(ctrlsize);
  228.     if (result == NULL)    /* this should never happen ... */
  229.         printf("Internal error: Out of memory, space = %ld.\n",space);
  230.     } else result = NULL;
  231.     return result;
  232. }
  233.  
  234. /****************************************************************************
  235. *                do_a_rest
  236. * Effect: parses a rest (R) command
  237. ****************************************************************************/
  238.  
  239. private void do_a_rest()
  240. {
  241.     if (fieldx < strlen(token))
  242.     fferror("Nothing expected after rest");
  243.     rest_flag = true;
  244. }
  245.  
  246. /****************************************************************************
  247. *                doabsdur
  248. * Effect: parses an absolute dur (U) command
  249. ****************************************************************************/
  250.  
  251. private void doabsdur()
  252. {
  253.     if (isdigit(token[fieldx])) {
  254.     dur = precise( (long) scanint());
  255.     dur = (dur * 100) / rate;
  256.     if (fieldx < strlen(token)) {
  257.         fieldx = 2;
  258.         fferror("U must be followed by digits only");
  259.     }
  260.     symbolic_dur_flag = false;
  261.     } else fferror("No digit after U");
  262. }
  263.  
  264. /****************************************************************************
  265. *                doabspitch
  266. * Effect: parses an absolute pitch (P) command
  267. ****************************************************************************/
  268.  
  269. private void doabspitch()
  270. {
  271.     if (isdigit (token[fieldx])) {
  272.     pitch = scanint();
  273.     pitch_flag = true;
  274.     if (fieldx < strlen(token))
  275.         fferror("P must be followed by digits only");
  276.     else if (pitch < minpitch) {
  277.         fieldx = 1;
  278.         fferror("Minimum pitch of 12 will be used");
  279.         pitch = minpitch;
  280.     } else if (pitch > maxpitch) {
  281.         fieldx = 1;
  282.         fferror("Maximum pitch of 115 will be used");
  283.         pitch = maxpitch;
  284.     }
  285.     } else fferror("No digits after P");
  286. }
  287.  
  288. /****************************************************************************
  289. *                docomment
  290. * Effect: parses a comment (*) command
  291. ****************************************************************************/
  292.  
  293. private void docomment()
  294. {
  295.     line[linex] = 0; /* force end of line to skip comment line */
  296. }
  297.  
  298. /****************************************************************************
  299. *                doctrl
  300. * Inputs:
  301. *    n: control number
  302. * Effect: parses a control (J, K, M, O, X, or Y) command
  303. ****************************************************************************/
  304.  
  305. private void doctrl(n)
  306.     int n;
  307. {
  308.     ctrlval[n] = scanint();
  309.     if (fieldx < strlen(token) ) {
  310.     fferror("Only digits expected here");
  311.     } else {
  312.     ctrlflag[n] = true;
  313.     ctrlflag[0] = true;    /* ctrlflag[0] set if any flag is set */
  314.     }
  315. }
  316.  
  317. /****************************************************************************
  318. *                dodur
  319. * Effect: parses a duration (S, I, Q, H, or W) command
  320. ****************************************************************************/
  321.  
  322. private void dodur()
  323. {
  324.     int i, dotcnt = 0;
  325.     long dotfactor;
  326.  
  327.     for (i=0; i<=5; i++) {
  328.     if (durtable[i].symbol == token[fieldx-1]) {
  329.         dur = precise(durtable[i].value);
  330.         break;
  331.     }
  332.     }
  333.     if (i == 5) {
  334.     fieldx--;
  335.     fferror("Duration expected: one of W, H, Q, I, or S");
  336.     return;
  337.     }
  338.     while (fieldx < strlen(token)) {
  339.     if (token[fieldx] == 'T') {    /* triplet notation */
  340.         dur = (dur*2) / 3;
  341.         fieldx++;
  342.     } else if (token[fieldx] == '.') {    /* dotted notation */
  343.         dotcnt++;
  344.         fieldx++;
  345.     } else if (isdigit(token[fieldx])) {    /* numbers are multipliers */
  346.         dur = dur * (long) scanint();
  347.     } else {
  348.         fferror("Bad duration");
  349.         fieldx = strlen(token) + 1;
  350.     }
  351.     }
  352.     dotfactor = 1;
  353.     for (i=1; i<=dotcnt; i++)
  354.     dotfactor = dotfactor * 2;
  355.     dur = (2 * dur) - (dur / dotfactor);
  356.     dur = (dur * 100) / tempo;    /* time in centiseconds */
  357.     dur = (dur * 100) / rate;
  358.     symbolic_dur_flag = true;    /* see symbolic_dur_flag declaration */
  359. }
  360.  
  361. /****************************************************************************
  362. *                doerror
  363. * Effect: parse an unrecognized field by reporting an error
  364. ****************************************************************************/
  365.  
  366. private void doerror()
  367. {
  368.     fieldx = 0;
  369.     fferror("Bad field");
  370. }
  371.  
  372. /****************************************************************************
  373. *                doloud
  374. * Effect: parse a loudness (L) command
  375. ****************************************************************************/
  376.  
  377. private void doloud()
  378. {
  379.     int i, j;
  380.  
  381.     if (strlen(token) <= 1) {
  382.     fieldx = 0;
  383.     fferror("L must be followed by loudness indication");
  384.     return;
  385.     }
  386.     if (isdigit(token[fieldx])) {
  387.     loud = scanint();
  388.     if (fieldx < strlen(token))
  389.         fferror("Digits expected after L");
  390.     else if (loud > 127) {
  391.         fieldx = 1;
  392.         fferror("Maximum loudness of 127 will be used");
  393.         loud = 127;
  394.     }
  395.     return;
  396.     }
  397.     if (strlen(token) > 4 ) {    /* maximum is 4, e.g. "Lppp" */
  398.     fieldx = 0;
  399.     fferror("Loudness field too long");
  400.     return;
  401.     }
  402.     if (strlen(token) != 4) {    /* pad short symbols with 0    */
  403.     i = strlen(token);    /* e.g. "p\0" -> "p\0\0"    */
  404.     token[i+1] = '\0';
  405.     }
  406.     
  407.     for (i = 0; i <= 7; i++) {    /* loop through possibilities    */
  408.     for (j = 0; j <= 2; j++) {    /* test 3 characters    */
  409.         if (token[fieldx+j] != loudtable[i].symbol[j])
  410.         break;
  411.     }
  412.     if (j == 3) {
  413.         loud = loudtable[i].value;
  414.         return;
  415.     }
  416.     }
  417.     fieldx = 1;
  418.     fferror("Bad loudness indication");
  419. }
  420.  
  421. /****************************************************************************
  422. *                donextdur
  423. * Effect: parse a next (N) command
  424. * Implementation:
  425. *    The syntax is N followed by a duration, so save dur and use dodur()
  426. *    to parse the duration field.  Then restore dur (what a hack!).
  427. *    The form N<digits> is parsed directly with scanint().
  428. ****************************************************************************/
  429.  
  430. private void donextdur()
  431. {
  432.     long save;    /* save the current duration */
  433.     
  434.     ndurp = true;    /* flag that N was given */
  435.     if (isdigit(token[fieldx])) {
  436.     ntime = precise( (long) scanint());
  437.     if (fieldx < strlen(token))
  438.         fferror("Only digits were expected here");
  439.     } else {
  440.     fieldx++;
  441.     save = dur;    
  442.     dodur();
  443.     ntime = dur;    /* get the result from dur, */
  444.     dur = save;    /* and then restore it    */
  445.     }
  446. }
  447.  
  448. /****************************************************************************
  449. *                dopitch
  450. * Effect: parses a pitch command
  451. ****************************************************************************/
  452.  
  453. private void dopitch()
  454. {
  455.     int p, octave;
  456.     int octflag = false;    /* set if octave is specified */
  457.  
  458.     p = pitchtable[token[0]-'A'];
  459.     while (true) {
  460.     if (token[fieldx] == 'S') {                   /* sharp */
  461.         p++;
  462.         fieldx++;
  463.     } else if (token[fieldx] == 'N') {            /* skip */
  464.         fieldx++;
  465.     } else if (token[fieldx] == 'F') {            /* flat */
  466.         p--;
  467.         fieldx++;
  468.     } else if (isdigit(token[fieldx]) && !octflag) {      /* octave */
  469.         octave = scanint();
  470.         octflag = true;
  471.     } else break;                   /* none of the above */
  472.     }
  473.     if (octflag) p = (p-48) + 12 * octave;  /* adjust p to given octave */
  474.     else {          /* adjust p to note nearest the default pitch */
  475.     int octdiff = (p + 126 - pitch) / 12;
  476.     p = p + 120 - (octdiff * 12);
  477.     }
  478.     if (fieldx != strlen(token))        /* any unparsed characters? */
  479.     fferror("Bad pitch indication");
  480.     if (p > maxpitch) {                     /* pitch in range? */
  481.     fieldx = 1;
  482.     fferror("Pitch too high");
  483.     p = maxpitch;
  484.     }
  485.     pitch = p;
  486.     pitch_flag = true;
  487. }
  488.  
  489. /****************************************************************************
  490. *                doprogram
  491. * Effect: parses a program change (Z) command
  492. ****************************************************************************/
  493.  
  494. private void doprogram()
  495. {
  496.     if (isdigit(token[fieldx])) {
  497.     program = scanint();
  498.     if (fieldx < strlen(token)) {
  499.         fferror("Z must be followed by digits only");
  500.     } else if (program < minprogram) {
  501.         fieldx = 1;
  502.         fferror("Minimum program of 1 will be used");
  503.         program = minprogram;
  504.     } else if (program > maxprogram) {
  505.         fieldx = 1;
  506.         fferror("Maximum program of 128 will be used");
  507.         program = maxprogram;
  508.     }
  509.     } else fferror("No digit after Z");
  510. }
  511.  
  512. /****************************************************************************
  513. *                dorate
  514. * Effect: parses a !rate command
  515. ****************************************************************************/
  516.  
  517. private void dorate()
  518. {
  519.     linex += scan(&line[linex]);
  520.     if (strlen(token) == 0)
  521.     fferror("rate number expected");
  522.     else {
  523.     long oldrate = rate;
  524.     fieldx = 0;
  525.     rate = scanint();
  526.     if (fieldx < strlen(token) )
  527.         fferror("Only digits expected here");
  528.     if (rate == 0) {
  529.         fieldx = 0;
  530.         fferror("Rate 100 will be used here");
  531.         rate = 100;
  532.     }
  533.     start = thetime;
  534.     /* adjust dur in case it is inherited by next note */
  535.         dur = (dur * oldrate);
  536.         dur = dur / rate;
  537.     }
  538. }
  539.  
  540. /****************************************************************************
  541. *                dospecial
  542. * Effect: parses special (those starting with "!") commands
  543. ****************************************************************************/
  544.  
  545. private void dospecial()
  546. {
  547.     switch (issymbol()) {
  548.     case sym_tempo: dotempo();
  549.         break;
  550.     case sym_rate: dorate();
  551.         break;
  552.     default: fferror("Special command expected");
  553.     }
  554.     parseend(); /* flush the rest of the line */
  555. }
  556.  
  557. /****************************************************************************
  558. *                dotempo
  559. * Effect: parses a !tempo command
  560. ****************************************************************************/
  561.  
  562. private void dotempo()
  563. {
  564.     linex += scan(&line[linex]);
  565.     if (strlen(token) == 0)
  566.     fferror("Tempo number expected");
  567.     else {
  568.     long oldtempo = tempo;
  569.     fieldx = 0;
  570.     tempo = scanint();
  571.     if (fieldx < strlen(token))
  572.         fferror("Only digits expected here");
  573.     if (tempo == 0) {
  574.         fieldx = 0;
  575.         fferror("Tempo 100 will be used here");
  576.         tempo = 100;
  577.     }
  578.     start = thetime;
  579.     /* adjust dur in case it is inherited by next note */
  580.     if (symbolic_dur_flag) {
  581.         dur = (dur * oldtempo);
  582.         dur = dur / tempo;
  583.     }
  584.     }
  585. }
  586.  
  587. /****************************************************************************
  588. *                dotime
  589. * Effect: parses a time (T) command
  590. * Implementation: see implementation of donextdur()
  591. ****************************************************************************/
  592.  
  593. private void dotime()
  594. {
  595.     int save;
  596.  
  597.     if (isdigit(token[fieldx])) {
  598.     thetime = precise( (long) scanint());
  599.     if (fieldx < strlen(token) )
  600.         fferror("Only digits were expected here");
  601.     } else {
  602.         fieldx++;
  603.         save = dur; 
  604.         dodur(); 
  605.         thetime = dur;
  606.         dur = save;
  607.     }
  608.     thetime += start;    /* time is relative to start */
  609. }
  610.  
  611. /****************************************************************************
  612. *                dovoice
  613. * Effect: parse a voice (V) command (the voice is the MIDI channel)
  614. ****************************************************************************/
  615.  
  616. private void dovoice()
  617. {
  618.     if (isdigit(token[fieldx])) {
  619.     voice = scanint();
  620.     if (fieldx < strlen(token))
  621.         fferror("V must be followed by digits only");
  622.     if (voice > 16) {
  623.         fferror("number too high, using 16 instead");
  624.         voice = 16;
  625.     } else if (voice < 1) {
  626.         fferror("number too low, using 1 instead");
  627.         voice = 1;
  628.     }
  629.     } else fferror("No digit after V");
  630. }
  631.  
  632. /****************************************************************************
  633. *                fferror
  634. * Inputs:
  635. *    char *s: an error message string
  636. * Effect:
  637. *    prints the line with the error
  638. *    puts a cursor (^) at the error location
  639. *    prints the error message (s)
  640. * Implementation:
  641. *    this routine prints a carat under the character that
  642. *    was copied into token[fieldx].    E.g. if fieldx = 0, the
  643. *    carat will point to the first character in the field.
  644. ****************************************************************************/
  645.  
  646. private void fferror(s)
  647. char *s;
  648. {
  649.     fprintf(stderr, "%3d | ", lineno);
  650.     fprintf(stderr, "%s", line);
  651.     marker(linex-strlen(token)+fieldx+1+6);
  652.     fprintf(stderr, "Error: %s.\n", s);
  653. }
  654.  
  655. /****************************************************************************
  656. *                init
  657. * Outputs:    Returns true if OK, false on error.
  658. * Effect:    Initializes program state.
  659. ****************************************************************************/
  660.  
  661. private boolean init()
  662. {
  663.     int i;
  664.  
  665.     debug = cl_switch("-print");
  666.  
  667.     for (i = 0; i < nctrl; i++) ctrlflag[i] = false;
  668.  
  669.     dur = precise ((long) 60); /* quarter note */
  670.     lineno = 0;
  671.     thetime = 0;
  672.     pitch = 48;
  673.     loud = 127;
  674.     voice = 1;
  675.     last_prog = program = 1;
  676.     tempo = 100;
  677.     rate = 100;
  678.     start = 0;
  679.     symbolic_dur_flag = true; /*scale dur by tempo*/
  680.     return true;
  681. }
  682.  
  683. /****************************************************************************
  684. *                ins_ctrl
  685. * Inputs:
  686. *    event_type *score: a linked list in which to insert
  687. * Outputs:
  688. *    returns true on success, false on error (not enough space)
  689. * Effect: 
  690. *    control events corresponding to current line are inserted in score
  691. * Implementation:
  692. *    ctrlflag[i] is true if control i was specified in this line, so
  693. *    insert one control change for each ctrlflag[i] that is true
  694. ****************************************************************************/
  695.  
  696. private boolean ins_ctrl(score)
  697.     event_type *score;
  698. {
  699.     int i;
  700.     event_type ctrl;
  701.  
  702.     for (i = 1; i < nctrl; i++) {
  703.     if (ctrlflag[i]) {
  704.         ctrlflag[i] = false;
  705.         if ((ctrl = ctrlalloc()) == NULL) {
  706.         return false;
  707.         }
  708.         ctrl->ntime = round(thetime);
  709.         ctrl->nvoice = ctrl_voice(i, voice-1);
  710.         ctrl->nline = lineno;
  711.         ctrl->next = NULL;
  712.         ctrl->u.ctrl.value = ctrlval[i];
  713.         ins_event(score, ctrl);
  714.         ctrl_count ++;
  715.     }
  716.     }
  717.     return true;
  718. }
  719.  
  720. /****************************************************************************
  721. *                ins_event
  722. * Inputs:
  723. *    event_type *p: a linked list in which to insert
  724. *    event_type event: the new event to insert
  725. * Effect: 
  726. *    inserts event into score in reverse time order (this makes inserts
  727. *    that are sequential in time go fast)
  728. ****************************************************************************/
  729.  
  730. private void ins_event(p, event)
  731.     event_type *p;    /* the score */
  732.     event_type event;    /* the new event to insert */
  733. {
  734.     event_type ptr = *p;
  735.     event_type prv;
  736.  
  737.     if (ptr == NULL || event->ntime >= ptr->ntime) {
  738.     event->next = ptr;    /* insert at head of list */
  739.     *p = event;
  740.     } else { /* list insert */
  741.     while (ptr != NULL && event->ntime < ptr->ntime) {
  742.         prv = ptr;
  743.         ptr = ptr->next;
  744.     }
  745.     prv->next = event;
  746.     event->next = ptr;
  747.     }
  748. }
  749.  
  750. /****************************************************************************
  751. *                ins_note
  752. * Inputs:
  753. *    event_type *score: a linked list in which to insert
  754. * Outputs:
  755. *    returns true on success, false on error (not enough space)
  756. * Effect:
  757. *    note event (if any) corresponding to current line are inserted in 
  758. *    score
  759. * Implementation:
  760. *    if a note on should occur after a note off and doesn't, and the
  761. *    two notes have the same pitch, then the note off can cancel the
  762. *    note on:
  763. *        |------------------| <- this cancels *
  764. *               this -> |-----------| 
  765. *    To make it unlikely that roundoff will cause this situation,
  766. *    dur is decreased by one half of a clock tick before rounding.
  767. *    Also, phase2 gives precedence to note-offs that are simultaneous
  768. *    with note-ons.
  769. ****************************************************************************/
  770.  
  771. private boolean ins_note(score)
  772.     event_type *score;
  773. {
  774.     event_type nalloc(), note;
  775.     if ((note = nalloc()) == NULL) {
  776.     return false;
  777.     }
  778.     note->ntime = round(thetime);
  779.     note->nvoice = voice - 1;
  780.     note->nline = lineno;
  781.     note->next = NULL;
  782.     if (rest_flag) note->u.note.npitch = NO_PITCH;    /* a rest */
  783.     else note->u.note.npitch = pitch;
  784.     note->u.note.ndur = round(dur - (unity/2));
  785.     note->u.note.nloud = loud;
  786.     note->u.note.nprogram = program;
  787.     if (debug)
  788.     printf("note: time %ld, dur %ld, pitch %d, voice %d, loudness %d\n",
  789.         note->ntime, note->u.note.ndur, note->u.note.npitch,
  790.         note->nvoice, note->u.note.nloud);
  791.     ins_event(score, note);
  792.     return true;
  793. }
  794.  
  795. /****************************************************************************
  796. *                issymbol
  797. * Outputs: returns symbol number, or -1 if no match
  798. * Assumes: token[1] has the symbol to look up (token[0] == '!')
  799. ****************************************************************************/
  800.  
  801. private int issymbol()
  802. {
  803.     int i, symb_num;
  804.     char *sym;
  805.  
  806.     for (symb_num = 0; symb_num < sym_n; symb_num++) {
  807.     sym = ssymbols[symb_num];
  808.     i = 1;
  809.     while (true) {
  810.         if (token[i] != *sym) break;
  811.         if (*sym == 0) return symb_num;
  812.         sym++; i++;
  813.     }
  814.     }
  815.     return -1;
  816. }
  817.  
  818. /****************************************************************************
  819. *                marker
  820. * Inputs:
  821. *    int count: the number of characters to indent
  822. * Effect: 
  823. *    prints a carat (^) at the position specified on file stderr
  824. ****************************************************************************/
  825.  
  826. private void marker(count)
  827. int count;
  828. {
  829.     int i;
  830.     for (i=1; i<=count-1; i++)
  831.     fprintf (stderr, " ");
  832.     fprintf (stderr, "^\n");
  833. }
  834.  
  835. /****************************************************************************
  836. *                nalloc
  837. * Outputs: returns event_type for an event allocated from heap, NULL on error
  838. * Effect: allocates memory, decreases space accordingly
  839. ****************************************************************************/
  840.  
  841. private event_type nalloc()
  842. {    
  843.    /* (char *)malloc(); */
  844.     event_type result;
  845.     space -= sizeof(struct event_struct);
  846.     if (space > 0) {
  847.     result = ((event_type ) malloc (sizeof(struct event_struct)));
  848.     if (result == NULL)
  849.         printf("Internal error: Out of memory, space = %ld.\n",space);
  850.     } else result = NULL;
  851.     return result;
  852. }
  853.  
  854. /*****************************************************************
  855. *            parseend
  856. * Effect:
  857. *    parse the note terminator, either ",", ";", or "\n"
  858. *
  859. ****************************************************************/
  860.  
  861. private void parseend()
  862. {
  863.     linex += scan1(&line[linex]);
  864.     switch (token[0]) {
  865.     case ',':
  866.         ndurp = true;    /* switch that next time was specified */
  867.         ntime = 0;
  868.         break;
  869.     case ';':
  870.     case '\n':
  871.         break;
  872.     default:
  873.         fferror("Internal error: illegal separator?");
  874.         break;
  875.     }
  876. }
  877.  
  878. /****************************************************************************
  879. *                parsefield
  880. * Effect: looks at first character of token and calls a parsing routine
  881. *
  882. ****************************************************************************/
  883.  
  884. private void parsefield()
  885. {
  886.     fieldx = 1;
  887.     switch (token[0]) {
  888.     case 'T' : dotime(); break;
  889.     case 'W': 
  890.     case 'H':
  891.     case 'Q':
  892.     case 'S':
  893.     case 'I': dodur()  ; break;
  894.     case 'R': do_a_rest(); break;
  895.     case 'A':
  896.     case 'B':
  897.     case 'C':
  898.     case 'D':
  899.     case 'E':
  900.     case 'F':
  901.     case 'G': dopitch(); break;
  902.     case 'P': doabspitch (); break;
  903.     case 'U': doabsdur(); break;
  904.     case 'L': doloud(); break;
  905.     case 'N': donextdur(); break;
  906.     case 'J': doctrl(1); break;
  907.     case 'K': doctrl(2); break;
  908.     case 'M': doctrl(3); break;
  909.     case 'O': doctrl(4); break;
  910.     case 'X': doctrl(5); break;
  911.     case 'Y': doctrl(6); break;
  912.     case 'V': dovoice(); break;
  913.     case 'Z': doprogram(); break;
  914.     default : doerror(); break;
  915.     }
  916. }
  917.  
  918. /****************************************************************************
  919. *                parsenote
  920. * Inputs:
  921. *    event_type *scoreptr: pointer to the note list
  922. * Effect: 
  923. *    parses a note line -- control events (if any) and note event (if
  924. *    present) are inserted into *scoreptr
  925. * Assumes:
  926. *    line contains a string to be parsed
  927. ****************************************************************************/
  928.  
  929. private boolean parsenote(scoreptr)
  930.     event_type *scoreptr;    /* the translated note list */
  931. {
  932.     boolean out_of_memory = false;
  933.  
  934.     ndurp = false;
  935.     rest_flag = false;
  936.  
  937.     /* this loop reads tokens for a note */
  938.     while (strlen(token) > 0) {
  939.     parsefield();
  940.     linex += scan(&line[linex]);
  941.     }
  942.  
  943.     parseend(); /* take care of note terminator */
  944.  
  945.     /* insert a note if
  946.      *    (1) a pitch was specified OR
  947.      *    (2) no control was specified and this is not a rest 
  948.      *        (it's a pitch by default) OR
  949.      *    (3) there is a program change (even if this is a rest)
  950.      *
  951.      * NOTE: program changes during rests are advised since
  952.      *    synthesizers may not be able to process a program
  953.      *    change followed immediately by a note-on.  In fact, this
  954.      *    is why we insert notes whose pitch is NO_PITCH -- so that
  955.      *    the program change can be processed during the rest.
  956.      */
  957.     if (pitch_flag ||
  958.     (!ctrlflag[0] && !rest_flag) ||
  959.     (program != last_prog)) {
  960.     out_of_memory = !ins_note(scoreptr);
  961.     note_count ++;
  962.     }
  963.     /*
  964.      * insert ctrl's last so that when the score is reversed,
  965.      * they will be first.
  966.      */
  967.     if (ctrlflag[0]) {
  968.     out_of_memory |= !ins_ctrl(scoreptr);
  969.     ctrlflag[0] = false;
  970.     }
  971.     last_prog = program;
  972.  
  973.     if (ndurp) thetime += ntime;
  974.     else thetime += dur;
  975.  
  976.     return out_of_memory;
  977. }
  978.  
  979. /****************************************************************************
  980. *                phase1
  981. * Inputs:
  982. *    FILE *fp: input file
  983. * Outputs:
  984. *    returns event_type: the parsed score
  985. * Effect: 
  986. *    parses score from input file and builds score data structure
  987. ****************************************************************************/
  988.  
  989. event_type phase1(fp)
  990. FILE *fp;
  991. {
  992.     event_type score = NULL;    /* the translated note list */
  993.     boolean out_of_memory = false;    /* set when no more memory */
  994.  
  995.     if (!init()) {  /* something bad happened in init(), STOP */
  996.     fprintf(stderr,"WOOPS; something strange happened in INIT()!  ...exiting\n");
  997.     exit(1);
  998.     return NULL;    /* make lint happy */
  999.     }
  1000.  
  1001.     lineno = 0;
  1002.  
  1003.     /* this loop reads lines */
  1004.     while ((fgets(line, linesize, fp) != NULL) && !out_of_memory) {
  1005.     lineno++;
  1006.     linex = 0;
  1007.     /* this loop reads notes from a line */
  1008.     while ((line[linex] != 0) && !out_of_memory) {
  1009.         /* loop invariant: line[linex] is first char of next note */
  1010.         pitch_flag = false;
  1011.         linex += scan(&line[linex]);
  1012.         if (!nullstring(token)) {
  1013.         if (token[0] == '*') docomment();
  1014.         else if (token[0] == '!') dospecial();
  1015.         else out_of_memory = parsenote(&score);
  1016.         } else parseend();
  1017.     }
  1018.     }
  1019.  
  1020.     fprintf (stderr,"\n");
  1021.  
  1022.     if (out_of_memory) {
  1023.     fprintf(stderr,"Out of note memory at line %d,\n", lineno-1);
  1024.     fprintf(stderr,"    the rest of your file will be ignored.\n");
  1025.     }
  1026.  
  1027.     printf (
  1028.     "\nPhase 1 completed; %d note(s), %d ctrl(s) have been translated.\n",
  1029.     note_count, ctrl_count);
  1030.  
  1031.     reverse(&score);
  1032.     return score;
  1033. }
  1034.  
  1035. /****************************************************************************
  1036. *                reverse
  1037. * Inputs:
  1038. *    event_type *p: pointer to a list of notes and control events
  1039. * Effect: reverses note and control events in p
  1040. ****************************************************************************/
  1041.  
  1042. private void reverse(p)
  1043. event_type *p;
  1044. {
  1045.     event_type p1, p2, p3;
  1046.     p1 = *p;
  1047.     if (p1 == NULL) return;
  1048.     p2 = p1->next;
  1049.     p1->next = NULL;
  1050.     while (p2 != NULL) {
  1051.     p3 = p2->next;
  1052.     p2->next = p1;
  1053.     p1 = p2;
  1054.     p2 = p3;
  1055.     }
  1056.     *p = p1;
  1057. }
  1058.  
  1059. /****************************************************************************
  1060. *                scan
  1061. * Inputs:
  1062. *    char *start: the string to scan
  1063. * Outputs:
  1064. *    returns int: the index of the next char in start to scan
  1065. * Effect: 
  1066. *    skips over leading blanks
  1067. *    copies characters from start into token, converting to upper case
  1068. *    scanning stops on delimiter: one of space, tab, newline, semicolon
  1069. ****************************************************************************/
  1070.  
  1071. private int scan(start)
  1072. char *start;
  1073. {
  1074.     int i = 0;
  1075.     int j = 0;
  1076.     char c;
  1077.  
  1078.     while ((start[i] == ' ')||(start[i] == '\t')) i++;
  1079.  
  1080.     while ((c = start[i]) != ' ' && c != '\t' && c != '\n' &&
  1081.        c != ',' && c != ';') {
  1082.     if (islower(start[i])) token[j] = toupper(start[i]);
  1083.     else token[j] = start[i];
  1084.     j++; i++;
  1085.     }
  1086.     token[j] = '\0';
  1087.     return i;
  1088. }
  1089.  
  1090. /****************************************************************************
  1091. *                scan1
  1092. * Inputs:
  1093. *    char *start: the string to scan
  1094. * Outputs:
  1095. *    returns int: the index of the next char in start to scan
  1096. * Effect: 
  1097. *    copies one char from start into token, converting to upper case
  1098. ****************************************************************************/
  1099.  
  1100. private int scan1(start)
  1101. char *start;
  1102. {
  1103.     int i = 0;
  1104.  
  1105.     token[0] = *start;
  1106.     if (islower(token[0])) token[0] = toupper(token[0]);
  1107.     
  1108.     if (!nullstring(token)) {
  1109.     token[1] = '\0';
  1110.     i = 1;
  1111.     }
  1112.     return i;
  1113. }
  1114.  
  1115. /****************************************************************************
  1116. *                scanint
  1117. * Outputs:
  1118. *    returns int: the scanned integer
  1119. * Effect:
  1120. *    scans an unsigned integer from token, starting at fieldx
  1121. *    fieldx is incremented to end of the integer
  1122. ****************************************************************************/
  1123.  
  1124. private int scanint()
  1125. {
  1126.     int i = 0;
  1127.     char c;
  1128.     while (fieldx < strlen(token)) {
  1129.     c = token[fieldx];
  1130.     if ((c >= '0') && (c<= '9')) {
  1131.         i = (i*10) + (c - '0');
  1132.         fieldx++;
  1133.     } else return i;
  1134.     }
  1135.     return i;
  1136. }
  1137.