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