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", ×ig->num, ×ig->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, ×ig, &curtime,
860 &lastbar, &lastnote, ¬etop, &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