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