1 
2 /*
3 #    Sfront, a SAOL to C translator
4 #    This file: Plays streaming data from .mp4 file.
5 #
6 # Copyright (c) 1999-2006, Regents of the University of California
7 # All rights reserved.
8 #
9 # Redistribution and use in source and binary forms, with or without
10 # modification, are permitted provided that the following conditions are
11 # met:
12 #
13 #  Redistributions of source code must retain the above copyright
14 #  notice, this list of conditions and the following disclaimer.
15 #
16 #  Redistributions in binary form must reproduce the above copyright
17 #  notice, this list of conditions and the following disclaimer in the
18 #  documentation and/or other materials provided with the distribution.
19 #
20 #  Neither the name of the University of California, Berkeley nor the
21 #  names of its contributors may be used to endorse or promote products
22 #  derived from this software without specific prior written permission.
23 #
24 # THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
25 # "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
26 # LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
27 # A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
28 # OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
29 # SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
30 # LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
31 # DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
32 # THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
33 # (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
34 # OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
35 #
36 #    Maintainer: John Lazzaro, lazzaro@cs.berkeley.edu
37 */
38 
39 
40 /****************************************************************/
41 /****************************************************************/
42 /*           streaming file control driver for sfront           */
43 /****************************************************************/
44 
45 #define SAMP_SR        5
46 #define SAMP_LOOPSTART 4
47 #define SAMP_LOOPEND   3
48 #define SAMP_BASEFREQ  2
49 #define SAMP_LLMEM     1
50 #define SAMP_DATABLOCK 5
51 
52 FILE * csysi_bitfile;   /* streaming file */
53 
54 /* bit-level state variables */
55 
56 unsigned char csysi_bitstoread = 0;
57 int csysi_bitreadpos = - 1;
58 
59 /* bit-level parsing constants */
60 
61 #define CSYSI_IDENT        0xF0
62 #define CSYSI_NUMBER       0xF1
63 #define CSYSI_INTGR        0xF2
64 #define CSYSI_STRCONST     0xF3
65 #define CSYSI_BYTE         0xF4
66 
67 #define CSYSI_BINORC   0
68 #define CSYSI_BINSCORE 1
69 #define CSYSI_BINMIDI  2
70 #define CSYSI_BINSAMP  3
71 #define CSYSI_BINSBF   4
72 #define CSYSI_BINSYM   5
73 
74 #define CSYSI_EVSCORE  0
75 #define CSYSI_EVMIDI   1
76 #define CSYSI_EVSAMPLE 2
77 
78 #define CSYSI_MIDIMASKCOM  0xF0
79 #define CSYSI_MIDISYSTEM   0xF0
80 #define CSYSI_MIDIMASKCHAN 0x0F
81 #define CSYSI_METATEMPO    0x51
82 
83 #define CSYSI_MAXENDTIME   21600.0F
84 
85 /* word-level state variables */
86 
87 float csysi_bitaccesstime = 0.0F;  /* current SA_access_unit time */
88 
89 int csysi_moreaccessunits = 1;     /* more access_units left to read */
90 int csysi_endofevent = 1;          /* no more events in access_unit  */
91 
92 int csysi_numabstime = 0;          /* number of abs-time sasl events */
93 int csysi_numscotime = 0;          /* number of rel-time sasl events */
94 int csysi_nummidi = 0;             /* number of midi events */
95 
96 int csysi_absready = 0;            /* abs-time sasl events triggered */
97 int csysi_scoready = 0;            /* rel-time sasl events triggered */
98 int csysi_midiready = 0;           /* midi events triggered */
99 
100 int csysi_targetvar = -1;         /* pointer into csys_target[] */
101 int csysi_targetcount = 0;        /* pointer info {instr,var}index  */
102 
103 unsigned char csysi_runstat = 0;  /* holds running status byte      */
104 int csysi_endflag = 0;            /* flag for issuing last end command */
105 float csysi_compendtime = 0;      /* supplied computed endtime         */
106 
107 
108 /* data structures for pending events */
109 
110 #define CSYSI_MAXSASL 64
111 
112 /* add at the head, consume from the tail */
113 
114 int csysi_headsco = 0;  /* next available place for data */
115 int csysi_tailsco = -1; /* first occupied place for data */
116 
117 int csysi_headabs = 0;  /* next available place for data */
118 int csysi_tailabs = -1; /* first occupied place for data */
119 
120 typedef struct csysi_sevent {
121   float atime;
122   float stime;
123   unsigned char cmd;
124   unsigned char priority;
125   unsigned short id;
126   unsigned short label;
127   float fval;
128   unsigned int pnum;
129   float * p;
130 } csysi_sevent;
131 
132 csysi_sevent csysi_scoqueue[CSYSI_MAXSASL];
133 csysi_sevent csysi_absqueue[CSYSI_MAXSASL];
134 
135 #define CSYSI_MAXMIDI 64
136 
137 /* add at the head, consume from the tail */
138 
139 int csysi_headmidi = 0;  /* next available place for data */
140 int csysi_tailmidi = -1; /* first occupied place for data */
141 
142 typedef struct csysi_mevent {
143   float atime;
144   unsigned char cmd;
145   unsigned char ndata;
146   unsigned char vdata;
147   unsigned short extchan;
148   float fval;
149 } csysi_mevent;
150 
151 csysi_mevent csysi_midiqueue[CSYSI_MAXMIDI];
152 
153 /* data structure for samples */
154 
155 typedef struct csysi_sampleunit {
156   float atime;
157   int token;
158   int len;
159   float * p;
160   struct csysi_sampleunit * next;
161 } csysi_sampleunit;
162 
163 csysi_sampleunit * csysi_samples = NULL;
164 
165 
166 /******************************************************************/
167 /*                   gets next byte from bitfile                  */
168 /******************************************************************/
169 
170 void csysi_readnextbyte(void)
171 
172 {
173   int retry = 0;
174 
175   while (fread(&csysi_bitstoread,sizeof(char),1,csysi_bitfile)!=1)
176     {
177       if (feof(csysi_bitfile))
178 	csys_terminate("premature end of .mp4 file");
179       if (++retry > IOERROR_RETRY)
180 	csys_terminate("i/o problems during .mp4 file read");
181       clearerr(csysi_bitfile);
182     }
183   csysi_bitreadpos = 7;
184 
185 }
186 
187 /******************************************************************/
188 /*           reads numbits LSBs of bitval from bitfile            */
189 /******************************************************************/
190 
191 
192 unsigned int csysi_readbit(unsigned int numbits)
193 
194 {
195   unsigned int ret = 0;
196 
197   while (numbits > 0)
198     {
199       if (csysi_bitreadpos < 0)
200 	csysi_readnextbyte();
201       ret |=
202 	((csysi_bitstoread & (1 << csysi_bitreadpos)) != 0) << (numbits-1);
203       numbits--;
204       csysi_bitreadpos--;
205     }
206   return ret;
207 
208 }
209 
210 /******************************************************************/
211 /*        checks for next accessunit, sets bitaccesstime          */
212 /******************************************************************/
213 
214 int csysi_readaccesstime()
215 
216 {
217   int numbits = 32;
218   union { unsigned int l; float f ; } u;
219   int retry = 0;
220 
221   u.l = 0;
222   while (numbits > 0)
223     {
224       while (csysi_bitreadpos >= 0)
225 	{
226 	  u.l |=
227 	    ((csysi_bitstoread & (1 << csysi_bitreadpos)) != 0) << (numbits-1);
228 	  csysi_bitreadpos--;
229 	  if (!(--numbits))
230 	    {
231 	      csysi_bitaccesstime = u.f;
232 	      return 1;
233 	    }
234 	}
235       while (fread(&csysi_bitstoread,sizeof(char),1,csysi_bitfile)!=1)
236 	{
237 	  if (feof(csysi_bitfile))
238 	    return 0;
239 	  if (++retry > IOERROR_RETRY)
240 	    csys_terminate("i/o problems during .mp4 file read");
241 	  clearerr(csysi_bitfile);
242 	}
243       csysi_bitreadpos = 7;
244     }
245   return 0;  /* should never happen */
246 }
247 
248 
249 /******************************************************************/
250 /*           flushes numbits of bitval from bitfile                */
251 /******************************************************************/
252 
253 
254 void csysi_readflush(unsigned int numbits)
255 
256 {
257 
258   while (numbits > 0)
259     {
260       if (csysi_bitreadpos < 0)
261 	csysi_readnextbyte();
262       numbits--;
263       csysi_bitreadpos--;
264     }
265 
266 }
267 
268 /******************************************************************/
269 /*           move past midi_file block                            */
270 /******************************************************************/
271 
272 void csysi_midifileflush(void)
273 
274 {
275 
276   csysi_readflush(8*csysi_readbit(32));
277 
278 }
279 
280 /******************************************************************/
281 /*           move past symboltable block                          */
282 /******************************************************************/
283 
284 void csysi_symboltableflush(void)
285 
286 {
287   unsigned int num;
288 
289   num = csysi_readbit(16);
290   while (num > 0)
291     {
292       csysi_readflush(8*csysi_readbit(4));
293       num--;
294     }
295 }
296 
297 /******************************************************************/
298 /*           move past orcfile block                          */
299 /******************************************************************/
300 
301 void csysi_orcfileflush(void)
302 
303 {
304   unsigned int num, token;
305 
306   num = csysi_readbit(16);
307   while (num > 0)
308     {
309       token = csysi_readbit(8);
310       switch(token) {
311       case CSYSI_IDENT:
312 	csysi_readflush(16);
313 	break;
314       case CSYSI_NUMBER:
315 	csysi_readflush(32);
316 	break;
317       case CSYSI_INTGR:
318 	csysi_readflush(32);
319 	break;
320       case CSYSI_STRCONST:
321 	csysi_readflush(8*csysi_readbit(8));
322 	break;
323       case CSYSI_BYTE:
324 	csysi_readflush(8);
325 	break;
326       default:
327 	break;
328       }
329       num--;
330     }
331 }
332 
333 /******************************************************************/
334 /*           move past one score_line                             */
335 /******************************************************************/
336 
337 void csysi_scorelineflush(void)
338 
339 {
340   int hastime, haslabel, scoretype;
341   int numpfields, destroy, refers, sym;
342 
343   hastime = csysi_readbit(1);
344   if (hastime)
345     csysi_readflush(33);
346   csysi_readflush(1);
347   scoretype = csysi_readbit(3);
348   switch (scoretype) {
349   case CSYS_SASL_INSTR:
350     haslabel = csysi_readbit(1);
351     if (haslabel)
352       csysi_readflush(16);
353     csysi_readflush(48);
354     numpfields = csysi_readbit(8);
355     csysi_readflush(32*numpfields);
356     break;
357   case CSYS_SASL_CONTROL:
358     haslabel = csysi_readbit(1);
359     if (haslabel)
360       csysi_readflush(16);
361     csysi_readflush(48);
362     break;
363   case CSYS_SASL_TABLE:
364     csysi_readflush(16);
365     destroy = csysi_readbit(1);
366     if (!destroy)
367       {
368 	sym = csysi_readbit(8);
369 	refers = csysi_readbit(1);
370 	if (refers)
371 	  csysi_readflush(16);
372 	numpfields = csysi_readbit(16);
373 	if (sym == CSYS_SASL_TGEN_CONCAT)
374 	  {
375 	    csysi_readflush(32);
376 	    if ((numpfields - 1) > 0)
377 	      csysi_readflush(16*(numpfields-1));
378 	  }
379 	else
380 	  csysi_readflush(32*numpfields);
381       }
382     break;
383   case CSYS_SASL_ENDTIME:
384     break;
385   case CSYS_SASL_TEMPO:
386     csysi_readflush(32);
387     break;
388   default:
389     csys_terminate("Unknown score line type in .mp4 file");
390   }
391 
392 }
393 
394 /******************************************************************/
395 /*           move past score_file block                           */
396 /******************************************************************/
397 
398 void csysi_scorefileflush(void)
399 
400 {
401   unsigned int numlines;
402 
403   numlines = csysi_readbit(20);
404   while (numlines > 0)
405     {
406       csysi_scorelineflush();
407       numlines--;
408     }
409 }
410 
411 
412 /******************************************************************/
413 /*           move past sample block                           */
414 /******************************************************************/
415 
416 void csysi_sampleflush(void)
417 
418 {
419 
420   unsigned int len;
421 
422   csysi_readflush(16);       /* symbol */
423   len = csysi_readbit(24);
424   if (csysi_readbit(1))      /* srate */
425     csysi_readflush(17);
426   if (csysi_readbit(1))      /* loop */
427     csysi_readflush(48);
428   if (csysi_readbit(1))      /* base */
429     csysi_readflush(32);
430   csysi_readflush((16+csysi_readbit(1)*16)*len);
431 
432 }
433 
434 /******************************************************************/
435 /*          flushes StructuredAudioSpecificConfig                 */
436 /******************************************************************/
437 
438 
439 void csysi_flushconfig(void)
440 
441 {
442   int type;
443 
444   while (csysi_readbit(1))
445     {
446       type = csysi_readbit(3);
447       switch (type) {
448       case CSYSI_BINORC:
449 	csysi_orcfileflush();
450 	break;
451       case CSYSI_BINSCORE:
452 	csysi_scorefileflush();
453 	break;
454       case CSYSI_BINMIDI:
455 	csysi_midifileflush();
456 	break;
457       case CSYSI_BINSAMP:
458 	csysi_sampleflush();
459 	break;
460       case CSYSI_BINSBF:
461 	csys_terminate(".mp4 uses SASBF");
462 	break;
463       case CSYSI_BINSYM:
464 	csysi_symboltableflush();
465 	break;
466       }
467     }
468 }
469 
470 /******************************************************************/
471 /*             puts score data in saslqueue[idx]                   */
472 /******************************************************************/
473 
474 void csysi_scorelinefill(void)
475 
476 {
477   union { unsigned int l; float f ; } u;
478   int sym, i, j, sampletoken, size, skip;
479   csysi_sampleunit * sidx;
480   csysi_sevent * cq;
481 
482   if (csysi_readbit(1))      /* has_time */
483     {
484       cq = &(csysi_scoqueue[csysi_headsco]);
485       cq->atime = csysi_bitaccesstime;
486       if (csysi_tailsco == -1)
487 	csysi_tailsco = csysi_headsco;
488       csysi_headsco = (csysi_headsco+1)&(CSYSI_MAXSASL-1);
489 
490       csysi_readflush(1);   /* use_if_late */
491       u.l = csysi_readbit(32);
492       cq->stime = u.f;
493       if (u.f < 0)
494 	cq->stime = -1.0F;
495       csysi_numscotime++;
496 
497     }
498   else
499     {
500       cq = &(csysi_absqueue[csysi_headabs]);
501       cq->atime = csysi_bitaccesstime;
502       if (csysi_tailabs == -1)
503 	csysi_tailabs = csysi_headabs;
504       csysi_headabs = (csysi_headabs+1)&(CSYSI_MAXSASL-1);
505 
506       csysi_numabstime++;
507     }
508   cq->priority = csysi_readbit(1);
509   switch (cq->cmd = csysi_readbit(3)) {
510   case CSYS_SASL_INSTR:
511     if (csysi_readbit(1)) /* has label */
512       cq->label = csysi_readbit(16);
513     else
514       cq->label = CSYS_NOLABEL;
515     cq->cmd = CSYS_SASL_NOOP;
516     sym = csysi_readbit(16);  /* token for instr */
517     for (i=0; i < CSYS_INSTRNUM; i++)
518       if (csys_instr[i].token == sym)
519 	{
520 	  cq->cmd = CSYS_SASL_INSTR;
521 	  cq->id = csys_instr[i].index;
522 	}
523     u.l = csysi_readbit(32);
524     cq->fval = u.f;  /* duration */
525 
526     /* pfields */
527     cq->p = malloc((cq->pnum = csysi_readbit(8))*sizeof(float));
528     for (i = 0; i < cq->pnum; i++)
529       {
530 	u.l = csysi_readbit(32);
531 	cq->p[i] =  u.f;
532       }
533     break;
534   case CSYS_SASL_CONTROL:
535     if (csysi_readbit(1)) /* has label */
536       {
537 	/* expands into to a set of calls later on */
538 
539 	cq->label = csysi_readbit(16);
540 	cq->pnum = csysi_readbit(16);
541       }
542     else
543       {
544 	sym = csysi_readbit(16);
545 	cq->cmd = CSYS_SASL_NOOP;
546 	cq->label = CSYS_NOLABEL;
547 	cq->id = CSYS_SASL_NOINSTR;
548 	for (i=0; i < CSYS_GLOBALNUM; i++)
549 	  if (csys_global[i].token == sym)
550 	    {
551 	      cq->cmd = CSYS_SASL_CONTROL;
552 	      cq->pnum = csys_global[i].index;
553 	      break;
554 	    }
555       }
556     u.l = csysi_readbit(32);
557     cq->fval = u.f;
558     break;
559   case CSYS_SASL_TABLE:
560     sidx = NULL;
561     sym = csysi_readbit(16);
562     if (csysi_readbit(1)) /* destroy */
563       {
564 	cq->label = CSYS_SASL_TGEN_DESTROY;
565 	cq->pnum = 0;
566 	cq->p = NULL;
567       }
568     else
569       {
570 	cq->label = csysi_readbit(8); /* generator */
571 	if (csysi_readbit(1)) /* refers to sample */
572 	  {
573 	    sampletoken = csysi_readbit(16);
574 	    sidx = csysi_samples;
575 	    while (sidx)
576 	      {
577 		if (sidx->token == sampletoken)
578 		  {
579 		    while (sidx->next &&
580 			   (sidx->next->token == sampletoken) &&
581 			   (sidx->next->atime <= csysi_bitaccesstime))
582 		      sidx = sidx->next;
583 		    break;
584 		  }
585 		sidx = sidx->next;
586 	      }
587 	  }
588 	cq->p = malloc((cq->pnum = csysi_readbit(16))*sizeof(float));
589 	for (i = 0; i < cq->pnum; i++)
590 	  {
591 	    if (i && (cq->label == CSYS_SASL_TGEN_CONCAT))
592 	      {
593 		u.l = csysi_readbit(16);
594 		cq->p[i] = -1.0F;
595 		for (j=0; j < CSYS_GLOBALNUM; j++)
596 		  if ((csys_global[j].token == u.l) &&
597 		      (csys_global[j].type == CSYS_TABLE))
598 		    {
599 		      cq->p[i] = csys_global[j].index;
600 		      break;
601 		    }
602 		if (cq->p[i] == -1.0F)
603 		  csys_terminate("concat uses an unknown table");
604 	      }
605 	    else
606 	      {
607 		u.l = csysi_readbit(32);
608 		cq->p[i] = u.f;
609 	      }
610 	  }
611 	cq->cmd = CSYS_SASL_NOOP;
612 	for (i=0; i < CSYS_GLOBALNUM; i++)
613 	  if ((csys_global[i].token == sym) &&
614 	      (csys_global[i].type == CSYS_TABLE))
615 	    {
616 	      cq->cmd = CSYS_SASL_TABLE;
617 	      cq->id = csys_global[i].index;
618 	      break;
619 	    }
620 	if (cq->label == CSYS_SASL_TGEN_SAMPLE)
621 	  {
622 	    if (!sidx)
623 	      csys_terminate("sample block not found");
624 
625 	    size = -1;
626 	    skip = 0;
627 	    if (cq->pnum)
628 	      size = ROUND(cq->p[0]);
629 	    if (cq->pnum > 2)
630 	      skip = ROUND(cq->p[2]);
631 	    /* free (cq->p); */
632 	    if ( ((size < 0) || (size + SAMP_DATABLOCK <= sidx->len))
633 		 && (skip <= 0))
634 	      {
635 		cq->p = sidx->p;
636 		if (size < 0)
637 		  cq->pnum = sidx->len;
638 		else
639 		  cq->pnum = size + SAMP_DATABLOCK;
640 	      }
641 	    else
642 	      {
643 		if (size < 0)
644 		  cq->pnum = size = sidx->len - skip;
645 		else
646 		  cq->pnum = size = size + SAMP_DATABLOCK;
647 		cq->p = calloc(size, sizeof(float));
648 		cq->p[size - SAMP_LLMEM] = 1;
649 		cq->p[size - SAMP_SR] = sidx->p[sidx->len - SAMP_SR];
650 		cq->p[size - SAMP_LOOPSTART] =
651 		  ROUND(sidx->p[sidx->len - SAMP_LOOPSTART]) - skip;
652 		cq->p[size - SAMP_LOOPEND] =
653 		  ROUND(sidx->p[sidx->len - SAMP_LOOPEND]) - skip;
654 		cq->p[size - SAMP_BASEFREQ] =
655 		  sidx->p[sidx->len - SAMP_BASEFREQ];
656 		j = skip;
657 		i = 0;
658 		while ((i < (size - SAMP_DATABLOCK)) && (j < (sidx->len - SAMP_DATABLOCK)))
659 		  cq->p[i++] = sidx->p[j++];
660 	      }
661 	  }
662       }
663     break;
664   case CSYS_SASL_ENDTIME:
665     csysi_endflag = 1;    /* obey SASL endtime command */
666     break;
667   case CSYS_SASL_TEMPO:
668     u.l = csysi_readbit(32);
669     cq->fval = u.f;
670     break;
671   default:
672     csys_terminate("Unknown score line type in .mp4 file");
673   }
674 
675 }
676 
677 /******************************************************************/
678 /*             reads the sample class                             */
679 /******************************************************************/
680 
681 void csysi_sampleread(void)
682 
683 {
684   int sym, i, len;
685   csysi_sampleunit * sidx, * newsamp;
686   union { unsigned int l; float f ; } u;
687   union { unsigned short us; signed short ss ; } s;
688 
689   sidx = (csysi_sampleunit *) malloc(sizeof(csysi_sampleunit));
690   sidx->token = sym = csysi_readbit(16);
691   sidx->len = len = csysi_readbit(24) + SAMP_DATABLOCK;
692   sidx->p = (float *) malloc(len*sizeof(float));
693 
694   sidx->p[len - SAMP_LLMEM] = 0;
695   if (csysi_readbit(1))  /* sampling rate */
696     sidx->p[len - SAMP_SR] = csysi_readbit(17);
697   else
698     sidx->p[len - SAMP_SR] = EV(ARATE);
699 
700   if (csysi_readbit(1))  /* loop points */
701     {
702       sidx->p[len - SAMP_LOOPSTART] = csysi_readbit(24);
703       sidx->p[len - SAMP_LOOPEND] = csysi_readbit(24);
704     }
705   else
706     {
707       sidx->p[len - SAMP_LOOPSTART] = -1;
708       sidx->p[len - SAMP_LOOPEND] = -1;
709     }
710 
711   if (csysi_readbit(1))  /* base frequency */
712     {
713       u.l = csysi_readbit(32);
714       sidx->p[len - SAMP_BASEFREQ] = u.f;
715     }
716   else
717     sidx->p[len - SAMP_BASEFREQ] = -1;
718 
719   i = 0;
720   if (csysi_readbit(1))  /* float sample */
721     {
722       while (i < (len - SAMP_DATABLOCK))
723 	{
724 	  u.l = csysi_readbit(32);
725 	  sidx->p[i++] = u.f;
726 	}
727     }
728   else
729     {
730       while (i < (len - SAMP_DATABLOCK))
731 	{
732 	  s.us = csysi_readbit(16);
733 	  sidx->p[i++] = s.ss*(1.0F/32767.0F);
734 	}
735     }
736 
737   newsamp = sidx;
738 
739   if (!csysi_samples)
740     {
741       csysi_samples = newsamp;
742       return;
743     }
744 
745   if ((sidx = csysi_samples)->token > sym)
746     {
747       newsamp->next = csysi_samples;
748       csysi_samples = newsamp;
749       return;
750     }
751 
752   while (sidx && (sidx->token <= sym))
753     {
754 
755       if ((sidx->next == NULL) ||
756 	  (sidx->next->token > sym))
757 	break;
758 
759       if (sidx->token == sym)
760 	{
761 	  while (sidx->next && (sidx->next->token == sym))
762 	    sidx = sidx->next;
763 	  break;
764 	}
765       sidx = sidx->next;
766     }
767 
768   newsamp->next = sidx->next;
769   sidx->next = newsamp;
770   return;
771 
772 }
773 
774 /******************************************************************/
775 /*             checks if buffer is empty                          */
776 /******************************************************************/
777 
778 int csysi_emptycheck(int len, csysi_mevent * mq)
779 
780 {
781   if (len)
782     return 0;
783 
784   mq->cmd = CSYS_MIDI_NOOP;
785   return 1;
786 }
787 
788 
789 /******************************************************************/
790 /*             puts midi data in csysi_midiqueue[idx]             */
791 /******************************************************************/
792 
793 void csysi_midilinefill(void)
794 
795 {
796   int len, system, bpm;
797   unsigned char nextbyte;
798   csysi_mevent * mq;
799 
800   mq = &(csysi_midiqueue[csysi_headmidi]);
801   mq->atime = csysi_bitaccesstime;
802 
803   if (csysi_tailmidi == -1)
804     csysi_tailmidi = csysi_headmidi;
805   csysi_headmidi = (csysi_headmidi+1)&(CSYSI_MAXMIDI-1);
806 
807   len = csysi_readbit(24);
808 
809   csysi_nummidi++;
810   if (csysi_emptycheck(len, mq))
811     return;
812   nextbyte = (unsigned char)csysi_readbit(8);
813   len--;
814 
815   if (!(nextbyte & 0x80))
816     {
817       mq->cmd = csysi_runstat;
818       mq->ndata = nextbyte;
819     }
820   else
821     {
822       mq->cmd = nextbyte;
823       if ((nextbyte & CSYSI_MIDIMASKCOM) != CSYSI_MIDISYSTEM)
824 	{
825 	  csysi_runstat = nextbyte;
826 	  if (csysi_emptycheck(len, mq))
827 	    return;
828 	  mq->ndata = (unsigned char)csysi_readbit(8);
829 	  len--;
830 	}
831     }
832 
833   mq->extchan = CSYSI_MIDIMASKCHAN & mq->cmd;
834 
835   switch ((mq->cmd)&CSYSI_MIDIMASKCOM) {
836   case CSYS_MIDI_NOTEOFF:  /* two byte commands */
837   case CSYS_MIDI_NOTEON:
838   case CSYS_MIDI_PTOUCH:
839   case CSYS_MIDI_WHEEL:
840   case CSYS_MIDI_CC:
841     if (csysi_emptycheck(len, mq))
842       return;
843     mq->vdata = (unsigned char)csysi_readbit(8);
844     len--;
845     break;
846   case CSYS_MIDI_CTOUCH:   /* one byte commands */
847   case CSYS_MIDI_PROGRAM:
848     break;
849   case CSYSI_MIDISYSTEM:   /* tempo command */
850     if (mq->cmd != 0xFF)
851       break;
852     if (csysi_emptycheck(len, mq))
853       return;
854     if (((unsigned char)csysi_readbit(8)) != CSYSI_METATEMPO )
855       {
856 	len--;
857 	break;
858       }
859     len--;
860 
861     if (len >= 4)
862       {
863 	csysi_readflush(8);
864 	bpm = csysi_readbit(24);
865 	len -= 4;
866 	if (bpm)
867 	  {
868 	    mq->fval = 60e6F/bpm;
869 	    mq->cmd = CSYS_MIDI_NEWTEMPO;
870 	  }
871 	else
872 	  mq->cmd = CSYS_MIDI_NOOP;
873       }
874     else
875       mq->cmd = CSYS_MIDI_NOOP;
876 
877     break;
878   }
879 
880   csysi_readflush(len*8);  /* one command per event, spec says */
881 
882 }
883 
884 /******************************************************************/
885 /*             finds next streaming score event                   */
886 /******************************************************************/
887 
888 int csysi_readnewevent(void)
889 
890 {
891   int type, ret;
892 
893   if (ret = csysi_readbit(1))  /* more data here */
894     {
895       type = csysi_readbit(2);
896       switch (type)
897 	{
898 	case CSYSI_EVSCORE:
899 	  csysi_scorelinefill();
900 	  break;
901 	case CSYSI_EVMIDI:
902 	  csysi_midilinefill();
903 	  break;
904 	case CSYSI_EVSAMPLE:
905 	  csysi_sampleread();
906 	  break;
907 	default:
908 	  csys_terminate("Unknown event type in .mp4 file");
909 	}
910     }
911   return ret;
912 
913 }
914 
915 /******************************************************************/
916 /*        adds an endtime command to a queue                      */
917 /******************************************************************/
918 
919 int csysi_setendtime(float fval)
920 
921 {
922   int ret = 0;
923 
924   if ((csysi_headmidi&(CSYSI_MAXMIDI-1)) != csysi_tailmidi)
925     {
926       csysi_midiqueue[csysi_headmidi].atime = csysi_bitaccesstime;
927       csysi_midiqueue[csysi_headmidi].cmd = CSYS_MIDI_ENDTIME;
928       csysi_midiqueue[csysi_headmidi].fval = fval;
929       if (csysi_tailmidi == -1)
930 	csysi_tailmidi = csysi_headmidi;
931       csysi_headmidi = (csysi_headmidi+1)&(CSYSI_MAXMIDI-1);
932       csysi_nummidi++;
933       ret = 1;
934     }
935   return ret;
936 
937 }
938 
939 
940 /****************************************************************/
941 /*           fill sasl and midi queues with more data           */
942 /****************************************************************/
943 
944 void csysi_fillqueues(void)
945 
946 {
947   /* while data is left in file, and room left in queues, */
948   /* fill queues with more data                           */
949 
950   while (csysi_moreaccessunits &&
951       ((csysi_headsco&(CSYSI_MAXSASL-1)) != csysi_tailsco) &&
952       ((csysi_headabs&(CSYSI_MAXSASL-1)) != csysi_tailabs) &&
953       ((csysi_headmidi&(CSYSI_MAXMIDI-1)) != csysi_tailmidi))
954     {
955       if (csysi_endofevent)
956 	{
957 	  csysi_moreaccessunits = csysi_readaccesstime();
958 	}
959       if (csysi_moreaccessunits)
960 	{
961 	  csysi_endofevent = !csysi_readnewevent();
962 	}
963     }
964 
965   if (!(CSYS_GIVENENDTIME) && !csysi_moreaccessunits &&
966       !(csysi_endflag))
967     {
968       csysi_endflag = csysi_setendtime(csysi_compendtime);
969     }
970 
971   return;
972 
973 }
974 
975 /****************************************************************/
976 /*           finds, opens, and seeks streaming file             */
977 /****************************************************************/
978 
979 void csysi_openfile(void)
980 
981 {
982   int i;
983   char * name;
984 
985   /* first search ./sa file command line for .mp4 file */
986 
987   for (i=1;i<EV(csys_argc); i++)
988     if (!strcmp(EV(csys_argv[i]),"-csys_fstr_file"))
989       {
990 	i++;
991 	if (i == EV(csys_argc))
992 	  csys_terminate(".mp4 file not specified");
993 	if (!(csysi_bitfile = fopen(EV(csys_argv[i]),"rb")))
994 	  {
995 	    name = (char *) calloc(strlen(EV(csys_argv[i]))+5, sizeof(char));
996 	    sprintf(name,"%s.mp4",EV(csys_argv[i]));
997 	    if (!(csysi_bitfile = fopen(name,"rb")))
998 	      csys_terminate(".mp4 file not found");
999 	  }
1000 	break;
1001       }
1002 
1003   /* then look though sfront command line for -bitc */
1004 
1005   if (!csysi_bitfile)
1006     {
1007       for (i=1;i<csys_sfront_argc; i++)
1008 	if (!strcmp(csys_sfront_argv[i],"-bitc"))
1009 	  {
1010 	    i++;
1011 	    if (i == csys_sfront_argc)
1012 	      csys_terminate("-bitc file.mp4 unspecified");
1013 	    if (!(csysi_bitfile = fopen(csys_sfront_argv[i],"rb")))
1014 	      {
1015 		name = (char *) calloc(strlen(csys_sfront_argv[i])+5,
1016 				       sizeof(char));
1017 		sprintf(name,"%s.mp4",csys_sfront_argv[i]);
1018 		if (!(csysi_bitfile = fopen(name,"rb")))
1019 		  csys_terminate("-bitc file.mp4 not found");
1020 	      }
1021 	    break;
1022 	  }
1023     }
1024 
1025   if (!csysi_bitfile)
1026     csys_terminate(
1027 	"Syntax: ./sa -csys_fstr_file file.mp4, or sfront -bitc file.mp4");
1028 
1029   /* if an explicit SASL endtime not give, invalidate computed endtime */
1030 
1031   if (!(CSYS_GIVENENDTIME))
1032     {
1033       csysi_compendtime = EV(endtime);
1034       if (!csysi_setendtime(CSYSI_MAXENDTIME))
1035 	csys_terminate("problem setting init endtime");
1036     }
1037 
1038   /* skip to access_units, fill up queues */
1039 
1040   csysi_flushconfig();
1041   csysi_fillqueues();
1042 
1043 }
1044 
1045 /****************************************************************/
1046 /*             initialization routine for control               */
1047 /****************************************************************/
1048 
1049 int csys_setup(void)
1050 
1051 {
1052   csysi_openfile();
1053   return CSYS_DONE;
1054 }
1055 
1056 
1057 /****************************************************************/
1058 /*             polling routine for new data                     */
1059 /****************************************************************/
1060 
1061 int csys_newdata(void)
1062 
1063 {
1064   int i, found;
1065 
1066   csysi_absready = 0;
1067   csysi_scoready = 0;
1068   csysi_midiready = 0;
1069 
1070   csysi_fillqueues();
1071 
1072   /* see if an event is ready */
1073 
1074   i = csysi_tailsco;
1075   found = ((i = csysi_tailsco) < 0);
1076   while (csysi_numscotime && !found)
1077     {
1078       if (csysi_scoqueue[i].stime <= EV(scorebeats))
1079 	csysi_scoready++;
1080       else
1081 	found = 1;
1082       i = (i+1)&(CSYSI_MAXSASL-1);
1083       if (i == csysi_headsco)
1084 	found = 1;
1085     }
1086 
1087   i = csysi_tailabs;
1088   found = ((i = csysi_tailabs) < 0);
1089   while (csysi_numabstime && !found)
1090     {
1091       if (csysi_absqueue[i].atime < EV(absolutetime))
1092 	csysi_absready++;
1093       else
1094 	found = 1;
1095       i = (i+1)&(CSYSI_MAXSASL-1);
1096       if (i == csysi_headabs)
1097 	found = 1;
1098     }
1099 
1100   i = csysi_tailmidi;
1101   found = ((i = csysi_tailmidi) < 0);
1102   while (csysi_nummidi && !found)
1103     {
1104       if (csysi_midiqueue[i].atime < EV(absolutetime))
1105 	csysi_midiready++;
1106       else
1107 	found = 1;
1108       i = (i+1)&(CSYSI_MAXMIDI-1);
1109       if (i == csysi_headmidi)
1110 	found = 1;
1111     }
1112 
1113   if (csysi_midiready)
1114     {
1115       if ((csysi_absready || csysi_scoready))
1116 	return CSYS_EVENTS;
1117       else
1118 	return CSYS_MIDIEVENTS;
1119     }
1120   else
1121     {
1122       if ((csysi_absready || csysi_scoready))
1123 	return CSYS_SASLEVENTS;
1124       else
1125 	return CSYS_NONE;
1126     }
1127 
1128 }
1129 
1130 /****************************************************************/
1131 /*                 processes a SASL event                       */
1132 /****************************************************************/
1133 
1134 int csys_saslevent(unsigned char * cmd, unsigned char * priority,
1135 		   unsigned short * id, unsigned short * label,
1136 		   float * fval, unsigned int * pnum, float ** p)
1137 
1138 {
1139   int i, done, j, scofound;
1140   csysi_sevent * cq;
1141 
1142 
1143   done = 1;
1144   if (csysi_scoready)
1145     {
1146       cq = &(csysi_scoqueue[csysi_tailsco]);
1147       scofound = 1;
1148     }
1149   else
1150     {
1151       if (csysi_absready)
1152 	{
1153 	  cq = &(csysi_absqueue[csysi_tailabs]);
1154 	  scofound = 0;
1155 	}
1156       else
1157 	csys_terminate("saslevent() queue error");
1158     }
1159 
1160   *priority = cq->priority;
1161   *id = cq->id;
1162   *label = cq->label;
1163   *fval = cq->fval;
1164   *pnum = cq->pnum;
1165   *p = cq->p;
1166 
1167   switch (*cmd = cq->cmd) {
1168   case CSYS_SASL_ENDTIME :
1169     *fval = EV(scorebeats);
1170     break;
1171   case CSYS_SASL_NOOP :
1172   case CSYS_SASL_TEMPO :
1173   case CSYS_SASL_TABLE :
1174   case CSYS_SASL_INSTR :
1175     break;
1176   case CSYS_SASL_CONTROL :
1177     if ((*id) == CSYS_SASL_NOINSTR)
1178       break;
1179     if (csysi_targetvar == -1)
1180       {
1181 	csysi_targetvar=0;
1182 	while (csysi_targetvar < CSYS_TARGETNUM)
1183 	  {
1184 	    if (csys_target[csysi_targetvar].token == (*pnum))
1185 	      break;
1186 	    csysi_targetvar++;
1187 	  }
1188 	if (csysi_targetvar == CSYS_TARGETNUM)
1189 	  {
1190 	    /* specified variable not imported -- abort command */
1191 	    *cmd = CSYS_SASL_NOOP;
1192 	    csysi_targetvar = -1;
1193 	    break;
1194 	  }
1195 	csysi_targetcount = 0;
1196       }
1197     *id = csys_target[csysi_targetvar].instrindex[csysi_targetcount];
1198     *pnum = csys_target[csysi_targetvar].varindex[csysi_targetcount];
1199     if ((++csysi_targetcount) < csys_target[csysi_targetvar].numinstr)
1200       done = 0;
1201     else
1202       csysi_targetvar = -1;
1203     break;
1204   }
1205 
1206   if (done)
1207     {
1208       if (scofound)
1209 	{
1210 	  csysi_scoready--;
1211 	  csysi_numscotime--;
1212 	  csysi_tailsco = (csysi_tailsco+1)&(CSYSI_MAXSASL-1);
1213 	  if (csysi_tailsco == csysi_headsco)  /* empty */
1214 	    {
1215 	      csysi_headsco = 0;
1216 	      csysi_tailsco = -1;
1217 	    }
1218 	}
1219       else
1220 	{
1221 	  csysi_absready--;
1222 	  csysi_numabstime--;
1223 	  csysi_tailabs = (csysi_tailabs+1)&(CSYSI_MAXSASL-1);
1224 	  if (csysi_tailabs == csysi_headabs)  /* empty */
1225 	    {
1226 	      csysi_headabs = 0;
1227 	      csysi_tailabs = -1;
1228 	    }
1229 	}
1230     }
1231 
1232   if (csysi_scoready || csysi_absready)
1233     return CSYS_SASLEVENTS;
1234   else
1235     return CSYS_NONE;
1236 
1237 }
1238 
1239 
1240 /****************************************************************/
1241 /*                  closing routine for control                 */
1242 /****************************************************************/
1243 
1244 void csys_shutdown(void)
1245 
1246 {
1247 }
1248 
1249 
1250 /****************************************************************/
1251 /*                 processes a MIDI event                       */
1252 /****************************************************************/
1253 
1254 
1255 int csys_midievent(unsigned char * cmd,   unsigned char * ndata,
1256 	           unsigned char * vdata, unsigned short * extchan,
1257 		   float * fval)
1258 
1259 {
1260 
1261   int i = csysi_tailmidi;
1262 
1263   *cmd = csysi_midiqueue[i].cmd;
1264   *ndata = csysi_midiqueue[i].ndata;
1265   *vdata = csysi_midiqueue[i].vdata;
1266   *extchan = csysi_midiqueue[i].extchan;
1267   *fval = csysi_midiqueue[i].fval;
1268 
1269   if (*cmd == CSYS_MIDI_ENDTIME)
1270     *fval = (*fval > EV(scorebeats) + 5.0F) ? *fval : EV(scorebeats) + 5.0F;
1271 
1272   csysi_midiready--;
1273   csysi_nummidi--;
1274 
1275   csysi_tailmidi = (csysi_tailmidi+1)&(CSYSI_MAXMIDI-1);
1276   if (csysi_tailmidi == csysi_headmidi)  /* empty */
1277     {
1278       csysi_headmidi = 0;
1279       csysi_tailmidi = -1;
1280     }
1281 
1282   if (csysi_midiready)
1283     return CSYS_MIDIEVENTS;
1284   else
1285     return CSYS_NONE;
1286 
1287 }
1288 
1289 #undef SAMP_SR
1290 #undef SAMP_LOOPSTART
1291 #undef SAMP_LOOPEND
1292 #undef SAMP_BASEFREQ
1293 #undef SAMP_DATABLOCK
1294 
1295 
1296