diff options
author | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:36 -0800 |
---|---|---|
committer | The Android Open Source Project <initial-contribution@android.com> | 2009-03-03 18:28:36 -0800 |
commit | 1b52a76815aa068a3477bfdfaf58718d41d7f9b4 (patch) | |
tree | 4b825dc642cb6eb9a060e54bf8d69288fbee4904 /arm-wt-22k/lib_src/eas_smf.c | |
parent | 251d5a6afb8ebdccc8df9d438acc2761001d8bec (diff) | |
download | android_external_sonivox-1b52a76815aa068a3477bfdfaf58718d41d7f9b4.tar.gz android_external_sonivox-1b52a76815aa068a3477bfdfaf58718d41d7f9b4.tar.bz2 android_external_sonivox-1b52a76815aa068a3477bfdfaf58718d41d7f9b4.zip |
auto import from //depot/cupcake/@135843
Diffstat (limited to 'arm-wt-22k/lib_src/eas_smf.c')
-rw-r--r-- | arm-wt-22k/lib_src/eas_smf.c | 1207 |
1 files changed, 0 insertions, 1207 deletions
diff --git a/arm-wt-22k/lib_src/eas_smf.c b/arm-wt-22k/lib_src/eas_smf.c deleted file mode 100644 index af02c93..0000000 --- a/arm-wt-22k/lib_src/eas_smf.c +++ /dev/null @@ -1,1207 +0,0 @@ -/*---------------------------------------------------------------------------- - * - * File: - * eas_smf.c - * - * Contents and purpose: - * SMF Type 0 and 1 File Parser - * - * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". - * - * 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: 803 $ - * $Date: 2007-08-01 09:57:00 -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_smfdata.h" -#include "eas_smf.h" - -#ifdef JET_INTERFACE -#include "jet_data.h" -#endif - -//3 dls: The timebase for this module is adequate to keep MIDI and -//3 digital audio synchronized for only a few minutes. It should be -//3 sufficient for most mobile applications. If better accuracy is -//3 required, more fractional bits should be added to the timebase. - -static const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; - -/* local prototypes */ -static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); -static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); -static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); -static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); -static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); -static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); - - -/*---------------------------------------------------------------------------- - * - * SMF_Parser - * - * This structure contains the functional interface for the SMF parser - *---------------------------------------------------------------------------- -*/ -const S_FILE_PARSER_INTERFACE EAS_SMF_Parser = -{ - SMF_CheckFileType, - SMF_Prepare, - SMF_Time, - SMF_Event, - SMF_State, - SMF_Close, - SMF_Reset, - SMF_Pause, - SMF_Resume, - NULL, - SMF_SetData, - SMF_GetData, - NULL -}; - -/*---------------------------------------------------------------------------- - * SMF_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: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) -{ - S_SMF_DATA* pSMFData; - EAS_RESULT result; - - /* seek to starting offset - usually 0 */ - *ppHandle = NULL; - if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) - return result; - - /* search through file for header - slow method */ - if (pEASData->searchHeaderFlag) - { - result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); - if (result != EAS_SUCCESS) - return (result == EAS_EOF) ? EAS_SUCCESS : result; - } - - /* read the first 4 bytes of the file - quick method */ - else { - EAS_U8 header[4]; - EAS_I32 count; - if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) - return result; - - /* check for 'MTrk' - return if no match */ - if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) - return EAS_SUCCESS; - } - - /* check for static memory allocation */ - if (pEASData->staticMemoryModel) - pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); - else - { - pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); - EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); - } - if (!pSMFData) - return EAS_ERROR_MALLOC_FAILED; - - /* initialize some critical data */ - pSMFData->fileHandle = fileHandle; - pSMFData->fileOffset = offset; - pSMFData->pSynth = NULL; - pSMFData->time = 0; - pSMFData->state = EAS_STATE_OPEN; - *ppHandle = pSMFData; - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_SMF_DATA* pSMFData; - EAS_RESULT result; - - /* check for valid state */ - pSMFData = (S_SMF_DATA *) pInstData; - if (pSMFData->state != EAS_STATE_OPEN) - return EAS_ERROR_NOT_VALID_IN_THIS_STATE; - - /* instantiate a synthesizer */ - if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } - return result; - } - - /* parse the file header and setup the individual stream parsers */ - if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) - return result; - - /* ready to play */ - pSMFData->state = EAS_STATE_READY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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) reserved for future use */ -EAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) -{ - S_SMF_DATA *pSMFData; - - pSMFData = (S_SMF_DATA*) pInstData; - - /* sanity check */ -#ifdef _CHECKED_BUILD - if (pSMFData->state == EAS_STATE_STOPPED) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } - } - - if (pSMFData->nextStream == NULL) - { - { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } - } -#endif - -#if 0 - /* return time in milliseconds */ - /* if chase mode, lie about time */ - if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) - *pTime = 0; - - else -#endif - - /*lint -e{704} use shift instead of division */ - *pTime = pSMFData->time >> 8; - - *pTime = pSMFData->time >> 8; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) -{ - S_SMF_DATA* pSMFData; - EAS_RESULT result; - EAS_I32 i; - EAS_U32 ticks; - EAS_U32 temp; - - /* establish pointer to instance data */ - pSMFData = (S_SMF_DATA*) pInstData; - if (pSMFData->state >= EAS_STATE_OPEN) - return EAS_SUCCESS; - - /* get current ticks */ - ticks = pSMFData->nextStream->ticks; - - /* assume that an error occurred */ - pSMFData->state = EAS_STATE_ERROR; - -#ifdef JET_INTERFACE - /* if JET has track muted, set parser mode to mute */ - if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) - parserMode = eParserModeMute; -#endif - - /* parse the next event from all the streams */ - if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) - { - /* check for unexpected end-of-file */ - if (result != EAS_EOF) - return result; - - /* indicate end of track for this stream */ - pSMFData->nextStream->ticks = SMF_END_OF_TRACK; - } - - /* get next delta time, unless already at end of track */ - else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) - { - if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) - { - /* check for unexpected end-of-file */ - if (result != EAS_EOF) - return result; - - /* indicate end of track for this stream */ - pSMFData->nextStream->ticks = SMF_END_OF_TRACK; - } - - /* if zero delta to next event, stay with this stream */ - else if (pSMFData->nextStream->ticks == ticks) - { - pSMFData->state = EAS_STATE_PLAY; - return EAS_SUCCESS; - } - } - - /* find next event in all streams */ - temp = 0x7ffffff; - pSMFData->nextStream = NULL; - for (i = 0; i < pSMFData->numStreams; i++) - { - if (pSMFData->streams[i].ticks < temp) - { - temp = pSMFData->streams[i].ticks; - pSMFData->nextStream = &pSMFData->streams[i]; - } - } - - /* are there any more events to parse? */ - if (pSMFData->nextStream) - { - pSMFData->state = EAS_STATE_PLAY; - - /* update the time of the next event */ - SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); - } - else - { - pSMFData->state = EAS_STATE_STOPPING; - VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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) reserved for future use */ -EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) -{ - S_SMF_DATA* pSMFData; - - /* establish pointer to instance data */ - pSMFData = (S_SMF_DATA*) pInstData; - - /* if stopping, check to see if synth voices are active */ - if (pSMFData->state == EAS_STATE_STOPPING) - { - if (VMActiveVoices(pSMFData->pSynth) == 0) - pSMFData->state = EAS_STATE_STOPPED; - } - - if (pSMFData->state == EAS_STATE_PAUSING) - { - if (VMActiveVoices(pSMFData->pSynth) == 0) - pSMFData->state = EAS_STATE_PAUSED; - } - - /* return current state */ - *pState = pSMFData->state; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_Close() - *---------------------------------------------------------------------------- - * Purpose: - * Close the file and clean up - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_SMF_DATA* pSMFData; - EAS_I32 i; - EAS_RESULT result; - - pSMFData = (S_SMF_DATA*) pInstData; - - /* close all the streams */ - for (i = 0; i < pSMFData->numStreams; i++) - { - if (pSMFData->streams[i].fileHandle != NULL) - { - if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) - return result; - } - } - if (pSMFData->fileHandle != NULL) - if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) - return result; - - /* free the synth */ - if (pSMFData->pSynth != NULL) - VMMIDIShutdown(pEASData, pSMFData->pSynth); - - /* if using dynamic memory, free it */ - if (!pEASData->staticMemoryModel) - { - if (pSMFData->streams) - EAS_HWFree(pEASData->hwInstData, pSMFData->streams); - - /* free the instance data */ - EAS_HWFree(pEASData->hwInstData, pSMFData); - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_SMF_DATA* pSMFData; - EAS_I32 i; - EAS_RESULT result; - EAS_U32 ticks; - - pSMFData = (S_SMF_DATA*) pInstData; - - /* reset time to zero */ - pSMFData->time = 0; - - /* reset the synth */ - VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); - - /* find the start of each track */ - ticks = 0x7fffffffL; - pSMFData->nextStream = NULL; - for (i = 0; i < pSMFData->numStreams; i++) - { - - /* reset file position to first byte of data in track */ - if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) - return result; - - /* initalize some data */ - pSMFData->streams[i].ticks = 0; - - /* initalize the MIDI parser data */ - EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); - - /* parse the first delta time in each stream */ - if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) - return result; - if (pSMFData->streams[i].ticks < ticks) - { - ticks = pSMFData->streams[i].ticks; - pSMFData->nextStream = &pSMFData->streams[i]; - } - } - - - pSMFData->state = EAS_STATE_READY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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: - * - *---------------------------------------------------------------------------- -*/ -EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_SMF_DATA *pSMFData; - - /* can't pause a stopped stream */ - pSMFData = (S_SMF_DATA*) pInstData; - if (pSMFData->state == EAS_STATE_STOPPED) - return EAS_ERROR_ALREADY_STOPPED; - - /* mute the synthesizer */ - VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); - pSMFData->state = EAS_STATE_PAUSING; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_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) reserved for future use */ -EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) -{ - S_SMF_DATA *pSMFData; - - /* can't resume a stopped stream */ - pSMFData = (S_SMF_DATA*) pInstData; - if (pSMFData->state == EAS_STATE_STOPPED) - return EAS_ERROR_ALREADY_STOPPED; - - /* nothing to do but resume playback */ - pSMFData->state = EAS_STATE_PLAY; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_SetData() - *---------------------------------------------------------------------------- - * Purpose: - * Sets parser parameters - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) reserved for future use */ -EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) -{ - S_SMF_DATA *pSMFData; - - pSMFData = (S_SMF_DATA*) pInstData; - switch (param) - { - - /* set metadata callback */ - case PARSER_DATA_METADATA_CB: - EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); - break; - -#ifdef JET_INTERFACE - /* set jet segment and track ID of all tracks for callback function */ - case PARSER_DATA_JET_CB: - { - EAS_U32 i; - EAS_U32 bit = (EAS_U32) value; - bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; - for (i = 0; i < pSMFData->numStreams; i++) - pSMFData->streams[i].midiStream.jetData = - (pSMFData->streams[i].midiStream.jetData & - ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | - i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; - pSMFData->flags |= SMF_FLAGS_JET_STREAM; - } - break; - - /* set state of all mute flags at once */ - case PARSER_DATA_MUTE_FLAGS: - { - EAS_INT i; - EAS_U32 bit = (EAS_U32) value; - for (i = 0; i < pSMFData->numStreams; i++) - { - if (bit & 1) - pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; - else - pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; - bit >>= 1; - } - } - break; - - /* set track mute */ - case PARSER_DATA_SET_MUTE: - if (value < pSMFData->numStreams) - pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; - else - return EAS_ERROR_PARAMETER_RANGE; - break; - - /* clear track mute */ - case PARSER_DATA_CLEAR_MUTE: - if (value < pSMFData->numStreams) - pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; - else - return EAS_ERROR_PARAMETER_RANGE; - break; -#endif - - default: - return EAS_ERROR_INVALID_PARAMETER; - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_GetData() - *---------------------------------------------------------------------------- - * Purpose: - * Retrieves parser parameters - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * handle - pointer to file handle - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -esym(715, pEASData) reserved for future use */ -EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) -{ - S_SMF_DATA *pSMFData; - - pSMFData = (S_SMF_DATA*) pInstData; - switch (param) - { - /* return file type */ - case PARSER_DATA_FILE_TYPE: - if (pSMFData->numStreams == 1) - *pValue = EAS_FILE_SMF0; - else - *pValue = EAS_FILE_SMF1; - break; - -/* now handled in eas_public.c */ -#if 0 - case PARSER_DATA_POLYPHONY: - if (pSMFData->pSynth) - VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); - else - return EAS_ERROR_NOT_VALID_IN_THIS_STATE; - break; - - case PARSER_DATA_PRIORITY: - if (pSMFData->pSynth) - VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); - break; - - /* set transposition */ - case PARSER_DATA_TRANSPOSITION: - *pValue = pSMFData->transposition; - break; -#endif - - case PARSER_DATA_SYNTH_HANDLE: - *pValue = (EAS_I32) pSMFData->pSynth; - break; - - default: - return EAS_ERROR_INVALID_PARAMETER; - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_GetVarLenData() - *---------------------------------------------------------------------------- - * Purpose: - * Reads a varible length quantity from an SMF file - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) -{ - EAS_RESULT result; - EAS_U32 data; - EAS_U8 c; - - /* read until bit 7 is zero */ - data = 0; - do - { - if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) - return result; - data = (data << 7) | (c & 0x7f); - } while (c & 0x80); - *pData = data; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_GetDeltaTime() - *---------------------------------------------------------------------------- - * Purpose: - * Reads a varible length quantity from an SMF file - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) -{ - EAS_RESULT result; - EAS_U32 ticks; - - if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) - return result; - - pSMFStream->ticks += ticks; - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_ParseMetaEvent() - *---------------------------------------------------------------------------- - * Purpose: - * Reads a varible length quantity from an SMF file - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) -{ - EAS_RESULT result; - EAS_U32 len; - EAS_I32 pos; - EAS_U32 temp; - EAS_U8 c; - - /* get the meta-event type */ - if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) - return result; - - /* get the length */ - if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) - return result; - - /* get the current file position so we can skip the event */ - if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) - return result; - pos += (EAS_I32) len; - - /* end of track? */ - if (c == SMF_META_END_OF_TRACK) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } - pSMFStream->ticks = SMF_END_OF_TRACK; - } - - /* tempo event? */ - else if (c == SMF_META_TEMPO) - { - /* read the 3-byte timebase value */ - temp = 0; - while (len--) - { - if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) - return result; - temp = (temp << 8) | c; - } - - pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); - pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; - } - - /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ - else if (c == SMF_META_TIME_SIGNATURE) - { - pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; - } - - /* if the host has registered a metadata callback return the metadata */ - else if (pSMFData->metadata.callback) - { - EAS_I32 readLen; - E_EAS_METADATA_TYPE metaType; - - metaType = EAS_METADATA_UNKNOWN; - - /* only process title on the first track */ - if (c == SMF_META_SEQTRK_NAME) - metaType = EAS_METADATA_TITLE; - else if (c == SMF_META_TEXT) - metaType = EAS_METADATA_TEXT; - else if (c == SMF_META_COPYRIGHT) - metaType = EAS_METADATA_COPYRIGHT; - else if (c == SMF_META_LYRIC) - metaType = EAS_METADATA_LYRIC; - - if (metaType != EAS_METADATA_UNKNOWN) - { - readLen = pSMFData->metadata.bufferSize - 1; - if ((EAS_I32) len < readLen) - readLen = (EAS_I32) len; - if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) - return result; - pSMFData->metadata.buffer[readLen] = 0; - pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); - } - } - - /* position file to next event - in case we ignored all or part of the meta-event */ - if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) - return result; - - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_ParseSysEx() - *---------------------------------------------------------------------------- - * Purpose: - * Reads a varible length quantity from an SMF file - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) -{ - EAS_RESULT result; - EAS_U32 len; - EAS_U8 c; - - /* get the length */ - if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) - return result; - - /* start of SysEx message? */ - if (f0 == 0xf0) - { - if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) - return result; - } - - /* feed the SysEx to the stream parser */ - while (len--) - { - if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) - return result; - if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) - return result; - - /* check for GM system ON */ - if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) - pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_ParseEvent() - *---------------------------------------------------------------------------- - * Purpose: - * Reads a varible length quantity from an SMF file - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) -{ - EAS_RESULT result; - EAS_U8 c; - - /* get the event type */ - if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) - return result; - - /* parse meta-event */ - if (c == 0xff) - { - if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) - return result; - } - - /* parse SysEx */ - else if ((c == 0xf0) || (c == 0xf7)) - { - if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) - return result; - } - - /* parse MIDI message */ - else - { - if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) - return result; - - /* keep streaming data to the MIDI parser until the message is complete */ - while (pSMFStream->midiStream.pending) - { - if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) - return result; - if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) - return result; - } - - } - - /* chase mode logic */ - if (pSMFData->time == 0) - { - if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) - { - if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) - pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; - } - else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) - pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; - } - - return EAS_SUCCESS; -} - -/*---------------------------------------------------------------------------- - * SMF_ParseHeader() - *---------------------------------------------------------------------------- - * Purpose: - * Parses the header of an SMF file, allocates memory the stream parsers and initializes the - * stream parsers. - * - * Inputs: - * pEASData - pointer to overall EAS data structure - * pSMFData - pointer to parser instance data - * fileHandle - file handle - * fileOffset - offset in the file where the header data starts, usually 0 - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ -EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) -{ - EAS_RESULT result; - EAS_I32 i; - EAS_U16 division; - EAS_U32 chunkSize; - EAS_U32 chunkStart; - EAS_U32 temp; - EAS_U32 ticks; - - /* rewind the file and find the end of the header chunk */ - if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) - goto ReadError; - if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) - goto ReadError; - - /* determine the number of tracks */ - if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) - goto ReadError; - if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) - goto ReadError; - - /* limit the number of tracks */ - if (pSMFData->numStreams > MAX_SMF_STREAMS) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } - pSMFData->numStreams = MAX_SMF_STREAMS; - } else if (pSMFData->numStreams == 0) - { - /* avoid 0 sized allocation */ - return EAS_ERROR_PARAMETER_RANGE; - } - - /* get the time division */ - if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) - goto ReadError; - - /* setup default timebase for 120 bpm */ - pSMFData->ppqn = 192; - if (!division || division & 0x8000) - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } - else - pSMFData->ppqn = (division & 0x7fff); - pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); - - /* dynamic memory allocation, allocate memory for streams */ - if (pSMFData->streams == NULL) - { - pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); - if (pSMFData->streams == NULL) - return EAS_ERROR_MALLOC_FAILED; - - /* zero the memory to insure complete initialization */ - EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); - } - - /* find the start of each track */ - chunkStart = (EAS_U32) pSMFData->fileOffset; - ticks = 0x7fffffffL; - pSMFData->nextStream = NULL; - for (i = 0; i < pSMFData->numStreams; i++) - { - - for (;;) - { - - /* calculate start of next chunk - checking for errors */ - temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; - if (temp <= chunkStart) - { - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } - return EAS_ERROR_FILE_FORMAT; - } - chunkStart = temp; - - /* seek to the start of the next chunk */ - if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) - goto ReadError; - - /* read the chunk identifier */ - if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) - goto ReadError; - - /* read the chunk size */ - if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) - goto ReadError; - - /* make sure this is an 'MTrk' chunk */ - if (temp == SMF_CHUNK_TYPE_TRACK) - break; - - { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } - } - - /* initalize some data */ - pSMFData->streams[i].ticks = 0; - pSMFData->streams[i].fileHandle = pSMFData->fileHandle; - - /* NULL the file handle so we don't try to close it twice */ - pSMFData->fileHandle = NULL; - - /* save this file position as the start of the track */ - pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; - - /* initalize the MIDI parser data */ - EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); - - /* parse the first delta time in each stream */ - if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) - goto ReadError; - - if (pSMFData->streams[i].ticks < ticks) - { - ticks = pSMFData->streams[i].ticks; - pSMFData->nextStream = &pSMFData->streams[i]; - } - - /* more tracks to do, create a duplicate file handle */ - if (i < (pSMFData->numStreams - 1)) - { - if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) - goto ReadError; - } - } - - /* update the time of the next event */ - if (pSMFData->nextStream) - SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); - - return EAS_SUCCESS; - - /* ugly goto: but simpler than structured */ - ReadError: - if (result == EAS_EOF) - return EAS_ERROR_FILE_FORMAT; - return result; -} - -/*---------------------------------------------------------------------------- - * SMF_UpdateTime() - *---------------------------------------------------------------------------- - * Purpose: - * Update the millisecond time base by converting the ticks into millieconds - * - * Inputs: - * - * - * Outputs: - * - * - * Side Effects: - * - *---------------------------------------------------------------------------- -*/ -static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) -{ - EAS_U32 temp1, temp2; - - if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) - return; - - temp1 = (ticks >> 10) * pSMFData->tickConv; - temp2 = (ticks & 0x3ff) * pSMFData->tickConv; - pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); -} - |