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