1 /*
2     cscorfns.c:
3 
4     Copyright (C) 1991 Barry Vercoe, John ffitch
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 #include "csoundCore.h"     /*                      CSCORFNS.C      */
25 #include "cscore.h"
26 #include "corfile.h"
27 
28 #define TYP_FREE   0
29 #define TYP_EVENT  1
30 #define TYP_EVLIST 2
31 #define TYP_SPACE  3
32 #define NSLOTS     100      /* default slots in cscoreListCreate list   */
33 #define MAXALLOC   32768L
34 
35 extern int lplay(CSOUND *, EVLIST *);
36 
37 typedef struct space {
38         CSHDR  h;
39         struct space *nxtspace;
40 } SPACE;
41 
42 /* RWD: moved from below for use in reset */
43 typedef struct {
44         FILE  *iscfp;
45         EVENT *next;
46         MYFLT until;
47         int   wasend, warped, atEOF;
48 } INFILE;
49 static INFILE *infiles = NULL;    /* array of infile status blks */
50 
51 /* next two from cscoreDefineEvent() really */
52 static  EVENT  *evtmp = NULL;
53 static  EVTBLK *evtmpblk;
54 
55 static SPACE  spaceanchor = { { NULL, NULL, TYP_SPACE, 0 }, NULL };
56 static CSHDR  *nxtfree = NULL;   /* fast pointer to yet unused free space */
57 static EVENT  *nxtevt = NULL;    /* to hold nxt infil event, PMAX pfields */
58 static EVTBLK *nxtevtblk;        /* cs.h EVTBLK subset of EVENT nxtevt    */
59 static int    warpout = 0;
60 static MYFLT  curuntil;          /* initialised to zero by cscoreFileOpen */
61 static int    wasend;            /* ditto */
62 static int    atEOF;             /* zero when file opened;
63                                     stays one once rdscor returns 0 */
64 
65 
cscoreRESET(CSOUND * csound)66 void cscoreRESET(CSOUND *csound)
67 {
68     nxtfree   = NULL;
69     nxtevt    = NULL;
70     nxtevtblk = NULL;
71     infiles   = NULL;            /* FIXME: leak? (any others here?) */
72     csound->warped  = warpout  = 0;
73     evtmp     = NULL;
74     evtmpblk  = NULL;
75     if (spaceanchor.nxtspace != NULL) {
76       SPACE *p = spaceanchor.nxtspace;
77       SPACE *n;
78       do {
79         n = p->nxtspace;
80         csound->Free(csound, p);
81         p = n;
82       }
83       while (p != NULL);
84     }
85     spaceanchor.nxtspace = NULL;
86     spaceanchor.h.prvblk = NULL;
87     spaceanchor.h.nxtblk = NULL;
88     spaceanchor.h.type = TYP_SPACE;
89     spaceanchor.h.size = 0;
90     return;
91 }
92 
morespace(CSOUND * csound)93 static SPACE *morespace(CSOUND *csound)
94 {                               /* alloc large amount of memory, keep in a */
95     SPACE *space, *prvspace;    /* chain. Put SPACE blk at top & init rem as */
96     CSHDR *free;                /* a FREE blk */
97 
98     prvspace = &spaceanchor;
99     while ((space = prvspace->nxtspace) != NULL)
100       prvspace = space;
101     space = (SPACE *) csound->Malloc(csound, (long) MAXALLOC);
102     prvspace->nxtspace = space;
103     space->nxtspace = NULL;
104     space->h.prvblk = NULL;
105     space->h.nxtblk = (CSHDR *) ((char *) space + sizeof(SPACE));
106     space->h.type = TYP_SPACE;
107     space->h.size = sizeof(SPACE);
108     free = space->h.nxtblk;
109     free->prvblk = (CSHDR *) space;    /* init rem as a TYP_FREE blk */
110     free->nxtblk = NULL;
111     free->type = TYP_FREE;
112     free->size = MAXALLOC - sizeof(SPACE);
113     return(space);
114 }
115 
116 /* search space chains for min size free blk */
117 /* else alloc new space blk & reset fast free */
118 
getfree(CSOUND * csound,int minfreesiz)119 static CSHDR *getfree(CSOUND *csound, int minfreesiz)
120 {
121     SPACE *curspace;
122     CSHDR *blkp;
123 
124     curspace = &spaceanchor;
125     while ((curspace = curspace->nxtspace) != NULL) {
126       blkp = curspace->h.nxtblk;
127       do {
128         if (blkp->type == TYP_FREE && blkp->size >= minfreesiz)
129           return(blkp);
130       } while ((blkp = blkp->nxtblk) != NULL);
131     }
132     curspace = morespace(csound);        /* else alloc more space, and  */
133     nxtfree = curspace->h.nxtblk;        /* reset the fast free pointer */
134     return(nxtfree);
135 }
136 
137 /* return a TYP_EVENT or TYP_EVLIST to free space */
138 /* consolidate with any prev or follow free space */
139 
csfree(CSHDR * bp)140 static void csfree(CSHDR *bp)
141 {
142     CSHDR *prvp, *nxtp;
143 
144     if ((prvp = bp->prvblk) != NULL && prvp->type == TYP_FREE) {
145       if ((nxtp = bp->nxtblk) != NULL && nxtp->type == TYP_FREE) {
146         if ((prvp->nxtblk = nxtp->nxtblk) != NULL)
147           nxtp->nxtblk->prvblk = prvp;
148         prvp->size += bp->size + nxtp->size;
149       }
150       else {
151         if ((prvp->nxtblk = bp->nxtblk) != NULL)
152           bp->nxtblk->prvblk = prvp;
153         prvp->size += bp->size;
154       }
155     }
156     else {
157       if ((nxtp = bp->nxtblk) != NULL && nxtp->type == TYP_FREE) {
158         if ((bp->nxtblk = nxtp->nxtblk) != NULL)
159           nxtp->nxtblk->prvblk = bp;
160         bp->size += nxtp->size;
161       }
162       bp->type = TYP_FREE;
163     }
164 }
165 
166 /* create an array of event pointer slots */
167 
cscoreListCreate(CSOUND * csound,int nslots)168 PUBLIC EVLIST * cscoreListCreate(CSOUND *csound, int nslots)
169 {
170     CSHDR *newblk, *newfree;
171     EVLIST *a;
172     int   needsiz = sizeof(EVLIST) + nslots * sizeof(EVENT *);
173     int   minfreesiz = needsiz + sizeof(CSHDR);
174 
175     if (UNLIKELY(minfreesiz > MAXALLOC)) {
176       csound->Message(csound, Str("Not enough memory\n"));
177       exit(1);
178     }
179     if (nxtfree != NULL && nxtfree->size >= minfreesiz)
180       newblk = nxtfree;
181     else newblk = getfree(csound, minfreesiz);
182     newfree = (CSHDR *) ((char *)newblk + needsiz);
183     newfree->prvblk = newblk;
184     newfree->nxtblk = newblk->nxtblk;
185     newfree->type = TYP_FREE;
186     newfree->size = newblk->size - needsiz;
187     newblk->nxtblk = newfree;
188     newblk->type = TYP_EVLIST;
189     newblk->size = needsiz;
190     if (newblk == nxtfree)  nxtfree = newfree;
191     a = (EVLIST *) newblk;
192     a->nslots = nslots;
193     a->nevents= 0;
194     return(a);
195 }
196 
197 /* creat a new event space */
198 
cscoreCreateEvent(CSOUND * csound,int pcnt)199 PUBLIC EVENT * cscoreCreateEvent(CSOUND *csound, int pcnt)
200 {
201     CSHDR *newblk, *newfree;
202     EVENT *e;
203     int   needsiz = sizeof(EVENT) + pcnt * sizeof(MYFLT);
204     int   minfreesiz = needsiz + sizeof(CSHDR);
205 
206     if (UNLIKELY(minfreesiz > MAXALLOC)) {
207       csound->Message(csound, Str("Not enough memory\n"));
208       exit(1);
209     }
210     if (nxtfree != NULL && nxtfree->size >= minfreesiz)
211       newblk = nxtfree;
212     else newblk = getfree(csound, minfreesiz);
213     newfree = (CSHDR *) ((char *)newblk + needsiz);
214     newfree->prvblk = newblk;
215     newfree->nxtblk = newblk->nxtblk;
216     newfree->type = TYP_FREE;
217     newfree->size = newblk->size - needsiz;
218     newblk->nxtblk = newfree;
219     newblk->type = TYP_EVENT;
220     newblk->size = needsiz;
221     if (newblk == nxtfree)  nxtfree = newfree;
222     e = (EVENT *) newblk;
223     e->pcnt = pcnt;
224     return(e);
225 }
226 
227 /* make a new copy of an event */
228 
cscoreCopyEvent(CSOUND * csound,EVENT * e)229 PUBLIC EVENT * cscoreCopyEvent(CSOUND *csound, EVENT *e)
230 {
231     EVENT *f;
232     int  n;
233     MYFLT *p, *q;
234 
235     n = e->pcnt;
236     f = cscoreCreateEvent(csound, n);
237     f->op = e->op;
238     f->strarg = e->strarg;
239     /* f->pcnt was set by cscoreCreateEvent */
240     /* previous method of copying these was dangerous! - akozar */
241     f->p2orig = e->p2orig;
242     f->p3orig = e->p3orig;
243     p = &e->p[0];
244     q = &f->p[0];
245     n += 1; /* p[] is one larger than pcnt b/c p[0] unused */
246     while (n--)
247       *q++ = *p++;
248     return(f);
249 }
250 
251 /* RWD: cannot addd init arg as this is a std public func */
252 /* Can only do reentry by moving statics outside: fortunately, */
253 /* names are unique */
254 
255 /* define an event from string arg */
256 
cscoreDefineEvent(CSOUND * csound,char * s)257 PUBLIC EVENT * cscoreDefineEvent(CSOUND *csound, char *s)
258 {
259     MYFLT *p, *q;
260 
261     if (evtmp == NULL) {
262       evtmp = cscoreCreateEvent(csound, PMAX);
263       evtmpblk = (EVTBLK *) &evtmp->strarg;
264     }
265     while (*s == ' ')
266       s++;
267     evtmp->op = *s++;                       /* read opcode */
268     while (*s == ' ')
269       s++;
270     p = &evtmp->p[1];
271     q = &evtmp->p[PMAX];
272 #ifdef USE_DOUBLE
273     while (CS_SSCANF(s,"%lf",p++) > 0)         /* read pfields */
274 #else
275     while (CS_SSCANF(s,"%f",p++) > 0)          /* read pfields */
276 #endif
277     {
278       while ((*s >= '0' && *s <= '9') || *s == '.' || *s == '-')
279         s++;
280       while (*s == ' ')
281         s++;
282       if (UNLIKELY(p > q && *s != '\0'))  {           /* too many ? */
283         p++;
284         csound->Message(csound,
285                         Str("PMAX exceeded, string event truncated.\n"));
286         break;
287       }
288     }
289     evtmp->pcnt = p - &evtmp->p[1] - 1;     /* set count of params recvd */
290     evtmp->p2orig = evtmp->p[2];
291     evtmp->p3orig = evtmp->p[3];
292     return (cscoreCopyEvent(csound, evtmp));    /* copy event to a new space */
293 }
294 
295 /* get nxt event from input score buf */
296 /*   and  refill the buf */
297 
cscoreGetEvent(CSOUND * csound)298 PUBLIC EVENT * cscoreGetEvent(CSOUND *csound)
299 {
300     EVENT *e;
301 
302     if (!atEOF && nxtevt->op != '\0')
303       e = cscoreCopyEvent(csound, nxtevt);
304     else e = NULL;
305     if (!(rdscor(csound, nxtevtblk))) {
306       nxtevt->op = '\0';
307       atEOF = 1;
308     }
309     return(e);
310 }
311 
312 /* put an event to cscore outfile */
313 
cscorePutEvent(CSOUND * csound,EVENT * e)314 PUBLIC void cscorePutEvent(CSOUND *csound, EVENT *e)
315 {
316     int  pcnt;
317     MYFLT *q;
318     int  c = e->op;
319 
320     if (c == 's')  warpout = 0;         /* new section:  init to non-warped */
321     putc(c, csound->oscfp);
322     q = &e->p[1];
323     if ((pcnt = e->pcnt)) {
324       if (pcnt--)       fprintf(csound->oscfp," %g",*q++);
325       //else goto termin; /* cannot happen */
326       if (pcnt--) {
327         if (warpout) {    fprintf(csound->oscfp," %g", e->p2orig);}
328                         fprintf(csound->oscfp," %g",*q++);
329       }
330       else goto termin;
331       if (pcnt--) {
332         if (warpout)  {  fprintf(csound->oscfp," %g", e->p3orig); }
333                         fprintf(csound->oscfp," %g",*q++);
334       }
335       else goto termin;
336       while (pcnt--)
337         { fprintf(csound->oscfp," %g",*q++); }
338     }
339  termin:
340     putc((int)'\n', csound->oscfp);
341     if (c == 'w')  warpout = 1; /* was warp statement: sect now warped */
342 }
343 
cscorePutString(CSOUND * csound,char * s)344 PUBLIC void cscorePutString(CSOUND *csound, char *s)
345 {
346     fprintf(csound->oscfp,"%s\n", s);
347     if (*s == 's')  warpout = 0;
348     else if (*s == 'w') warpout = 1;
349 }
350 
351 /* expand an event list by NSLOTS more slots */
352 /* copy the previous list, free up the old   */
353 
lexpand(CSOUND * csound,EVLIST * a)354 static EVLIST * lexpand(CSOUND *csound, EVLIST *a)
355 {
356     EVLIST *b;
357     EVENT **p, **q;
358     int n;
359 
360     b = cscoreListCreate(csound, a->nslots + NSLOTS);
361     b->nevents = n = a->nevents;
362     p = &a->e[1];
363     q = &b->e[1];
364     while (n--)
365       *q++ = *p++;
366     csfree((CSHDR *) a);
367     return(b);
368 }
369 
370 /* append an event to a list */
371 
cscoreListAppendEvent(CSOUND * csound,EVLIST * a,EVENT * e)372 PUBLIC EVLIST * cscoreListAppendEvent(CSOUND *csound, EVLIST *a, EVENT *e)
373 {
374     int  n;
375 
376     if ((n = a->nevents) == a->nslots)
377       a = lexpand(csound, a);
378     a->e[n+1] = e;
379     a->nevents++;
380     return(a);
381 }
382 
383 /* append a string event to a list */
384 
cscoreListAppendStringEvent(CSOUND * csound,EVLIST * a,char * s)385 PUBLIC EVLIST * cscoreListAppendStringEvent(CSOUND *csound, EVLIST *a, char *s)
386 {
387     EVENT *e = cscoreDefineEvent(csound, s);
388     return(cscoreListAppendEvent(csound,a,e));
389 }
390 
391 /* get section events from the scorefile */
392 
cscoreListGetSection(CSOUND * csound)393 PUBLIC EVLIST * cscoreListGetSection(CSOUND *csound)
394 {
395     EVLIST *a;
396     EVENT *e, **p;
397     int nevents = 0;
398 
399     a = cscoreListCreate(csound, NSLOTS);
400     p = &a->e[1];
401     if (UNLIKELY(csound->scstr == NULL || csound->scstr->body[0] == '\0'))
402       return a;
403     while ((e = cscoreGetEvent(csound)) != NULL) {
404       if (e->op == 's' || e->op == 'e')
405         break;
406       if (nevents == a->nslots) {
407         a->nevents = nevents;
408         a = lexpand(csound, a);
409         p = &a->e[nevents+1];
410       }
411       *p++ = e;
412       nevents++;
413     }
414     a->nevents = nevents;
415     return(a);
416 }
417 
418 /* get section events from the scorefile */
419 
cscoreListGetUntil(CSOUND * csound,MYFLT beatno)420 PUBLIC EVLIST * cscoreListGetUntil(CSOUND *csound, MYFLT beatno)
421 {
422     EVLIST *a;
423     EVENT *e, **p;
424     int nevents = 0;
425     char op;
426 
427     a = cscoreListCreate(csound, NSLOTS);
428     p = &a->e[1];
429     while ((op = nxtevt->op) == 't' || op == 'w' || op == 's' || op == 'e'
430            || (op != '\0' && nxtevt->p2orig < beatno)) {
431       e = cscoreGetEvent(csound);
432       if (e->op == 's') {
433         wasend = 1;
434         break;
435       }
436       if (e->op == 'e')
437         break;
438       if (nevents == a->nslots) {
439         a->nevents = nevents;
440         a = lexpand(csound,a);
441         p = &a->e[nevents+1];
442       }
443       *p++ = e;
444       nevents++;
445     }
446     a->nevents = nevents;
447     return(a);
448 }
449 
450 /* get section events from the scorefile */
451 
cscoreListGetNext(CSOUND * csound,MYFLT nbeats)452 PUBLIC EVLIST * cscoreListGetNext(CSOUND *csound, MYFLT nbeats)
453 {
454     if (wasend) {
455       wasend = 0;
456       curuntil = nbeats;
457     }
458     else curuntil += nbeats;
459     return(cscoreListGetUntil(csound,curuntil));
460 }
461 
462 /* put listed events to cscore output */
463 
cscoreListPut(CSOUND * csound,EVLIST * a)464 PUBLIC void cscoreListPut(CSOUND *csound, EVLIST *a)
465 {
466     EVENT **p;
467     int  n;
468 
469     n = a->nevents;
470     p = &a->e[1];
471     while (n--)
472       cscorePutEvent(csound, *p++);
473 }
474 
cscoreListPlay(CSOUND * csound,EVLIST * a)475 PUBLIC int cscoreListPlay(CSOUND *csound, EVLIST *a)
476 {
477     return lplay(csound, a);
478 }
479 
cscoreListCopy(CSOUND * csound,EVLIST * a)480 PUBLIC EVLIST * cscoreListCopy(CSOUND *csound, EVLIST *a)
481 {
482     EVLIST *b;
483     EVENT **p, **q;
484     int  n = a->nevents;
485 
486     b = cscoreListCreate(csound, n);
487     b->nevents = n;
488     p = &a->e[1];
489     q = &b->e[1];
490     while (n--)
491       *q++ = *p++;
492     return(b);
493 }
494 
cscoreListCopyEvents(CSOUND * csound,EVLIST * a)495 PUBLIC EVLIST * cscoreListCopyEvents(CSOUND *csound, EVLIST *a)
496 {
497     EVLIST *b;
498     EVENT **p, **q;
499     int  n = a->nevents;
500 
501     b = cscoreListCreate(csound, n);
502     b->nevents = n;
503     p = &a->e[1];
504     q = &b->e[1];
505     while (n--)
506       *q++ = cscoreCopyEvent(csound, *p++);
507     return(b);
508 }
509 
cscoreListAppendList(CSOUND * csound,EVLIST * a,EVLIST * b)510 PUBLIC EVLIST * cscoreListAppendList(CSOUND *csound, EVLIST *a, EVLIST *b)
511 {
512     EVENT **p, **q;
513     int i, j;
514 
515     i = a->nevents;
516     j = b->nevents;
517     if (i + j >= a->nslots) {
518       EVLIST *c;
519       int n = i;
520       c = cscoreListCreate(csound, i+j);
521       p = &a->e[1];
522       q = &c->e[1];
523       while (n--)
524         *q++ = *p++;
525       csfree((CSHDR *) a);
526       a = c;
527     }
528     a->nevents = i+j;
529     p = &a->e[i+1];
530     q = &b->e[1];
531     while (j--)
532       *p++ = *q++;
533     return(a);
534 }
535 
cscoreListConcatenate(CSOUND * csound,EVLIST * a,EVLIST * b)536 PUBLIC EVLIST * cscoreListConcatenate(CSOUND *csound, EVLIST *a, EVLIST *b)
537 {
538     return cscoreListAppendList(csound, a, b);
539 }
540 
541 /* put evlist pointers into chronological order */
542 
cscoreListSort(CSOUND * csound,EVLIST * a)543 PUBLIC void cscoreListSort(CSOUND *csound, EVLIST *a)
544 {
545     IGN(csound);
546     EVENT **p, **q;
547     EVENT *e, *f;
548     int  n, gap, i, j;
549 
550     n = a->nevents;
551     e = a->e[n];
552     if (e->op == 's' || e->op == 'e')
553       --n;
554     for (gap = n/2;  gap > 0;  gap /=2)
555       for (i = gap;  i < n;  i++)
556         for (j = i-gap;  j >= 0;  j -= gap) {
557           p = &a->e[j+1];     e = *p;
558           q = &a->e[j+1+gap]; f = *q;
559           if (e->op == 'w')
560             break;
561           if (e->p[2] < f->p[2])
562             break;
563           if (e->p[2] == f->p[2]) {
564             if (e->op == f->op) {
565               if (e->op == 'f')
566                 break;
567               if (e->p[1] < f->p[1])
568                 break;
569               if (e->p[1] == f->p[1])
570                 if (e->p[3] <= f->p[3])
571                   break;
572             }
573             else if (e->op < f->op)
574               break;
575           }
576           *p = f;  *q = e;
577         }
578 }
579 
cscoreListExtractInstruments(CSOUND * csound,EVLIST * a,char * s)580 PUBLIC EVLIST * cscoreListExtractInstruments(CSOUND *csound,
581                EVLIST *a, char *s) /* list extract by instr numbers */
582 {
583     int     x[5], xcnt;
584     int     xn, *xp, insno, n;
585     EVENT   **p, **q, *e;
586     EVLIST  *b, *c;
587 
588     xcnt = sscanf(s,"%d%d%d%d%d",&x[0],&x[1],&x[2],&x[3],&x[4]);
589     n = a->nevents;
590     b = cscoreListCreate(csound, n);
591     p = &a->e[1];
592     q = &b->e[1];
593     while ((n--) && (e = *p++) != NULL) {
594       if (e->op != 'i')
595         *q++ = e;
596       else {
597         insno = (int)e->p[1];
598         xn = xcnt;  xp = x;
599         while (xn--)
600           if (*xp++ == insno) {
601             *q++ = e;
602             break;
603           }
604       }
605     }
606     c = cscoreListCopy(csound,b);
607     csfree((CSHDR *) b);
608     return(c);
609 }
610 
cscoreListExtractTime(CSOUND * csound,EVLIST * a,MYFLT from,MYFLT to)611 PUBLIC EVLIST * cscoreListExtractTime(CSOUND *csound,
612                  EVLIST *a, MYFLT from, MYFLT to) /* list extract by time */
613 {
614     EVENT **p, **q, *e;
615     EVLIST *b, *c;
616     MYFLT maxp3;
617     int  n;
618 
619     n = a->nevents;
620     b = cscoreListCreate(csound,n);
621     p = &a->e[1];
622     q = &b->e[1];
623     maxp3 = to - from;
624     while ((n--) && (e = *p++) != NULL)
625       switch (e->op) {
626       case 'f':
627         if (e->p[2] < to) {
628           *q++ = e = cscoreCopyEvent(csound,e);
629           b->nevents++;
630           if (e->p[2] <= from)
631             e->p[2] = FL(0.0);
632           else e->p[2] -= from;
633         }
634         break;
635       case 'i':
636         if (e->p[2] < from) {
637           if (e->p[2] + e->p[3] > from) {
638             *q++ = e = cscoreCopyEvent(csound,e);
639             b->nevents++;
640             e->p[3] -= from - e->p[2];
641             e->p[2] = FL(0.0);
642             if (e->p[3] > maxp3)
643               e->p[3] = maxp3;
644           }
645         }
646         else if ((e->p[2] >= from) && (e->p[2] < to)) {
647           *q++ = e = cscoreCopyEvent(csound, e);
648           b->nevents++;
649           if (e->p[2] + e->p[3] > to)
650             e->p[3] = to - e->p[2];
651           e->p[2] -= from;
652         }
653         break;
654       default:
655         *q++ = cscoreCopyEvent(csound,e);
656         b->nevents++;
657         break;
658       }
659     c = cscoreListCopy(csound,b);
660     csfree((CSHDR *) b);
661     return(c);
662 }
663 
664 /* look for f statements with non-0 p[2] */
665 
fp2chk(CSOUND * csound,EVLIST * a,char * s)666 static void fp2chk(CSOUND *csound, EVLIST *a, char *s)
667 {
668     EVENT *e, **ep = &a->e[1];
669     int n = a->nevents, count = 0;
670 
671     while (n--)
672       if ((e = *ep++) && e->op == 'f' && e->p[2] != 0.)
673         count++;
674     if (count)
675       csound->Message(csound, Str("%s found %d f event%s with non-zero p2\n"),
676                               s, count, count==1 ? "" : Str("s"));
677 }
678 
679 /* separate f events from evlist */
680 
cscoreListSeparateF(CSOUND * csound,EVLIST * a)681 PUBLIC EVLIST * cscoreListSeparateF(CSOUND *csound, EVLIST *a)
682 {
683     EVLIST  *b, *c;
684     EVENT   **p, **q, **r;
685     int     n;
686 
687     n = a->nevents;
688     b = cscoreListCreate(csound, n);
689     p = q = &a->e[1];
690     r = &b->e[1];
691     while (n--) {
692       if ((*p)->op == 'f')
693         *r++ = *p++;
694       else *q++ = *p++;
695     }
696     a->nevents = q - &a->e[1];
697     b->nevents = r - &b->e[1];
698     c = cscoreListCopy(csound,b);
699     csfree((CSHDR *) b);
700     fp2chk(csound, c, "cscoreListSeparateF");
701     return(c);
702 }
703 
704 /* separate t,w,f events from evlist */
705 
cscoreListSeparateTWF(CSOUND * csound,EVLIST * a)706 PUBLIC EVLIST * cscoreListSeparateTWF(CSOUND *csound, EVLIST *a)
707 {
708     EVLIST *b, *c;
709     EVENT **p, **q, **r;
710     int   n, op;
711 
712     n = a->nevents;
713     b = cscoreListCreate(csound,n);
714     p = q = &a->e[1];
715     r = &b->e[1];
716     while (n--) {
717       if ((op = (*p)->op) == 't' || op == 'w' || op == 'f')
718         *r++ = *p++;
719       else *q++ = *p++;
720     }
721     a->nevents = q - &a->e[1];
722     b->nevents = r - &b->e[1];
723     c = cscoreListCopy(csound,b);
724     csfree((CSHDR *) b);
725     fp2chk(csound, c, "cscoreListSeparateTWF");
726     return(c);
727 }
728 
729 /* give back event space */
730 
cscoreFreeEvent(CSOUND * csound,EVENT * e)731 PUBLIC void cscoreFreeEvent(CSOUND *csound, EVENT *e)
732 {
733     IGN(csound);
734     csfree((CSHDR *) e);
735 }
736 
737 /* give back list space */
738 
cscoreListFree(CSOUND * csound,EVLIST * a)739 PUBLIC void cscoreListFree(CSOUND *csound, EVLIST *a)
740 {
741      IGN(csound);
742     csfree((CSHDR *) a);
743 }
744 
745 /* give back list and its event spaces */
746 
cscoreListFreeEvents(CSOUND * csound,EVLIST * a)747 PUBLIC void cscoreListFreeEvents(CSOUND *csound, EVLIST *a)
748 {
749      IGN(csound);
750     EVENT **p = &a->e[1];
751     int  n = a->nevents;
752 
753     while (n--)
754       csfree((CSHDR *) *p++);
755     csfree((CSHDR *) a);
756 }
757 
758 #define MAXOPEN 5
759 
savinfdata(CSOUND * csound,FILE * fp,EVENT * next,MYFLT until,int wasend,int warp,int eof)760 static void savinfdata(         /* store input file data */
761   CSOUND *csound,
762   FILE  *fp,
763   EVENT *next,
764   MYFLT until,
765   int   wasend,
766   int   warp,
767   int   eof)
768 {
769     INFILE *infp;
770     int    n;
771 
772     if ((infp = infiles) == NULL) {
773       infp = infiles = (INFILE *) csound->Calloc(csound, MAXOPEN * sizeof(INFILE));
774       goto save;
775     }
776     for (n = MAXOPEN; n--; infp++)
777       if (infp->iscfp == fp)
778         goto save;
779     for (infp = infiles, n = MAXOPEN; n--; infp++)
780       if (infp->iscfp == NULL)
781         goto save;
782     csound->ErrorMsg(csound, Str("cscore: too many input files open"));
783     exit(0);     /* FIXME: should not call exit */
784 
785  save:
786     infp->iscfp = fp;
787     infp->next = next;
788     infp->until = until;
789     infp->wasend = wasend;
790     infp->warped = warp;
791     infp->atEOF = eof;
792 }
793 
794 /* make fp the cur scfp & retreive other data */
795 /* set nxtevtblk to subset cs.h EVTBLK struct */
796 /* if nxtevt buffer is empty, read one event  */
797 
makecurrent(CSOUND * csound,FILE * fp)798 static void makecurrent(CSOUND *csound, FILE *fp)
799 {
800     INFILE *infp;
801     int    n;
802 
803     if ((infp = infiles) != NULL)
804       for (n = MAXOPEN; n--; infp++)
805         if (infp->iscfp == fp) {
806           csound->scfp = fp;
807           nxtevt = infp->next;
808           nxtevtblk = (EVTBLK *) &nxtevt->strarg;
809           curuntil = infp->until;
810           wasend = infp->wasend;
811           atEOF = infp->atEOF;
812           csound->warped = infp->warped;
813           if (nxtevt->op == '\0')
814             if (csound->scstr == NULL ||
815                 csound->scstr->body[0] == '\0' ||
816                 !(rdscor(csound, nxtevtblk))) {
817               nxtevt->op = '\0';
818               atEOF = 1;
819             }
820           return;
821         }
822     csound->ErrorMsg(csound, Str("cscore: tried to set an unknown file pointer"
823                                  " as the current file"));
824     exit(0);     /* FIXME: should not call exit */
825 }
826 
827 /* verify initial scfp, init other data */
828 /* record & make all this current       */
csoundInitializeCscore(CSOUND * csound,FILE * insco,FILE * outsco)829 PUBLIC int csoundInitializeCscore(CSOUND *csound, FILE* insco, FILE* outsco)
830 {
831     EVENT  *next;
832 
833     if (insco != NULL) {
834       CORFIL *inf = corfile_create_w(csound);
835       int c;
836       while ((c=getc(insco))!=EOF) corfile_putc(csound, c, inf);
837       corfile_rewind(inf);
838       csound->scstr = inf;
839     }
840     if (outsco == NULL) {
841       csound->ErrorMsg(csound,
842                        Str("csoundInitializeCscore: no output score given."));
843       return CSOUND_INITIALIZATION;
844     }
845     csound->scfp = insco;
846     csound->oscfp = outsco;
847 
848     next = cscoreCreateEvent(csound, PMAX); /* creat EVENT blk receiving buf */
849     next->op = '\0';
850 
851     savinfdata(csound, csound->scfp,
852                next, FL(0.0), 1, 0, 0);/* curuntil 0, wasend, non-warp, not eof */
853     makecurrent(csound, csound->scfp);  /* make all this current         */
854 
855     return CSOUND_SUCCESS;
856 }
857 
858 
859 
860 /* open new cscore input file, init data */
861 /* & save;  no rdscor until made current */
862 
cscoreFileOpen(CSOUND * csound,char * name)863 PUBLIC FILE *cscoreFileOpen(CSOUND *csound, char *name)
864 {
865     FILE    *fp;
866     EVENT   *next;
867     char    *pathname;
868 
869     /* keeping fopen() because the FILE* is returned to the user control
870        program and who knows what they will do with it ... */
871     pathname = csoundFindInputFile(csound, name, "INCDIR");
872     if (pathname == NULL || (fp = fopen(pathname, "r")) == NULL) {
873       csound->ErrorMsg(csound, Str("cscoreFileOpen: error opening %s"), name);
874       exit(0);     /* FIXME: should not call exit */
875     }
876     csoundNotifyFileOpened(csound, pathname, CSFTYPE_SCORE, 0, 0);
877     csound->Free(csound, pathname);
878     /* alloc a receiving evtblk */
879     next = cscoreCreateEvent(csound,PMAX);  /* FIXME: need next->op = '\0' ?? */
880     /* save all, wasend, non-warped, not eof */
881     savinfdata(csound, fp, next, FL(0.0), 1, 0, 0);
882     return(fp);
883 }
884 
cscoreFileClose(CSOUND * csound,FILE * fp)885 PUBLIC void cscoreFileClose(CSOUND *csound, FILE *fp)
886 {
887     INFILE *infp;
888     int n;
889 
890     if (fp == NULL) {
891       csound->Message(csound, Str("cscoreFileClose: NULL file pointer\n"));
892       return;
893     }
894     if ((infp = infiles) != NULL)
895       for (n = MAXOPEN; n--; infp++)
896         if (infp->iscfp == fp) {
897           infp->iscfp = NULL;
898           csound->Free(csound, (char *)infp->next);
899           fclose(fp);
900           if (csound->scfp == fp) csound->scfp = NULL;
901           return;
902         }
903     csound->Message(csound, Str("cscoreFileClose: fp not recorded\n"));
904 }
905 
cscoreFileGetCurrent(CSOUND * csound)906 PUBLIC FILE *cscoreFileGetCurrent(CSOUND *csound)
907 {
908     if (csound->scfp == NULL) {
909       csound->ErrorMsg(csound, Str("cscoreFileGetCurrent: no fp current"));
910       exit(0);     /* FIXME: should not call exit */
911     }
912     return(csound->scfp);
913 }
914 
915 /* save the current infil states */
916 /* make fp & its states current  */
917 
cscoreFileSetCurrent(CSOUND * csound,FILE * fp)918 PUBLIC void cscoreFileSetCurrent(CSOUND *csound, FILE *fp)
919 {
920     if (fp != NULL) {
921       CORFIL *inf = corfile_create_w(csound);
922       int c;
923       fseek(fp, 0, SEEK_SET);
924       while ((c=getc(fp))!=EOF) corfile_putc(csound, c, inf);
925       corfile_rewind(inf);
926       corfile_rm(csound, &csound->scstr);
927       csound->scstr = inf;
928       nxtevt->op = '\0';
929       atEOF = 0;
930     }
931     if (csound->scfp != NULL)
932       savinfdata(csound,
933                  csound->scfp, nxtevt, curuntil, wasend, csound->warped, atEOF);
934     makecurrent(csound, fp);
935 }
936 
937 /* count entries in event list */
938 
cscoreListCount(CSOUND * csound,EVLIST * a)939 PUBLIC int cscoreListCount(CSOUND *csound, EVLIST *a)
940 {
941      IGN(csound);
942     EVENT **p;
943     int  n, nrem;
944 
945     n = 0;
946     nrem = a->nslots;
947     p = &a->e[1];
948     while ((nrem--) && *p++ != NULL)
949       n++;
950     return(n);
951 }
952 
953