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