eas_ota.c revision e442bb7cd6a085b33a4dd52c0e20a157ada7feb1
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