14a10645c70199c8d8567fbc46312158c419720abChris Lattner/*---------------------------------------------------------------------------- 27c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * 37c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * File: 47c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * eas_smf.c 57c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * 67c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * Contents and purpose: 77c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * SMF Type 0 and 1 File Parser 87c0e022c5c4be4b11e199a53f73bbdd84e34aa80John Criswell * 94a10645c70199c8d8567fbc46312158c419720abChris Lattner * For SMF timebase analysis, see "MIDI Sequencer Analysis.xls". 104a10645c70199c8d8567fbc46312158c419720abChris Lattner * 114a10645c70199c8d8567fbc46312158c419720abChris Lattner * Copyright Sonic Network Inc. 2005 124a10645c70199c8d8567fbc46312158c419720abChris Lattner 134a10645c70199c8d8567fbc46312158c419720abChris Lattner * Licensed under the Apache License, Version 2.0 (the "License"); 144a10645c70199c8d8567fbc46312158c419720abChris Lattner * you may not use this file except in compliance with the License. 15126840f49e8d49156a342e836d4b2adca46dc3baChris Lattner * You may obtain a copy of the License at 164a10645c70199c8d8567fbc46312158c419720abChris Lattner * 17e49603d79d220a795bd50684c8b1f503ee40f97fMisha Brukman * http://www.apache.org/licenses/LICENSE-2.0 18640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 19640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * Unless required by applicable law or agreed to in writing, software 203d9cafa003a114bf9974bc80d5b69b0ed1d29290Misha Brukman * distributed under the License is distributed on an "AS IS" BASIS, 21fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 224a10645c70199c8d8567fbc46312158c419720abChris Lattner * See the License for the specific language governing permissions and 23efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * limitations under the License. 24fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner * 25fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner *---------------------------------------------------------------------------- 26fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner * Revision Control: 27fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner * $Revision: 803 $ 28fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner * $Date: 2007-08-01 09:57:00 -0700 (Wed, 01 Aug 2007) $ 29fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner *---------------------------------------------------------------------------- 30fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner*/ 31fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner 32fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner#include "eas_data.h" 33640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#include "eas_miditypes.h" 34640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#include "eas_parser.h" 3539aebca3a2d1dd389a6d9cdfb51a53f625e244f0Chris Lattner#include "eas_report.h" 3606943add8b2b764e131979cca064eda9f28826c9Chris Lattner#include "eas_host.h" 3706943add8b2b764e131979cca064eda9f28826c9Chris Lattner#include "eas_midi.h" 38640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#include "eas_config.h" 3906943add8b2b764e131979cca064eda9f28826c9Chris Lattner#include "eas_vm_protos.h" 40640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#include "eas_smfdata.h" 41640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#include "eas_smf.h" 42640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 4306943add8b2b764e131979cca064eda9f28826c9Chris Lattner#ifdef JET_INTERFACE 449f71e799c3e6e4cc0c71de82bda81f8753e82942Chris Lattner#include "jet_data.h" 45640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner#endif 465ef681c19de9c675a265211f8fb0ae49cc3a3a66Chris Lattner 475ef681c19de9c675a265211f8fb0ae49cc3a3a66Chris Lattner//3 dls: The timebase for this module is adequate to keep MIDI and 48025262692a6710de29a48e2b3905672cd12d13d2Chris Lattner//3 digital audio synchronized for only a few minutes. It should be 49640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner//3 sufficient for most mobile applications. If better accuracy is 50640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner//3 required, more fractional bits should be added to the timebase. 51640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 525073336cd4da5df4ae13a167582d1dc90f32e4e0Misha Brukmanstatic const EAS_U8 smfHeader[] = { 'M', 'T', 'h', 'd' }; 53640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 54640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner/* local prototypes */ 55640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerstatic EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData); 56640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerstatic EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream); 57640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerstatic EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode); 58640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerstatic EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode); 59640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerstatic EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream); 6006943add8b2b764e131979cca064eda9f28826c9Chris Lattnerstatic void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks); 61bc0e998c497446f5448425b3cbd7f8f19a458764Misha Brukman 62640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 63640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner/*---------------------------------------------------------------------------- 64640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 65640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * SMF_Parser 66640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 67640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * This structure contains the functional interface for the SMF parser 68640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner *---------------------------------------------------------------------------- 69640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner*/ 70640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattnerconst S_FILE_PARSER_INTERFACE EAS_SMF_Parser = 71640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner{ 729f71e799c3e6e4cc0c71de82bda81f8753e82942Chris Lattner SMF_CheckFileType, 73640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_Prepare, 749c6cfe1bffd37f29a265457b7515839c445b3e6aChris Lattner SMF_Time, 759c6cfe1bffd37f29a265457b7515839c445b3e6aChris Lattner SMF_Event, 76025262692a6710de29a48e2b3905672cd12d13d2Chris Lattner SMF_State, 77640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_Close, 78640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_Reset, 79640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_Pause, 805073336cd4da5df4ae13a167582d1dc90f32e4e0Misha Brukman SMF_Resume, 81640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner NULL, 82640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_SetData, 83640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner SMF_GetData, 84640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner NULL 85640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner}; 86640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 87640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner/*---------------------------------------------------------------------------- 88640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * SMF_CheckFileType() 89640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner *---------------------------------------------------------------------------- 90efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * Purpose: 91640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * Check the file type to see if we can parse it 92640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 93640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * Inputs: 94640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * pEASData - pointer to overall EAS data structure 95640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * handle - pointer to file handle 96640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 97640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * Outputs: 9806943add8b2b764e131979cca064eda9f28826c9Chris Lattner * 99640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 100640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * Side Effects: 101640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner * 102efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner *---------------------------------------------------------------------------- 10306943add8b2b764e131979cca064eda9f28826c9Chris Lattner*/ 1049f71e799c3e6e4cc0c71de82bda81f8753e82942Chris LattnerEAS_RESULT SMF_CheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *ppHandle, EAS_I32 offset) 105640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner{ 1065ef681c19de9c675a265211f8fb0ae49cc3a3a66Chris Lattner S_SMF_DATA* pSMFData; 1079c6cfe1bffd37f29a265457b7515839c445b3e6aChris Lattner EAS_RESULT result; 108025262692a6710de29a48e2b3905672cd12d13d2Chris Lattner 109640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* seek to starting offset - usually 0 */ 110640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner *ppHandle = NULL; 111640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, offset)) != EAS_SUCCESS) 1125073336cd4da5df4ae13a167582d1dc90f32e4e0Misha Brukman return result; 113640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 114640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* search through file for header - slow method */ 11506943add8b2b764e131979cca064eda9f28826c9Chris Lattner if (pEASData->searchHeaderFlag) 116640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner { 117640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner result = EAS_SearchFile(pEASData, fileHandle, smfHeader, sizeof(smfHeader), &offset); 118640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner if (result != EAS_SUCCESS) 119640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner return (result == EAS_EOF) ? EAS_SUCCESS : result; 120efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner } 121640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 122640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* read the first 4 bytes of the file - quick method */ 123640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner else { 124efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner EAS_U8 header[4]; 125fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner EAS_I32 count; 126fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, header, sizeof(header), &count)) != EAS_SUCCESS) 127b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return result; 128fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner 129b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* check for 'MTrk' - return if no match */ 130b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if ((header[0] != 'M') || (header[1] != 'T') || (header[2] != 'h') || (header[3] != 'd')) 131b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return EAS_SUCCESS; 132fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner } 133fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner 134fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner /* check for static memory allocation */ 135be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner if (pEASData->staticMemoryModel) 136fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner pSMFData = EAS_CMEnumData(EAS_CM_SMF_DATA); 137be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner else 138fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner { 139fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner pSMFData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_SMF_DATA)); 140fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner EAS_HWMemSet((void *)pSMFData,0, sizeof(S_SMF_DATA)); 141fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner } 142be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner if (!pSMFData) 143fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner return EAS_ERROR_MALLOC_FAILED; 144fa76183e8e28985dfd17b1d6291c939dab4cbe1dChris Lattner 145640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* initialize some critical data */ 146efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner pSMFData->fileHandle = fileHandle; 147efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner pSMFData->fileOffset = offset; 148a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner pSMFData->pSynth = NULL; 149a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner pSMFData->time = 0; 150a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner pSMFData->state = EAS_STATE_OPEN; 151a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *ppHandle = pSMFData; 152a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 153efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner return EAS_SUCCESS; 154efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner} 155a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 156efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner/*---------------------------------------------------------------------------- 157efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * SMF_Prepare() 158efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner *---------------------------------------------------------------------------- 159efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * Purpose: 160efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * Prepare to parse the file. Allocates instance data (or uses static allocation for 161a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * static memory model). 162efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * 163efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * Inputs: 164efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * pEASData - pointer to overall EAS data structure 165efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * handle - pointer to file handle 166efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * 167efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * Outputs: 168efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * 169efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner * 170a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Side Effects: 1715313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * 172efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner *---------------------------------------------------------------------------- 173efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner*/ 174efdc0b505712d1ca4460def27e51c430f033d58dChris LattnerEAS_RESULT SMF_Prepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 175be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner{ 176640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner S_SMF_DATA* pSMFData; 177640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner EAS_RESULT result; 178be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner 179be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner /* check for valid state */ 180be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner pSMFData = (S_SMF_DATA *) pInstData; 181a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner if (pSMFData->state != EAS_STATE_OPEN) 182efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner return EAS_ERROR_NOT_VALID_IN_THIS_STATE; 183be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner 184640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* instantiate a synthesizer */ 185be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner if ((result = VMInitMIDI(pEASData, &pSMFData->pSynth)) != EAS_SUCCESS) 186efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner { 187efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "VMInitMIDI returned %d\n", result); */ } 188640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner return result; 189b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 190b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 191640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* parse the file header and setup the individual stream parsers */ 192640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner if ((result = SMF_ParseHeader(pEASData->hwInstData, pSMFData)) != EAS_SUCCESS) 193a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner return result; 194a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 195a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* ready to play */ 196b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->state = EAS_STATE_READY; 197b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return EAS_SUCCESS; 198a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner} 199a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 200a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner/*---------------------------------------------------------------------------- 201a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * SMF_Time() 202a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *---------------------------------------------------------------------------- 203a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Purpose: 204a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Returns the time of the next event in msecs 205a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * 206a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Inputs: 207a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * pEASData - pointer to overall EAS data structure 208a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * handle - pointer to file handle 209a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * pTime - pointer to variable to hold time of next event (in msecs) 210a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * 211a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Outputs: 212a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * 213a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * 214a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Side Effects: 215a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * 216a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *---------------------------------------------------------------------------- 217a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner*/ 218a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner/*lint -esym(715, pEASData) reserved for future use */ 219a1cf1c8c87f10f12343ff6ae75f332390e7205abChris LattnerEAS_RESULT SMF_Time (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_U32 *pTime) 220a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner{ 221a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner S_SMF_DATA *pSMFData; 222a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 223a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner pSMFData = (S_SMF_DATA*) pInstData; 224a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 225a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* sanity check */ 226a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner#ifdef _CHECKED_BUILD 227a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner if (pSMFData->state == EAS_STATE_STOPPED) 228a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner { 229a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Can't ask for time on a stopped stream\n"); */ } 230a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner } 231b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 232b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if (pSMFData->nextStream == NULL) 233b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 234b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { /* dpp: EAS_ReportEx( _EAS_SEVERITY_ERROR, "no is NULL\n"); */ } 235b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 236b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner#endif 237a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 238a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner#if 0 239b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* return time in milliseconds */ 240b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* if chase mode, lie about time */ 241a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 242a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *pTime = 0; 243b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 244b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner else 245b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner#endif 246b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 247a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /*lint -e{704} use shift instead of division */ 248a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *pTime = pSMFData->time >> 8; 249a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 250a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *pTime = pSMFData->time >> 8; 251a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner return EAS_SUCCESS; 252a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner} 253a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 254a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner/*---------------------------------------------------------------------------- 255a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * SMF_Event() 256a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner *---------------------------------------------------------------------------- 257a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner * Purpose: 258d3a533d94dae1e57194001af08763eb3ba199c8fChris Lattner * Parse the next event in the file 259d3a533d94dae1e57194001af08763eb3ba199c8fChris Lattner * 2605313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * Inputs: 2615313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * pEASData - pointer to overall EAS data structure 2625313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * handle - pointer to file handle 2635313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * 2645313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * Outputs: 2655313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * 26602bb481881fe6aaa876f9bf79f38f40f56a35a01Chris Lattner * 26702bb481881fe6aaa876f9bf79f38f40f56a35a01Chris Lattner * Side Effects: 2685313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner * 2695313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner *---------------------------------------------------------------------------- 2705313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner*/ 271d3a533d94dae1e57194001af08763eb3ba199c8fChris LattnerEAS_RESULT SMF_Event (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_INT parserMode) 2725313f23b8c3d22a2028beb731c60fc1a25beb149Chris Lattner{ 273d3a533d94dae1e57194001af08763eb3ba199c8fChris Lattner S_SMF_DATA* pSMFData; 274a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner EAS_RESULT result; 275a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner EAS_I32 i; 276a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner EAS_U32 ticks; 277a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner EAS_U32 temp; 278a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 279b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* establish pointer to instance data */ 280b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData = (S_SMF_DATA*) pInstData; 281b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if (pSMFData->state >= EAS_STATE_OPEN) 282b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return EAS_SUCCESS; 283b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 284640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner if (!pSMFData->nextStream) { 285640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner return EAS_ERROR_FILE_FORMAT; 286640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner } 287640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 288640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 289b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* get current ticks */ 290b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner ticks = pSMFData->nextStream->ticks; 291640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 292640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* assume that an error occurred */ 2934a10645c70199c8d8567fbc46312158c419720abChris Lattner pSMFData->state = EAS_STATE_ERROR; 294640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 295b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner#ifdef JET_INTERFACE 296640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* if JET has track muted, set parser mode to mute */ 297de9750def7c5ca6cb789f3bba7c913e237cdf849Chris Lattner if (pSMFData->nextStream->midiStream.jetData & MIDI_FLAGS_JET_MUTE) 298de9750def7c5ca6cb789f3bba7c913e237cdf849Chris Lattner parserMode = eParserModeMute; 299de9750def7c5ca6cb789f3bba7c913e237cdf849Chris Lattner#endif 300640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 301640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner /* parse the next event from all the streams */ 3024a10645c70199c8d8567fbc46312158c419720abChris Lattner if ((result = SMF_ParseEvent(pEASData, pSMFData, pSMFData->nextStream, parserMode)) != EAS_SUCCESS) 303a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner { 304a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* check for unexpected end-of-file */ 305b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if (result != EAS_EOF) 306a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner return result; 307a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 308a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* indicate end of track for this stream */ 309a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner pSMFData->nextStream->ticks = SMF_END_OF_TRACK; 310b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 311a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner 312a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* get next delta time, unless already at end of track */ 313a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner else if (pSMFData->nextStream->ticks != SMF_END_OF_TRACK) 314a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner { 315a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner if ((result = SMF_GetDeltaTime(pEASData->hwInstData, pSMFData->nextStream)) != EAS_SUCCESS) 316a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner { 317a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner /* check for unexpected end-of-file */ 318a1cf1c8c87f10f12343ff6ae75f332390e7205abChris Lattner if (result != EAS_EOF) 319b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return result; 320b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 321b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* indicate end of track for this stream */ 322b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->nextStream->ticks = SMF_END_OF_TRACK; 323b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 324b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 325b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* if zero delta to next event, stay with this stream */ 326b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner else if (pSMFData->nextStream->ticks == ticks) 327b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 328b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->state = EAS_STATE_PLAY; 329b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner return EAS_SUCCESS; 330b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 331b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 332b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 333b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* find next event in all streams */ 334b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner temp = 0x7ffffff; 335b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->nextStream = NULL; 336b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner for (i = 0; i < pSMFData->numStreams; i++) 337b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 338b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if (pSMFData->streams[i].ticks < temp) 339b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 340b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner temp = pSMFData->streams[i].ticks; 341b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->nextStream = &pSMFData->streams[i]; 342b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 343b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 344b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 345b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* are there any more events to parse? */ 346b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner if (pSMFData->nextStream) 347b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 348b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->state = EAS_STATE_PLAY; 349b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner 350b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner /* update the time of the next event */ 351b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks - ticks); 352b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 353b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner else 354b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner { 355b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner pSMFData->state = EAS_STATE_STOPPING; 356b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner VMReleaseAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); 357b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner } 358640f22e66d90439857a97a83896ee68c4f7128c9Chris Lattner 359be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner return EAS_SUCCESS; 360efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner} 361efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner 362efdc0b505712d1ca4460def27e51c430f033d58dChris Lattner/*---------------------------------------------------------------------------- 363be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * SMF_State() 364be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner *---------------------------------------------------------------------------- 365b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner * Purpose: 366be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * Returns the current state of the stream 367be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * 368be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * Inputs: 369be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * pEASData - pointer to overall EAS data structure 370b15825b0a29e527b361b63a6e41aff5fdb8fdd5aChris Lattner * handle - pointer to file handle 371be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * pState - pointer to variable to store state 372be21ca54e08339ede5dd4bbb882182d22e274988Chris Lattner * 3734a10645c70199c8d8567fbc46312158c419720abChris Lattner * Outputs: 3744a10645c70199c8d8567fbc46312158c419720abChris Lattner * 3754a10645c70199c8d8567fbc46312158c419720abChris Lattner * 376d0fde30ce850b78371fd1386338350591f9ff494Brian Gaeke * Side Effects: 377 * 378 *---------------------------------------------------------------------------- 379*/ 380/*lint -esym(715, pEASData) reserved for future use */ 381EAS_RESULT SMF_State (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pState) 382{ 383 S_SMF_DATA* pSMFData; 384 385 /* establish pointer to instance data */ 386 pSMFData = (S_SMF_DATA*) pInstData; 387 388 /* if stopping, check to see if synth voices are active */ 389 if (pSMFData->state == EAS_STATE_STOPPING) 390 { 391 if (VMActiveVoices(pSMFData->pSynth) == 0) 392 pSMFData->state = EAS_STATE_STOPPED; 393 } 394 395 if (pSMFData->state == EAS_STATE_PAUSING) 396 { 397 if (VMActiveVoices(pSMFData->pSynth) == 0) 398 pSMFData->state = EAS_STATE_PAUSED; 399 } 400 401 /* return current state */ 402 *pState = pSMFData->state; 403 return EAS_SUCCESS; 404} 405 406/*---------------------------------------------------------------------------- 407 * SMF_Close() 408 *---------------------------------------------------------------------------- 409 * Purpose: 410 * Close the file and clean up 411 * 412 * Inputs: 413 * pEASData - pointer to overall EAS data structure 414 * handle - pointer to file handle 415 * 416 * Outputs: 417 * 418 * 419 * Side Effects: 420 * 421 *---------------------------------------------------------------------------- 422*/ 423EAS_RESULT SMF_Close (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 424{ 425 S_SMF_DATA* pSMFData; 426 EAS_I32 i; 427 EAS_RESULT result; 428 429 pSMFData = (S_SMF_DATA*) pInstData; 430 431 /* close all the streams */ 432 for (i = 0; i < pSMFData->numStreams; i++) 433 { 434 if (pSMFData->streams[i].fileHandle != NULL) 435 { 436 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->streams[i].fileHandle)) != EAS_SUCCESS) 437 return result; 438 } 439 } 440 if (pSMFData->fileHandle != NULL) 441 if ((result = EAS_HWCloseFile(pEASData->hwInstData, pSMFData->fileHandle)) != EAS_SUCCESS) 442 return result; 443 444 /* free the synth */ 445 if (pSMFData->pSynth != NULL) 446 VMMIDIShutdown(pEASData, pSMFData->pSynth); 447 448 /* if using dynamic memory, free it */ 449 if (!pEASData->staticMemoryModel) 450 { 451 if (pSMFData->streams) 452 EAS_HWFree(pEASData->hwInstData, pSMFData->streams); 453 454 /* free the instance data */ 455 EAS_HWFree(pEASData->hwInstData, pSMFData); 456 } 457 458 return EAS_SUCCESS; 459} 460 461/*---------------------------------------------------------------------------- 462 * SMF_Reset() 463 *---------------------------------------------------------------------------- 464 * Purpose: 465 * Reset the sequencer. Used for locating backwards in the file. 466 * 467 * Inputs: 468 * pEASData - pointer to overall EAS data structure 469 * handle - pointer to file handle 470 * 471 * Outputs: 472 * 473 * 474 * Side Effects: 475 * 476 *---------------------------------------------------------------------------- 477*/ 478EAS_RESULT SMF_Reset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 479{ 480 S_SMF_DATA* pSMFData; 481 EAS_I32 i; 482 EAS_RESULT result; 483 EAS_U32 ticks; 484 485 pSMFData = (S_SMF_DATA*) pInstData; 486 487 /* reset time to zero */ 488 pSMFData->time = 0; 489 490 /* reset the synth */ 491 VMReset(pEASData->pVoiceMgr, pSMFData->pSynth, EAS_TRUE); 492 493 /* find the start of each track */ 494 ticks = 0x7fffffffL; 495 pSMFData->nextStream = NULL; 496 for (i = 0; i < pSMFData->numStreams; i++) 497 { 498 499 /* reset file position to first byte of data in track */ 500 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFData->streams[i].fileHandle, pSMFData->streams[i].startFilePos)) != EAS_SUCCESS) 501 return result; 502 503 /* initalize some data */ 504 pSMFData->streams[i].ticks = 0; 505 506 /* initalize the MIDI parser data */ 507 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); 508 509 /* parse the first delta time in each stream */ 510 if ((result = SMF_GetDeltaTime(pEASData->hwInstData,&pSMFData->streams[i])) != EAS_SUCCESS) 511 return result; 512 if (pSMFData->streams[i].ticks < ticks) 513 { 514 ticks = pSMFData->streams[i].ticks; 515 pSMFData->nextStream = &pSMFData->streams[i]; 516 } 517 } 518 519 520 pSMFData->state = EAS_STATE_READY; 521 return EAS_SUCCESS; 522} 523 524/*---------------------------------------------------------------------------- 525 * SMF_Pause() 526 *---------------------------------------------------------------------------- 527 * Purpose: 528 * Pauses the sequencer. Mutes all voices and sets state to pause. 529 * 530 * Inputs: 531 * pEASData - pointer to overall EAS data structure 532 * handle - pointer to file handle 533 * 534 * Outputs: 535 * 536 * 537 * Side Effects: 538 * 539 *---------------------------------------------------------------------------- 540*/ 541EAS_RESULT SMF_Pause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 542{ 543 S_SMF_DATA *pSMFData; 544 545 /* can't pause a stopped stream */ 546 pSMFData = (S_SMF_DATA*) pInstData; 547 if (pSMFData->state == EAS_STATE_STOPPED) 548 return EAS_ERROR_ALREADY_STOPPED; 549 550 /* mute the synthesizer */ 551 VMMuteAllVoices(pEASData->pVoiceMgr, pSMFData->pSynth); 552 pSMFData->state = EAS_STATE_PAUSING; 553 return EAS_SUCCESS; 554} 555 556/*---------------------------------------------------------------------------- 557 * SMF_Resume() 558 *---------------------------------------------------------------------------- 559 * Purpose: 560 * Resume playing after a pause, sets state back to playing. 561 * 562 * Inputs: 563 * pEASData - pointer to overall EAS data structure 564 * handle - pointer to file handle 565 * 566 * Outputs: 567 * 568 * 569 * Side Effects: 570 * 571 *---------------------------------------------------------------------------- 572*/ 573/*lint -esym(715, pEASData) reserved for future use */ 574EAS_RESULT SMF_Resume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData) 575{ 576 S_SMF_DATA *pSMFData; 577 578 /* can't resume a stopped stream */ 579 pSMFData = (S_SMF_DATA*) pInstData; 580 if (pSMFData->state == EAS_STATE_STOPPED) 581 return EAS_ERROR_ALREADY_STOPPED; 582 583 /* nothing to do but resume playback */ 584 pSMFData->state = EAS_STATE_PLAY; 585 return EAS_SUCCESS; 586} 587 588/*---------------------------------------------------------------------------- 589 * SMF_SetData() 590 *---------------------------------------------------------------------------- 591 * Purpose: 592 * Sets parser parameters 593 * 594 * Inputs: 595 * pEASData - pointer to overall EAS data structure 596 * handle - pointer to file handle 597 * 598 * Outputs: 599 * 600 * 601 * Side Effects: 602 * 603 *---------------------------------------------------------------------------- 604*/ 605/*lint -esym(715, pEASData) reserved for future use */ 606EAS_RESULT SMF_SetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value) 607{ 608 S_SMF_DATA *pSMFData; 609 610 pSMFData = (S_SMF_DATA*) pInstData; 611 switch (param) 612 { 613 614 /* set metadata callback */ 615 case PARSER_DATA_METADATA_CB: 616 EAS_HWMemCpy(&pSMFData->metadata, (void*) value, sizeof(S_METADATA_CB)); 617 break; 618 619#ifdef JET_INTERFACE 620 /* set jet segment and track ID of all tracks for callback function */ 621 case PARSER_DATA_JET_CB: 622 { 623 EAS_U32 i; 624 EAS_U32 bit = (EAS_U32) value; 625 bit = (bit << JET_EVENT_SEG_SHIFT) & JET_EVENT_SEG_MASK; 626 for (i = 0; i < pSMFData->numStreams; i++) 627 pSMFData->streams[i].midiStream.jetData = 628 (pSMFData->streams[i].midiStream.jetData & 629 ~(JET_EVENT_TRACK_MASK | JET_EVENT_SEG_MASK)) | 630 i << JET_EVENT_TRACK_SHIFT | bit | MIDI_FLAGS_JET_CB; 631 pSMFData->flags |= SMF_FLAGS_JET_STREAM; 632 } 633 break; 634 635 /* set state of all mute flags at once */ 636 case PARSER_DATA_MUTE_FLAGS: 637 { 638 EAS_INT i; 639 EAS_U32 bit = (EAS_U32) value; 640 for (i = 0; i < pSMFData->numStreams; i++) 641 { 642 if (bit & 1) 643 pSMFData->streams[i].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; 644 else 645 pSMFData->streams[i].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; 646 bit >>= 1; 647 } 648 } 649 break; 650 651 /* set track mute */ 652 case PARSER_DATA_SET_MUTE: 653 if (value < pSMFData->numStreams) 654 pSMFData->streams[value].midiStream.jetData |= MIDI_FLAGS_JET_MUTE; 655 else 656 return EAS_ERROR_PARAMETER_RANGE; 657 break; 658 659 /* clear track mute */ 660 case PARSER_DATA_CLEAR_MUTE: 661 if (value < pSMFData->numStreams) 662 pSMFData->streams[value].midiStream.jetData &= ~MIDI_FLAGS_JET_MUTE; 663 else 664 return EAS_ERROR_PARAMETER_RANGE; 665 break; 666#endif 667 668 default: 669 return EAS_ERROR_INVALID_PARAMETER; 670 } 671 672 return EAS_SUCCESS; 673} 674 675/*---------------------------------------------------------------------------- 676 * SMF_GetData() 677 *---------------------------------------------------------------------------- 678 * Purpose: 679 * Retrieves parser parameters 680 * 681 * Inputs: 682 * pEASData - pointer to overall EAS data structure 683 * handle - pointer to file handle 684 * 685 * Outputs: 686 * 687 * 688 * Side Effects: 689 * 690 *---------------------------------------------------------------------------- 691*/ 692/*lint -esym(715, pEASData) reserved for future use */ 693EAS_RESULT SMF_GetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue) 694{ 695 S_SMF_DATA *pSMFData; 696 697 pSMFData = (S_SMF_DATA*) pInstData; 698 switch (param) 699 { 700 /* return file type */ 701 case PARSER_DATA_FILE_TYPE: 702 if (pSMFData->numStreams == 1) 703 *pValue = EAS_FILE_SMF0; 704 else 705 *pValue = EAS_FILE_SMF1; 706 break; 707 708/* now handled in eas_public.c */ 709#if 0 710 case PARSER_DATA_POLYPHONY: 711 if (pSMFData->pSynth) 712 VMGetPolyphony(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); 713 else 714 return EAS_ERROR_NOT_VALID_IN_THIS_STATE; 715 break; 716 717 case PARSER_DATA_PRIORITY: 718 if (pSMFData->pSynth) 719 VMGetPriority(pEASData->pVoiceMgr, pSMFData->pSynth, pValue); 720 break; 721 722 /* set transposition */ 723 case PARSER_DATA_TRANSPOSITION: 724 *pValue = pSMFData->transposition; 725 break; 726#endif 727 728 case PARSER_DATA_SYNTH_HANDLE: 729 *pValue = (EAS_I32) pSMFData->pSynth; 730 break; 731 732 default: 733 return EAS_ERROR_INVALID_PARAMETER; 734 } 735 736 return EAS_SUCCESS; 737} 738 739/*---------------------------------------------------------------------------- 740 * SMF_GetVarLenData() 741 *---------------------------------------------------------------------------- 742 * Purpose: 743 * Reads a varible length quantity from an SMF file 744 * 745 * Inputs: 746 * 747 * 748 * Outputs: 749 * 750 * 751 * Side Effects: 752 * 753 *---------------------------------------------------------------------------- 754*/ 755static EAS_RESULT SMF_GetVarLenData (EAS_HW_DATA_HANDLE hwInstData, EAS_FILE_HANDLE fileHandle, EAS_U32 *pData) 756{ 757 EAS_RESULT result; 758 EAS_U32 data; 759 EAS_U8 c; 760 761 /* read until bit 7 is zero */ 762 data = 0; 763 do 764 { 765 if ((result = EAS_HWGetByte(hwInstData, fileHandle,&c)) != EAS_SUCCESS) 766 return result; 767 data = (data << 7) | (c & 0x7f); 768 } while (c & 0x80); 769 *pData = data; 770 return EAS_SUCCESS; 771} 772 773/*---------------------------------------------------------------------------- 774 * SMF_GetDeltaTime() 775 *---------------------------------------------------------------------------- 776 * Purpose: 777 * Reads a varible length quantity from an SMF file 778 * 779 * Inputs: 780 * 781 * 782 * Outputs: 783 * 784 * 785 * Side Effects: 786 * 787 *---------------------------------------------------------------------------- 788*/ 789static EAS_RESULT SMF_GetDeltaTime (EAS_HW_DATA_HANDLE hwInstData, S_SMF_STREAM *pSMFStream) 790{ 791 EAS_RESULT result; 792 EAS_U32 ticks; 793 794 if ((result = SMF_GetVarLenData(hwInstData, pSMFStream->fileHandle, &ticks)) != EAS_SUCCESS) 795 return result; 796 797 pSMFStream->ticks += ticks; 798 return EAS_SUCCESS; 799} 800 801/*---------------------------------------------------------------------------- 802 * SMF_ParseMetaEvent() 803 *---------------------------------------------------------------------------- 804 * Purpose: 805 * Reads a varible length quantity from an SMF file 806 * 807 * Inputs: 808 * 809 * 810 * Outputs: 811 * 812 * 813 * Side Effects: 814 * 815 *---------------------------------------------------------------------------- 816*/ 817static EAS_RESULT SMF_ParseMetaEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream) 818{ 819 EAS_RESULT result; 820 EAS_U32 len; 821 EAS_I32 pos; 822 EAS_U32 temp; 823 EAS_U8 c; 824 825 /* get the meta-event type */ 826 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 827 return result; 828 829 /* get the length */ 830 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) 831 return result; 832 833 /* get the current file position so we can skip the event */ 834 if ((result = EAS_HWFilePos(pEASData->hwInstData, pSMFStream->fileHandle, &pos)) != EAS_SUCCESS) 835 return result; 836 pos += (EAS_I32) len; 837 838 /* end of track? */ 839 if (c == SMF_META_END_OF_TRACK) 840 { 841 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: end of track\n", c, len); */ } 842 pSMFStream->ticks = SMF_END_OF_TRACK; 843 } 844 845 /* tempo event? */ 846 else if (c == SMF_META_TEMPO) 847 { 848 /* read the 3-byte timebase value */ 849 temp = 0; 850 while (len--) 851 { 852 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 853 return result; 854 temp = (temp << 8) | c; 855 } 856 857 pSMFData->tickConv = (EAS_U16) (((temp * 1024) / pSMFData->ppqn + 500) / 1000); 858 pSMFData->flags |= SMF_FLAGS_HAS_TEMPO; 859 } 860 861 /* check for time signature - see iMelody spec V1.4 section 4.1.2.2.3.6 */ 862 else if (c == SMF_META_TIME_SIGNATURE) 863 { 864 pSMFData->flags |= SMF_FLAGS_HAS_TIME_SIG; 865 } 866 867 /* if the host has registered a metadata callback return the metadata */ 868 else if (pSMFData->metadata.callback) 869 { 870 EAS_I32 readLen; 871 E_EAS_METADATA_TYPE metaType; 872 873 metaType = EAS_METADATA_UNKNOWN; 874 875 /* only process title on the first track */ 876 if (c == SMF_META_SEQTRK_NAME) 877 metaType = EAS_METADATA_TITLE; 878 else if (c == SMF_META_TEXT) 879 metaType = EAS_METADATA_TEXT; 880 else if (c == SMF_META_COPYRIGHT) 881 metaType = EAS_METADATA_COPYRIGHT; 882 else if (c == SMF_META_LYRIC) 883 metaType = EAS_METADATA_LYRIC; 884 885 if (metaType != EAS_METADATA_UNKNOWN) 886 { 887 readLen = pSMFData->metadata.bufferSize - 1; 888 if ((EAS_I32) len < readLen) 889 readLen = (EAS_I32) len; 890 if ((result = EAS_HWReadFile(pEASData->hwInstData, pSMFStream->fileHandle, pSMFData->metadata.buffer, readLen, &readLen)) != EAS_SUCCESS) 891 return result; 892 pSMFData->metadata.buffer[readLen] = 0; 893 pSMFData->metadata.callback(metaType, pSMFData->metadata.buffer, pSMFData->metadata.pUserData); 894 } 895 } 896 897 /* position file to next event - in case we ignored all or part of the meta-event */ 898 if ((result = EAS_HWFileSeek(pEASData->hwInstData, pSMFStream->fileHandle, pos)) != EAS_SUCCESS) 899 return result; 900 901 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Meta-event: type=%02x, len=%d\n", c, len); */ } 902 return EAS_SUCCESS; 903} 904 905/*---------------------------------------------------------------------------- 906 * SMF_ParseSysEx() 907 *---------------------------------------------------------------------------- 908 * Purpose: 909 * Reads a varible length quantity from an SMF file 910 * 911 * Inputs: 912 * 913 * 914 * Outputs: 915 * 916 * 917 * Side Effects: 918 * 919 *---------------------------------------------------------------------------- 920*/ 921static EAS_RESULT SMF_ParseSysEx (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_U8 f0, EAS_INT parserMode) 922{ 923 EAS_RESULT result; 924 EAS_U32 len; 925 EAS_U8 c; 926 927 /* get the length */ 928 if ((result = SMF_GetVarLenData(pEASData->hwInstData, pSMFStream->fileHandle, &len)) != EAS_SUCCESS) 929 return result; 930 931 /* start of SysEx message? */ 932 if (f0 == 0xf0) 933 { 934 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, f0, parserMode)) != EAS_SUCCESS) 935 return result; 936 } 937 938 /* feed the SysEx to the stream parser */ 939 while (len--) 940 { 941 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 942 return result; 943 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 944 return result; 945 946 /* check for GM system ON */ 947 if (pSMFStream->midiStream.flags & MIDI_FLAG_GM_ON) 948 pSMFData->flags |= SMF_FLAGS_HAS_GM_ON; 949 } 950 951 return EAS_SUCCESS; 952} 953 954/*---------------------------------------------------------------------------- 955 * SMF_ParseEvent() 956 *---------------------------------------------------------------------------- 957 * Purpose: 958 * Reads a varible length quantity from an SMF file 959 * 960 * Inputs: 961 * 962 * 963 * Outputs: 964 * 965 * 966 * Side Effects: 967 * 968 *---------------------------------------------------------------------------- 969*/ 970static EAS_RESULT SMF_ParseEvent (S_EAS_DATA *pEASData, S_SMF_DATA *pSMFData, S_SMF_STREAM *pSMFStream, EAS_INT parserMode) 971{ 972 EAS_RESULT result; 973 EAS_U8 c; 974 975 /* get the event type */ 976 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 977 return result; 978 979 /* parse meta-event */ 980 if (c == 0xff) 981 { 982 if ((result = SMF_ParseMetaEvent(pEASData, pSMFData, pSMFStream)) != EAS_SUCCESS) 983 return result; 984 } 985 986 /* parse SysEx */ 987 else if ((c == 0xf0) || (c == 0xf7)) 988 { 989 if ((result = SMF_ParseSysEx(pEASData, pSMFData, pSMFStream, c, parserMode)) != EAS_SUCCESS) 990 return result; 991 } 992 993 /* parse MIDI message */ 994 else 995 { 996 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 997 return result; 998 999 /* keep streaming data to the MIDI parser until the message is complete */ 1000 while (pSMFStream->midiStream.pending) 1001 { 1002 if ((result = EAS_HWGetByte(pEASData->hwInstData, pSMFStream->fileHandle, &c)) != EAS_SUCCESS) 1003 return result; 1004 if ((result = EAS_ParseMIDIStream(pEASData, pSMFData->pSynth, &pSMFStream->midiStream, c, parserMode)) != EAS_SUCCESS) 1005 return result; 1006 } 1007 1008 } 1009 1010 /* chase mode logic */ 1011 if (pSMFData->time == 0) 1012 { 1013 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 1014 { 1015 if (pSMFStream->midiStream.flags & MIDI_FLAG_FIRST_NOTE) 1016 pSMFData->flags &= ~SMF_FLAGS_CHASE_MODE; 1017 } 1018 else if ((pSMFData->flags & SMF_FLAGS_SETUP_BAR) == SMF_FLAGS_SETUP_BAR) 1019 pSMFData->flags = (pSMFData->flags & ~SMF_FLAGS_SETUP_BAR) | SMF_FLAGS_CHASE_MODE; 1020 } 1021 1022 return EAS_SUCCESS; 1023} 1024 1025/*---------------------------------------------------------------------------- 1026 * SMF_ParseHeader() 1027 *---------------------------------------------------------------------------- 1028 * Purpose: 1029 * Parses the header of an SMF file, allocates memory the stream parsers and initializes the 1030 * stream parsers. 1031 * 1032 * Inputs: 1033 * pEASData - pointer to overall EAS data structure 1034 * pSMFData - pointer to parser instance data 1035 * fileHandle - file handle 1036 * fileOffset - offset in the file where the header data starts, usually 0 1037 * 1038 * 1039 * Outputs: 1040 * 1041 * 1042 * Side Effects: 1043 * 1044 *---------------------------------------------------------------------------- 1045*/ 1046/*lint -e{801} we know that 'goto' is deprecated - but it's cleaner in this case */ 1047EAS_RESULT SMF_ParseHeader (EAS_HW_DATA_HANDLE hwInstData, S_SMF_DATA *pSMFData) 1048{ 1049 EAS_RESULT result; 1050 EAS_I32 i; 1051 EAS_U16 division; 1052 EAS_U32 chunkSize; 1053 EAS_U32 chunkStart; 1054 EAS_U32 temp; 1055 EAS_U32 ticks; 1056 1057 /* rewind the file and find the end of the header chunk */ 1058 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_HEADER_SIZE)) != EAS_SUCCESS) 1059 goto ReadError; 1060 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) 1061 goto ReadError; 1062 1063 /* determine the number of tracks */ 1064 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, pSMFData->fileOffset + SMF_OFS_NUM_TRACKS)) != EAS_SUCCESS) 1065 goto ReadError; 1066 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &pSMFData->numStreams, EAS_TRUE)) != EAS_SUCCESS) 1067 goto ReadError; 1068 1069 /* limit the number of tracks */ 1070 if (pSMFData->numStreams > MAX_SMF_STREAMS) 1071 { 1072 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "SMF file contains %u tracks, playing %d tracks\n", pSMFData->numStreams, MAX_SMF_STREAMS); */ } 1073 pSMFData->numStreams = MAX_SMF_STREAMS; 1074 } else if (pSMFData->numStreams == 0) 1075 { 1076 /* avoid 0 sized allocation */ 1077 return EAS_ERROR_PARAMETER_RANGE; 1078 } 1079 1080 /* get the time division */ 1081 if ((result = EAS_HWGetWord(hwInstData, pSMFData->fileHandle, &division, EAS_TRUE)) != EAS_SUCCESS) 1082 goto ReadError; 1083 1084 /* setup default timebase for 120 bpm */ 1085 pSMFData->ppqn = 192; 1086 if (!division || division & 0x8000) 1087 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"No support for SMPTE code timebase\n"); */ } 1088 else 1089 pSMFData->ppqn = (division & 0x7fff); 1090 pSMFData->tickConv = (EAS_U16) (((SMF_DEFAULT_TIMEBASE * 1024) / pSMFData->ppqn + 500) / 1000); 1091 1092 /* dynamic memory allocation, allocate memory for streams */ 1093 if (pSMFData->streams == NULL) 1094 { 1095 pSMFData->streams = EAS_HWMalloc(hwInstData,sizeof(S_SMF_STREAM) * pSMFData->numStreams); 1096 if (pSMFData->streams == NULL) 1097 return EAS_ERROR_MALLOC_FAILED; 1098 1099 /* zero the memory to insure complete initialization */ 1100 EAS_HWMemSet((void *)(pSMFData->streams), 0, sizeof(S_SMF_STREAM) * pSMFData->numStreams); 1101 } 1102 1103 /* find the start of each track */ 1104 chunkStart = (EAS_U32) pSMFData->fileOffset; 1105 ticks = 0x7fffffffL; 1106 pSMFData->nextStream = NULL; 1107 for (i = 0; i < pSMFData->numStreams; i++) 1108 { 1109 1110 for (;;) 1111 { 1112 1113 /* calculate start of next chunk - checking for errors */ 1114 temp = chunkStart + SMF_CHUNK_INFO_SIZE + chunkSize; 1115 if (temp <= chunkStart) 1116 { 1117 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Error in chunk size at offset %d\n", chunkStart); */ } 1118 return EAS_ERROR_FILE_FORMAT; 1119 } 1120 chunkStart = temp; 1121 1122 /* seek to the start of the next chunk */ 1123 if ((result = EAS_HWFileSeek(hwInstData, pSMFData->fileHandle, (EAS_I32) chunkStart)) != EAS_SUCCESS) 1124 goto ReadError; 1125 1126 /* read the chunk identifier */ 1127 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &temp, EAS_TRUE)) != EAS_SUCCESS) 1128 goto ReadError; 1129 1130 /* read the chunk size */ 1131 if ((result = EAS_HWGetDWord(hwInstData, pSMFData->fileHandle, &chunkSize, EAS_TRUE)) != EAS_SUCCESS) 1132 goto ReadError; 1133 1134 /* make sure this is an 'MTrk' chunk */ 1135 if (temp == SMF_CHUNK_TYPE_TRACK) 1136 break; 1137 1138 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING,"Unexpected chunk type: 0x%08x\n", temp); */ } 1139 } 1140 1141 /* initalize some data */ 1142 pSMFData->streams[i].ticks = 0; 1143 pSMFData->streams[i].fileHandle = pSMFData->fileHandle; 1144 1145 /* NULL the file handle so we don't try to close it twice */ 1146 pSMFData->fileHandle = NULL; 1147 1148 /* save this file position as the start of the track */ 1149 pSMFData->streams[i].startFilePos = (EAS_I32) chunkStart + SMF_CHUNK_INFO_SIZE; 1150 1151 /* initalize the MIDI parser data */ 1152 EAS_InitMIDIStream(&pSMFData->streams[i].midiStream); 1153 1154 /* parse the first delta time in each stream */ 1155 if ((result = SMF_GetDeltaTime(hwInstData, &pSMFData->streams[i])) != EAS_SUCCESS) 1156 goto ReadError; 1157 1158 if (pSMFData->streams[i].ticks < ticks) 1159 { 1160 ticks = pSMFData->streams[i].ticks; 1161 pSMFData->nextStream = &pSMFData->streams[i]; 1162 } 1163 1164 /* more tracks to do, create a duplicate file handle */ 1165 if (i < (pSMFData->numStreams - 1)) 1166 { 1167 if ((result = EAS_HWDupHandle(hwInstData, pSMFData->streams[i].fileHandle, &pSMFData->fileHandle)) != EAS_SUCCESS) 1168 goto ReadError; 1169 } 1170 } 1171 1172 /* update the time of the next event */ 1173 if (pSMFData->nextStream) 1174 SMF_UpdateTime(pSMFData, pSMFData->nextStream->ticks); 1175 1176 return EAS_SUCCESS; 1177 1178 /* ugly goto: but simpler than structured */ 1179 ReadError: 1180 if (result == EAS_EOF) 1181 return EAS_ERROR_FILE_FORMAT; 1182 return result; 1183} 1184 1185/*---------------------------------------------------------------------------- 1186 * SMF_UpdateTime() 1187 *---------------------------------------------------------------------------- 1188 * Purpose: 1189 * Update the millisecond time base by converting the ticks into millieconds 1190 * 1191 * Inputs: 1192 * 1193 * 1194 * Outputs: 1195 * 1196 * 1197 * Side Effects: 1198 * 1199 *---------------------------------------------------------------------------- 1200*/ 1201static void SMF_UpdateTime (S_SMF_DATA *pSMFData, EAS_U32 ticks) 1202{ 1203 EAS_U32 temp1, temp2; 1204 1205 if (pSMFData->flags & SMF_FLAGS_CHASE_MODE) 1206 return; 1207 1208 temp1 = (ticks >> 10) * pSMFData->tickConv; 1209 temp2 = (ticks & 0x3ff) * pSMFData->tickConv; 1210 pSMFData->time += (EAS_I32)((temp1 << 8) + (temp2 >> 2)); 1211} 1212 1213