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 */
84 static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
85 static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
86 static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
87 static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
88 static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
89 static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
90 static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
91 static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
92 static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
93 static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
94 static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
95 static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData);
96 static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue);
97 static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc);
98 static 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 */
108 const 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 */
132 static 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 */
OTA_CheckFileType(S_EAS_DATA * pEASData,EAS_FILE_HANDLE fileHandle,EAS_VOID_PTR * ppHandle,EAS_I32 offset)161 static 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 */
OTA_Prepare(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)244 static 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 */
OTA_Time(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_U32 * pTime)288 static 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 */
OTA_Event(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_INT parserMode)317 static 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 */
OTA_State(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 * pState)572 static 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 */
OTA_Close(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)614 static 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 */
OTA_Reset(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)653 static 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 */
OTA_Pause(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)690 static 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 */
OTA_Resume(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData)723 static 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 */
OTA_SetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 value)755 static 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 */
OTA_GetData(S_EAS_DATA * pEASData,EAS_VOID_PTR pInstData,EAS_I32 param,EAS_I32 * pValue)793 static 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 */
OTA_ParseHeader(S_EAS_DATA * pEASData,S_OTA_DATA * pData)844 static 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 */
OTA_FetchBitField(EAS_HW_DATA_HANDLE hwInstData,S_OTA_DATA * pData,EAS_I32 numBits,EAS_U8 * pValue)989 static 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 */
OTA_SavePosition(EAS_HW_DATA_HANDLE hwInstData,S_OTA_DATA * pData,S_OTA_LOC * pLoc)1049 static 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 */
OTA_RestorePosition(EAS_HW_DATA_HANDLE hwInstData,S_OTA_DATA * pData,S_OTA_LOC * pLoc)1071 static 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