summaryrefslogtreecommitdiffstats
path: root/arm-fm-22k/lib_src/eas_imelody.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm-fm-22k/lib_src/eas_imelody.c')
-rw-r--r--arm-fm-22k/lib_src/eas_imelody.c1738
1 files changed, 1738 insertions, 0 deletions
diff --git a/arm-fm-22k/lib_src/eas_imelody.c b/arm-fm-22k/lib_src/eas_imelody.c
new file mode 100644
index 0000000..9f4d541
--- /dev/null
+++ b/arm-fm-22k/lib_src/eas_imelody.c
@@ -0,0 +1,1738 @@
+/*----------------------------------------------------------------------------
+ *
+ * File:
+ * eas_imelody.c
+ *
+ * Contents and purpose:
+ * iMelody 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.
+ * You may obtain a copy of the License at
+ *
+ * http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * 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: 797 $
+ * $Date: 2007-08-01 00:15:56 -0700 (Wed, 01 Aug 2007) $
+ *----------------------------------------------------------------------------
+*/
+
+/* lint doesn't like the way some string.h files look */
+#ifdef _lint
+#include "lint_stdlib.h"
+#else
+#include <string.h>
+#endif
+
+#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_imelodydata.h"
+#include "eas_ctype.h"
+
+// #define _DEBUG_IMELODY
+
+/* increase gain for mono ringtones */
+#define IMELODY_GAIN_OFFSET 8
+
+/* length of 32nd note in 1/256ths of a msec for 120 BPM tempo */
+#define DEFAULT_TICK_CONV 16000
+#define TICK_CONVERT 1920000
+
+/* default channel and program for iMelody playback */
+#define IMELODY_CHANNEL 0
+#define IMELODY_PROGRAM 80
+#define IMELODY_VEL_MUL 4
+#define IMELODY_VEL_OFS 67
+
+/* multiplier for fixed point triplet conversion */
+#define TRIPLET_MULTIPLIER 683
+#define TRIPLET_SHIFT 10
+
+static const char* const tokens[] =
+{
+ "BEGIN:IMELODY",
+ "VERSION:",
+ "FORMAT:CLASS",
+ "NAME:",
+ "COMPOSER:",
+ "BEAT:",
+ "STYLE:",
+ "VOLUME:",
+ "MELODY:",
+ "END:IMELODY"
+};
+
+/* ledon or ledoff */
+static const char ledStr[] = "edo";
+
+/* vibeon or vibeoff */
+static const char vibeStr[] = "ibeo";
+
+/* backon or backoff */
+static const char backStr[] = "cko";
+
+typedef enum
+{
+ TOKEN_BEGIN,
+ TOKEN_VERSION,
+ TOKEN_FORMAT,
+ TOKEN_NAME,
+ TOKEN_COMPOSER,
+ TOKEN_BEAT,
+ TOKEN_STYLE,
+ TOKEN_VOLUME,
+ TOKEN_MELODY,
+ TOKEN_END,
+ TOKEN_INVALID
+} ENUM_IMELODY_TOKENS;
+
+/* lookup table for note values */
+static const EAS_I8 noteTable[] = { 9, 11, 0, 2, 4, 5, 7 };
+
+/* inline functions */
+#ifdef _DEBUG_IMELODY
+static void PutBackChar (S_IMELODY_DATA *pData)
+{
+ if (pData->index)
+ pData->index--;
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "PutBackChar '%c'\n", pData->buffer[pData->index]); */ }
+}
+#else
+EAS_INLINE void PutBackChar (S_IMELODY_DATA *pData) { if (pData->index) pData->index--; }
+#endif
+
+
+/* local prototypes */
+static EAS_RESULT IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset);
+static EAS_RESULT IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime);
+static EAS_RESULT IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode);
+static EAS_RESULT IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
+static EAS_RESULT IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
+static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
+static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode);
+static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
+static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration);
+static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
+static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
+static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData);
+static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader);
+static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader);
+static EAS_RESULT IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData);
+static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader);
+static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine);
+static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex);
+
+
+/*----------------------------------------------------------------------------
+ *
+ * EAS_iMelody_Parser
+ *
+ * This structure contains the functional interface for the iMelody parser
+ *----------------------------------------------------------------------------
+*/
+const S_FILE_PARSER_INTERFACE EAS_iMelody_Parser =
+{
+ IMY_CheckFileType,
+ IMY_Prepare,
+ IMY_Time,
+ IMY_Event,
+ IMY_State,
+ IMY_Close,
+ IMY_Reset,
+ IMY_Pause,
+ IMY_Resume,
+ NULL,
+ IMY_SetData,
+ IMY_GetData,
+ NULL
+};
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset)
+{
+ S_IMELODY_DATA* pData;
+ EAS_I8 buffer[MAX_LINE_SIZE+1];
+ EAS_U8 index;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_CheckFileType\n"); */ }
+#endif
+
+ /* read the first line of the file */
+ *ppHandle = NULL;
+ if (IMY_ReadLine(pEASData->hwInstData, fileHandle, buffer, NULL) != EAS_SUCCESS)
+ return EAS_SUCCESS;
+
+ /* check for header string */
+ if (IMY_ParseLine(buffer, &index) == TOKEN_BEGIN)
+ {
+
+ /* check for static memory allocation */
+ if (pEASData->staticMemoryModel)
+ pData = EAS_CMEnumData(EAS_CM_IMELODY_DATA);
+ else
+ pData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_IMELODY_DATA));
+ if (!pData)
+ return EAS_ERROR_MALLOC_FAILED;
+ EAS_HWMemSet(pData, 0, sizeof(S_IMELODY_DATA));
+
+ /* initialize */
+ pData->fileHandle = fileHandle;
+ pData->fileOffset = offset;
+ pData->state = EAS_STATE_ERROR;
+ pData->state = EAS_STATE_OPEN;
+
+ /* return a pointer to the instance data */
+ *ppHandle = pData;
+ }
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_IMELODY_DATA* pData;
+ EAS_RESULT result;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_Prepare\n"); */ }
+#endif
+
+ /* check for valid state */
+ pData = (S_IMELODY_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;
+ }
+
+ /* parse the header */
+ if ((result = IMY_ParseHeader(pEASData, pData)) != EAS_SUCCESS)
+ return result;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Prepare: state set to EAS_STATE_READY\n"); */ }
+#endif
+
+ pData ->state = EAS_STATE_READY;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime)
+{
+ S_IMELODY_DATA *pData;
+
+ pData = (S_IMELODY_DATA*) pInstData;
+
+ /* return time in milliseconds */
+ /*lint -e{704} use shift instead of division */
+ *pTime = pData->time >> 8;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode)
+{
+ S_IMELODY_DATA* pData;
+ EAS_RESULT result;
+ EAS_I8 c;
+ EAS_BOOL eof;
+ EAS_INT temp;
+
+ pData = (S_IMELODY_DATA*) pInstData;
+ if (pData->state >= EAS_STATE_OPEN)
+ return EAS_SUCCESS;
+
+ /* initialize MIDI channel when the track starts playing */
+ if (pData->time == 0)
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: Reset\n"); */ }
+#endif
+ /* set program to square lead */
+ VMProgramChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, IMELODY_PROGRAM);
+
+ /* set channel volume to max */
+ VMControlChange(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, 7, 127);
+ }
+
+ /* check for end of note */
+ if (pData->note)
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Stopping note %d\n", pData->note); */ }
+#endif
+ /* stop the note */
+ VMStopNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, 0);
+ pData->note = 0;
+
+ /* check for rest between notes */
+ if (pData->restTicks)
+ {
+ pData->time += pData->restTicks;
+ pData->restTicks = 0;
+ return EAS_SUCCESS;
+ }
+ }
+
+ /* parse the next event */
+ eof = EAS_FALSE;
+ while (!eof)
+ {
+
+ /* get next character */
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
+
+ switch (c)
+ {
+ /* start repeat */
+ case '(':
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter repeat section\n", c); */ }
+#endif
+
+ if (pData->repeatOffset < 0)
+ {
+ pData->repeatOffset = pData->startLine + (EAS_I32) pData->index;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat offset = %d\n", pData->repeatOffset); */ }
+#endif
+ }
+ else
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring nested repeat section\n"); */ }
+ break;
+
+ /* end repeat */
+ case ')':
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "End repeat section, repeat offset = %d\n", pData->repeatOffset); */ }
+#endif
+ /* ignore invalid repeats */
+ if (pData->repeatCount >= 0)
+ {
+
+ /* decrement repeat count (repeatCount == 0 means infinite loop) */
+ if (pData->repeatCount > 0)
+ {
+ if (--pData->repeatCount == 0)
+ {
+ pData->repeatCount = -1;
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat loop complete\n"); */ }
+#endif
+ }
+ }
+
+//2 TEMPORARY FIX: If locating, don't do infinite loops.
+//3 We need a different mode for metadata parsing where we don't loop at all
+ if ((parserMode == eParserModePlay) || (pData->repeatCount != 0))
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Rewinding file for repeat\n"); */ }
+#endif
+ /* rewind to start of loop */
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->repeatOffset)) != EAS_SUCCESS)
+ return result;
+ IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine);
+ pData->index = 0;
+
+ /* if last loop, prevent future loops */
+ if (pData->repeatCount == -1)
+ pData->repeatOffset = -1;
+ }
+ }
+ break;
+
+ /* repeat count */
+ case '@':
+ if (!IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_FALSE))
+ eof = EAS_TRUE;
+ else if (pData->repeatOffset > 0)
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Repeat count = %dt", pData->repeatCount); */ }
+#endif
+ if (pData->repeatCount < 0)
+ pData->repeatCount = (EAS_I16) temp;
+ }
+ break;
+
+ /* volume */
+ case 'V':
+ if (!IMY_GetVolume(pEASData->hwInstData, pData, EAS_FALSE))
+ eof = EAS_TRUE;
+ break;
+
+ /* flat */
+ case '&':
+ pData->noteModifier = -1;
+ break;
+
+ /* sharp */
+ case '#':
+ pData->noteModifier = +1;
+ break;
+
+ /* octave */
+ case '*':
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
+ if (IsDigit(c))
+ pData->octave = (EAS_U8) ((c - '0' + 1) * 12);
+ else if (!c)
+ eof = EAS_TRUE;
+ break;
+
+ /* ledon or ledoff */
+ case 'l':
+ if (!IMY_GetLEDState(pEASData, pData))
+ eof = EAS_TRUE;
+ break;
+
+ /* vibeon or vibeoff */
+ case 'v':
+ if (!IMY_GetVibeState(pEASData, pData))
+ eof = EAS_TRUE;
+ break;
+
+ /* either a B note or backon or backoff */
+ case 'b':
+ if (IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE) == 'a')
+ {
+ if (!IMY_GetBackState(pEASData, pData))
+ eof = EAS_TRUE;
+ }
+ else
+ {
+ PutBackChar(pData);
+ if (IMY_PlayNote(pEASData, pData, c, parserMode))
+ return EAS_SUCCESS;
+ eof = EAS_TRUE;
+ }
+ break;
+
+ /* rest */
+ case 'r':
+ case 'R':
+ if (IMY_PlayRest(pEASData, pData))
+ return EAS_SUCCESS;
+ eof = EAS_TRUE;
+ break;
+
+ /* EOF */
+ case 0:
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: end of iMelody file detected\n"); */ }
+#endif
+ eof = EAS_TRUE;
+ break;
+
+ /* must be a note */
+ default:
+ c = ToLower(c);
+ if ((c >= 'a') && (c <= 'g'))
+ {
+ if (IMY_PlayNote(pEASData, pData, c, parserMode))
+ return EAS_SUCCESS;
+ eof = EAS_TRUE;
+ }
+ else
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unexpected character '%c' [0x%02x]\n", c, c); */ }
+ break;
+ }
+ }
+
+ /* handle EOF */
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Event: state set to EAS_STATE_STOPPING\n"); */ }
+#endif
+ pData->state = EAS_STATE_STOPPING;
+ VMReleaseAllVoices(pEASData->pVoiceMgr, pData->pSynth);
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState)
+{
+ S_IMELODY_DATA* pData;
+
+ /* establish pointer to instance data */
+ pData = (S_IMELODY_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;
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_STOPPED\n"); */ }
+#endif
+ }
+ }
+
+ if (pData->state == EAS_STATE_PAUSING)
+ {
+ if (VMActiveVoices(pData->pSynth) == 0)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_State: state set to EAS_STATE_PAUSED\n"); */ }
+#endif
+ pData->state = EAS_STATE_PAUSED;
+ }
+ }
+
+ /* return current state */
+ *pState = pData->state;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_IMELODY_DATA* pData;
+ EAS_RESULT result;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Close: close file\n"); */ }
+#endif
+
+ pData = (S_IMELODY_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;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_IMELODY_DATA* pData;
+ EAS_RESULT result;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: reset file\n"); */ }
+#endif
+ pData = (S_IMELODY_DATA*) pInstData;
+
+ /* reset the synth */
+ VMReset(pEASData->pVoiceMgr, pData->pSynth, EAS_TRUE);
+
+ /* reset time to zero */
+ pData->time = 0;
+ pData->note = 0;
+
+ /* reset file position and re-parse header */
+ pData->state = EAS_STATE_ERROR;
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, pData->fileHandle, pData->fileOffset)) != EAS_SUCCESS)
+ return result;
+ if ((result = IMY_ParseHeader (pEASData, pData)) != EAS_SUCCESS)
+ return result;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Reset: state set to EAS_STATE_ERROR\n"); */ }
+#endif
+
+ pData->state = EAS_STATE_READY;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_IMELODY_DATA *pData;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Pause: pause file\n"); */ }
+#endif
+
+ /* can't pause a stopped stream */
+ pData = (S_IMELODY_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;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_IMELODY_DATA *pData;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_Resume: resume file\n"); */ }
+#endif
+
+ /* can't resume a stopped stream */
+ pData = (S_IMELODY_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;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_SetData()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Adjust tempo relative to song tempo
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * pInstData - pointer to iMelody instance data
+ * rate - rate (28-bit fractional amount)
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
+static EAS_RESULT IMY_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
+{
+ S_IMELODY_DATA *pData;
+
+ pData = (S_IMELODY_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;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetData()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Return the file type
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * pInstData - pointer to iMelody instance data
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pEASData) common decoder interface - pEASData not used */
+static EAS_RESULT IMY_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
+{
+ S_IMELODY_DATA *pData;
+
+ pData = (S_IMELODY_DATA*) pInstData;
+
+ switch (param)
+ {
+ /* return file type as iMelody */
+ case PARSER_DATA_FILE_TYPE:
+ *pValue = EAS_FILE_IMELODY;
+ break;
+
+ case PARSER_DATA_SYNTH_HANDLE:
+ *pValue = (EAS_I32) pData->pSynth;
+ break;
+
+ case PARSER_DATA_GAIN_OFFSET:
+ *pValue = IMELODY_GAIN_OFFSET;
+ break;
+
+ default:
+ return EAS_ERROR_INVALID_PARAMETER;
+ }
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_PlayNote()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_PlayNote (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData, EAS_I8 note, EAS_INT parserMode)
+{
+ EAS_I32 duration;
+ EAS_U8 velocity;
+
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: start note %d\n", note); */ }
+#endif
+
+ /* get the duration */
+ if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration))
+ return EAS_FALSE;
+
+ /* save note value */
+ pData->note = (EAS_U8) (pData->octave + noteTable[note - 'a'] + pData->noteModifier);
+ velocity = (EAS_U8) (pData->volume ? pData->volume * IMELODY_VEL_MUL + IMELODY_VEL_OFS : 0);
+
+ /* start note only if in play mode */
+ if (parserMode == eParserModePlay)
+ VMStartNote(pEASData->pVoiceMgr, pData->pSynth, IMELODY_CHANNEL, pData->note, velocity);
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayNote: Start note %d, duration %d\n", pData->note, duration); */ }
+#endif
+
+ /* determine note length */
+ switch (pData->style)
+ {
+ case 0:
+ /*lint -e{704} shift for performance */
+ pData->restTicks = duration >> 4;
+ break;
+ case 1:
+ pData->restTicks = 0;
+ break;
+ case 2:
+ /*lint -e{704} shift for performance */
+ pData->restTicks = duration >> 1;
+ break;
+ default:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "IMY_PlayNote: Note style out of range: %d\n", pData->style); */ }
+ /*lint -e{704} shift for performance */
+ pData->restTicks = duration >> 4;
+ break;
+ }
+
+ /* next event is at end of this note */
+ pData->time += duration - pData->restTicks;
+
+ /* reset the flat/sharp modifier */
+ pData->noteModifier = 0;
+
+ return EAS_TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_PlayRest()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_PlayRest (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
+{
+ EAS_I32 duration;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_PlayRest]n"); */ }
+#endif
+
+ /* get the duration */
+ if (!IMY_GetDuration(pEASData->hwInstData, pData, &duration))
+ return EAS_FALSE;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_PlayRest: note duration %d\n", duration); */ }
+#endif
+
+ /* next event is at end of this note */
+ pData->time += duration;
+ return EAS_TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetDuration()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+
+static EAS_BOOL IMY_GetDuration (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_I32 *pDuration)
+{
+ EAS_I32 duration;
+ EAS_I8 c;
+
+ /* get the duration */
+ *pDuration = 0;
+ c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE);
+ if (!c)
+ return EAS_FALSE;
+ if ((c < '0') || (c > '5'))
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetDuration: error in duration '%c'\n", c); */ }
+#endif
+ return EAS_FALSE;
+ }
+
+ /* calculate total length of note */
+ duration = pData->tick * (1 << ('5' - c));
+
+ /* check for duration modifier */
+ c = IMY_GetNextChar(hwInstData, pData, EAS_FALSE);
+ if (c)
+ {
+ if (c == '.')
+ /*lint -e{704} shift for performance */
+ duration += duration >> 1;
+ else if (c == ':')
+ /*lint -e{704} shift for performance */
+ duration += (duration >> 1) + (duration >> 2);
+ else if (c == ';')
+ /*lint -e{704} shift for performance */
+ duration = (duration * TRIPLET_MULTIPLIER) >> TRIPLET_SHIFT;
+ else
+ PutBackChar(pData);
+ }
+
+ *pDuration = duration;
+ return EAS_TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetLEDState()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetLEDState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
+{
+ EAS_I8 c;
+ EAS_INT i;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetLEDState\n"); */ }
+#endif
+
+ for (i = 0; i < 5; i++)
+ {
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
+ if (!c)
+ return EAS_FALSE;
+ switch (i)
+ {
+ case 3:
+ if (c == 'n')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED on\n"); */ }
+#endif
+ EAS_HWLED(pEASData->hwInstData, EAS_TRUE);
+ return EAS_TRUE;
+ }
+ else if (c != 'f')
+ return EAS_FALSE;
+ break;
+
+ case 4:
+ if (c == 'f')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetLEDState: LED off\n"); */ }
+#endif
+ EAS_HWLED(pEASData->hwInstData, EAS_FALSE);
+ return EAS_TRUE;
+ }
+ return EAS_FALSE;
+
+ default:
+ if (c != ledStr[i])
+ return EAS_FALSE;
+ break;
+ }
+ }
+ return EAS_FALSE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetVibeState()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetVibeState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
+{
+ EAS_I8 c;
+ EAS_INT i;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVibeState\n"); */ }
+#endif
+
+ for (i = 0; i < 6; i++)
+ {
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
+ if (!c)
+ return EAS_FALSE;
+ switch (i)
+ {
+ case 4:
+ if (c == 'n')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate on\n"); */ }
+#endif
+ EAS_HWVibrate(pEASData->hwInstData, EAS_TRUE);
+ return EAS_TRUE;
+ }
+ else if (c != 'f')
+ return EAS_FALSE;
+ break;
+
+ case 5:
+ if (c == 'f')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVibeState: vibrate off\n"); */ }
+#endif
+ EAS_HWVibrate(pEASData->hwInstData, EAS_FALSE);
+ return EAS_TRUE;
+ }
+ return EAS_FALSE;
+
+ default:
+ if (c != vibeStr[i])
+ return EAS_FALSE;
+ break;
+ }
+ }
+ return EAS_FALSE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetBackState()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetBackState (S_EAS_DATA *pEASData, S_IMELODY_DATA *pData)
+{
+ EAS_I8 c;
+ EAS_INT i;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetBackState\n"); */ }
+#endif
+
+ for (i = 0; i < 5; i++)
+ {
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_FALSE);
+ if (!c)
+ return EAS_FALSE;
+ switch (i)
+ {
+ case 3:
+ if (c == 'n')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight on\n"); */ }
+#endif
+ EAS_HWBackLight(pEASData->hwInstData, EAS_TRUE);
+ return EAS_TRUE;
+ }
+ else if (c != 'f')
+ return EAS_FALSE;
+ break;
+
+ case 4:
+ if (c == 'f')
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetBackState: backlight off\n"); */ }
+#endif
+ EAS_HWBackLight(pEASData->hwInstData, EAS_FALSE);
+ return EAS_TRUE;
+ }
+ return EAS_FALSE;
+
+ default:
+ if (c != backStr[i])
+ return EAS_FALSE;
+ break;
+ }
+ }
+ return EAS_FALSE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetVolume()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetVolume (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader)
+{
+ EAS_INT temp;
+ EAS_I8 c;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetVolume\n"); */ }
+#endif
+
+ c = IMY_GetNextChar(hwInstData, pData, inHeader);
+ if (c == '+')
+ {
+ if (pData->volume < 15)
+ pData->volume++;
+ return EAS_TRUE;
+ }
+ else if (c == '-')
+ {
+ if (pData->volume > 0)
+ pData->volume--;
+ return EAS_TRUE;
+ }
+ else if (IsDigit(c))
+ temp = c - '0';
+ else
+ return EAS_FALSE;
+
+ c = IMY_GetNextChar(hwInstData, pData, inHeader);
+ if (IsDigit(c))
+ temp = temp * 10 + c - '0';
+ else if (c)
+ PutBackChar(pData);
+ if ((temp >= 0) && (temp <= 15))
+ {
+ if (inHeader && (temp == 0))
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring V0 encountered in header\n"); */ }
+ else
+ pData->volume = (EAS_U8) temp;
+ }
+ return EAS_TRUE;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetNumber()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetNumber (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_INT *temp, EAS_BOOL inHeader)
+{
+ EAS_BOOL ok;
+ EAS_I8 c;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_GetNumber\n"); */ }
+#endif
+
+ *temp = 0;
+ ok = EAS_FALSE;
+ for (;;)
+ {
+ c = IMY_GetNextChar(hwInstData, pData, inHeader);
+ if (IsDigit(c))
+ {
+ *temp = *temp * 10 + c - '0';
+ ok = EAS_TRUE;
+ }
+ else
+ {
+ if (c)
+ PutBackChar(pData);
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNumber: value %d\n", *temp); */ }
+#endif
+
+ return ok;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetVersion()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_BOOL IMY_GetVersion (S_IMELODY_DATA *pData, EAS_INT *pVersion)
+{
+ EAS_I8 c;
+ EAS_INT temp;
+ EAS_INT version;
+
+ version = temp = 0;
+ for (;;)
+ {
+ c = pData->buffer[pData->index++];
+ if ((c == 0) || (c == '.'))
+ {
+ /*lint -e{701} use shift for performance */
+ version = (version << 8) + temp;
+ if (c == 0)
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetVersion: version 0x%04x\n", version); */ }
+#endif
+
+ *pVersion = version;
+ return EAS_TRUE;
+ }
+ temp = 0;
+ }
+ else if (IsDigit(c))
+ temp = (temp * 10) + c - '0';
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_MetaData()
+ *----------------------------------------------------------------------------
+ * 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 void IMY_MetaData (S_IMELODY_DATA *pData, E_EAS_METADATA_TYPE metaType, EAS_I8 *buffer)
+{
+ EAS_I32 len;
+
+ /* check for callback */
+ if (!pData->metadata.callback)
+ return;
+
+ /* copy data to host buffer */
+ len = (EAS_I32) strlen((char*) buffer);
+ if (len >pData->metadata.bufferSize)
+ len = pData->metadata.bufferSize;
+ strncpy((char*) pData->metadata.buffer, (char*) buffer, (size_t) len);
+ pData->metadata.buffer[len] = 0;
+
+ /* callback to host */
+ pData->metadata.callback(metaType, pData->metadata.buffer, pData->metadata.pUserData);
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_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 IMY_ParseHeader (S_EAS_DATA *pEASData, S_IMELODY_DATA* pData)
+{
+ EAS_RESULT result;
+ EAS_INT token;
+ EAS_INT temp;
+ EAS_I8 c;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Enter IMY_ParseHeader\n"); */ }
+#endif
+
+ /* initialize some defaults */
+ pData->time = 0;
+ pData->tick = DEFAULT_TICK_CONV;
+ pData->note = 0;
+ pData->noteModifier = 0;
+ pData ->restTicks = 0;
+ pData->volume = 7;
+ pData->octave = 60;
+ pData->repeatOffset = -1;
+ pData->repeatCount = -1;
+ pData->style = 0;
+
+ /* force the read of the first line */
+ pData->index = 1;
+
+ /* read data until we get to melody */
+ for (;;)
+ {
+ /* read a line from the file and parse the token */
+ if (pData->index != 0)
+ {
+ if ((result = IMY_ReadLine(pEASData->hwInstData, pData->fileHandle, pData->buffer, &pData->startLine)) != EAS_SUCCESS)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: IMY_ReadLine returned %d\n", result); */ }
+#endif
+ return result;
+ }
+ }
+ token = IMY_ParseLine(pData->buffer, &pData->index);
+
+ switch (token)
+ {
+ /* ignore these valid tokens */
+ case TOKEN_BEGIN:
+ break;
+
+ case TOKEN_FORMAT:
+ if (!IMY_GetVersion(pData, &temp))
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid FORMAT field '%s'\n", pData->buffer); */ }
+ return EAS_ERROR_FILE_FORMAT;
+ }
+ if ((temp != 0x0100) && (temp != 0x0200))
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported FORMAT %02x\n", temp); */ }
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+ }
+ break;
+
+ case TOKEN_VERSION:
+ if (!IMY_GetVersion(pData, &temp))
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Invalid VERSION field '%s'\n", pData->buffer); */ }
+ return EAS_ERROR_FILE_FORMAT;
+ }
+ if ((temp != 0x0100) && (temp != 0x0102))
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unsupported VERSION %02x\n", temp); */ }
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+ }
+ break;
+
+ case TOKEN_NAME:
+ IMY_MetaData(pData, EAS_METADATA_TITLE, pData->buffer + pData->index);
+ break;
+
+ case TOKEN_COMPOSER:
+ IMY_MetaData(pData, EAS_METADATA_AUTHOR, pData->buffer + pData->index);
+ break;
+
+ /* handle beat */
+ case TOKEN_BEAT:
+ IMY_GetNumber(pEASData->hwInstData, pData, &temp, EAS_TRUE);
+ if ((temp >= 25) && (temp <= 900))
+ pData->tick = TICK_CONVERT / temp;
+ break;
+
+ /* handle style */
+ case TOKEN_STYLE:
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
+ if (c == 'S')
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
+ if ((c >= '0') && (c <= '2'))
+ pData->style = (EAS_U8) (c - '0');
+ else
+ {
+ PutBackChar(pData);
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in style command: %s\n", pData->buffer); */ }
+ }
+ break;
+
+ /* handle volume */
+ case TOKEN_VOLUME:
+ c = IMY_GetNextChar(pEASData->hwInstData, pData, EAS_TRUE);
+ if (c != 'V')
+ {
+ PutBackChar(pData);
+ if (!IsDigit(c))
+ {
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error in volume command: %s\n", pData->buffer); */ }
+ break;
+ }
+ }
+ IMY_GetVolume(pEASData->hwInstData, pData, EAS_TRUE);
+ break;
+
+ case TOKEN_MELODY:
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Header successfully parsed\n"); */ }
+#endif
+ return EAS_SUCCESS;
+
+ case TOKEN_END:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Unexpected END:IMELODY encountered\n"); */ }
+ return EAS_ERROR_FILE_FORMAT;
+
+ default:
+ /* force a read of the next line */
+ pData->index = 1;
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Ignoring unrecognized token in iMelody file: %s\n", pData->buffer); */ }
+ break;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_GetNextChar()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_I8 IMY_GetNextChar (EAS_HW_DATA_HANDLE hwInstData, S_IMELODY_DATA *pData, EAS_BOOL inHeader)
+{
+ EAS_I8 c;
+ EAS_U8 index;
+
+ for (;;)
+ {
+ /* get next character */
+ c = pData->buffer[pData->index++];
+
+ /* buffer empty, read more */
+ if (!c)
+ {
+ /* don't read the next line in the header */
+ if (inHeader)
+ return 0;
+
+ pData->index = 0;
+ pData->buffer[0] = 0;
+ if (IMY_ReadLine(hwInstData, pData->fileHandle, pData->buffer, &pData->startLine) != EAS_SUCCESS)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: EOF\n"); */ }
+#endif
+ return 0;
+ }
+
+ /* check for END:IMELODY token */
+ if (IMY_ParseLine(pData->buffer, &index) == TOKEN_END)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar: found END:IMELODY\n"); */ }
+#endif
+ pData->buffer[0] = 0;
+ return 0;
+ }
+ continue;
+ }
+
+ /* ignore white space */
+ if (!IsSpace(c))
+ {
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_GetNextChar returned '%c'\n", c); */ }
+#endif
+ return c;
+ }
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_ReadLine()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Reads a line of input from the file, discarding the CR/LF
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT IMY_ReadLine (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I8 *buffer, EAS_I32 *pStartLine)
+{
+ EAS_RESULT result;
+ EAS_INT i;
+ EAS_I8 c;
+
+ /* fetch current file position and save it */
+ if (pStartLine != NULL)
+ {
+ if ((result = EAS_HWFilePos(hwInstData, fileHandle, pStartLine)) != EAS_SUCCESS)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseHeader: EAS_HWFilePos returned %d\n", result); */ }
+#endif
+ return result;
+ }
+ }
+
+ buffer[0] = 0;
+ for (i = 0; i < MAX_LINE_SIZE; )
+ {
+ if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS)
+ {
+ if ((result == EAS_EOF) && (i > 0))
+ break;
+ return result;
+ }
+
+ /* return on LF or end of data */
+ if (c == '\n')
+ break;
+
+ /* store characters in buffer */
+ if (c != '\r')
+ buffer[i++] = c;
+ }
+ buffer[i] = 0;
+
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ReadLine read %s\n", buffer); */ }
+#endif
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * IMY_ParseLine()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ *
+ * Inputs:
+ *
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_INT IMY_ParseLine (EAS_I8 *buffer, EAS_U8 *pIndex)
+{
+ EAS_INT i;
+ EAS_INT j;
+
+ /* there's no strnicmp() in stdlib, so we have to roll our own */
+ for (i = 0; i < TOKEN_INVALID; i++)
+ {
+ for (j = 0; ; j++)
+ {
+ /* end of token, must be a match */
+ if (tokens[i][j] == 0)
+ {
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine found token %d\n", i); */ }
+#endif
+ *pIndex = (EAS_U8) j;
+ return i;
+ }
+ if (tokens[i][j] != ToUpper(buffer[j]))
+ break;
+ }
+ }
+#ifdef _DEBUG_IMELODY
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "IMY_ParseLine: no token found\n"); */ }
+#endif
+ return TOKEN_INVALID;
+}
+