From a8c89077d78769bf4840fa91609edc51fe2fa02d Mon Sep 17 00:00:00 2001 From: Jean-Baptiste Queru Date: Thu, 12 Nov 2009 18:45:37 -0800 Subject: eclair snapshot --- arm-wt-22k/lib_src/eas_ota.c | 2130 +++++++++++++++++++++--------------------- 1 file changed, 1065 insertions(+), 1065 deletions(-) (limited to 'arm-wt-22k/lib_src/eas_ota.c') diff --git a/arm-wt-22k/lib_src/eas_ota.c b/arm-wt-22k/lib_src/eas_ota.c index fb81d62..5bc9062 100644 --- a/arm-wt-22k/lib_src/eas_ota.c +++ b/arm-wt-22k/lib_src/eas_ota.c @@ -1,12 +1,12 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_ota.c - * - * Contents and purpose: - * OTA parser - * - * Copyright Sonic Network Inc. 2005 +/*---------------------------------------------------------------------------- + * + * File: + * eas_ota.c + * + * Contents and purpose: + * OTA parser + * + * Copyright Sonic Network Inc. 2005 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. @@ -19,1059 +19,1059 @@ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. - * - *---------------------------------------------------------------------------- - * Revision Control: - * $Revision: 795 $ - * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ - *---------------------------------------------------------------------------- -*/ - -#include "eas_data.h" -#include "eas_miditypes.h" -#include "eas_parser.h" -#include "eas_report.h" -#include "eas_host.h" -#include "eas_midi.h" -#include "eas_config.h" -#include "eas_vm_protos.h" -#include "eas_otadata.h" - -/* increase gain for mono ringtones */ -#define OTA_GAIN_OFFSET 8 - -/* file definitions */ -#define OTA_RINGTONE 0x25 -#define OTA_SOUND 0x1d -#define OTA_UNICODE 0x22 - -/* song type definitions */ -#define OTA_BASIC_SONG_TYPE 0x01 -#define OTA_TEMPORARY_SONG_TYPE 0x02 - -/* instruction ID coding */ -#define OTA_PATTERN_HEADER_ID 0x00 -#define OTA_NOTE_INST_ID 0x01 -#define OTA_SCALE_INST_ID 0x02 -#define OTA_STYLE_INST_ID 0x03 -#define OTA_TEMPO_INST_ID 0x04 -#define OTA_VOLUME_INST_ID 0x05 - -/* note durations */ -#define OTA_NORMAL_DURATION 0x00 -#define OTA_DOTTED_NOTE 0x01 -#define OTA_DOUBLE_DOTTED_NOTE 0x02 -#define OTA_TRIPLET_NOTE 0x03 - -/* loop count value for infinite loop */ -#define OTA_INFINITE_LOOP 0x0f - -/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ -#define DEFAULT_TICK_CONV 30476 - -/* default channel and program for OTA playback */ -#define OTA_CHANNEL 0 -#define OTA_PROGRAM 80 -#define OTA_VEL_MUL 4 -#define OTA_VEL_OFS 67 -#define OTA_VEL_DEFAULT 95 - -/* multiplier for fixed point triplet conversion */ -#define TRIPLET_MULTIPLIER 683 -#define TRIPLET_SHIFT 10 - -/* local prototypes */ -static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); -static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); -static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); -static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); -static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); -static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); -static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); -static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); -static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); -static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); -static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); - - -/*---------------------------------------------------------------------------- - * - * EAS_OTA_Parser - * - * This structure contains the functional interface for the OTA parser - *---------------------------------------------------------------------------- -*/ -const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = -{ - OTA_CheckFileType, - OTA_Prepare, - OTA_Time, - OTA_Event, - OTA_State, - OTA_Close, - OTA_Reset, - OTA_Pause, - OTA_Resume, - NULL, - OTA_SetData, - OTA_GetData, - NULL -}; - -/*---------------------------------------------------------------------------- - * - * bpmTable - * - * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note - *---------------------------------------------------------------------------- -*/ -static const EAS_U32 bpmTable[32] = -{ - 76800, 68571, 61935, 54857, - 48000, 42667, 38400, 34286, - 30476, 27429, 24000, 21333, - 19200, 17143, 15360, 13714, - 12000, 10667, 9600, 8533, - 7680, 6737, 6000, 5408, - 4800, 4267, 3840, 3398, - 3024, 2685, 2400, 2133 -}; - -/*---------------------------------------------------------------------------- - * OTA_CheckFileType() - *---------------------------------------------------------------------------- - * Purpose: - * Check the file type to see if we can parse it - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) -{ - S_OTA_DATA* pData; - EAS_RESULT result; - EAS_INT cmdLen; - EAS_INT state; - EAS_U8 temp; - - /* read the first byte, should be command length */ - *ppHandle = NULL; - if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) - return result; - - /* read all the commands */ - cmdLen = temp; - state = 0; - while (cmdLen--) - { - - /* read the command, upper 7 bits */ - if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) - return result; - temp = temp >> 1; - - if (state == 0) - { - if (temp != OTA_RINGTONE) - break; - state++; - } - else - { - - if (temp == OTA_SOUND) - { - - /* check for static memory allocation */ - if (pEASData->staticMemoryModel) - pData = EAS_CMEnumData(EAS_CM_OTA_DATA); - else - pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); - if (!pData) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } - return EAS_ERROR_MALLOC_FAILED; - } - EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); - - /* return a pointer to the instance data */ - pData->fileHandle = fileHandle; - pData->fileOffset = offset; - pData->state = EAS_STATE_OPEN; - *ppHandle = pData; - break; - } - - if (temp != OTA_UNICODE) - break; - } - } - - /* not recognized */ - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Prepare() - *---------------------------------------------------------------------------- - * Purpose: - * Prepare to parse the file. Allocates instance data (or uses static allocation for - * static memory model). - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_OTA_DATA* pData; - EAS_RESULT result; - - /* check for valid state */ - pData = (S_OTA_DATA*) pInstData; - if (pData->state != EAS_STATE_OPEN) - return EAS_ERROR_NOT_VALID_IN_THIS_STATE; - - /* instantiate a synthesizer */ - if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } - return result; - } - - pData->state = EAS_STATE_ERROR; - if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) - return result; - - pData->state = EAS_STATE_READY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Time() - *---------------------------------------------------------------------------- - * Purpose: - * Returns the time of the next event in msecs - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * pTime - pointer to variable to hold time of next event (in msecs) - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ -static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) -{ - S_OTA_DATA *pData; - - pData = (S_OTA_DATA*) pInstData; - - /* return time in milliseconds */ - /*lint -e{704} use shift instead of division */ - *pTime = pData->time >> 8; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Event() - *---------------------------------------------------------------------------- - * Purpose: - * Parse the next event in the file - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) -{ - S_OTA_DATA* pData; - EAS_RESULT result; - EAS_U32 duration; - EAS_U8 temp; - - pData = (S_OTA_DATA*) pInstData; - if (pData->state >= EAS_STATE_OPEN) - return EAS_SUCCESS; - - /* initialize MIDI channel when the track starts playing */ - if (pData->time == 0) - { - /* set program to square lead */ - if (parserMode != eParserModeMetaData) - VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); - - /* set channel volume to max */ - if (parserMode != eParserModeMetaData) - VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); - } - - /* check for end of note */ - if (pData->note) - { - /* stop the note */ - VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); - pData->note = 0; - - /* check for rest between notes */ - if (pData->restTicks) - { - pData->time += (EAS_I32) pData->restTicks; - pData->restTicks = 0; - return EAS_SUCCESS; - } - } - - /* if not in a pattern, read the pattern header */ - while (pData->current.patternLen == 0) - { - - /* check for loop - don't do infinite loops when locating */ - if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) - { - /* if not infinite loop, decrement loop count */ - if (pData->loopCount != OTA_INFINITE_LOOP) - pData->loopCount--; - - /* back to start of pattern*/ - if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) - return result; - } - - /* if no previous position to restore, continue forward */ - else if (pData->restore.fileOffset < 0) - { - - /* check for end of song */ - if (pData->numPatterns == 0) - { - pData->state = EAS_STATE_STOPPING; - VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); - return EAS_SUCCESS; - } - - /* read the next pattern header */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) - return result; - if (temp != OTA_PATTERN_HEADER_ID) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - - /* get the pattern ID */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) - return result; - - /* get the loop count */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) - return result; - - /* get the pattern length */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) - return result; - - /* if pattern definition, save the current position */ - if (pData->current.patternLen) - { - if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) - return result; - } - - /* if pattern length is zero, repeat a previous pattern */ - else - { - /* make sure it's a valid pattern */ - if (pData->patterns[pData->currentPattern].fileOffset < 0) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - - /* save current position and data */ - if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) - return result; - - /* seek to the pattern in the file */ - if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) - return result; - } - - /* decrement pattern count */ - pData->numPatterns--; - } - - /* restore previous position */ - else - { - if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) - return result; - } - } - - /* get the next event */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) - return result; - - switch (temp) - { - case OTA_NOTE_INST_ID: - /* fetch note value */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) - return result; - - /* fetch note duration */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) - return result; - duration = pData->tick * (0x20 >> temp); - - /* fetch note duration modifier */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) - return result; - switch (temp) - { - case OTA_NORMAL_DURATION: - break; - - case OTA_DOTTED_NOTE: - duration += duration >> 1; - break; - - case OTA_DOUBLE_DOTTED_NOTE: - duration += (duration >> 1) + (duration >> 2); - break; - - case OTA_TRIPLET_NOTE: - duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; - break; - - default: - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } - break; - } - - /* check for note */ - if (pData->note) - { - - /* determine note length based on style */ - switch (pData->style) - { - case 0: - pData->restTicks = duration >> 4; - break; - case 1: - pData->restTicks = 0; - break; - case 2: - pData->restTicks = duration >> 1; - break; - default: - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } - } - - /* add octave */ - pData->note += pData->octave; - if (parserMode == eParserModePlay) - VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); - pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; - } - - /* this is a rest */ - else - pData->time += (EAS_I32) duration; - break; - - case OTA_SCALE_INST_ID: - /* fetch octave */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) - return result; - pData->octave = (EAS_U8) (temp * 12 + 59); - break; - - case OTA_STYLE_INST_ID: - /* fetch note style */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) - return result; - break; - - case OTA_TEMPO_INST_ID: - /* fetch tempo */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) - return result; - pData->tick = bpmTable[temp]; - break; - - case OTA_VOLUME_INST_ID: - /* fetch volume */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) - return result; - pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; - break; - - default: - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - - /* decrement pattern length */ - pData->current.patternLen--; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_State() - *---------------------------------------------------------------------------- - * Purpose: - * Returns the current state of the stream - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * pState - pointer to variable to store state - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ -static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) -{ - S_OTA_DATA* pData; - - /* establish pointer to instance data */ - pData = (S_OTA_DATA*) pInstData; - - /* if stopping, check to see if synth voices are active */ - if (pData->state == EAS_STATE_STOPPING) - { - if (VMActiveVoices(pData->pSynth) == 0) - pData->state = EAS_STATE_STOPPED; - } - - if (pData->state == EAS_STATE_PAUSING) - { - if (VMActiveVoices(pData->pSynth) == 0) - pData->state = EAS_STATE_PAUSED; - } - - /* return current state */ - *pState = pData->state; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Close() - *---------------------------------------------------------------------------- - * Purpose: - * Close the file and clean up - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_OTA_DATA* pData; - EAS_RESULT result; - - pData = (S_OTA_DATA*) pInstData; - - /* close the file */ - if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) - return result; - - /* free the synth */ - if (pData->pSynth != NULL) - VMMIDIShutdown(pEASData, pData->pSynth); - - /* if using dynamic memory, free it */ - if (!pEASData->staticMemoryModel) - EAS_HWFree(pEASData->hwInstData, pData); - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Reset() - *---------------------------------------------------------------------------- - * Purpose: - * Reset the sequencer. Used for locating backwards in the file. - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_OTA_DATA* pData; - EAS_RESULT result; - - pData = (S_OTA_DATA*) pInstData; - - /* reset the synth */ - VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); - pData->note = 0; - - /* reset file position and re-parse header */ - pData->state = EAS_STATE_ERROR; - if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) - return result; - - pData->state = EAS_STATE_READY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Pause() - *---------------------------------------------------------------------------- - * Purpose: - * Pauses the sequencer. Mutes all voices and sets state to pause. - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_OTA_DATA *pData; - - /* can't pause a stopped stream */ - pData = (S_OTA_DATA*) pInstData; - if (pData->state == EAS_STATE_STOPPED) - return EAS_ERROR_ALREADY_STOPPED; - - /* mute the synthesizer */ - VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); - pData->state = EAS_STATE_PAUSING; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_Resume() - *---------------------------------------------------------------------------- - * Purpose: - * Resume playing after a pause, sets state back to playing. - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ -static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_OTA_DATA *pData; - - /* can't resume a stopped stream */ - pData = (S_OTA_DATA*) pInstData; - if (pData->state == EAS_STATE_STOPPED) - return EAS_ERROR_ALREADY_STOPPED; - - /* nothing to do but resume playback */ - pData->state = EAS_STATE_PLAY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_SetData() - *---------------------------------------------------------------------------- - * Purpose: - * Return file type - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ -static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) -{ - S_OTA_DATA *pData; - - pData = (S_OTA_DATA *) pInstData; - switch (param) - { - - /* set metadata callback */ - case PARSER_DATA_METADATA_CB: - EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); - break; - - default: - return EAS_ERROR_INVALID_PARAMETER; - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_GetData() - *---------------------------------------------------------------------------- - * Purpose: - * Return file type - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ -static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) -{ - S_OTA_DATA *pData; - - pData = (S_OTA_DATA*) pInstData; - switch (param) - { - /* return file type as OTA */ - case PARSER_DATA_FILE_TYPE: - *pValue = EAS_FILE_OTA; - break; - -#if 0 - /* set transposition */ - case PARSER_DATA_TRANSPOSITION: - *pValue = pData->transposition; - break; -#endif - - case PARSER_DATA_SYNTH_HANDLE: - *pValue = (EAS_I32) pData->pSynth; - break; - - case PARSER_DATA_GAIN_OFFSET: - *pValue = OTA_GAIN_OFFSET; - break; - - default: - return EAS_ERROR_INVALID_PARAMETER; - } - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_ParseHeader() - *---------------------------------------------------------------------------- - * Purpose: - * Prepare to parse the file. Allocates instance data (or uses static allocation for - * static memory model). - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) -{ - EAS_RESULT result; - EAS_INT i; - EAS_INT state; - EAS_U8 temp; - EAS_U8 titleLen; - - /* initialize some data */ - pData->flags = 0; - pData->time = 0; - pData->tick = DEFAULT_TICK_CONV; - pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = - pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; - pData->current.bitCount = 0; - pData->current.patternLen = 0; - pData->loopCount = 0; - pData->restore.fileOffset = -1; - pData->note = 0; - pData->restTicks = 0; - pData->velocity = OTA_VEL_DEFAULT; - pData->style = 0; - pData->octave = 59; - - /* seek to start of data */ - if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) - return result; - - /* read the first byte, should be command length */ - if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) - return result; - - /* read all the commands */ - i = temp; - state = 0; - while (i--) - { - - /* fetch command, always starts on byte boundary */ - pData->current.bitCount = 0; - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) - return result; - - if (state == 0) - { - if (temp != OTA_RINGTONE) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - state++; - } - else - { - - if (temp == OTA_SOUND) - break; - - if (temp == OTA_UNICODE) - pData->flags |= OTA_FLAGS_UNICODE; - else - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - } - } - - /* get song type */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) - return result; - - /* check for basic song type */ - if (temp == OTA_BASIC_SONG_TYPE) - { - /* fetch title length */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) - return result; - - /* if unicode, double the length */ - if (pData->flags & OTA_FLAGS_UNICODE) - titleLen = (EAS_U8) (titleLen << 1); - - /* zero the metadata buffer */ - if (pData->metadata.buffer) - EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); - - /* read the song title */ - for (i = 0; i < titleLen; i++) - { - /* fetch character */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) - return result; - - /* check for metadata callback */ - if (pData->metadata.callback) - { - if (i < (pData->metadata.bufferSize - 1)) - pData->metadata.buffer[i] = (char) temp; - } - } - - /* if host has registered callback, call it now */ - if (pData->metadata.callback) - (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); - } - - /* must be temporary song */ - else if (temp != OTA_TEMPORARY_SONG_TYPE) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - - /* get the song length */ - if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) - return result; - - /* sanity check */ - if (pData->numPatterns == 0) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } - return EAS_ERROR_FILE_FORMAT; - } - - /* at start of first pattern */ - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_FetchBitField() - *---------------------------------------------------------------------------- - * Purpose: - * Fetch a specified number of bits from the input stream - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) -{ - EAS_RESULT result; - EAS_I32 bitsLeft; - EAS_U8 value; - - value = 0; - - /* do we have enough bits? */ - bitsLeft = pData->current.bitCount - numBits; - - /* not enough bits, assemble them from 2 characters */ - if (bitsLeft < 0) - { - /* grab the remaining bits from the previous byte */ - if (pData->current.bitCount) - /*lint -e{504,734} this is a legitimate shift operation */ - value = pData->current.dataByte << -bitsLeft; - - /* read the next byte */ - if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) - return result; - bitsLeft += 8; - } - - /* more bits than needed? */ - if (bitsLeft > 0) - { - value |= pData->current.dataByte >> bitsLeft; - pData->current.bitCount = (EAS_U8) bitsLeft; - pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); - } - - /* exactly the right number of bits */ - else - { - value |= pData->current.dataByte; - pData->current.bitCount = 0; - } - - *pValue = value; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * OTA_SavePosition() - *---------------------------------------------------------------------------- - * Purpose: - * - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) -{ - EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); - return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); -} - -/*---------------------------------------------------------------------------- - * OTA_RestorePosition() - *---------------------------------------------------------------------------- - * Purpose: - * - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) -{ - EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); - pData->restore.fileOffset = -1; - return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); -} - + * + *---------------------------------------------------------------------------- + * Revision Control: + * $Revision: 795 $ + * $Date: 2007-08-01 00:14:45 -0700 (Wed, 01 Aug 2007) $ + *---------------------------------------------------------------------------- +*/ + +#include "eas_data.h" +#include "eas_miditypes.h" +#include "eas_parser.h" +#include "eas_report.h" +#include "eas_host.h" +#include "eas_midi.h" +#include "eas_config.h" +#include "eas_vm_protos.h" +#include "eas_otadata.h" + +/* increase gain for mono ringtones */ +#define OTA_GAIN_OFFSET 8 + +/* file definitions */ +#define OTA_RINGTONE 0x25 +#define OTA_SOUND 0x1d +#define OTA_UNICODE 0x22 + +/* song type definitions */ +#define OTA_BASIC_SONG_TYPE 0x01 +#define OTA_TEMPORARY_SONG_TYPE 0x02 + +/* instruction ID coding */ +#define OTA_PATTERN_HEADER_ID 0x00 +#define OTA_NOTE_INST_ID 0x01 +#define OTA_SCALE_INST_ID 0x02 +#define OTA_STYLE_INST_ID 0x03 +#define OTA_TEMPO_INST_ID 0x04 +#define OTA_VOLUME_INST_ID 0x05 + +/* note durations */ +#define OTA_NORMAL_DURATION 0x00 +#define OTA_DOTTED_NOTE 0x01 +#define OTA_DOUBLE_DOTTED_NOTE 0x02 +#define OTA_TRIPLET_NOTE 0x03 + +/* loop count value for infinite loop */ +#define OTA_INFINITE_LOOP 0x0f + +/* length of 32nd note in 1/256ths of a msec for 63 BPM tempo */ +#define DEFAULT_TICK_CONV 30476 + +/* default channel and program for OTA playback */ +#define OTA_CHANNEL 0 +#define OTA_PROGRAM 80 +#define OTA_VEL_MUL 4 +#define OTA_VEL_OFS 67 +#define OTA_VEL_DEFAULT 95 + +/* multiplier for fixed point triplet conversion */ +#define TRIPLET_MULTIPLIER 683 +#define TRIPLET_SHIFT 10 + +/* local prototypes */ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData); +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue); +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc); + + +/*---------------------------------------------------------------------------- + * + * EAS_OTA_Parser + * + * This structure contains the functional interface for the OTA parser + *---------------------------------------------------------------------------- +*/ +const S_FILE_PARSER_INTERFACE EAS_OTA_Parser = +{ + OTA_CheckFileType, + OTA_Prepare, + OTA_Time, + OTA_Event, + OTA_State, + OTA_Close, + OTA_Reset, + OTA_Pause, + OTA_Resume, + NULL, + OTA_SetData, + OTA_GetData, + NULL +}; + +/*---------------------------------------------------------------------------- + * + * bpmTable + * + * BPM conversion table. Converts bpm values to 256ths of a millisecond for a 32nd note + *---------------------------------------------------------------------------- +*/ +static const EAS_U32 bpmTable[32] = +{ + 76800, 68571, 61935, 54857, + 48000, 42667, 38400, 34286, + 30476, 27429, 24000, 21333, + 19200, 17143, 15360, 13714, + 12000, 10667, 9600, 8533, + 7680, 6737, 6000, 5408, + 4800, 4267, 3840, 3398, + 3024, 2685, 2400, 2133 +}; + +/*---------------------------------------------------------------------------- + * OTA_CheckFileType() + *---------------------------------------------------------------------------- + * Purpose: + * Check the file type to see if we can parse it + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_INT cmdLen; + EAS_INT state; + EAS_U8 temp; + + /* read the first byte, should be command length */ + *ppHandle = NULL; + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + cmdLen = temp; + state = 0; + while (cmdLen--) + { + + /* read the command, upper 7 bits */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &temp)) != EAS_SUCCESS) + return result; + temp = temp >> 1; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + break; + state++; + } + else + { + + if (temp == OTA_SOUND) + { + + /* check for static memory allocation */ + if (pEASData->staticMemoryModel) + pData = EAS_CMEnumData(EAS_CM_OTA_DATA); + else + pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_OTA_DATA)); + if (!pData) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Malloc failed in OTA_Prepare\n"); */ } + return EAS_ERROR_MALLOC_FAILED; + } + EAS_HWMemSet(pData, 0, sizeof(S_OTA_DATA)); + + /* return a pointer to the instance data */ + pData->fileHandle = fileHandle; + pData->fileOffset = offset; + pData->state = EAS_STATE_OPEN; + *ppHandle = pData; + break; + } + + if (temp != OTA_UNICODE) + break; + } + } + + /* not recognized */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Prepare() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + /* check for valid state */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state != EAS_STATE_OPEN) + return EAS_ERROR_NOT_VALID_IN_THIS_STATE; + + /* instantiate a synthesizer */ + if ((result = VMInitMIDI(pEASData, &pData->pSynth)) != EAS_SUCCESS) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } + return result; + } + + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader(pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Time() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the time of the next event in msecs + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pTime - pointer to variable to hold time of next event (in msecs) + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + + /* return time in milliseconds */ + /*lint -e{704} use shift instead of division */ + *pTime = pData->time >> 8; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Event() + *---------------------------------------------------------------------------- + * Purpose: + * Parse the next event in the file + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + EAS_U32 duration; + EAS_U8 temp; + + pData = (S_OTA_DATA*) pInstData; + if (pData->state >= EAS_STATE_OPEN) + return EAS_SUCCESS; + + /* initialize MIDI channel when the track starts playing */ + if (pData->time == 0) + { + /* set program to square lead */ + if (parserMode != eParserModeMetaData) + VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, OTA_PROGRAM); + + /* set channel volume to max */ + if (parserMode != eParserModeMetaData) + VMControlChange(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, 7, 127); + } + + /* check for end of note */ + if (pData->note) + { + /* stop the note */ + VMStopNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, 0); + pData->note = 0; + + /* check for rest between notes */ + if (pData->restTicks) + { + pData->time += (EAS_I32) pData->restTicks; + pData->restTicks = 0; + return EAS_SUCCESS; + } + } + + /* if not in a pattern, read the pattern header */ + while (pData->current.patternLen == 0) + { + + /* check for loop - don't do infinite loops when locating */ + if (pData->loopCount && ((parserMode == eParserModePlay) || (pData->loopCount != OTA_INFINITE_LOOP))) + { + /* if not infinite loop, decrement loop count */ + if (pData->loopCount != OTA_INFINITE_LOOP) + pData->loopCount--; + + /* back to start of pattern*/ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if no previous position to restore, continue forward */ + else if (pData->restore.fileOffset < 0) + { + + /* check for end of song */ + if (pData->numPatterns == 0) + { + pData->state = EAS_STATE_STOPPING; + VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth); + return EAS_SUCCESS; + } + + /* read the next pattern header */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + if (temp != OTA_PATTERN_HEADER_ID) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA pattern header\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the pattern ID */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->currentPattern)) != EAS_SUCCESS) + return result; + + /* get the loop count */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->loopCount)) != EAS_SUCCESS) + return result; + + /* get the pattern length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->current.patternLen)) != EAS_SUCCESS) + return result; + + /* if pattern definition, save the current position */ + if (pData->current.patternLen) + { + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* if pattern length is zero, repeat a previous pattern */ + else + { + /* make sure it's a valid pattern */ + if (pData->patterns[pData->currentPattern].fileOffset < 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA pattern error, invalid pattern specified\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* save current position and data */ + if ((result = OTA_SavePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + + /* seek to the pattern in the file */ + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->patterns[pData->currentPattern])) != EAS_SUCCESS) + return result; + } + + /* decrement pattern count */ + pData->numPatterns--; + } + + /* restore previous position */ + else + { + if ((result = OTA_RestorePosition(pEASData->hwInstData, pData, &pData->restore)) != EAS_SUCCESS) + return result; + } + } + + /* get the next event */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + switch (temp) + { + case OTA_NOTE_INST_ID: + /* fetch note value */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &pData->note)) != EAS_SUCCESS) + return result; + + /* fetch note duration */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + duration = pData->tick * (0x20 >> temp); + + /* fetch note duration modifier */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + switch (temp) + { + case OTA_NORMAL_DURATION: + break; + + case OTA_DOTTED_NOTE: + duration += duration >> 1; + break; + + case OTA_DOUBLE_DOTTED_NOTE: + duration += (duration >> 1) + (duration >> 2); + break; + + case OTA_TRIPLET_NOTE: + duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note duration ignored\n"); */ } + break; + } + + /* check for note */ + if (pData->note) + { + + /* determine note length based on style */ + switch (pData->style) + { + case 0: + pData->restTicks = duration >> 4; + break; + case 1: + pData->restTicks = 0; + break; + case 2: + pData->restTicks = duration >> 1; + break; + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unrecognized note style ignored\n"); */ } + } + + /* add octave */ + pData->note += pData->octave; + if (parserMode == eParserModePlay) + VMStartNote(pEASData->pVoiceMgr, pData->pSynth, OTA_CHANNEL, pData->note, pData->velocity); + pData->time += (EAS_I32) duration - (EAS_I32) pData->restTicks; + } + + /* this is a rest */ + else + pData->time += (EAS_I32) duration; + break; + + case OTA_SCALE_INST_ID: + /* fetch octave */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &temp)) != EAS_SUCCESS) + return result; + pData->octave = (EAS_U8) (temp * 12 + 59); + break; + + case OTA_STYLE_INST_ID: + /* fetch note style */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 2, &pData->style)) != EAS_SUCCESS) + return result; + break; + + case OTA_TEMPO_INST_ID: + /* fetch tempo */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 5, &temp)) != EAS_SUCCESS) + return result; + pData->tick = bpmTable[temp]; + break; + + case OTA_VOLUME_INST_ID: + /* fetch volume */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &temp)) != EAS_SUCCESS) + return result; + pData->velocity = temp ? (EAS_U8) (temp * OTA_VEL_MUL + OTA_VEL_OFS) : 0; + break; + + default: + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected instruction ID in OTA stream\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* decrement pattern length */ + pData->current.patternLen--; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_State() + *---------------------------------------------------------------------------- + * Purpose: + * Returns the current state of the stream + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * pState - pointer to variable to store state + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) +{ + S_OTA_DATA* pData; + + /* establish pointer to instance data */ + pData = (S_OTA_DATA*) pInstData; + + /* if stopping, check to see if synth voices are active */ + if (pData->state == EAS_STATE_STOPPING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_STOPPED; + } + + if (pData->state == EAS_STATE_PAUSING) + { + if (VMActiveVoices(pData->pSynth) == 0) + pData->state = EAS_STATE_PAUSED; + } + + /* return current state */ + *pState = pData->state; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Close() + *---------------------------------------------------------------------------- + * Purpose: + * Close the file and clean up + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* close the file */ + if ((result = EAS_HWCloseFile(pEASData->hwInstData, pData->fileHandle)) != EAS_SUCCESS) + return result; + + /* free the synth */ + if (pData->pSynth != NULL) + VMMIDIShutdown(pEASData, pData->pSynth); + + /* if using dynamic memory, free it */ + if (!pEASData->staticMemoryModel) + EAS_HWFree(pEASData->hwInstData, pData); + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Reset() + *---------------------------------------------------------------------------- + * Purpose: + * Reset the sequencer. Used for locating backwards in the file. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA* pData; + EAS_RESULT result; + + pData = (S_OTA_DATA*) pInstData; + + /* reset the synth */ + VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE); + pData->note = 0; + + /* reset file position and re-parse header */ + pData->state = EAS_STATE_ERROR; + if ((result = OTA_ParseHeader (pEASData, pData)) != EAS_SUCCESS) + return result; + + pData->state = EAS_STATE_READY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Pause() + *---------------------------------------------------------------------------- + * Purpose: + * Pauses the sequencer. Mutes all voices and sets state to pause. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't pause a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* mute the synthesizer */ + VMMuteAllVoices(pEASData->pVoiceMgr, pData->pSynth); + pData->state = EAS_STATE_PAUSING; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_Resume() + *---------------------------------------------------------------------------- + * Purpose: + * Resume playing after a pause, sets state back to playing. + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) +{ + S_OTA_DATA *pData; + + /* can't resume a stopped stream */ + pData = (S_OTA_DATA*) pInstData; + if (pData->state == EAS_STATE_STOPPED) + return EAS_ERROR_ALREADY_STOPPED; + + /* nothing to do but resume playback */ + pData->state = EAS_STATE_PLAY; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA *) pInstData; + switch (param) + { + + /* set metadata callback */ + case PARSER_DATA_METADATA_CB: + EAS_HWMemCpy(&pData->metadata, (void*) value, sizeof(S_METADATA_CB)); + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_GetData() + *---------------------------------------------------------------------------- + * Purpose: + * Return file type + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +/*lint -esym(715, pEASData) common decoder interface - pEASData not used */ +static EAS_RESULT OTA_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) +{ + S_OTA_DATA *pData; + + pData = (S_OTA_DATA*) pInstData; + switch (param) + { + /* return file type as OTA */ + case PARSER_DATA_FILE_TYPE: + *pValue = EAS_FILE_OTA; + break; + +#if 0 + /* set transposition */ + case PARSER_DATA_TRANSPOSITION: + *pValue = pData->transposition; + break; +#endif + + case PARSER_DATA_SYNTH_HANDLE: + *pValue = (EAS_I32) pData->pSynth; + break; + + case PARSER_DATA_GAIN_OFFSET: + *pValue = OTA_GAIN_OFFSET; + break; + + default: + return EAS_ERROR_INVALID_PARAMETER; + } + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_ParseHeader() + *---------------------------------------------------------------------------- + * Purpose: + * Prepare to parse the file. Allocates instance data (or uses static allocation for + * static memory model). + * + * Inputs: + * pEASData - pointer to overall EAS data structure + * handle - pointer to file handle + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_ParseHeader (S_EAS_DATA *pEASData, S_OTA_DATA* pData) +{ + EAS_RESULT result; + EAS_INT i; + EAS_INT state; + EAS_U8 temp; + EAS_U8 titleLen; + + /* initialize some data */ + pData->flags = 0; + pData->time = 0; + pData->tick = DEFAULT_TICK_CONV; + pData->patterns[0].fileOffset = pData->patterns[1].fileOffset = + pData->patterns[2].fileOffset = pData->patterns[3].fileOffset = -1; + pData->current.bitCount = 0; + pData->current.patternLen = 0; + pData->loopCount = 0; + pData->restore.fileOffset = -1; + pData->note = 0; + pData->restTicks = 0; + pData->velocity = OTA_VEL_DEFAULT; + pData->style = 0; + pData->octave = 59; + + /* seek to start of data */ + if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS) + return result; + + /* read the first byte, should be command length */ + if ((result = EAS_HWGetByte(pEASData->hwInstData, pData->fileHandle, &temp)) != EAS_SUCCESS) + return result; + + /* read all the commands */ + i = temp; + state = 0; + while (i--) + { + + /* fetch command, always starts on byte boundary */ + pData->current.bitCount = 0; + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 7, &temp)) != EAS_SUCCESS) + return result; + + if (state == 0) + { + if (temp != OTA_RINGTONE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Ring Tone Programming type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + state++; + } + else + { + + if (temp == OTA_SOUND) + break; + + if (temp == OTA_UNICODE) + pData->flags |= OTA_FLAGS_UNICODE; + else + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA Sound or Unicode type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + } + } + + /* get song type */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 3, &temp)) != EAS_SUCCESS) + return result; + + /* check for basic song type */ + if (temp == OTA_BASIC_SONG_TYPE) + { + /* fetch title length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 4, &titleLen)) != EAS_SUCCESS) + return result; + + /* if unicode, double the length */ + if (pData->flags & OTA_FLAGS_UNICODE) + titleLen = (EAS_U8) (titleLen << 1); + + /* zero the metadata buffer */ + if (pData->metadata.buffer) + EAS_HWMemSet(pData->metadata.buffer, 0, pData->metadata.bufferSize); + + /* read the song title */ + for (i = 0; i < titleLen; i++) + { + /* fetch character */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &temp)) != EAS_SUCCESS) + return result; + + /* check for metadata callback */ + if (pData->metadata.callback) + { + if (i < (pData->metadata.bufferSize - 1)) + pData->metadata.buffer[i] = (char) temp; + } + } + + /* if host has registered callback, call it now */ + if (pData->metadata.callback) + (*pData->metadata.callback)(EAS_METADATA_TITLE, pData->metadata.buffer, pData->metadata.pUserData); + } + + /* must be temporary song */ + else if (temp != OTA_TEMPORARY_SONG_TYPE) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Expected OTA basic or temporary song type\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* get the song length */ + if ((result = OTA_FetchBitField(pEASData->hwInstData, pData, 8, &pData->numPatterns)) != EAS_SUCCESS) + return result; + + /* sanity check */ + if (pData->numPatterns == 0) + { + { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "OTA number of patterns is zero\n"); */ } + return EAS_ERROR_FILE_FORMAT; + } + + /* at start of first pattern */ + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_FetchBitField() + *---------------------------------------------------------------------------- + * Purpose: + * Fetch a specified number of bits from the input stream + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_FetchBitField (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, EAS_I32 numBits, EAS_U8 *pValue) +{ + EAS_RESULT result; + EAS_I32 bitsLeft; + EAS_U8 value; + + value = 0; + + /* do we have enough bits? */ + bitsLeft = pData->current.bitCount - numBits; + + /* not enough bits, assemble them from 2 characters */ + if (bitsLeft < 0) + { + /* grab the remaining bits from the previous byte */ + if (pData->current.bitCount) + /*lint -e{504,734} this is a legitimate shift operation */ + value = pData->current.dataByte << -bitsLeft; + + /* read the next byte */ + if ((result = EAS_HWGetByte(hwInstData, pData->fileHandle, &pData->current.dataByte)) != EAS_SUCCESS) + return result; + bitsLeft += 8; + } + + /* more bits than needed? */ + if (bitsLeft > 0) + { + value |= pData->current.dataByte >> bitsLeft; + pData->current.bitCount = (EAS_U8) bitsLeft; + pData->current.dataByte = pData->current.dataByte & (0xff >> (8 - bitsLeft)); + } + + /* exactly the right number of bits */ + else + { + value |= pData->current.dataByte; + pData->current.bitCount = 0; + } + + *pValue = value; + return EAS_SUCCESS; +} + +/*---------------------------------------------------------------------------- + * OTA_SavePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_SavePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(pLoc, &pData->current, sizeof(S_OTA_LOC)); + return EAS_HWFilePos(hwInstData, pData->fileHandle, &pLoc->fileOffset); +} + +/*---------------------------------------------------------------------------- + * OTA_RestorePosition() + *---------------------------------------------------------------------------- + * Purpose: + * + * + * Inputs: + * + * + * Outputs: + * + * + * Side Effects: + * + *---------------------------------------------------------------------------- +*/ +static EAS_RESULT OTA_RestorePosition (EAS_HW_DATA_HANDLE hwInstData, S_OTA_DATA *pData, S_OTA_LOC *pLoc) +{ + EAS_HWMemCpy(&pData->current, pLoc, sizeof(S_OTA_LOC)); + pData->restore.fileOffset = -1; + return EAS_HWFileSeek(hwInstData, pData->fileHandle, pLoc->fileOffset); +} + -- cgit v1.2.3