/*---------------------------------------------------------------------------- | |
* | |
* File: | |
* eas_xmf.c | |
* 5 | |
* Contents and purpose: | |
* XMF File 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: 501 $ | |
* $Date: 2006-12-11 17:53:36 -0800 (Mon, 11 Dec 2006) $ | |
*---------------------------------------------------------------------------- | |
*/ | |
#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_xmf.h" | |
#include "eas_xmfdata.h" | |
#include "eas_config.h" | |
#include "eas_vm_protos.h" | |
#include "eas_mdls.h" | |
#include "eas_smf.h" | |
/* XMF header file type */ | |
#define XMF_IDENTIFIER 0x584d465f | |
#define XMF_VERSION_2_00 0x322e3030 | |
#define XMF_FILE_TYPE 0x00000002 | |
#define XMF_SPEC_LEVEL 0x00000001 | |
#define XMF_RIFF_CHUNK 0x52494646 | |
#define XMF_RIFF_DLS 0x444c5320 | |
#define XMF_SMF_CHUNK 0x4d546864 | |
/* local prototypes */ | |
static EAS_RESULT XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset); | |
static EAS_RESULT XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); | |
static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime); | |
static EAS_RESULT XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode); | |
static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState); | |
static EAS_RESULT XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); | |
static EAS_RESULT XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); | |
static EAS_RESULT XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); | |
static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData); | |
static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value); | |
static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue); | |
static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData); | |
static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength); | |
static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value); | |
/*---------------------------------------------------------------------------- | |
* | |
* XMF_Parser | |
* | |
* This structure contains the functional interface for the XMF parser | |
*---------------------------------------------------------------------------- | |
*/ | |
const S_FILE_PARSER_INTERFACE EAS_XMF_Parser = | |
{ | |
XMF_CheckFileType, | |
XMF_Prepare, | |
XMF_Time, | |
XMF_Event, | |
XMF_State, | |
XMF_Close, | |
XMF_Reset, | |
XMF_Pause, | |
XMF_Resume, | |
NULL, | |
XMF_SetData, | |
XMF_GetData, | |
NULL | |
}; | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) | |
{ | |
S_XMF_DATA *pXMFData; | |
EAS_RESULT result; | |
EAS_U32 temp; | |
/* assume we don't recognize it initially */ | |
*ppHandle = NULL; | |
/* read the file identifier */ | |
if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
if (temp != XMF_IDENTIFIER) | |
return EAS_SUCCESS; | |
/* read the version */ | |
if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
if (temp != XMF_VERSION_2_00) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file version was 0x%08x, expected 0x%08x\n", temp, XMF_VERSION_2_00); */ } | |
return EAS_SUCCESS; | |
} | |
/* read the file type */ | |
if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
if (temp != XMF_FILE_TYPE) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file type was 0x%08x, expected 0x%08x\n", temp, XMF_FILE_TYPE); */ } | |
return EAS_SUCCESS; | |
} | |
/* read the spec level */ | |
if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
if (temp != XMF_SPEC_LEVEL) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "XMF file spec was 0x%08x, expected 0x%08x\n", temp, XMF_SPEC_LEVEL); */ } | |
return EAS_SUCCESS; | |
} | |
/* check for static memory allocation */ | |
if (pEASData->staticMemoryModel) | |
pXMFData = EAS_CMEnumData(EAS_CM_XMF_DATA); | |
else | |
pXMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_XMF_DATA)); | |
if (!pXMFData) | |
return EAS_ERROR_MALLOC_FAILED; | |
/* zero the memory to insure complete initialization */ | |
EAS_HWMemSet((void *)pXMFData,0, sizeof(S_XMF_DATA)); | |
pXMFData->fileHandle = fileHandle; | |
pXMFData->fileOffset = offset; | |
*ppHandle = pXMFData; | |
/* locate the SMF and DLS contents */ | |
if ((result = XMF_FindFileContents(pEASData->hwInstData, pXMFData)) != EAS_SUCCESS) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ } | |
return result; | |
} | |
/* let the SMF parser take over */ | |
if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pXMFData->midiOffset)) != EAS_SUCCESS) | |
return result; | |
return SMF_CheckFileType(pEASData, fileHandle, &pXMFData->pSMFData, pXMFData->midiOffset); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) | |
{ | |
S_XMF_DATA* pXMFData; | |
EAS_RESULT result; | |
/* parse DLS collection */ | |
pXMFData = (S_XMF_DATA*) pInstData; | |
if (pXMFData->dlsOffset != 0) | |
{ | |
if ((result = DLSParser(pEASData->hwInstData, pXMFData->fileHandle, pXMFData->dlsOffset, &pXMFData->pDLS)) != EAS_SUCCESS) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "Error converting XMF DLS data\n"); */ } | |
return result; | |
} | |
} | |
/* Prepare the SMF parser */ | |
if ((result = SMF_Prepare(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS) | |
return result; | |
/* if no DLS file, skip this step */ | |
if (pXMFData->pDLS == NULL) | |
return EAS_SUCCESS; | |
/* tell the synth to use the DLS collection */ | |
result = VMSetDLSLib(((S_SMF_DATA*) pXMFData->pSMFData)->pSynth, pXMFData->pDLS); | |
if (result == EAS_SUCCESS) | |
{ | |
DLSAddRef(pXMFData->pDLS); | |
VMInitializeAllChannels(pEASData->pVoiceMgr, ((S_SMF_DATA*) pXMFData->pSMFData)->pSynth); | |
} | |
return result; | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) | |
{ | |
return SMF_Time(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pTime); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) | |
{ | |
return SMF_Event(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, parserMode); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) | |
{ | |
return SMF_State(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, pState); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) | |
{ | |
S_XMF_DATA* pXMFData; | |
EAS_RESULT result; | |
pXMFData = (S_XMF_DATA *)pInstData; | |
/* close the SMF stream, it will close the file handle */ | |
if ((result = SMF_Close(pEASData, pXMFData->pSMFData)) != EAS_SUCCESS) | |
return result; | |
if (pXMFData->pDLS) | |
DLSCleanup(pEASData->hwInstData, pXMFData->pDLS); | |
/* if using dynamic memory, free it */ | |
if (!pEASData->staticMemoryModel) | |
{ | |
/* free the instance data */ | |
EAS_HWFree(pEASData->hwInstData, pXMFData); | |
} | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) | |
{ | |
return SMF_Reset(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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 XMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) | |
{ | |
return SMF_Pause(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_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: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) | |
{ | |
return SMF_Resume(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_SetData() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* Sets the playback rate of the underlying SMF file | |
* | |
* Inputs: | |
* pEASData - pointer to overall EAS data structure | |
* handle - pointer to file handle | |
* rate - rate (28-bit fraction) | |
* | |
* Outputs: | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) | |
{ | |
return SMF_SetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, value); | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_GetData() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* Gets the file type | |
* | |
* Inputs: | |
* pEASData - pointer to overall EAS data structure | |
* handle - pointer to file handle | |
* rate - rate (28-bit fraction) | |
* | |
* Outputs: | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) | |
{ | |
EAS_RESULT result; | |
/* call SMF parser to get value */ | |
if ((result = SMF_GetData(pEASData, ((S_XMF_DATA*) pInstData)->pSMFData, param, pValue)) != EAS_SUCCESS) | |
return result; | |
/* special case for file type */ | |
if (param == PARSER_DATA_FILE_TYPE) | |
{ | |
if (*pValue == EAS_FILE_SMF0) | |
*pValue = EAS_FILE_XMF0; | |
else if (*pValue == EAS_FILE_SMF1) | |
*pValue = EAS_FILE_XMF1; | |
} | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_FindFileContents() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* Finds SMF data and DLS data in XMF file, and remembers offset for each. | |
* If more than one is found, uses the first one found of each. | |
* Makes assumptions about the format of a mobile XMF file | |
* | |
* Inputs: | |
* pEASData - pointer to overall EAS data structure | |
* pXMFData - pointer to XMF parser instance data | |
* handle - pointer to file handle | |
* | |
* Outputs: | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_FindFileContents (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData) | |
{ | |
EAS_RESULT result; | |
EAS_I32 value; | |
EAS_I32 length; | |
/* initialize offsets */ | |
pXMFData->dlsOffset = pXMFData->midiOffset = 0; | |
/* read file length, ignore it for now */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* read MetaDataTypesTable length and skip over it */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, value)) != EAS_SUCCESS) | |
return result; | |
/* get TreeStart offset and jump to it */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
if ((result = XMF_ReadNode(hwInstData, pXMFData, value, &length)) != EAS_SUCCESS) | |
return result; | |
/* check for SMF data */ | |
if (pXMFData->midiOffset == 0) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "No SMF data found in XMF file\n"); */ } | |
return EAS_ERROR_FILE_FORMAT; | |
} | |
/* check for SFM in wrong order */ | |
if ((pXMFData->dlsOffset > 0) && (pXMFData->midiOffset < pXMFData->dlsOffset)) | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "DLS data must precede SMF data in Mobile XMF file\n"); */ } | |
return EAS_SUCCESS; | |
} | |
/*---------------------------------------------------------------------------- | |
* XMF_ReadNode() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* | |
* Inputs: | |
* | |
* Outputs: | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_ReadNode (EAS_HW_DATA_HANDLE hwInstData, S_XMF_DATA *pXMFData, EAS_I32 nodeOffset, EAS_I32 *pLength) | |
{ | |
EAS_RESULT result; | |
EAS_I32 refType; | |
EAS_I32 numItems; | |
EAS_I32 offset; | |
EAS_I32 length; | |
EAS_I32 headerLength; | |
EAS_U32 chunkType; | |
/* seek to start of node */ | |
if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset)) != EAS_SUCCESS) | |
return result; | |
/* get node length */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, pLength)) != EAS_SUCCESS) | |
return result; | |
/* get number of contained items */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &numItems)) != EAS_SUCCESS) | |
return result; | |
/* get node header length */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &headerLength)) != EAS_SUCCESS) | |
return result; | |
/* get metadata length */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &length)) != EAS_SUCCESS) | |
return result; | |
/* get the current location */ | |
if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) | |
return result; | |
/* skip to node contents */ | |
if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, nodeOffset + headerLength)) != EAS_SUCCESS) | |
return result; | |
/* get reference type */ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &refType)) != EAS_SUCCESS) | |
return result; | |
/* get the current location */ | |
if ((result = EAS_HWFilePos(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) | |
return result; | |
/* process file node */ | |
if (numItems == 0) | |
{ | |
/* if in-file resource, find out where it is and jump to it */ | |
if (refType == 2) | |
{ | |
if ((result = XMF_ReadVLQ(hwInstData, pXMFData->fileHandle, &offset)) != EAS_SUCCESS) | |
return result; | |
offset += pXMFData->fileOffset; | |
if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS) | |
return result; | |
} | |
/* or else it must be an inline resource */ | |
else if (refType != 1) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Unexpected reference type %d\n", refType); */ } | |
return EAS_ERROR_FILE_FORMAT; | |
} | |
/* get the chunk type */ | |
if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
/* found a RIFF chunk, check for DLS type */ | |
if (chunkType == XMF_RIFF_CHUNK) | |
{ | |
/* skip length */ | |
if ((result = EAS_HWFileSeekOfs(hwInstData, pXMFData->fileHandle, sizeof(EAS_I32))) != EAS_SUCCESS) | |
return result; | |
/* get RIFF file type */ | |
if ((result = EAS_HWGetDWord(hwInstData, pXMFData->fileHandle, &chunkType, EAS_TRUE)) != EAS_SUCCESS) | |
return result; | |
if (chunkType == XMF_RIFF_DLS) | |
pXMFData->dlsOffset = offset; | |
} | |
/* found an SMF chunk */ | |
else if (chunkType == XMF_SMF_CHUNK) | |
pXMFData->midiOffset = offset; | |
} | |
/* folder node, process the items in the list */ | |
else | |
{ | |
for ( ; numItems > 0; numItems--) | |
{ | |
/* process this item */ | |
if ((result = XMF_ReadNode(hwInstData, pXMFData, offset, &length)) != EAS_SUCCESS) | |
return result; | |
/* seek to start of next item */ | |
offset += length; | |
if ((result = EAS_HWFileSeek(hwInstData, pXMFData->fileHandle, offset)) != EAS_SUCCESS) | |
return result; | |
} | |
} | |
return EAS_SUCCESS; | |
} | |
#if 0 | |
/*---------------------------------------------------------------------------- | |
* XMF_FindFileContents() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* Finds SMF data and DLS data in XMF file, and remembers offset for each. | |
* If more than one is found, uses the first one found of each. | |
* Makes assumptions about the format of a mobile XMF file | |
* | |
* Inputs: | |
* pEASData - pointer to overall EAS data structure | |
* pXMFData - pointer to XMF parser instance data | |
* handle - pointer to file handle | |
* | |
* Outputs: | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_FindFileContents(S_EAS_DATA *pEASData, S_XMF_DATA *pXMFData, EAS_FILE_HANDLE fileHandle) | |
{ | |
EAS_RESULT result; | |
EAS_I32 offset; | |
EAS_I32 value; | |
EAS_I32 numItems; | |
EAS_I32 length; | |
EAS_CHAR id[4]; | |
EAS_I32 location; | |
/* init dls offset, so that we know we haven't found a dls chunk yet */ | |
pXMFData->dlsOffset = 0; | |
/* read file length, ignore it for now */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* read MetaDataTypesTable length and skip over it */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
if ((result = EAS_HWFileSeekOfs(pEASData, fileHandle, value)) != EAS_SUCCESS) | |
return result; | |
/* get TreeStart offset and jump to it */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &offset)) != EAS_SUCCESS) | |
return result; | |
if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) | |
return result; | |
/* read node length, ignore it for now */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* read number of contained items */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &numItems)) != EAS_SUCCESS) | |
return result; | |
/*read node header length */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/*go to the node offset */ | |
if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS) | |
return result; | |
/* read Reference Type */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* make sure it is an in-line resource, for now */ | |
if (value != 1) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file tree\n"); */ } | |
return EAS_FAILURE; | |
} | |
/* parse through the list of items */ | |
while (numItems > 0) | |
{ | |
/*get current offset */ | |
if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &offset)) != EAS_SUCCESS) | |
return result; | |
/*read node length */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &length)) != EAS_SUCCESS) | |
return result; | |
/* read number of items */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* make sure not a folder */ | |
if (value != 0) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ } | |
return EAS_FAILURE; | |
} | |
/* read offset to resource and jump to it */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + value)) != EAS_SUCCESS) | |
return result; | |
/* read Reference Type */ | |
if ((result = XMF_ReadVLQ(pEASData, fileHandle, &value)) != EAS_SUCCESS) | |
return result; | |
/* make sure it is an in-line resource */ | |
if (value != 1) | |
{ | |
{ /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Problem parsing XMF file node\n"); */ } | |
return EAS_FAILURE; | |
} | |
/* get current offset as a possible location for SMF file or DLS file */ | |
if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &location)) != EAS_SUCCESS) | |
return result; | |
/* read four bytes */ | |
if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, id, sizeof(id), &value)) != EAS_SUCCESS) | |
return result; | |
/* check if DLS */ | |
if (pXMFData->dlsOffset == 0 && id[0] == 'R' && id[1] == 'I' && id[2] == 'F' && id[3] == 'F') | |
{ | |
//remember offset | |
pXMFData->dlsOffset = location; | |
} | |
/* else check if SMF */ | |
else if (id[0] == 'M' && id[1] == 'T' && id[2] == 'h' && id[3] == 'd') | |
{ | |
//remember offset | |
pXMFData->midiOffset = location; | |
//we are done | |
return EAS_SUCCESS; | |
} | |
//one less item | |
numItems--; | |
//if more data, go to the next item | |
if (numItems >0) | |
{ | |
if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset + length)) != EAS_SUCCESS) | |
return result; | |
} | |
} | |
return EAS_FAILURE; | |
} | |
#endif | |
/*---------------------------------------------------------------------------- | |
* XMF_ReadVLQ() | |
*---------------------------------------------------------------------------- | |
* Purpose: | |
* Reads a VLQ encoded value from the file referenced by fileHandle | |
* | |
* Inputs: | |
* pEASData - pointer to overall EAS data structure | |
* fileHandle - pointer to file handle | |
* | |
* Outputs: | |
* value - pointer to the value decoded from the VLQ data | |
* | |
* | |
* Side Effects: | |
* | |
*---------------------------------------------------------------------------- | |
*/ | |
static EAS_RESULT XMF_ReadVLQ (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_I32 *value) | |
{ | |
EAS_RESULT result; | |
EAS_U8 c; | |
*value = 0; | |
if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) | |
return result; | |
while (c > 0x7F) | |
{ | |
/*lint -e{703} shift for performance */ | |
*value = (*value << 7) | (c & 0x7F); | |
if ((result = EAS_HWGetByte(hwInstData, fileHandle, &c)) != EAS_SUCCESS) | |
return result; | |
} | |
/*lint -e{703} shift for performance */ | |
*value = (*value << 7) | c; | |
return EAS_SUCCESS; | |
} | |