1 /*---------------------------------------------------------------------------- 2 * 3 * File: 4 * eas_smf.c 5 * 6 * Contents and purpose: 7 * SMF Type 0 and 1 File Parser 8 * 9 * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". 10 * 11 * Copyright Sonic Network Inc. 2005 12 13 * Licensed under the Apache License, Version 2.0 (the "License"); 14 * you may not use this file except in compliance with the License. 15 * You may obtain a copy of the License at 16 * 17 * http://www.apache.org/licenses/LICENSE-2.0 18 * 19 * Unless required by applicable law or agreed to in writing, software 20 * distributed under the License is distributed on an "AS IS" BASIS, 21 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 22 * See the License for the specific language governing permissions and 23 * limitations under the License. 24 * 25 *---------------------------------------------------------------------------- 26 * Revision Control: 27 * $Revision: 803 $ 28 * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ 29 *---------------------------------------------------------------------------- 30 */ 31 32 #include "log/log.h" 33 34 #include "eas_data.h" 35 #include "eas_miditypes.h" 36 #include "eas_parser.h" 37 #include "eas_report.h" 38 #include "eas_host.h" 39 #include "eas_midi.h" 40 #include "eas_config.h" 41 #include "eas_vm_protos.h" 42 #include "eas_smfdata.h" 43 #include "eas_smf.h" 44 45 #ifdef JET_INTERFACE 46 #include "jet_data.h" 47 #endif 48 49 //3 dls: The timebase for this module is adequate to keep MIDI and 50 //3 digital audio synchronized for only a few minutes. It should be 51 //3 sufficient for most mobile applications. If better accuracy is 52 //3 required, more fractional bits should be added to the timebase. 53 54 static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; 55 56 /* local prototypes */ 57 static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); 58 static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); 59 static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); 60 static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); 61 static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); 62 static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); 63 64 65 /*---------------------------------------------------------------------------- 66 * 67 * SMF_Parser 68 * 69 * This structure contains the functional interface for the SMF parser 70 *---------------------------------------------------------------------------- 71 */ 72 const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = 73 { 74 SMF_CheckFileType, 75 SMF_Prepare, 76 SMF_Time, 77 SMF_Event, 78 SMF_State, 79 SMF_Close, 80 SMF_Reset, 81 SMF_Pause, 82 SMF_Resume, 83 NULL, 84 SMF_SetData, 85 SMF_GetData, 86 NULL 87 }; 88 89 /*---------------------------------------------------------------------------- 90 * SMF_CheckFileType() 91 *---------------------------------------------------------------------------- 92 * Purpose: 93 * Check the file type to see if we can parse it 94 * 95 * Inputs: 96 * pEASData - pointer to overall EAS data structure 97 * handle - pointer to file handle 98 * 99 * Outputs: 100 * 101 * 102 * Side Effects: 103 * 104 *---------------------------------------------------------------------------- 105 */ 106 EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) 107 { 108 S_SMF_DATA* pSMFData; 109 EAS_RESULT result; 110 111 /* seek to starting offset - usually 0 */ 112 *ppHandle = NULL; 113 if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) 114 return result; 115 116 /* search through file for header - slow method */ 117 if (pEASData->searchHeaderFlag) 118 { 119 result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); 120 if (result != EAS_SUCCESS) 121 return (result == EAS_EOF) ? EAS_SUCCESS : result; 122 } 123 124 /* read the first 4 bytes of the file - quick method */ 125 else { 126 EAS_U8 header[4]; 127 EAS_I32 count; 128 if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) 129 return result; 130 131 /* check for 'MTrk' - return if no match */ 132 if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) 133 return EAS_SUCCESS; 134 } 135 136 /* check for static memory allocation */ 137 if (pEASData->staticMemoryModel) 138 pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); 139 else 140 { 141 pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); 142 EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); 143 } 144 if (!pSMFData) 145 return EAS_ERROR_MALLOC_FAILED; 146 147 /* initialize some critical data */ 148 pSMFData->fileHandle = fileHandle; 149 pSMFData->fileOffset = offset; 150 pSMFData->pSynth = NULL; 151 pSMFData->time = 0; 152 pSMFData->state = EAS_STATE_OPEN; 153 *ppHandle = pSMFData; 154 155 return EAS_SUCCESS; 156 } 157 158 /*---------------------------------------------------------------------------- 159 * SMF_Prepare() 160 *---------------------------------------------------------------------------- 161 * Purpose: 162 * Prepare to parse the file. Allocates instance data (or uses static allocation for 163 * static memory model). 164 * 165 * Inputs: 166 * pEASData - pointer to overall EAS data structure 167 * handle - pointer to file handle 168 * 169 * Outputs: 170 * 171 * 172 * Side Effects: 173 * 174 *---------------------------------------------------------------------------- 175 */ 176 EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 177 { 178 S_SMF_DATA* pSMFData; 179 EAS_RESULT result; 180 181 /* check for valid state */ 182 pSMFData = (S_SMF_DATA *) pInstData; 183 if (pSMFData->state != EAS_STATE_OPEN) 184 return EAS_ERROR_NOT_VALID_IN_THIS_STATE; 185 186 /* instantiate a synthesizer */ 187 if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) 188 { 189 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } 190 return result; 191 } 192 193 /* parse the file header and setup the individual stream parsers */ 194 if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) 195 return result; 196 197 /* ready to play */ 198 pSMFData->state = EAS_STATE_READY; 199 return EAS_SUCCESS; 200 } 201 202 /*---------------------------------------------------------------------------- 203 * SMF_Time() 204 *---------------------------------------------------------------------------- 205 * Purpose: 206 * Returns the time of the next event in msecs 207 * 208 * Inputs: 209 * pEASData - pointer to overall EAS data structure 210 * handle - pointer to file handle 211 * pTime - pointer to variable to hold time of next event (in msecs) 212 * 213 * Outputs: 214 * 215 * 216 * Side Effects: 217 * 218 *---------------------------------------------------------------------------- 219 */ 220 /*lint -esym(715, pEASData) reserved for future use */ 221 EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) 222 { 223 S_SMF_DATA *pSMFData; 224 225 pSMFData = (S_SMF_DATA*) pInstData; 226 227 /* sanity check */ 228 #ifdef _CHECKED_BUILD 229 if (pSMFData->state == EAS_STATE_STOPPED) 230 { 231 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } 232 } 233 234 if (pSMFData->nextStream == NULL) 235 { 236 { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } 237 } 238 #endif 239 240 #if 0 241 /* return time in milliseconds */ 242 /* if chase mode, lie about time */ 243 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 244 *pTime = 0; 245 246 else 247 #endif 248 249 /*lint -e{704} use shift instead of division */ 250 *pTime = pSMFData->time >> 8; 251 252 *pTime = pSMFData->time >> 8; 253 return EAS_SUCCESS; 254 } 255 256 /*---------------------------------------------------------------------------- 257 * SMF_Event() 258 *---------------------------------------------------------------------------- 259 * Purpose: 260 * Parse the next event in the file 261 * 262 * Inputs: 263 * pEASData - pointer to overall EAS data structure 264 * handle - pointer to file handle 265 * 266 * Outputs: 267 * 268 * 269 * Side Effects: 270 * 271 *---------------------------------------------------------------------------- 272 */ 273 EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) 274 { 275 S_SMF_DATA* pSMFData; 276 EAS_RESULT result; 277 EAS_I32 i; 278 EAS_U32 ticks; 279 EAS_U32 temp; 280 281 /* establish pointer to instance data */ 282 pSMFData = (S_SMF_DATA*) pInstData; 283 if (pSMFData->state >= EAS_STATE_OPEN) 284 return EAS_SUCCESS; 285 286 if (!pSMFData->nextStream) { 287 return EAS_ERROR_FILE_FORMAT; 288 } 289 290 291 /* get current ticks */ 292 ticks = pSMFData->nextStream->ticks; 293 294 /* assume that an error occurred */ 295 pSMFData->state = EAS_STATE_ERROR; 296 297 #ifdef JET_INTERFACE 298 /* if JET has track muted, set parser mode to mute */ 299 if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) 300 parserMode = eParserModeMute; 301 #endif 302 303 /* parse the next event from all the streams */ 304 if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) 305 { 306 /* check for unexpected end-of-file */ 307 if (result != EAS_EOF) 308 return result; 309 310 /* indicate end of track for this stream */ 311 pSMFData->nextStream->ticks = SMF_END_OF_TRACK; 312 } 313 314 /* get next delta time, unless already at end of track */ 315 else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) 316 { 317 if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) 318 { 319 /* check for unexpected end-of-file */ 320 if (result != EAS_EOF) 321 return result; 322 323 /* indicate end of track for this stream */ 324 pSMFData->nextStream->ticks = SMF_END_OF_TRACK; 325 } 326 327 /* if zero delta to next event, stay with this stream */ 328 else if (pSMFData->nextStream->ticks == ticks) 329 { 330 pSMFData->state = EAS_STATE_PLAY; 331 return EAS_SUCCESS; 332 } 333 } 334 335 /* find next event in all streams */ 336 temp = 0x7ffffff; 337 pSMFData->nextStream = NULL; 338 for (i = 0; i < pSMFData->numStreams; i++) 339 { 340 if (pSMFData->streams[i].ticks < temp) 341 { 342 temp = pSMFData->streams[i].ticks; 343 pSMFData->nextStream = &pSMFData->streams[i]; 344 } 345 } 346 347 /* are there any more events to parse? */ 348 if (pSMFData->nextStream) 349 { 350 pSMFData->state = EAS_STATE_PLAY; 351 352 /* update the time of the next event */ 353 SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); 354 } 355 else 356 { 357 pSMFData->state = EAS_STATE_STOPPING; 358 VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); 359 } 360 361 return EAS_SUCCESS; 362 } 363 364 /*---------------------------------------------------------------------------- 365 * SMF_State() 366 *---------------------------------------------------------------------------- 367 * Purpose: 368 * Returns the current state of the stream 369 * 370 * Inputs: 371 * pEASData - pointer to overall EAS data structure 372 * handle - pointer to file handle 373 * pState - pointer to variable to store state 374 * 375 * Outputs: 376 * 377 * 378 * Side Effects: 379 * 380 *---------------------------------------------------------------------------- 381 */ 382 /*lint -esym(715, pEASData) reserved for future use */ 383 EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) 384 { 385 S_SMF_DATA* pSMFData; 386 387 /* establish pointer to instance data */ 388 pSMFData = (S_SMF_DATA*) pInstData; 389 390 /* if stopping, check to see if synth voices are active */ 391 if (pSMFData->state == EAS_STATE_STOPPING) 392 { 393 if (VMActiveVoices(pSMFData->pSynth) == 0) 394 pSMFData->state = EAS_STATE_STOPPED; 395 } 396 397 if (pSMFData->state == EAS_STATE_PAUSING) 398 { 399 if (VMActiveVoices(pSMFData->pSynth) == 0) 400 pSMFData->state = EAS_STATE_PAUSED; 401 } 402 403 /* return current state */ 404 *pState = pSMFData->state; 405 return EAS_SUCCESS; 406 } 407 408 /*---------------------------------------------------------------------------- 409 * SMF_Close() 410 *---------------------------------------------------------------------------- 411 * Purpose: 412 * Close the file and clean up 413 * 414 * Inputs: 415 * pEASData - pointer to overall EAS data structure 416 * handle - pointer to file handle 417 * 418 * Outputs: 419 * 420 * 421 * Side Effects: 422 * 423 *---------------------------------------------------------------------------- 424 */ 425 EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 426 { 427 S_SMF_DATA* pSMFData; 428 EAS_I32 i; 429 EAS_RESULT result; 430 431 pSMFData = (S_SMF_DATA*) pInstData; 432 433 /* close all the streams */ 434 for (i = 0; i < pSMFData->numStreams; i++) 435 { 436 if (pSMFData->streams[i].fileHandle != NULL) 437 { 438 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) 439 return result; 440 } 441 } 442 if (pSMFData->fileHandle != NULL) 443 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) 444 return result; 445 446 /* free the synth */ 447 if (pSMFData->pSynth != NULL) 448 VMMIDIShutdown(pEASData, pSMFData->pSynth); 449 450 /* if using dynamic memory, free it */ 451 if (!pEASData->staticMemoryModel) 452 { 453 if (pSMFData->streams) 454 EAS_HWFree(pEASData->hwInstData, pSMFData->streams); 455 456 /* free the instance data */ 457 EAS_HWFree(pEASData->hwInstData, pSMFData); 458 } 459 460 return EAS_SUCCESS; 461 } 462 463 /*---------------------------------------------------------------------------- 464 * SMF_Reset() 465 *---------------------------------------------------------------------------- 466 * Purpose: 467 * Reset the sequencer. Used for locating backwards in the file. 468 * 469 * Inputs: 470 * pEASData - pointer to overall EAS data structure 471 * handle - pointer to file handle 472 * 473 * Outputs: 474 * 475 * 476 * Side Effects: 477 * 478 *---------------------------------------------------------------------------- 479 */ 480 EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 481 { 482 S_SMF_DATA* pSMFData; 483 EAS_I32 i; 484 EAS_RESULT result; 485 EAS_U32 ticks; 486 487 pSMFData = (S_SMF_DATA*) pInstData; 488 489 /* reset time to zero */ 490 pSMFData->time = 0; 491 492 /* reset the synth */ 493 VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); 494 495 /* find the start of each track */ 496 ticks = 0x7fffffffL; 497 pSMFData->nextStream = NULL; 498 for (i = 0; i < pSMFData->numStreams; i++) 499 { 500 501 /* reset file position to first byte of data in track */ 502 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) 503 return result; 504 505 /* initalize some data */ 506 pSMFData->streams[i].ticks = 0; 507 508 /* initalize the MIDI parser data */ 509 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); 510 511 /* parse the first delta time in each stream */ 512 if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) 513 return result; 514 if (pSMFData->streams[i].ticks < ticks) 515 { 516 ticks = pSMFData->streams[i].ticks; 517 pSMFData->nextStream = &pSMFData->streams[i]; 518 } 519 } 520 521 522 pSMFData->state = EAS_STATE_READY; 523 return EAS_SUCCESS; 524 } 525 526 /*---------------------------------------------------------------------------- 527 * SMF_Pause() 528 *---------------------------------------------------------------------------- 529 * Purpose: 530 * Pauses the sequencer. Mutes all voices and sets state to pause. 531 * 532 * Inputs: 533 * pEASData - pointer to overall EAS data structure 534 * handle - pointer to file handle 535 * 536 * Outputs: 537 * 538 * 539 * Side Effects: 540 * 541 *---------------------------------------------------------------------------- 542 */ 543 EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 544 { 545 S_SMF_DATA *pSMFData; 546 547 /* can't pause a stopped stream */ 548 pSMFData = (S_SMF_DATA*) pInstData; 549 if (pSMFData->state == EAS_STATE_STOPPED) 550 return EAS_ERROR_ALREADY_STOPPED; 551 552 /* mute the synthesizer */ 553 VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); 554 pSMFData->state = EAS_STATE_PAUSING; 555 return EAS_SUCCESS; 556 } 557 558 /*---------------------------------------------------------------------------- 559 * SMF_Resume() 560 *---------------------------------------------------------------------------- 561 * Purpose: 562 * Resume playing after a pause, sets state back to playing. 563 * 564 * Inputs: 565 * pEASData - pointer to overall EAS data structure 566 * handle - pointer to file handle 567 * 568 * Outputs: 569 * 570 * 571 * Side Effects: 572 * 573 *---------------------------------------------------------------------------- 574 */ 575 /*lint -esym(715, pEASData) reserved for future use */ 576 EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 577 { 578 S_SMF_DATA *pSMFData; 579 580 /* can't resume a stopped stream */ 581 pSMFData = (S_SMF_DATA*) pInstData; 582 if (pSMFData->state == EAS_STATE_STOPPED) 583 return EAS_ERROR_ALREADY_STOPPED; 584 585 /* nothing to do but resume playback */ 586 pSMFData->state = EAS_STATE_PLAY; 587 return EAS_SUCCESS; 588 } 589 590 /*---------------------------------------------------------------------------- 591 * SMF_SetData() 592 *---------------------------------------------------------------------------- 593 * Purpose: 594 * Sets parser parameters 595 * 596 * Inputs: 597 * pEASData - pointer to overall EAS data structure 598 * handle - pointer to file handle 599 * 600 * Outputs: 601 * 602 * 603 * Side Effects: 604 * 605 *---------------------------------------------------------------------------- 606 */ 607 /*lint -esym(715, pEASData) reserved for future use */ 608 EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) 609 { 610 S_SMF_DATA *pSMFData; 611 612 pSMFData = (S_SMF_DATA*) pInstData; 613 switch (param) 614 { 615 616 /* set metadata callback */ 617 case PARSER_DATA_METADATA_CB: 618 EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); 619 break; 620 621 #ifdef JET_INTERFACE 622 /* set jet segment and track ID of all tracks for callback function */ 623 case PARSER_DATA_JET_CB: 624 { 625 EAS_U32 i; 626 EAS_U32 bit = (EAS_U32) value; 627 bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; 628 for (i = 0; i < pSMFData->numStreams; i++) 629 pSMFData->streams[i].midiStream.jetData = 630 (pSMFData->streams[i].midiStream.jetData & 631 ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | 632 i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; 633 pSMFData->flags |= SMF_FLAGS_JET_STREAM; 634 } 635 break; 636 637 /* set state of all mute flags at once */ 638 case PARSER_DATA_MUTE_FLAGS: 639 { 640 EAS_INT i; 641 EAS_U32 bit = (EAS_U32) value; 642 for (i = 0; i < pSMFData->numStreams; i++) 643 { 644 if (bit & 1) 645 pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; 646 else 647 pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; 648 bit >>= 1; 649 } 650 } 651 break; 652 653 /* set track mute */ 654 case PARSER_DATA_SET_MUTE: 655 if (value < pSMFData->numStreams) 656 pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; 657 else 658 return EAS_ERROR_PARAMETER_RANGE; 659 break; 660 661 /* clear track mute */ 662 case PARSER_DATA_CLEAR_MUTE: 663 if (value < pSMFData->numStreams) 664 pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; 665 else 666 return EAS_ERROR_PARAMETER_RANGE; 667 break; 668 #endif 669 670 default: 671 return EAS_ERROR_INVALID_PARAMETER; 672 } 673 674 return EAS_SUCCESS; 675 } 676 677 /*---------------------------------------------------------------------------- 678 * SMF_GetData() 679 *---------------------------------------------------------------------------- 680 * Purpose: 681 * Retrieves parser parameters 682 * 683 * Inputs: 684 * pEASData - pointer to overall EAS data structure 685 * handle - pointer to file handle 686 * 687 * Outputs: 688 * 689 * 690 * Side Effects: 691 * 692 *---------------------------------------------------------------------------- 693 */ 694 /*lint -esym(715, pEASData) reserved for future use */ 695 EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) 696 { 697 S_SMF_DATA *pSMFData; 698 699 pSMFData = (S_SMF_DATA*) pInstData; 700 switch (param) 701 { 702 /* return file type */ 703 case PARSER_DATA_FILE_TYPE: 704 if (pSMFData->numStreams == 1) 705 *pValue = EAS_FILE_SMF0; 706 else 707 *pValue = EAS_FILE_SMF1; 708 break; 709 710 /* now handled in eas_public.c */ 711 #if 0 712 case PARSER_DATA_POLYPHONY: 713 if (pSMFData->pSynth) 714 VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); 715 else 716 return EAS_ERROR_NOT_VALID_IN_THIS_STATE; 717 break; 718 719 case PARSER_DATA_PRIORITY: 720 if (pSMFData->pSynth) 721 VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); 722 break; 723 724 /* set transposition */ 725 case PARSER_DATA_TRANSPOSITION: 726 *pValue = pSMFData->transposition; 727 break; 728 #endif 729 730 case PARSER_DATA_SYNTH_HANDLE: 731 *pValue = (EAS_I32) pSMFData->pSynth; 732 break; 733 734 default: 735 return EAS_ERROR_INVALID_PARAMETER; 736 } 737 738 return EAS_SUCCESS; 739 } 740 741 /*---------------------------------------------------------------------------- 742 * SMF_GetVarLenData() 743 *---------------------------------------------------------------------------- 744 * Purpose: 745 * Reads a varible length quantity from an SMF file 746 * 747 * Inputs: 748 * 749 * 750 * Outputs: 751 * 752 * 753 * Side Effects: 754 * 755 *---------------------------------------------------------------------------- 756 */ 757 static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) 758 { 759 EAS_RESULT result; 760 EAS_U32 data; 761 EAS_U8 c; 762 763 /* read until bit 7 is zero */ 764 data = 0; 765 do 766 { 767 if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) 768 return result; 769 data = (data << 7) | (c & 0x7f); 770 } while (c & 0x80); 771 *pData = data; 772 return EAS_SUCCESS; 773 } 774 775 /*---------------------------------------------------------------------------- 776 * SMF_GetDeltaTime() 777 *---------------------------------------------------------------------------- 778 * Purpose: 779 * Reads a varible length quantity from an SMF file 780 * 781 * Inputs: 782 * 783 * 784 * Outputs: 785 * 786 * 787 * Side Effects: 788 * 789 *---------------------------------------------------------------------------- 790 */ 791 static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) 792 { 793 EAS_RESULT result; 794 EAS_U32 ticks; 795 796 if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) 797 return result; 798 799 pSMFStream->ticks += ticks; 800 return EAS_SUCCESS; 801 } 802 803 /*---------------------------------------------------------------------------- 804 * SMF_ParseMetaEvent() 805 *---------------------------------------------------------------------------- 806 * Purpose: 807 * Reads a varible length quantity from an SMF file 808 * 809 * Inputs: 810 * 811 * 812 * Outputs: 813 * 814 * 815 * Side Effects: 816 * 817 *---------------------------------------------------------------------------- 818 */ 819 static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) 820 { 821 EAS_RESULT result; 822 EAS_U32 len; 823 EAS_I32 pos; 824 EAS_U32 temp; 825 EAS_U8 c; 826 827 /* get the meta-event type */ 828 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 829 return result; 830 831 /* get the length */ 832 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) 833 return result; 834 835 /* get the current file position so we can skip the event */ 836 if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) 837 return result; 838 839 /* prevent a large unsigned length from being treated as a negative length */ 840 if ((EAS_I32) len < 0) { 841 /* note that EAS_I32 is a long, which can be 64-bits on some computers */ 842 ALOGE("b/68953854 SMF_ParseMetaEvent, negative len = %ld\n", (EAS_I32) len); 843 return EAS_ERROR_FILE_FORMAT; 844 } 845 /* prevent numeric overflow caused by a very large len, assume pos > 0 */ 846 const EAS_I32 EAS_I32_MAX = 0x7FFFFFFF; 847 if ((EAS_I32) len > (EAS_I32_MAX - pos)) { 848 ALOGE("b/68953854 SMF_ParseMetaEvent, too large len = %ld\n", (EAS_I32) len); 849 return EAS_ERROR_FILE_FORMAT; 850 } 851 852 pos += (EAS_I32) len; 853 854 /* end of track? */ 855 if (c == SMF_META_END_OF_TRACK) 856 { 857 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } 858 pSMFStream->ticks = SMF_END_OF_TRACK; 859 } 860 861 /* tempo event? */ 862 else if (c == SMF_META_TEMPO) 863 { 864 /* read the 3-byte timebase value */ 865 temp = 0; 866 while (len--) 867 { 868 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 869 return result; 870 temp = (temp << 8) | c; 871 } 872 873 pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); 874 pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; 875 } 876 877 /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ 878 else if (c == SMF_META_TIME_SIGNATURE) 879 { 880 pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; 881 } 882 883 /* if the host has registered a metadata callback return the metadata */ 884 else if (pSMFData->metadata.callback) 885 { 886 EAS_I32 readLen; 887 E_EAS_METADATA_TYPE metaType; 888 889 metaType = EAS_METADATA_UNKNOWN; 890 891 /* only process title on the first track */ 892 if (c == SMF_META_SEQTRK_NAME) 893 metaType = EAS_METADATA_TITLE; 894 else if (c == SMF_META_TEXT) 895 metaType = EAS_METADATA_TEXT; 896 else if (c == SMF_META_COPYRIGHT) 897 metaType = EAS_METADATA_COPYRIGHT; 898 else if (c == SMF_META_LYRIC) 899 metaType = EAS_METADATA_LYRIC; 900 901 if (metaType != EAS_METADATA_UNKNOWN) 902 { 903 readLen = pSMFData->metadata.bufferSize - 1; 904 if ((EAS_I32) len < readLen) 905 readLen = (EAS_I32) len; 906 if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) 907 return result; 908 pSMFData->metadata.buffer[readLen] = 0; 909 pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); 910 } 911 } 912 913 /* position file to next event - in case we ignored all or part of the meta-event */ 914 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) 915 return result; 916 917 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } 918 return EAS_SUCCESS; 919 } 920 921 /*---------------------------------------------------------------------------- 922 * SMF_ParseSysEx() 923 *---------------------------------------------------------------------------- 924 * Purpose: 925 * Reads a varible length quantity from an SMF file 926 * 927 * Inputs: 928 * 929 * 930 * Outputs: 931 * 932 * 933 * Side Effects: 934 * 935 *---------------------------------------------------------------------------- 936 */ 937 static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) 938 { 939 EAS_RESULT result; 940 EAS_U32 len; 941 EAS_U8 c; 942 943 /* get the length */ 944 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) 945 return result; 946 947 /* start of SysEx message? */ 948 if (f0 == 0xf0) 949 { 950 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) 951 return result; 952 } 953 954 /* feed the SysEx to the stream parser */ 955 while (len--) 956 { 957 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 958 return result; 959 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 960 return result; 961 962 /* check for GM system ON */ 963 if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) 964 pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; 965 } 966 967 return EAS_SUCCESS; 968 } 969 970 /*---------------------------------------------------------------------------- 971 * SMF_ParseEvent() 972 *---------------------------------------------------------------------------- 973 * Purpose: 974 * Reads a varible length quantity from an SMF file 975 * 976 * Inputs: 977 * 978 * 979 * Outputs: 980 * 981 * 982 * Side Effects: 983 * 984 *---------------------------------------------------------------------------- 985 */ 986 static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) 987 { 988 EAS_RESULT result; 989 EAS_U8 c; 990 991 /* get the event type */ 992 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 993 return result; 994 995 /* parse meta-event */ 996 if (c == 0xff) 997 { 998 if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) 999 return result; 1000 } 1001 1002 /* parse SysEx */ 1003 else if ((c == 0xf0) || (c == 0xf7)) 1004 { 1005 if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) 1006 return result; 1007 } 1008 1009 /* parse MIDI message */ 1010 else 1011 { 1012 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 1013 return result; 1014 1015 /* keep streaming data to the MIDI parser until the message is complete */ 1016 while (pSMFStream->midiStream.pending) 1017 { 1018 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 1019 return result; 1020 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 1021 return result; 1022 } 1023 1024 } 1025 1026 /* chase mode logic */ 1027 if (pSMFData->time == 0) 1028 { 1029 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 1030 { 1031 if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) 1032 pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; 1033 } 1034 else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) 1035 pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; 1036 } 1037 1038 return EAS_SUCCESS; 1039 } 1040 1041 /*---------------------------------------------------------------------------- 1042 * SMF_ParseHeader() 1043 *---------------------------------------------------------------------------- 1044 * Purpose: 1045 * Parses the header of an SMF file, allocates memory the stream parsers and initializes the 1046 * stream parsers. 1047 * 1048 * Inputs: 1049 * pEASData - pointer to overall EAS data structure 1050 * pSMFData - pointer to parser instance data 1051 * fileHandle - file handle 1052 * fileOffset - offset in the file where the header data starts, usually 0 1053 * 1054 * 1055 * Outputs: 1056 * 1057 * 1058 * Side Effects: 1059 * 1060 *---------------------------------------------------------------------------- 1061 */ 1062 /*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ 1063 EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) 1064 { 1065 EAS_RESULT result; 1066 EAS_I32 i; 1067 EAS_U16 division; 1068 EAS_U16 numStreams; 1069 EAS_U32 chunkSize; 1070 EAS_U32 chunkStart; 1071 EAS_U32 temp; 1072 EAS_U32 ticks; 1073 1074 /* explicitly set numStreams to 0. It will later be used by SMF_Close to 1075 * determine whether we have valid streams or not. */ 1076 pSMFData->numStreams = 0; 1077 1078 /* rewind the file and find the end of the header chunk */ 1079 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) 1080 goto ReadError; 1081 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) 1082 goto ReadError; 1083 1084 /* determine the number of tracks */ 1085 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) 1086 goto ReadError; 1087 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &numStreams, EAS_TRUE)) != EAS_SUCCESS) 1088 goto ReadError; 1089 1090 /* limit the number of tracks */ 1091 if (numStreams > MAX_SMF_STREAMS) 1092 { 1093 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", numStreams, MAX_SMF_STREAMS); */ } 1094 numStreams = MAX_SMF_STREAMS; 1095 } else if (numStreams == 0) 1096 { 1097 /* avoid 0 sized allocation */ 1098 return EAS_ERROR_PARAMETER_RANGE; 1099 } 1100 1101 /* get the time division */ 1102 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) 1103 goto ReadError; 1104 1105 /* setup default timebase for 120 bpm */ 1106 pSMFData->ppqn = 192; 1107 if (!division || division & 0x8000) 1108 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } 1109 else 1110 pSMFData->ppqn = (division & 0x7fff); 1111 pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); 1112 1113 /* dynamic memory allocation, allocate memory for streams */ 1114 if (pSMFData->streams == NULL) 1115 { 1116 pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * numStreams); 1117 if (pSMFData->streams == NULL) 1118 return EAS_ERROR_MALLOC_FAILED; 1119 1120 /* zero the memory to insure complete initialization */ 1121 EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * numStreams); 1122 } 1123 pSMFData->numStreams = numStreams; 1124 1125 /* find the start of each track */ 1126 chunkStart = (EAS_U32) pSMFData->fileOffset; 1127 ticks = 0x7fffffffL; 1128 pSMFData->nextStream = NULL; 1129 for (i = 0; i < pSMFData->numStreams; i++) 1130 { 1131 1132 for (;;) 1133 { 1134 1135 /* calculate start of next chunk - checking for errors */ 1136 temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; 1137 if (temp <= chunkStart) 1138 { 1139 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } 1140 return EAS_ERROR_FILE_FORMAT; 1141 } 1142 chunkStart = temp; 1143 1144 /* seek to the start of the next chunk */ 1145 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) 1146 goto ReadError; 1147 1148 /* read the chunk identifier */ 1149 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) 1150 goto ReadError; 1151 1152 /* read the chunk size */ 1153 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) 1154 goto ReadError; 1155 1156 /* make sure this is an 'MTrk' chunk */ 1157 if (temp == SMF_CHUNK_TYPE_TRACK) 1158 break; 1159 1160 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } 1161 } 1162 1163 /* initalize some data */ 1164 pSMFData->streams[i].ticks = 0; 1165 pSMFData->streams[i].fileHandle = pSMFData->fileHandle; 1166 1167 /* NULL the file handle so we don't try to close it twice */ 1168 pSMFData->fileHandle = NULL; 1169 1170 /* save this file position as the start of the track */ 1171 pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; 1172 1173 /* initalize the MIDI parser data */ 1174 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); 1175 1176 /* parse the first delta time in each stream */ 1177 if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) 1178 goto ReadError; 1179 1180 if (pSMFData->streams[i].ticks < ticks) 1181 { 1182 ticks = pSMFData->streams[i].ticks; 1183 pSMFData->nextStream = &pSMFData->streams[i]; 1184 } 1185 1186 /* more tracks to do, create a duplicate file handle */ 1187 if (i < (pSMFData->numStreams - 1)) 1188 { 1189 if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) 1190 goto ReadError; 1191 } 1192 } 1193 1194 /* update the time of the next event */ 1195 if (pSMFData->nextStream) 1196 SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); 1197 1198 return EAS_SUCCESS; 1199 1200 /* ugly goto: but simpler than structured */ 1201 ReadError: 1202 if (result == EAS_EOF) 1203 return EAS_ERROR_FILE_FORMAT; 1204 return result; 1205 } 1206 1207 /*---------------------------------------------------------------------------- 1208 * SMF_UpdateTime() 1209 *---------------------------------------------------------------------------- 1210 * Purpose: 1211 * Update the millisecond time base by converting the ticks into millieconds 1212 * 1213 * Inputs: 1214 * 1215 * 1216 * Outputs: 1217 * 1218 * 1219 * Side Effects: 1220 * 1221 *---------------------------------------------------------------------------- 1222 */ 1223 static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) 1224 { 1225 EAS_U32 temp1, temp2; 1226 1227 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 1228 return; 1229 1230 temp1 = (ticks >> 10) * pSMFData->tickConv; 1231 temp2 = (ticks & 0x3ff) * pSMFData->tickConv; 1232 pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); 1233 } 1234 1235