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