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