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