1/*---------------------------------------------------------------------------- 2 * 3 * File: 4 * eas_ota.c 5 * 6 * Contents and purpose: 7 * OTA parser 8 * 9 * Copyright Sonic Network Inc. 2005 10 11 * Licensed under the Apache License, Version 2.0 (the "License"); 12 * you may not use this file except in compliance with the License. 13 * You may obtain a copy of the License at 14 * 15 * http://www.apache.org/licenses/LICENSE-2.0 16 * 17 * Unless required by applicable law or agreed to in writing, software 18 * distributed under the License is distributed on an "AS IS" BASIS, 19 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 20 * See the License for the specific language governing permissions and 21 * limitations under the License. 22 * 23 *---------------------------------------------------------------------------- 24 * Revision Control: 25 * $Revision: 795 $ 26 * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ 27 *---------------------------------------------------------------------------- 28*/ 29 30#include "eas_data.h" 31#include "eas_miditypes.h" 32#include "eas_parser.h" 33#include "eas_report.h" 34#include "eas_host.h" 35#include "eas_midi.h" 36#include "eas_config.h" 37#include "eas_vm_protos.h" 38#include "eas_otadata.h" 39 40/* increase gain for mono ringtones */ 41#define OTA_GAIN_OFFSET 8 42 43/* file definitions */ 44#define OTA_RINGTONE 0x25 45#define OTA_SOUND 0x1d 46#define OTA_UNICODE 0x22 47 48/* song type definitions */ 49#define OTA_BASIC_SONG_TYPE 0x01 50#define OTA_TEMPORARY_SONG_TYPE 0x02 51 52/* instruction ID coding */ 53#define OTA_PATTERN_HEADER_ID 0x00 54#define OTA_NOTE_INST_ID 0x01 55#define OTA_SCALE_INST_ID 0x02 56#define OTA_STYLE_INST_ID 0x03 57#define OTA_TEMPO_INST_ID 0x04 58#define OTA_VOLUME_INST_ID 0x05 59 60/* note durations */ 61#define OTA_NORMAL_DURATION 0x00 62#define OTA_DOTTED_NOTE 0x01 63#define OTA_DOUBLE_DOTTED_NOTE 0x02 64#define OTA_TRIPLET_NOTE 0x03 65 66/* loop count value for infinite loop */ 67#define OTA_INFINITE_LOOP 0x0f 68 69/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ 70#define DEFAULT_TICK_CONV 30476 71 72/* default channel and program for OTA playback */ 73#define OTA_CHANNEL 0 74#define OTA_PROGRAM 80 75#define OTA_VEL_MUL 4 76#define OTA_VEL_OFS 67 77#define OTA_VEL_DEFAULT 95 78 79/* multiplier for fixed point triplet conversion */ 80#define TRIPLET_MULTIPLIER 683 81#define TRIPLET_SHIFT 10 82 83/* local prototypes */ 84static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); 85static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); 86static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); 87static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); 88static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); 89static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); 90static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); 91static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); 92static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); 93static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); 94static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); 95static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); 96static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); 97static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); 98static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); 99 100 101/*---------------------------------------------------------------------------- 102 * 103 * EAS_OTA_Parser 104 * 105 * This structure contains the functional interface for the OTA parser 106 *---------------------------------------------------------------------------- 107*/ 108const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = 109{ 110 OTA_CheckFileType, 111 OTA_Prepare, 112 OTA_Time, 113 OTA_Event, 114 OTA_State, 115 OTA_Close, 116 OTA_Reset, 117 OTA_Pause, 118 OTA_Resume, 119 NULL, 120 OTA_SetData, 121 OTA_GetData, 122 NULL 123}; 124 125/*---------------------------------------------------------------------------- 126 * 127 * bpmTable 128 * 129 * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note 130 *---------------------------------------------------------------------------- 131*/ 132static const EAS_U32 bpmTable[32] = 133{ 134 76800, 68571, 61935, 54857, 135 48000, 42667, 38400, 34286, 136 30476, 27429, 24000, 21333, 137 19200, 17143, 15360, 13714, 138 12000, 10667, 9600, 8533, 139 7680, 6737, 6000, 5408, 140 4800, 4267, 3840, 3398, 141 3024, 2685, 2400, 2133 142}; 143 144/*---------------------------------------------------------------------------- 145 * OTA_CheckFileType() 146 *---------------------------------------------------------------------------- 147 * Purpose: 148 * Check the file type to see if we can parse it 149 * 150 * Inputs: 151 * pEASData - pointer to overall EAS data structure 152 * handle - pointer to file handle 153 * 154 * Outputs: 155 * 156 * 157 * Side Effects: 158 * 159 *---------------------------------------------------------------------------- 160*/ 161static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) 162{ 163 S_OTA_DATA* pData; 164 EAS_RESULT result; 165 EAS_INT cmdLen; 166 EAS_INT state; 167 EAS_U8 temp; 168 169 /* read the first byte, should be command length */ 170 *ppHandle = NULL; 171 if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) 172 return result; 173 174 /* read all the commands */ 175 cmdLen = temp; 176 state = 0; 177 while (cmdLen--) 178 { 179 180 /* read the command, upper 7 bits */ 181 if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) 182 return result; 183 temp = temp >> 1; 184 185 if (state == 0) 186 { 187 if (temp != OTA_RINGTONE) 188 break; 189 state++; 190 } 191 else 192 { 193 194 if (temp == OTA_SOUND) 195 { 196 197 /* check for static memory allocation */ 198 if (pEASData->staticMemoryModel) 199 pData = EAS_CMEnumData(EAS_CM_OTA_DATA); 200 else 201 pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); 202 if (!pData) 203 { 204 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } 205 return EAS_ERROR_MALLOC_FAILED; 206 } 207 EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); 208 209 /* return a pointer to the instance data */ 210 pData->fileHandle = fileHandle; 211 pData->fileOffset = offset; 212 pData->state = EAS_STATE_OPEN; 213 *ppHandle = pData; 214 break; 215 } 216 217 if (temp != OTA_UNICODE) 218 break; 219 } 220 } 221 222 /* not recognized */ 223 return EAS_SUCCESS; 224} 225 226/*---------------------------------------------------------------------------- 227 * OTA_Prepare() 228 *---------------------------------------------------------------------------- 229 * Purpose: 230 * Prepare to parse the file. Allocates instance data (or uses static allocation for 231 * static memory model). 232 * 233 * Inputs: 234 * pEASData - pointer to overall EAS data structure 235 * handle - pointer to file handle 236 * 237 * Outputs: 238 * 239 * 240 * Side Effects: 241 * 242 *---------------------------------------------------------------------------- 243*/ 244static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 245{ 246 S_OTA_DATA* pData; 247 EAS_RESULT result; 248 249 /* check for valid state */ 250 pData = (S_OTA_DATA*) pInstData; 251 if (pData->state != EAS_STATE_OPEN) 252 return EAS_ERROR_NOT_VALID_IN_THIS_STATE; 253 254 /* instantiate a synthesizer */ 255 if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) 256 { 257 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } 258 return result; 259 } 260 261 pData->state = EAS_STATE_ERROR; 262 if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) 263 return result; 264 265 pData->state = EAS_STATE_READY; 266 return EAS_SUCCESS; 267} 268 269/*---------------------------------------------------------------------------- 270 * OTA_Time() 271 *---------------------------------------------------------------------------- 272 * Purpose: 273 * Returns the time of the next event in msecs 274 * 275 * Inputs: 276 * pEASData - pointer to overall EAS data structure 277 * handle - pointer to file handle 278 * pTime - pointer to variable to hold time of next event (in msecs) 279 * 280 * Outputs: 281 * 282 * 283 * Side Effects: 284 * 285 *---------------------------------------------------------------------------- 286*/ 287/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ 288static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) 289{ 290 S_OTA_DATA *pData; 291 292 pData = (S_OTA_DATA*) pInstData; 293 294 /* return time in milliseconds */ 295 /*lint -e{704} use shift instead of division */ 296 *pTime = pData->time >> 8; 297 return EAS_SUCCESS; 298} 299 300/*---------------------------------------------------------------------------- 301 * OTA_Event() 302 *---------------------------------------------------------------------------- 303 * Purpose: 304 * Parse the next event in the file 305 * 306 * Inputs: 307 * pEASData - pointer to overall EAS data structure 308 * handle - pointer to file handle 309 * 310 * Outputs: 311 * 312 * 313 * Side Effects: 314 * 315 *---------------------------------------------------------------------------- 316*/ 317static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) 318{ 319 S_OTA_DATA* pData; 320 EAS_RESULT result; 321 EAS_U32 duration; 322 EAS_U8 temp; 323 324 pData = (S_OTA_DATA*) pInstData; 325 if (pData->state >= EAS_STATE_OPEN) 326 return EAS_SUCCESS; 327 328 /* initialize MIDI channel when the track starts playing */ 329 if (pData->time == 0) 330 { 331 /* set program to square lead */ 332 if (parserMode != eParserModeMetaData) 333 VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); 334 335 /* set channel volume to max */ 336 if (parserMode != eParserModeMetaData) 337 VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); 338 } 339 340 /* check for end of note */ 341 if (pData->note) 342 { 343 /* stop the note */ 344 VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); 345 pData->note = 0; 346 347 /* check for rest between notes */ 348 if (pData->restTicks) 349 { 350 pData->time += (EAS_I32) pData->restTicks; 351 pData->restTicks = 0; 352 return EAS_SUCCESS; 353 } 354 } 355 356 /* if not in a pattern, read the pattern header */ 357 while (pData->current.patternLen == 0) 358 { 359 360 /* check for loop - don't do infinite loops when locating */ 361 if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) 362 { 363 /* if not infinite loop, decrement loop count */ 364 if (pData->loopCount != OTA_INFINITE_LOOP) 365 pData->loopCount--; 366 367 /* back to start of pattern*/ 368 if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) 369 return result; 370 } 371 372 /* if no previous position to restore, continue forward */ 373 else if (pData->restore.fileOffset < 0) 374 { 375 376 /* check for end of song */ 377 if (pData->numPatterns == 0) 378 { 379 pData->state = EAS_STATE_STOPPING; 380 VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); 381 return EAS_SUCCESS; 382 } 383 384 /* read the next pattern header */ 385 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) 386 return result; 387 if (temp != OTA_PATTERN_HEADER_ID) 388 { 389 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } 390 return EAS_ERROR_FILE_FORMAT; 391 } 392 393 /* get the pattern ID */ 394 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) 395 return result; 396 397 /* get the loop count */ 398 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) 399 return result; 400 401 /* get the pattern length */ 402 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) 403 return result; 404 405 /* if pattern definition, save the current position */ 406 if (pData->current.patternLen) 407 { 408 if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) 409 return result; 410 } 411 412 /* if pattern length is zero, repeat a previous pattern */ 413 else 414 { 415 /* make sure it's a valid pattern */ 416 if (pData->patterns[pData->currentPattern].fileOffset < 0) 417 { 418 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } 419 return EAS_ERROR_FILE_FORMAT; 420 } 421 422 /* save current position and data */ 423 if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) 424 return result; 425 426 /* seek to the pattern in the file */ 427 if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) 428 return result; 429 } 430 431 /* decrement pattern count */ 432 pData->numPatterns--; 433 } 434 435 /* restore previous position */ 436 else 437 { 438 if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) 439 return result; 440 } 441 } 442 443 /* get the next event */ 444 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) 445 return result; 446 447 switch (temp) 448 { 449 case OTA_NOTE_INST_ID: 450 /* fetch note value */ 451 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) 452 return result; 453 454 /* fetch note duration */ 455 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) 456 return result; 457 duration = pData->tick * (0x20 >> temp); 458 459 /* fetch note duration modifier */ 460 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) 461 return result; 462 switch (temp) 463 { 464 case OTA_NORMAL_DURATION: 465 break; 466 467 case OTA_DOTTED_NOTE: 468 duration += duration >> 1; 469 break; 470 471 case OTA_DOUBLE_DOTTED_NOTE: 472 duration += (duration >> 1) + (duration >> 2); 473 break; 474 475 case OTA_TRIPLET_NOTE: 476 duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; 477 break; 478 479 default: 480 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } 481 break; 482 } 483 484 /* check for note */ 485 if (pData->note) 486 { 487 488 /* determine note length based on style */ 489 switch (pData->style) 490 { 491 case 0: 492 pData->restTicks = duration >> 4; 493 break; 494 case 1: 495 pData->restTicks = 0; 496 break; 497 case 2: 498 pData->restTicks = duration >> 1; 499 break; 500 default: 501 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } 502 } 503 504 /* add octave */ 505 pData->note += pData->octave; 506 if (parserMode == eParserModePlay) 507 VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); 508 pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; 509 } 510 511 /* this is a rest */ 512 else 513 pData->time += (EAS_I32) duration; 514 break; 515 516 case OTA_SCALE_INST_ID: 517 /* fetch octave */ 518 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) 519 return result; 520 pData->octave = (EAS_U8) (temp * 12 + 59); 521 break; 522 523 case OTA_STYLE_INST_ID: 524 /* fetch note style */ 525 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) 526 return result; 527 break; 528 529 case OTA_TEMPO_INST_ID: 530 /* fetch tempo */ 531 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) 532 return result; 533 pData->tick = bpmTable[temp]; 534 break; 535 536 case OTA_VOLUME_INST_ID: 537 /* fetch volume */ 538 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) 539 return result; 540 pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; 541 break; 542 543 default: 544 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } 545 return EAS_ERROR_FILE_FORMAT; 546 } 547 548 /* decrement pattern length */ 549 pData->current.patternLen--; 550 return EAS_SUCCESS; 551} 552 553/*---------------------------------------------------------------------------- 554 * OTA_State() 555 *---------------------------------------------------------------------------- 556 * Purpose: 557 * Returns the current state of the stream 558 * 559 * Inputs: 560 * pEASData - pointer to overall EAS data structure 561 * handle - pointer to file handle 562 * pState - pointer to variable to store state 563 * 564 * Outputs: 565 * 566 * 567 * Side Effects: 568 * 569 *---------------------------------------------------------------------------- 570*/ 571/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ 572static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) 573{ 574 S_OTA_DATA* pData; 575 576 /* establish pointer to instance data */ 577 pData = (S_OTA_DATA*) pInstData; 578 579 /* if stopping, check to see if synth voices are active */ 580 if (pData->state == EAS_STATE_STOPPING) 581 { 582 if (VMActiveVoices(pData->pSynth) == 0) 583 pData->state = EAS_STATE_STOPPED; 584 } 585 586 if (pData->state == EAS_STATE_PAUSING) 587 { 588 if (VMActiveVoices(pData->pSynth) == 0) 589 pData->state = EAS_STATE_PAUSED; 590 } 591 592 /* return current state */ 593 *pState = pData->state; 594 return EAS_SUCCESS; 595} 596 597/*---------------------------------------------------------------------------- 598 * OTA_Close() 599 *---------------------------------------------------------------------------- 600 * Purpose: 601 * Close the file and clean up 602 * 603 * Inputs: 604 * pEASData - pointer to overall EAS data structure 605 * handle - pointer to file handle 606 * 607 * Outputs: 608 * 609 * 610 * Side Effects: 611 * 612 *---------------------------------------------------------------------------- 613*/ 614static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 615{ 616 S_OTA_DATA* pData; 617 EAS_RESULT result; 618 619 pData = (S_OTA_DATA*) pInstData; 620 621 /* close the file */ 622 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) 623 return result; 624 625 /* free the synth */ 626 if (pData->pSynth != NULL) 627 VMMIDIShutdown(pEASData, pData->pSynth); 628 629 /* if using dynamic memory, free it */ 630 if (!pEASData->staticMemoryModel) 631 EAS_HWFree(pEASData->hwInstData, pData); 632 633 return EAS_SUCCESS; 634} 635 636/*---------------------------------------------------------------------------- 637 * OTA_Reset() 638 *---------------------------------------------------------------------------- 639 * Purpose: 640 * Reset the sequencer. Used for locating backwards in the file. 641 * 642 * Inputs: 643 * pEASData - pointer to overall EAS data structure 644 * handle - pointer to file handle 645 * 646 * Outputs: 647 * 648 * 649 * Side Effects: 650 * 651 *---------------------------------------------------------------------------- 652*/ 653static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 654{ 655 S_OTA_DATA* pData; 656 EAS_RESULT result; 657 658 pData = (S_OTA_DATA*) pInstData; 659 660 /* reset the synth */ 661 VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); 662 pData->note = 0; 663 664 /* reset file position and re-parse header */ 665 pData->state = EAS_STATE_ERROR; 666 if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) 667 return result; 668 669 pData->state = EAS_STATE_READY; 670 return EAS_SUCCESS; 671} 672 673/*---------------------------------------------------------------------------- 674 * OTA_Pause() 675 *---------------------------------------------------------------------------- 676 * Purpose: 677 * Pauses the sequencer. Mutes all voices and sets state to pause. 678 * 679 * Inputs: 680 * pEASData - pointer to overall EAS data structure 681 * handle - pointer to file handle 682 * 683 * Outputs: 684 * 685 * 686 * Side Effects: 687 * 688 *---------------------------------------------------------------------------- 689*/ 690static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 691{ 692 S_OTA_DATA *pData; 693 694 /* can't pause a stopped stream */ 695 pData = (S_OTA_DATA*) pInstData; 696 if (pData->state == EAS_STATE_STOPPED) 697 return EAS_ERROR_ALREADY_STOPPED; 698 699 /* mute the synthesizer */ 700 VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); 701 pData->state = EAS_STATE_PAUSING; 702 return EAS_SUCCESS; 703} 704 705/*---------------------------------------------------------------------------- 706 * OTA_Resume() 707 *---------------------------------------------------------------------------- 708 * Purpose: 709 * Resume playing after a pause, sets state back to playing. 710 * 711 * Inputs: 712 * pEASData - pointer to overall EAS data structure 713 * handle - pointer to file handle 714 * 715 * Outputs: 716 * 717 * 718 * Side Effects: 719 * 720 *---------------------------------------------------------------------------- 721*/ 722/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ 723static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 724{ 725 S_OTA_DATA *pData; 726 727 /* can't resume a stopped stream */ 728 pData = (S_OTA_DATA*) pInstData; 729 if (pData->state == EAS_STATE_STOPPED) 730 return EAS_ERROR_ALREADY_STOPPED; 731 732 /* nothing to do but resume playback */ 733 pData->state = EAS_STATE_PLAY; 734 return EAS_SUCCESS; 735} 736 737/*---------------------------------------------------------------------------- 738 * OTA_SetData() 739 *---------------------------------------------------------------------------- 740 * Purpose: 741 * Return file type 742 * 743 * Inputs: 744 * pEASData - pointer to overall EAS data structure 745 * handle - pointer to file handle 746 * 747 * Outputs: 748 * 749 * 750 * Side Effects: 751 * 752 *---------------------------------------------------------------------------- 753*/ 754/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ 755static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) 756{ 757 S_OTA_DATA *pData; 758 759 pData = (S_OTA_DATA *) pInstData; 760 switch (param) 761 { 762 763 /* set metadata callback */ 764 case PARSER_DATA_METADATA_CB: 765 EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); 766 break; 767 768 default: 769 return EAS_ERROR_INVALID_PARAMETER; 770 } 771 772 return EAS_SUCCESS; 773} 774 775/*---------------------------------------------------------------------------- 776 * OTA_GetData() 777 *---------------------------------------------------------------------------- 778 * Purpose: 779 * Return file type 780 * 781 * Inputs: 782 * pEASData - pointer to overall EAS data structure 783 * handle - pointer to file handle 784 * 785 * Outputs: 786 * 787 * 788 * Side Effects: 789 * 790 *---------------------------------------------------------------------------- 791*/ 792/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ 793static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) 794{ 795 S_OTA_DATA *pData; 796 797 pData = (S_OTA_DATA*) pInstData; 798 switch (param) 799 { 800 /* return file type as OTA */ 801 case PARSER_DATA_FILE_TYPE: 802 *pValue = EAS_FILE_OTA; 803 break; 804 805#if 0 806 /* set transposition */ 807 case PARSER_DATA_TRANSPOSITION: 808 *pValue = pData->transposition; 809 break; 810#endif 811 812 case PARSER_DATA_SYNTH_HANDLE: 813 *pValue = (EAS_I32) pData->pSynth; 814 break; 815 816 case PARSER_DATA_GAIN_OFFSET: 817 *pValue = OTA_GAIN_OFFSET; 818 break; 819 820 default: 821 return EAS_ERROR_INVALID_PARAMETER; 822 } 823 return EAS_SUCCESS; 824} 825 826/*---------------------------------------------------------------------------- 827 * OTA_ParseHeader() 828 *---------------------------------------------------------------------------- 829 * Purpose: 830 * Prepare to parse the file. Allocates instance data (or uses static allocation for 831 * static memory model). 832 * 833 * Inputs: 834 * pEASData - pointer to overall EAS data structure 835 * handle - pointer to file handle 836 * 837 * Outputs: 838 * 839 * 840 * Side Effects: 841 * 842 *---------------------------------------------------------------------------- 843*/ 844static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) 845{ 846 EAS_RESULT result; 847 EAS_INT i; 848 EAS_INT state; 849 EAS_U8 temp; 850 EAS_U8 titleLen; 851 852 /* initialize some data */ 853 pData->flags = 0; 854 pData->time = 0; 855 pData->tick = DEFAULT_TICK_CONV; 856 pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = 857 pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; 858 pData->current.bitCount = 0; 859 pData->current.patternLen = 0; 860 pData->loopCount = 0; 861 pData->restore.fileOffset = -1; 862 pData->note = 0; 863 pData->restTicks = 0; 864 pData->velocity = OTA_VEL_DEFAULT; 865 pData->style = 0; 866 pData->octave = 59; 867 868 /* seek to start of data */ 869 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) 870 return result; 871 872 /* read the first byte, should be command length */ 873 if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) 874 return result; 875 876 /* read all the commands */ 877 i = temp; 878 state = 0; 879 while (i--) 880 { 881 882 /* fetch command, always starts on byte boundary */ 883 pData->current.bitCount = 0; 884 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) 885 return result; 886 887 if (state == 0) 888 { 889 if (temp != OTA_RINGTONE) 890 { 891 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } 892 return EAS_ERROR_FILE_FORMAT; 893 } 894 state++; 895 } 896 else 897 { 898 899 if (temp == OTA_SOUND) 900 break; 901 902 if (temp == OTA_UNICODE) 903 pData->flags |= OTA_FLAGS_UNICODE; 904 else 905 { 906 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } 907 return EAS_ERROR_FILE_FORMAT; 908 } 909 } 910 } 911 912 /* get song type */ 913 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) 914 return result; 915 916 /* check for basic song type */ 917 if (temp == OTA_BASIC_SONG_TYPE) 918 { 919 /* fetch title length */ 920 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) 921 return result; 922 923 /* if unicode, double the length */ 924 if (pData->flags & OTA_FLAGS_UNICODE) 925 titleLen = (EAS_U8) (titleLen << 1); 926 927 /* zero the metadata buffer */ 928 if (pData->metadata.buffer) 929 EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); 930 931 /* read the song title */ 932 for (i = 0; i < titleLen; i++) 933 { 934 /* fetch character */ 935 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) 936 return result; 937 938 /* check for metadata callback */ 939 if (pData->metadata.callback) 940 { 941 if (i < (pData->metadata.bufferSize - 1)) 942 pData->metadata.buffer[i] = (char) temp; 943 } 944 } 945 946 /* if host has registered callback, call it now */ 947 if (pData->metadata.callback) 948 (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); 949 } 950 951 /* must be temporary song */ 952 else if (temp != OTA_TEMPORARY_SONG_TYPE) 953 { 954 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } 955 return EAS_ERROR_FILE_FORMAT; 956 } 957 958 /* get the song length */ 959 if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) 960 return result; 961 962 /* sanity check */ 963 if (pData->numPatterns == 0) 964 { 965 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } 966 return EAS_ERROR_FILE_FORMAT; 967 } 968 969 /* at start of first pattern */ 970 return EAS_SUCCESS; 971} 972 973/*---------------------------------------------------------------------------- 974 * OTA_FetchBitField() 975 *---------------------------------------------------------------------------- 976 * Purpose: 977 * Fetch a specified number of bits from the input stream 978 * 979 * Inputs: 980 * 981 * 982 * Outputs: 983 * 984 * 985 * Side Effects: 986 * 987 *---------------------------------------------------------------------------- 988*/ 989static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) 990{ 991 EAS_RESULT result; 992 EAS_I32 bitsLeft; 993 EAS_U8 value; 994 995 value = 0; 996 997 /* do we have enough bits? */ 998 bitsLeft = pData->current.bitCount - numBits; 999 1000 /* not enough bits, assemble them from 2 characters */ 1001 if (bitsLeft < 0) 1002 { 1003 /* grab the remaining bits from the previous byte */ 1004 if (pData->current.bitCount) 1005 /*lint -e{504,734} this is a legitimate shift operation */ 1006 value = pData->current.dataByte << -bitsLeft; 1007 1008 /* read the next byte */ 1009 if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) 1010 return result; 1011 bitsLeft += 8; 1012 } 1013 1014 /* more bits than needed? */ 1015 if (bitsLeft > 0) 1016 { 1017 value |= pData->current.dataByte >> bitsLeft; 1018 pData->current.bitCount = (EAS_U8) bitsLeft; 1019 pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); 1020 } 1021 1022 /* exactly the right number of bits */ 1023 else 1024 { 1025 value |= pData->current.dataByte; 1026 pData->current.bitCount = 0; 1027 } 1028 1029 *pValue = value; 1030 return EAS_SUCCESS; 1031} 1032 1033/*---------------------------------------------------------------------------- 1034 * OTA_SavePosition() 1035 *---------------------------------------------------------------------------- 1036 * Purpose: 1037 * 1038 * 1039 * Inputs: 1040 * 1041 * 1042 * Outputs: 1043 * 1044 * 1045 * Side Effects: 1046 * 1047 *---------------------------------------------------------------------------- 1048*/ 1049static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) 1050{ 1051 EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); 1052 return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); 1053} 1054 1055/*---------------------------------------------------------------------------- 1056 * OTA_RestorePosition() 1057 *---------------------------------------------------------------------------- 1058 * Purpose: 1059 * 1060 * 1061 * Inputs: 1062 * 1063 * 1064 * Outputs: 1065 * 1066 * 1067 * Side Effects: 1068 * 1069 *---------------------------------------------------------------------------- 1070*/ 1071static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) 1072{ 1073 EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); 1074 pData->restore.fileOffset = -1; 1075 return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); 1076} 1077 1078