• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
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