1 /*
2     scot.c:
3 
4     Copyright (C) 1991 Alan deLespinasse
5 
6     This file is part of Csound.
7 
8     The Csound Library is free software; you can redistribute it
9     and/or modify it under the terms of the GNU Lesser General Public
10     License as published by the Free Software Foundation; either
11     version 2.1 of the License, or (at your option) any later version.
12 
13     Csound is distributed in the hope that it will be useful,
14     but WITHOUT ANY WARRANTY; without even the implied warranty of
15     MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
16     GNU Lesser General Public License for more details.
17 
18     You should have received a copy of the GNU Lesser General Public
19     License along with Csound; if not, write to the Free Software
20     Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA
21     02110-1301 USA
22 */
23 
24 /*                                                      SCOT.C       */
25 /* aldel Jul 91 */
26 
27 #include "scot.h"
28 
29 #define Str(x)  (x)
30 #if defined(HAVE_GCC3)
31 #  define UNLIKELY(x)   __builtin_expect(!!(x),0)
32 #else
33 #  define UNLIKELY(x)   x
34 #endif
35 
36 static  char    curline[MAXLINE + 1];   /* current line of infile */
37 static  int     inx,                    /* column # */
38                 iny,                    /* line # */
39                 errcount;               /* errors so far */
40 static  FILE   *infile, *outfile;
41 static  char   *infilename;
42 
43 static  int     naturals[PITCHCLASSES] = { 0, 2, 4, 5, 7, 9, 11 };
44 
45 static  Macro   *gmac;                  /* global macro list */
46 
47 /* main externally-visible procedure */
48 
scot(FILE * inf,FILE * outf,char * fil)49 int scot(FILE *inf, FILE *outf, char *fil)
50 {
51     char    s[128];
52     Inst   *insttop, *ip;
53 
54     initf(inf, outf, fil);
55     if (findword(s) || strcmp(s, "orchestra"))
56       scotferror(Str("Score must start with orchestra section"));
57     readorch(&insttop);
58     for (;;) {
59       if (findword(s))
60         break;
61       if (!strcmp(s, "functions"))
62         readfunctions();
63       else if (!strcmp(s, "score"))
64         readscore(insttop);
65       else
66         scotferror(Str("Expected score or functions section"));
67     }
68     fputs("e\n", outfile);
69     while (insttop) {
70       ip = insttop;
71       insttop = insttop->next;
72       free(ip->name);
73       free((char *) ip);
74     }
75     if (errcount)
76       reporterrcount();
77     return errcount;
78 }
79 
80 static                          /* reads from one $instrument to the next */
readinstsec(Inst * inst,Nextp ** nextlist,Rat * grpmul,Rat * timesig,Rat * curtime,Rat * lastbar,Rat * lastnote,Note ** notetop,Note ** ln,Tempo ** tempop,int * accidentals,int * octaves,int * vertical,int * key,int * barkey,int * transpose,char * endchar)81 void readinstsec(Inst *inst,
82                  Nextp **nextlist,
83                  Rat *grpmul,
84                  Rat *timesig,
85                  Rat *curtime,
86                  Rat *lastbar,
87                  Rat *lastnote,
88                  Note **notetop,
89                  Note **ln,
90                  Tempo **tempop,
91                  int *accidentals,
92                  int *octaves,
93                  int *vertical,
94                  int *key, int *barkey, int *transpose, char *endchar)
95 {
96     static Rat durdiv = { 4L, 1L };
97 
98     int     c, z, lastpitchclass;
99     char    s[128], *sp;
100     Rat     ratstack, rattmp;
101     Note   *pn, *nn, *pn2 = NULL;
102     Strlist *ps;
103     Nextp  *nextpp;
104 
105 #ifdef DEBUG
106     printf("Reading instrument section: %s\n", inst->name);
107 #endif
108 
109     pn = (*notetop);
110     for (;;) {
111       findchar(&c);
112       if (strchr(endchar, c))
113         break;
114 
115 #ifdef DEBUG
116       printf("Processing char: %c\n", c);
117 #endif
118 
119       switch (c) {
120       case 't':
121         if (findint(&c)) {
122           scoterror(Str("Tempo must be specified"));
123           break;
124         }
125         if ((*tempop)->next) {
126           scoterror(Str("Redefinition of tempo"));
127           break;
128         }
129         (*tempop)->next = (Tempo *) malloc(sizeof(Tempo));
130         *tempop = (*tempop)->next;
131         (*tempop)->next = NULL;
132         ratass(&((*tempop)->time), curtime);
133         (*tempop)->val = c;
134         break;
135       case '!':
136         efindword(s);
137         if ((c = strlen(s)) < 2)
138           scoterror(Str("Must specify 2 or more letters of keyword"));
139         if (!strncmp(s, "accidentals", c)) {
140           if (findonoff(accidentals))
141             scoterror(Str("Must be \"on\" or \"off\""));
142 
143 #ifdef DEBUG
144           printf(" accidentals %s\n", accidentals ? "on" : "off");
145 #endif
146 
147         }
148         else if (!strncmp(s, "octaves", c)) {
149           if (findonoff(octaves))
150             scoterror(Str("Must be \"on\" or \"off\""));
151 
152 #ifdef DEBUG
153           printf(" ocatves %s\n", *octaves ? "on" : "off");
154 #endif
155 
156         }
157         else if (!strncmp(s, "vertical", c)) {
158           if (findonoff(vertical))
159             scoterror(Str("Must be \"on\" or \"off\""));
160 
161 #ifdef DEBUG
162           printf(" vertical %s\n", *vertical ? "on" : "off");
163 #endif
164 
165         }
166         else if (!strncmp(s, "timesignature", c)) {
167           efindword(s);
168 
169           if ((sscanf(s, "%lu/%lu", &timesig->num, &timesig->denom) != 2)
170               ||
171               (&(timesig->denom) == 0) ) {
172             scoterror(Str("Invalid time signature"));
173             timesig->num = 0;
174             timesig->denom = 1;
175           }
176 
177 #ifdef DEBUG
178           printf(" time sig=%lu/%lu\n", timesig->num, timesig->denom);
179 #endif
180 
181           ratstack.num = 4;
182           ratstack.denom = 1;
183           ratmul(timesig, timesig, &ratstack);
184 
185 #ifdef DEBUG
186           printf(" measure length=%f\n", ratval(timesig));
187 #endif
188 
189         }
190         else if (!strncmp(s, "key", c)) {
191           int     y;
192 
193           efindword(s);
194           for (z = 0; z < PITCHCLASSES; z++)
195             key[z] = 0;
196           c = y = 0;
197           for (z = 0; s[z] != (char) 0; z++)
198             switch ((int) s[z]) {
199             case '#':
200               c = y + 1;
201               y++;
202               break;
203             case '-':
204               c = y - 1;
205               y--;
206               break;
207             default:
208               if (!isalpha(s[z]))
209                 scoterror(Str("Bad key signature"));
210               key[letterval((int) s[z])] = c;
211               y = 0;
212             }
213           for (z = 0; z < PITCHCLASSES; z++)
214             barkey[z] = key[z];
215         }
216         else if (!strncmp(s, "transpose", c)) {
217           efindword(s);
218           *transpose = 0;
219           for (z = 0; s[z]; z++) {
220             switch (s[z]) {
221             case ',':
222               (*transpose) -= NOTESPEROCT;
223               break;
224             case '\'':
225               (*transpose) += NOTESPEROCT;
226               break;
227             case '=':
228               (*transpose) = 0;
229               break;
230             case '#':
231               (*transpose)++;
232               break;
233             case '-':
234               (*transpose)--;
235               break;
236             default:
237               (*transpose) += naturals[letterval((int) s[z])];
238             }
239           }
240         }
241         else if (!strncmp(s, "next", c)) {
242           efindword(s);
243           if (sscanf(s, "p%d", &c) != 1) {
244             scoterror(Str("Invalid field"));
245             efindword(s);
246             break;
247           }
248           efindword(s);
249           if (sscanf(s, "p%d", &z) != 1) {
250             scoterror(Str("Invalid field"));
251             break;
252           }
253           if (*nextlist == NULL) {
254             *nextlist = (Nextp *) malloc(sizeof(Nextp));
255             nextpp = (*nextlist);
256             nextpp->next = NULL;
257           }
258           else {
259             nextpp = (*nextlist);
260             if ((c == nextpp->dst) || (z == nextpp->src))
261               scoterror(Str("Nested next-parameter passing"));
262             while (nextpp->next) {
263               nextpp = nextpp->next;
264               if ((c == nextpp->dst) || (z == nextpp->src))
265                 scoterror(Str("Nested next-parameter passing"));
266             }
267             nextpp->next = (Nextp *) malloc(sizeof(Nextp));
268             nextpp = nextpp->next;
269             nextpp->next = NULL;
270           }
271           nextpp->src = c;
272           nextpp->dst = z;
273         }
274         else
275           scoterror(Str("Unrecognised keyword"));
276         break;
277       case '{':
278         findint(&c);
279         expectchar(':');
280         if (!c) {
281           ratstack.num = 2L;
282           ratstack.denom = 3L;
283         }
284         else {
285           ratstack.denom = (unsigned long) c;
286           findint(&c);
287           if (!c) {
288             for (z = 1; (unsigned long) z < ratstack.denom; z *= 2);
289             z /= 2;
290             ratstack.num = (unsigned long) z;
291           }
292           else
293             ratstack.num = (unsigned long) c;
294           expectchar(':');
295         }
296         ratmul(grpmul, grpmul, &ratstack);
297         readinstsec(inst, nextlist, grpmul, timesig, curtime,
298                     lastbar, lastnote, notetop, ln, tempop, accidentals,
299                     octaves, vertical, key, barkey, transpose, ":");
300         ratdiv(grpmul, grpmul, &ratstack);
301         expectchar(':');
302         expectchar('}');
303         break;
304       case '(':
305         ratass(&ratstack, curtime);
306         if (pn == (*notetop)) {
307           readinstsec(inst, nextlist, grpmul, timesig, curtime,
308                       lastbar, lastnote, notetop, ln, tempop, accidentals,
309                       octaves, vertical, key, barkey, transpose, ")");
310           pn = (*notetop);
311         }
312         else {
313           readinstsec(inst, nextlist, grpmul, timesig, curtime,
314                       lastbar, lastnote, &pn2->next, ln, tempop, accidentals,
315                       octaves, vertical, key, barkey, transpose, ")");
316           pn = pn2->next;
317         }
318         expectchar(')');
319         ratass(lastnote, &ratstack);
320         break;
321       case '/':
322         ratadd(lastbar, lastbar, timesig);
323         if ((timesig->num) && (ratcmp(lastbar, curtime))) {
324           scoterror(Str("Wrong number of beats in bar"));
325           ratass(lastbar, curtime);
326         }
327         for (z = 0; z < PITCHCLASSES; z++)
328           barkey[z] = key[z];
329         break;
330       case '<':
331         if (pn == NULL) {
332           scoterror(Str("Syntax error: cannot back up"));
333           break;
334         }
335         if (pn->next == NULL) {
336           pn->next = (Note *) malloc(sizeof(Note));
337           initnote(pn->next);
338           pn->next->instrum = pn->instrum + 0.01;
339         }
340         pn2 = pn;
341         pn = pn->next;
342         ratass(curtime, lastnote);
343         break;
344       default:
345 
346 #ifdef DEBUG
347         printf("Reading note\n");
348         printf(" time=%lu/%lu\n", curtime->num, curtime->denom);
349         printf(" =%f\n", ratval(curtime));
350 #endif
351 
352         scotungetc();
353         nn = (Note *) malloc(sizeof(Note));
354         nn->p = NULL;
355         nn->written = FALSE;
356         if (*notetop == NULL) {
357           pn = (*ln) = (*notetop) = (Note *) malloc(sizeof(Note));
358           initnote(*notetop);
359           (*notetop)->instrum = (double) inst->number + 0.01;
360         }
361         else if (ratcmp(curtime, lastnote))
362           pn = (*notetop);
363         nn->instrum = pn->instrum;
364 
365 #ifdef DEBUG
366         printf(" instrument #%f\n", nn->instrum);
367 #endif
368 
369         if (*vertical)
370           strlistcopy(&nn->carryp, &(*ln)->carryp);
371         else
372           strlistcopy(&nn->carryp, &pn->carryp);
373         for (nextpp = (*nextlist); nextpp; nextpp = nextpp->next) {
374           sp = findparam(nextpp->dst, &nn->carryp);
375           if (!strcmp(sp, "."))
376             strcpy(sp, NEXTP);
377         }
378         ratass(&nn->start, curtime);
379         if (!findint(&c)) {
380           ratstack.num = (unsigned long) c;
381           ratstack.denom = 1L;
382           ratdiv(&nn->dur, &durdiv, &ratstack);
383           ratass(&ratstack, &nn->dur);
384           rattmp.num = 1L;
385           rattmp.denom = 2L;
386           for (;;) {
387             findchar(&c);
388             if (c != '.')
389               break;
390             ratmul(&ratstack, &ratstack, &rattmp);
391             ratadd(&nn->dur, &nn->dur, &ratstack);
392           }
393         }
394         else {
395           if (*vertical)
396             ratass(&nn->dur, &((*ln)->lastdur));
397           else
398             ratass(&nn->dur, &pn->lastdur);
399           findchar(&c);
400         }
401         ratass(&nn->lastdur, &nn->dur);
402         ratmul(&nn->dur, &nn->dur, grpmul);
403 
404 #ifdef DEBUG
405         printf(" duration=%f\n", ratval(&nn->dur));
406         printf(" c=%c\n", c);
407 #endif
408 
409         if (c == '=') {
410           nn->octave = 8;
411           lastpitchclass = 0;
412         }
413         else {
414           nn->octave = pn->octave;
415           lastpitchclass = pn->pitchclass;
416           scotungetc();
417         }
418         for (;;) {
419           findchar(&c);
420           if (c == '\'')
421             nn->octave++;
422           else if (c == ',')
423             nn->octave--;
424           else
425             break;
426         }
427         if (c == 'r') {
428           ratass(lastnote, curtime);
429           ratmul(&rattmp, &nn->lastdur, grpmul);
430           ratadd(curtime, curtime, &rattmp);
431           ratass(&(*ln)->lastdur, &nn->lastdur);
432           ratass(&pn->lastdur, &nn->lastdur);
433           freenote(nn);
434           break;
435         }
436         else {
437           nn->pitchclass = letterval(c);
438           if (*octaves) {
439             c = nn->pitchclass - lastpitchclass;
440             if (c < -(PITCHCLASSES / 2))
441               nn->octave++;
442             else if (c > PITCHCLASSES / 2)
443               nn->octave--;
444           }
445         }
446         nn->accid = 0;
447         nn->accmod = FALSE;
448         for (;;) {
449           findchar(&c);
450           if (c == '#') {
451             nn->accid++;
452             nn->accmod = TRUE;
453           }
454           else if (c == '-') {
455             nn->accid--;
456             nn->accmod = TRUE;
457           }
458           else if (c == 'n') {
459             nn->accid = 0;
460             nn->accmod = TRUE;
461           }
462           else
463             break;
464         }
465         if (!nn->accmod)
466           nn->accid = barkey[nn->pitchclass];
467         else if (*accidentals)
468           barkey[nn->pitchclass] = nn->accid;
469 
470 #ifdef DEBUG
471         printf(" transpose=%d\n", *transpose);
472         printf(" octave=%d pitchclass=%d accid=%d transpose=%d pitch=%f\n",
473                nn->octave, nn->pitchclass, nn->accid, *transpose,
474                pitchval(nn->octave, nn->pitchclass, nn->accid, *transpose));
475 #endif
476 
477         if (c == '_') {
478           findchar(&c);
479           if (c == '_') {
480             nn->tie = TRUE;
481             nn->slur = 0;
482             findchar(&c);
483           }
484           else {
485             nn->slur = 1;
486             nn->tie = FALSE;
487           }
488         }
489         else {
490           nn->slur = 0;
491           nn->tie = FALSE;
492         }
493         if (pn->slur & 1)
494           nn->slur += 2;
495 
496 #ifdef DEBUG
497         printf(" slur=%d tie=%d\n", nn->slur, nn->tie);
498 #endif
499 
500         if (pn->tie) {
501           ratadd(&rattmp, &pn->start, &pn->dur);
502           if (ratcmp(&rattmp, curtime))
503             scoterror(Str("Improper tie"));
504           if (((nn->octave != pn->octave) ||
505                (nn->pitchclass != pn->pitchclass) ||
506                ((nn->accid != pn->accid) && (nn->accmod))) &&
507               (pitchval(nn->octave, nn->pitchclass, nn->accid, *transpose) !=
508                pitchval(pn->octave, pn->pitchclass, pn->accid, *transpose)))
509             scoterror(Str("Tie between different pitches"));
510           ratadd(&pn->dur, &pn->dur, &nn->dur);
511           ratass(&pn->lastdur, &nn->lastdur);
512           pn->slur += nn->slur;
513           pn->tie = nn->tie;
514           freenote(nn);
515           nn = pn;
516           if (c == (char) '[')
517             scoterror(Str("Warning: params changed on tie"));
518         }
519         else {
520           ps = nn->p = (Strlist *) malloc(sizeof(Strlist));
521           for (z = 0; z < 4; z++) {
522             ps->next = (Strlist *) malloc(sizeof(Strlist));
523             ps = ps->next;
524           }
525           ps->next = NULL;
526         }
527         ps = nn->p;
528         sprintf(ps->str, "%.02f", nn->instrum);
529         ps = ps->next;
530         sprintf(ps->str, "%g", ratval(&nn->start));
531         ps = ps->next;
532         sprintf(ps->str, "%g", ratval(&nn->dur));
533         ps = ps->next;
534         sprintf(ps->str, "%d", nn->slur);
535         ps = ps->next;
536         sprintf(ps->str, "%.02f",
537                 pitchval(nn->octave, nn->pitchclass, nn->accid, *transpose));
538         if (c == '[') {
539           char   *pars;
540           int     pnum;
541 
542           pars = readparams(inst);
543 
544 #ifdef DEBUG
545           printf("Params: %s\n", pars);
546 #endif
547 
548           z = 0;
549           pnum = 6;
550           while (strchr(" \t\r\n", (int) pars[z]))
551             z++;
552           for (;;) {
553             if (pars[z] == (char) ']')
554               break;
555             c = 0;
556             while (!strchr(" \t\r\n:]", (int) pars[z]))
557               s[c++] = pars[z++];
558             s[c] = (char) 0;
559 
560 #ifdef DEBUG
561             printf("Read: %s\n", s);
562 #endif
563 
564             while (strchr(" \t\r\n", (int) pars[z]))
565               z++;
566             if (pars[z] == (char) ':') {
567               pnum = atoi(s);
568               if (pnum < 6)
569                 scoterror(Str("Parameter number out of range"));
570               z++;
571               while (strchr(" \t\r\n", (int) pars[z]))
572                 z++;
573               continue;
574             }
575 
576 #ifdef DEBUG
577             printf("Param #%d: %s\n", pnum, s);
578 #endif
579 
580             if (s[0] == (char) '\'') {
581               addparam(pnum, &s[1], &nn->p);
582               addparam(pnum, ".", &nn->carryp);
583             }
584             else {
585               addparam(pnum, s, &nn->p);
586               addparam(pnum, s, &nn->carryp);
587             }
588             pnum++;
589           }
590           free(pars);
591         }
592         else
593           scotungetc();
594         if ((nn != pn) && (!pn->written)) {
595 
596 #ifdef DEBUG
597           printf("  doing nextp stuff:\n");
598 #endif
599 
600           for (nextpp = (*nextlist); nextpp; nextpp = nextpp->next) {
601 
602 #ifdef DEBUG
603             printf("   carrying p%d to p%d?\n", nextpp->src, nextpp->dst);
604 #endif
605 
606             if (!strcmp(findparam(nextpp->dst, &pn->carryp), NEXTP)) {
607               sp = findparam(nextpp->dst, &pn->p);
608               if (!strcmp(sp, ".")) {
609                 char   *sp2;
610 
611                 sp2 = findparam(nextpp->src, &nn->p);
612                 if (!strcmp(sp2, "."))
613                   sp2 = findparam(nextpp->src, &nn->carryp);
614                 strcpy(sp, sp2);
615 
616 #ifdef DEBUG
617                 printf("   Yes.\n");
618 #endif
619 
620               }
621             }
622           }
623           writenote(pn);
624         }
625         if ((!(*nextlist)) && (!nn->tie))
626           writenote(nn);
627         if (nn != pn) {
628           if (!pn->written)
629             scoterror(Str("Lost previous note: not written"));
630 
631 #ifdef DEBUG
632           if (pn->next == nn)
633             printf("* pn->next==nn\n");
634 #endif
635 
636           nn->next = pn->next;
637 
638 #ifdef DEBUG
639           if (pn2 == nn)
640             printf("* pn2==nn\n");
641 #endif
642 
643           if (pn == *notetop)
644             *notetop = nn;
645           else
646             pn2->next = nn;
647           freenote(pn);
648           pn = nn;
649 
650 #ifdef DEBUG
651           if (nn->next == nn)
652             printf("* Circular list created\n");
653 #endif
654 
655         }
656 
657 #ifdef DEBUG
658         printf(" nn linked into note list\n");
659         printf(" curtime=%lu/%lu\n", curtime->num, curtime->denom);
660         printf(" nn->dur=%lu/%lu\n", nn->dur.num, nn->dur.denom);
661 #endif
662 
663         *ln = nn;
664         ratass(lastnote, curtime);
665         ratmul(&rattmp, &nn->lastdur, grpmul);
666         ratadd(curtime, curtime, &rattmp);
667 
668 #ifdef DEBUG
669         printf(" curtime=%lu/%lu\n", curtime->num, curtime->denom);
670         printf(" Done with note\n");
671 #endif
672 
673       }
674     }
675     scotungetc();
676 }
677 
678 static                          /* puts parameter in plist */
addparam(int n,char * s,Strlist ** ptop)679 void addparam(int n,            /* number of param to change */
680               char *s,          /* parameter */
681               Strlist **ptop)
682 {                               /* top of list */
683     char   *ps;
684 
685     ps = findparam(n, ptop);
686     if (strcmp(s, "."))
687       strncpy(ps, s, 31);
688 }
689 
690 static                          /* returns pointer to */
findparam(int n,Strlist ** ptop)691 char   *findparam(int n,        /* nth parameter */
692                   Strlist **ptop)
693 {                               /* in plist */
694     int     z;
695     Strlist *p;
696 
697     if (!(*ptop)) {
698       *ptop = (Strlist *) malloc(sizeof(Strlist));
699       (*ptop)->next = NULL;
700       strcpy((*ptop)->str, ".");
701     }
702     p = (*ptop);
703     for (z = 1; z < n; z++) {
704       if (!p->next) {
705         p->next = (Strlist *) malloc(sizeof(Strlist));
706         p = p->next;
707         p->next = NULL;
708         strcpy(p->str, ".");
709       }
710       else
711         p = p->next;
712     }
713     return p->str;
714 }
715 
716 static                          /* reads parameter list and */
readparams(Inst * n)717 char   *readparams(Inst *n)
718 {                               /* substitutes macros for local macro list */
719     char   *s;
720     int     z;
721 
722     s = (char *) malloc(300);
723     z = 0;
724     for (;;) {
725       if ((s[z] = (char) getccom()) == (char) ']')
726         break;
727       z++;
728     }
729     s[z + 1] = (char) 0;
730     while (applymacs(&s, n));
731     return s;
732 }
733 
734 static                          /* substitutes 1 or 0 macros in s */
applymacs(char ** s,Inst * n)735 int applymacs(char **s, Inst *n)
736 {                               /* returns TRUE if substituted */
737     char   *news, *mv;
738     int     sz, nz;
739 
740 #ifdef DEBUG
741     printf(" Applying macros to %s\n", *s);
742 #endif
743 
744     news = (char *) malloc(300);
745     nz = (-1);
746     for (sz = 0; (*s)[sz]; sz++) {
747       if (sz >= 300) {
748         scoterror(Str("Macro expansion too long -- circular macros?"));
749         free(news);
750         return FALSE;
751       }
752       news[sz] = (*s)[sz];
753       if (isalpha((int) (*s)[sz])) {
754         if (nz == (-1))
755           nz = sz;
756       }
757       else if (nz != (-1)) {
758         news[sz] = (char) 0;
759         mv = macval(&news[nz], n);
760         if (mv) {
761           strcpy(&news[nz], mv);
762           strcat(news, &(*s)[sz]);
763           free(*s);
764           *s = news;
765           return TRUE;
766         }
767         nz = (-1);
768       }
769     }
770     free(news);
771     return FALSE;
772 }
773 
774 static                          /* returns value of macro */
macval(char * s,Inst * n)775 char   *macval(char *s, Inst *n)
776 {
777     Macro  *p;
778 
779     for (p = n->lmac; p; p = p->next)
780       if (!strcmp(s, p->name))
781         return p->text;
782     for (p = gmac; p; p = p->next)
783       if (!strcmp(s, p->name))
784         return p->text;
785     return NULL;
786 }
787 
initnote(Note * pn)788 static void initnote(Note *pn)
789 {
790     pn->next = NULL;
791     pn->p = pn->carryp = NULL;
792     pn->start.num = 0L;
793     pn->start.denom = 1L;
794     pn->dur.num = 1L;
795     pn->dur.denom = 1L;
796     pn->lastdur.num = 1L;
797     pn->lastdur.denom = 1L;
798     pn->octave = 8;
799     pn->pitchclass = 0;
800     pn->slur = 0;
801     pn->tie = FALSE;
802     pn->written = TRUE;
803 }
804 
805 static                          /* reads score{} section */
readscore(Inst * insttop)806 void readscore(Inst *insttop)
807 {
808     char    s[128];
809     Inst   *p;
810     Rat     grpmul, timesig, curtime, lastbar, lastnote, rattmp;
811     Tempo  *tempotop, *tempop;
812     Note   *notetop, *pn, *qn, *ln;
813     Nextp  *nextlist, *nextpp;
814     int     accidentals,
815             octaves,
816             vertical, key[PITCHCLASSES], barkey[PITCHCLASSES], transpose, z;
817     double  maxtime, fcurtime;
818 
819 #ifdef DEBUG
820     printf("Reading score section\n");
821 #endif
822 
823     maxtime = 0.0;
824     if (expectchar('{'))
825       scotferror(Str("Syntax error: no {"));
826     tempotop = (Tempo *) malloc(sizeof(Tempo));
827     tempotop->time.num = 0;
828     tempotop->time.denom = 1;
829     tempotop->val = 60;
830     tempotop->next = NULL;
831     for (;;) {
832       tempop = tempotop;
833       efindword(s);
834       if (s[0] == '}')
835         break;
836       if (s[0] != '$')
837         scotferror(Str("No instrument specified"));
838       p = insttop;
839       while ((p != NULL) && (strcmp(&s[1], p->name)))
840         p = p->next;
841       if (p == NULL)
842         scotferror(Str("Instrument not defined"));
843       notetop = ln = NULL;
844       grpmul.num = 1;
845       grpmul.denom = 1;
846       timesig.num = 0;
847       timesig.denom = 1;
848       curtime.num = 0;
849       curtime.denom = 1;
850       lastbar.num = 0;
851       lastbar.denom = 1;
852       lastnote.num = 0;
853       lastnote.denom = 1;
854       accidentals = octaves = vertical = TRUE;
855       for (z = 0; z < PITCHCLASSES; z++)
856         key[z] = barkey[z] = 0;
857       transpose = 0;
858       nextlist = NULL;
859       readinstsec(p, &nextlist, &grpmul, &timesig, &curtime,
860                   &lastbar, &lastnote, &notetop, &ln, &tempop, &accidentals,
861                   &octaves, &vertical, key, barkey, &transpose, "}$");
862       for (pn = notetop; pn; pn = pn->next) {
863         if (!pn->written) {
864           char   *ps, *ps2;
865 
866           for (nextpp = nextlist; nextpp; nextpp = nextpp->next) {
867             ps = findparam(nextpp->dst, &pn->carryp);
868             if (!strcmp(ps, NEXTP)) {
869               ps2 = findparam(nextpp->src, &pn->p);
870               if (!strcmp(ps2, "."))
871                 ps2 = findparam(nextpp->src, &pn->carryp);
872               strcpy(ps, ps2);
873             }
874           }
875           writenote(pn);
876         }
877         if (pn->tie)
878           scoterror(Str("unresolved tie"));
879         if (pn->slur & 1)
880           scoterror(Str("unresolved slur"));
881         ratadd(&rattmp, &pn->start, &pn->dur);
882         if (ratcmp(&rattmp, &curtime) > 0)
883           ratass(&curtime, &rattmp);
884 
885 #ifdef DEBUG
886         if (pn == pn->next)
887           scotferror(Str("Circular note list\n"));
888 #endif
889 
890       }
891       while (nextlist) {
892         nextpp = nextlist;
893         nextlist = nextlist->next;
894         free((char *) nextpp);
895       }
896       pn = notetop;
897       while (pn) {
898         qn = pn;
899         pn = pn->next;
900         freenote(qn);
901       }
902       fcurtime = ratval(&curtime);
903       if (fcurtime > maxtime)
904         maxtime = fcurtime;
905     }
906     tempop = tempotop;
907     putc('t', outfile);
908     for (;;) {
909       tempotop = tempop;
910       tempop = tempop->next;
911       fprintf(outfile, "%g %d", ratval(&tempotop->time), tempotop->val);
912       free((char *) tempotop);
913       if (!tempop)
914         break;
915       putc(' ', outfile);
916     }
917     fprintf(outfile, "\nf0 %g\ns\n", maxtime);
918 }
919 
920 static                          /* functions{} section */
readfunctions(void)921 void readfunctions(void)
922 {
923     int     c;
924 
925 #ifdef DEBUG
926     printf("Reading function section\n");
927 #endif
928 
929     if (expectchar('{'))
930       scotferror(Str("Syntax error: no {"));
931     for (;;) {
932       if ((c = getccom()) == EOF)
933         scotferror(Str("Unexpected end of file"));
934       if (c == '}') {
935         putc('\n', outfile);
936         return;
937       }
938       putc(c, outfile);
939     }
940 }
941 
942 static                          /* orchestra{} section */
readorch(Inst ** insttopp)943 void readorch(Inst **insttopp)
944 {
945     char    s[128];
946     Inst   *p, *q = NULL;
947 
948 #ifdef DEBUG
949     printf("Reading orchestra section\n");
950 #endif
951 
952     gmac = NULL;
953     if (expectchar('{'))
954       scotferror(Str("Syntax error: no {"));
955     p = (*insttopp) = (Inst *) malloc(sizeof(Inst));
956     p->lmac = NULL;
957     for (;;) {
958       efindword(s);
959       if (s[0] == (char) '}')
960         break;
961       if (s[0] == (char) '[') {
962         if (p == (*insttopp))
963           readmacros(&gmac);
964         else
965           readmacros(&q->lmac);
966         continue;
967       }
968       p->name = (char *) malloc(strlen(s) + 1);
969       strcpy(p->name, s);
970 
971 #ifdef DEBUG
972       printf("Instrument name: %s ", p->name);
973 #endif
974 
975       if (expectchar('='))
976         scoterror(Str("Syntax error: no ="));
977       if (findint((int *) &p->number))
978         scoterror(Str("Syntax error: no number"));
979 
980 #ifdef DEBUG
981       printf(" number: %d\n", p->number);
982 #endif
983 
984       p->next = (Inst *) malloc(sizeof(Inst));
985       q = p;
986       p = p->next;
987       p->lmac = NULL;
988     }
989     if (p == *insttopp)
990       scotferror(Str("No instruments declared"));
991     free((char *) p);
992     q->next = NULL;
993 }
994 
995 static                          /* reads macro list from score section */
readmacros(Macro ** mtop)996 void readmacros(Macro **mtop)
997 {
998     Macro  *p, *q;
999 
1000 #ifdef DEBUG
1001     printf("Reading macro definitions\n");
1002 #endif
1003 
1004     p = (*mtop) = (Macro *) malloc(sizeof(Macro));
1005     efindword(p->name);
1006     for (;;) {
1007       q = p;
1008       if (p->name[0] == (char) ']')
1009         break;
1010       if (expectchar('='))
1011         scoterror(Str("Expected ="));
1012       efindword(p->text);
1013 
1014 #ifdef DEBUG
1015       printf(" %s = %s\n", p->name, p->text);
1016 #endif
1017 
1018       p = p->next = (Macro *) malloc(sizeof(Macro));
1019       efindword(p->name);
1020     }
1021     q->next = NULL;
1022     free((char *) p);
1023 }
1024 
1025 static                          /* returns TRUE if ch is NOT */
expectchar(int ch)1026 int expectchar(int ch)
1027 {                               /* the next non-whitespace char */
1028     int     c;
1029 
1030     do {
1031       if ((c = getccom()) == EOF)
1032         return TRUE;
1033     } while (strchr(" \t\r\n", c));
1034     return !(c == ch);
1035 }
1036 
1037 /* all these find* functions return their found values in
1038    their passed-by-pointer operands. They only return TRUE
1039    upon failure. */
1040 
findchar(int * ip)1041 static int findchar(int *ip)
1042 {
1043     int     c;
1044 
1045     do {
1046       if ((c = getccom()) == EOF)
1047         scotferror(Str("Unexpected end of file"));
1048     } while (strchr(" \t\r\n", c));
1049     *ip = c;
1050     return FALSE;
1051 }
1052 
findint(int * ip)1053 static int findint(int *ip)
1054 {
1055     int     c, t;
1056 
1057     t = TRUE;
1058     *ip = 0;
1059     do {
1060       if ((c = getccom()) == EOF)
1061         scotferror(Str("Unexpected end of file"));
1062     } while (strchr(" \t\r\n", c));
1063     while (isdigit(c)) {
1064       t = FALSE;
1065       *ip *= 10;
1066       *ip += (c - '0');
1067       if ((c = getccom()) == EOF)
1068         scotferror(Str("Unexpected end of file"));
1069     }
1070     scotungetc();
1071     return t;
1072 }
1073 
findonoff(int * ip)1074 static int findonoff(int *ip)
1075 {
1076     char    s[32];
1077 
1078     efindword(s);
1079     if (!strcmp(s, "on")) {
1080       *ip = TRUE;
1081       return FALSE;
1082     }
1083     if (!strcmp(s, "off")) {
1084       *ip = FALSE;
1085       return FALSE;
1086     }
1087     return TRUE;
1088 }
1089 
efindword(char * s)1090 static void efindword(char *s)
1091 {
1092     if (findword(s))
1093       scotferror(Str("Unexpected end of file"));
1094 }
1095 
findword(char * s)1096 static int findword(char *s)
1097 {
1098     int     c, n;
1099 
1100     n = 0;
1101     do {
1102       if ((c = getccom()) == EOF)
1103         return TRUE;
1104     } while (strchr(" \t\r\n", c));
1105     if (c == '\"') {
1106       while ((c = scotgetc()) != '\"') {
1107         if (c == EOF)
1108           return TRUE;
1109         s[n++] = (char) c;
1110       }
1111       s[n] = (char) 0;
1112       return FALSE;
1113     }
1114     if (strchr("{}[]", c)) {
1115       s[0] = (char) c;
1116       s[1] = (char) 0;
1117       return FALSE;
1118     }
1119     do {
1120       s[n++] = (char) c;
1121       if ((c = getccom()) == EOF)
1122         return TRUE;
1123     } while (!strchr(" \t\r\n{}[]=\"", c));
1124     s[n] = (char) 0;
1125     scotungetc();
1126     return FALSE;
1127 }
1128 
1129 static                          /* gets a char from file, but */
getccom(void)1130 int getccom(void)
1131 {                               /* ignores comments. */
1132     int     c;
1133 
1134     c = scotgetc();
1135     if (c != ';')
1136       return c;
1137     while (scotgetc() != '\n');
1138     return '\n';
1139 }
1140 
letterval(int c)1141 static int letterval(int c)
1142 {
1143     switch (c) {
1144     case 'a':
1145       return 5;
1146     case 'b':
1147       return 6;
1148     case 'c':
1149       return 0;
1150     case 'd':
1151       return 1;
1152     case 'e':
1153       return 2;
1154     case 'f':
1155       return 3;
1156     case 'g':
1157       return 4;
1158     default:
1159       scoterror(Str("Invalid pitch class"));
1160       return 0;
1161     }
1162 }
1163 
1164 static                          /* returns octave.pitchclass */
pitchval(int oct,int pit,int acc,int transpose)1165 double pitchval(int oct, int pit, int acc, int transpose)
1166 {
1167 #ifdef DEBUG
1168     printf("  Computing pitchval(%d,%d,%d,%d)\n", oct, pit, acc, transpose);
1169 #endif
1170 
1171     pit = naturals[pit] + acc + transpose;
1172 
1173 #ifdef DEBUG
1174     printf("  pit=%d\n", pit);
1175 #endif
1176 
1177     while (pit < 0) {
1178       pit += NOTESPEROCT;
1179       oct--;
1180 
1181 #ifdef DEBUG
1182       printf("  oct=%d pit=%d\n", oct, pit);
1183 #endif
1184 
1185     }
1186     while (pit >= NOTESPEROCT) {
1187       pit -= NOTESPEROCT;
1188       oct++;
1189 
1190 #ifdef DEBUG
1191       printf("  oct=%d pit=%d\n", oct, pit);
1192 #endif
1193 
1194     }
1195 
1196 #ifdef DEBUG
1197     printf("  pitchval: %d.%02d\n", oct, pit);
1198 #endif
1199 
1200     return (double) oct + (double) pit * 0.01;
1201 }
1202 
1203 static                          /* just writes pfields from n->p, */
writenote(Note * n)1204 void writenote(Note *n)
1205 {                               /* or n->carryp if others are blank "." */
1206     Strlist *ps, *cps;
1207 
1208 #ifdef DEBUG
1209     printf(" writing: i");
1210 #endif
1211 
1212     n->written = TRUE;
1213     putc('i', outfile);
1214     ps = n->p;
1215     cps = n->carryp;
1216     for (;;) {
1217       if (ps && strcmp(ps->str, ".")) {
1218         fputs(ps->str, outfile);
1219 
1220 #ifdef DEBUG
1221         printf(" %s", ps->str);
1222 #endif
1223 
1224       }
1225       else if (cps && strcmp(cps->str, ".")) {
1226         fputs(cps->str, outfile);
1227 
1228 #ifdef DEBUG
1229         printf(" %s(c)", cps->str);
1230 #endif
1231 
1232       }
1233       else {                    /* if (ps || cps) */
1234 
1235         fputs(" 0", outfile);
1236 
1237 #ifdef DEBUG
1238         printf(" 0(.)");
1239 #endif
1240 
1241       }
1242       if (ps)
1243         ps = ps->next;
1244       if (cps)
1245         cps = cps->next;
1246       if (!(ps || cps))
1247         break;
1248       putc(' ', outfile);
1249     }
1250     putc('\n', outfile);
1251 
1252 #ifdef DEBUG
1253     printf("\n");
1254 #endif
1255 
1256 }
1257 
1258 static                          /* deallocates a note and */
freenote(Note * n)1259 void freenote(Note *n)
1260 {                               /* its pfield lists */
1261     freeps(n->p);
1262     freeps(n->carryp);
1263     free((char *) n);
1264 }
1265 
1266 static                          /* deallocates a pfield list */
freeps(Strlist * pp)1267 void freeps(Strlist *pp)
1268 {
1269     Strlist *pq;
1270 
1271     while (pp) {
1272       pq = pp;
1273       pp = pp->next;
1274       free((char *) pq);
1275     }
1276 }
1277 
1278 static                          /* copies a pfield list */
strlistcopy(Strlist ** dest,Strlist ** source)1279 void strlistcopy(Strlist **dest, Strlist **source)
1280 {
1281     Strlist *sp, *dp;
1282 
1283     if ((*source) == NULL) {
1284       *dest = NULL;
1285       return;
1286     }
1287     sp = (*source);
1288     dp = (*dest) = (Strlist *) malloc(sizeof(Strlist));
1289     for (;;) {
1290       strcpy(dp->str, sp->str);
1291       sp = sp->next;
1292       if (sp == NULL)
1293         break;
1294       dp = dp->next = (Strlist *) malloc(sizeof(Strlist));
1295     }
1296     dp->next = NULL;
1297 }
1298 
1299 /* rational number functions */
1300 
ratval(Rat * r)1301 static double ratval(Rat *r)
1302 {                               /* evaluate r */
1303     if (!r->denom) {
1304       scoterror(Str("Division by zero"));
1305       return (double) 1.0;
1306     }
1307     return (double) r->num / (double) r->denom;
1308 }
1309 
ratreduce(Rat * r)1310 static void ratreduce(Rat *r)
1311 {                               /* reduce r */
1312     unsigned long a, b, x;
1313 
1314     if (!r->num) {
1315       r->denom = 1;
1316       return;
1317     }
1318     if (!r->denom) {
1319       scoterror(Str("Division by zero"));
1320       return;
1321     }
1322     if (r->num > r->denom) {
1323       a = r->num;
1324       b = r->denom;
1325     }
1326     else {
1327       a = r->denom;
1328       b = r->num;
1329     }
1330     while ((x = a % b)) {
1331       a = b;
1332       b = x;
1333     }
1334     r->num /= b;
1335     r->denom /= b;
1336 }
1337 
ratadd(Rat * d,Rat * a1,Rat * a2)1338 static void ratadd(Rat *d, Rat *a1, Rat *a2)
1339 {                               /* d=a1+a2; OK if d=a1=a2 */
1340     unsigned long lcd;
1341 
1342 #ifdef DEBUG
1343     printf("  ratadd (%lu/%lu)+(%lu/%lu)\n", a1->num, a1->denom, a2->num,
1344            a2->denom);
1345 #endif
1346 
1347     lcd = (a1->denom) * (a2->denom);
1348     d->num = (a1->num) * (a2->denom) + (a2->num) * (a1->denom);
1349     d->denom = lcd;
1350 
1351 #ifdef DEBUG
1352     printf("  unreduced result: %lu/%lu\n", d->num, d->denom);
1353 #endif
1354 
1355     ratreduce(d);
1356 
1357 #ifdef DEBUG
1358     printf("  reduced result: %lu/%lu\n", d->num, d->denom);
1359 #endif
1360 
1361 }
1362 
ratmul(Rat * d,Rat * a1,Rat * a2)1363 static void ratmul(Rat *d, Rat *a1, Rat *a2)
1364 {                               /* d=a1*a2; OK if d=a1=a2 */
1365     d->num = a1->num * a2->num;
1366     d->denom = a1->denom * a2->denom;
1367     ratreduce(d);
1368 }
1369 
ratdiv(Rat * d,Rat * a1,Rat * a2)1370 static void ratdiv(Rat *d, Rat *a1, Rat *a2)
1371 {                               /* d=a1/a2; OK if d=a1=a2 */
1372     if (!a2->num) {
1373       scoterror(Str("Division by zero"));
1374       ratass(d, a1);
1375       return;
1376     }
1377     d->num = a1->num * a2->denom;
1378     d->denom = a1->denom * a2->num;
1379     ratreduce(d);
1380 }
1381 
ratcmp(Rat * a,Rat * b)1382 static int ratcmp(Rat *a, Rat *b)
1383 {
1384     unsigned long m, n;
1385 
1386     m = a->num * b->denom;
1387     n = b->num * a->denom;
1388     if (m < n)
1389       return -1;
1390     if (m == n)
1391       return 0;
1392     return 1;
1393 }
1394 
ratass(Rat * a,Rat * b)1395 static void ratass(Rat *a, Rat *b)
1396 {                               /* sorry about the name... a=b; */
1397     a->num = b->num;
1398     a->denom = b->denom;
1399 }
1400 
1401 /* i/o and error routines */
1402 
1403 static                          /* call once to start reading infile */
initf(FILE * inf,FILE * outf,char * fil)1404 void initf(FILE *inf, FILE *outf, char *fil)
1405 {
1406     infile = inf;
1407     outfile = outf;
1408     infilename = fil;
1409     if (UNLIKELY(NULL == fgets(curline, MAXLINE, infile))) {
1410       fprintf(stderr, "Read failure\n");
1411       exit(1);
1412     }
1413 #ifdef DEBUG
1414     printf("1: %s", curline);
1415 #endif
1416 
1417     inx = 0;
1418     iny = 1;
1419     errcount = 0;
1420 }
1421 
1422 static                          /* use like getc(infile) */
scotgetc(void)1423 int scotgetc(void)
1424 {
1425     if (inx < 0) {
1426       inx = 0;
1427       return '\n';
1428     }
1429     if (curline[inx] == (char) 0) {
1430       if (!fgets(curline, MAXLINE, infile))
1431         return EOF;
1432       inx = 0;
1433       iny++;
1434 
1435 #ifdef DEBUG
1436       printf("%d: %s", iny, curline);
1437 #endif
1438 
1439     }
1440     inx++;
1441     return (int) curline[inx - 1];
1442 }
1443 
scotungetc(void)1444 static void scotungetc(void)
1445 {
1446     inx--;
1447 }
1448 
scoterror(char * s)1449 static void scoterror(char *s)
1450 {
1451     int     z;
1452 
1453     fprintf(stderr, "%s(%d) %s\n", infilename, iny, s);
1454     fputs(curline, stderr);
1455     for (z = 1; z < inx; z++)
1456       putc(' ', stderr);
1457     fprintf(stderr, "^\n");
1458     errcount++;
1459 }
1460 
scotferror(char * s)1461 static void scotferror(char *s)         /* fatal error */
1462 {
1463     scoterror(s);
1464     fprintf(stderr, Str("scot processing terminated\n"));
1465     reporterrcount();
1466     exit(1);
1467 }
1468 
reporterrcount(void)1469 static void reporterrcount(void)
1470 {
1471     fprintf(stderr, Str("scot: %d errors.\n"), errcount);
1472 }
1473 
1474