1 /*----------------------------------------------------------------------------
2  *
3  * File:
4  * eas_public.c
5  *
6  * Contents and purpose:
7  * Contains EAS library public interface
8  *
9  * Copyright Sonic Network Inc. 2004
10 
11  * Licensed under the Apache License, Version 2.0 (the "License");
12  * you may not use this file except in compliance with the License.
13  * You may obtain a copy of the License at
14  *
15  *      http://www.apache.org/licenses/LICENSE-2.0
16  *
17  * Unless required by applicable law or agreed to in writing, software
18  * distributed under the License is distributed on an "AS IS" BASIS,
19  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
20  * See the License for the specific language governing permissions and
21  * limitations under the License.
22  *
23  *----------------------------------------------------------------------------
24  * Revision Control:
25  *   $Revision: 842 $
26  *   $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $
27  *----------------------------------------------------------------------------
28 */
29 
30 #define LOG_TAG "Sonivox"
31 #include "log/log.h"
32 
33 #include "eas_synthcfg.h"
34 #include "eas.h"
35 #include "eas_config.h"
36 #include "eas_host.h"
37 #include "eas_report.h"
38 #include "eas_data.h"
39 #include "eas_parser.h"
40 #include "eas_pcm.h"
41 #include "eas_midi.h"
42 #include "eas_mixer.h"
43 #include "eas_build.h"
44 #include "eas_vm_protos.h"
45 #include "eas_math.h"
46 
47 #ifdef JET_INTERFACE
48 #include "jet_data.h"
49 #endif
50 
51 #ifdef DLS_SYNTHESIZER
52 #include "eas_mdls.h"
53 #endif
54 
55 /* number of events to parse before calling EAS_HWYield function */
56 #define YIELD_EVENT_COUNT       10
57 
58 /*----------------------------------------------------------------------------
59  * easLibConfig
60  *
61  * This structure is available through the EAS public interface to allow
62  * the user to check the configuration of the library.
63  *----------------------------------------------------------------------------
64 */
65 static const S_EAS_LIB_CONFIG easLibConfig =
66 {
67     LIB_VERSION,
68 #ifdef _CHECKED_BUILD
69     EAS_TRUE,
70 #else
71     EAS_FALSE,
72 #endif
73     MAX_SYNTH_VOICES,
74     NUM_OUTPUT_CHANNELS,
75     _OUTPUT_SAMPLE_RATE,
76     BUFFER_SIZE_IN_MONO_SAMPLES,
77 #ifdef _FILTER_ENABLED
78     EAS_TRUE,
79 #else
80     EAS_FALSE,
81 #endif
82     _BUILD_TIME_,
83     _BUILD_VERSION_
84 };
85 
86 /* local prototypes */
87 static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode);
88 
89 /*----------------------------------------------------------------------------
90  * EAS_SetStreamParameter
91  *----------------------------------------------------------------------------
92  * Sets the specified parameter in the stream. Allows access to
93  * customizable settings within the individual file parsers.
94  *----------------------------------------------------------------------------
95  * pEASData         - pointer to EAS persistent data object
96  * pStream          - stream handle
97  * param            - enumerated parameter (see eas_parser.h)
98  * value            - new value
99  *----------------------------------------------------------------------------
100 */
EAS_SetStreamParameter(S_EAS_DATA * pEASData,EAS_HANDLE pStream,EAS_I32 param,EAS_I32 value)101 EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value)
102 {
103     S_FILE_PARSER_INTERFACE *pParserModule;
104 
105     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
106     if (pParserModule->pfSetData)
107         return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value);
108     return EAS_ERROR_FEATURE_NOT_AVAILABLE;
109 }
110 
111 /*----------------------------------------------------------------------------
112  * EAS_GetStreamParameter
113  *----------------------------------------------------------------------------
114  * Sets the specified parameter in the stream. Allows access to
115  * customizable settings within the individual file parsers.
116  *----------------------------------------------------------------------------
117  * pEASData         - pointer to EAS persistent data object
118  * pStream          - stream handle
119  * param            - enumerated parameter (see eas_parser.h)
120  * pValue           - pointer to variable to receive current setting
121  *----------------------------------------------------------------------------
122 */
EAS_GetStreamParameter(S_EAS_DATA * pEASData,EAS_HANDLE pStream,EAS_I32 param,EAS_I32 * pValue)123 EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue)
124 {
125     S_FILE_PARSER_INTERFACE *pParserModule;
126 
127     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
128     if (pParserModule->pfGetData)
129         return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue);
130     return EAS_ERROR_FEATURE_NOT_AVAILABLE;
131 }
132 
133 /*----------------------------------------------------------------------------
134  * EAS_StreamReady()
135  *----------------------------------------------------------------------------
136  * This routine sets common parameters like transpose, volume, etc.
137  * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
138  * fails, it attempts to get the synth handle from the parser and
139  * set the parameter directly on the synth. This eliminates duplicate
140  * code in the parser.
141  *----------------------------------------------------------------------------
142 */
EAS_StreamReady(S_EAS_DATA * pEASData,EAS_HANDLE pStream)143 EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream)
144 {
145     S_FILE_PARSER_INTERFACE *pParserModule;
146     EAS_STATE state;
147 
148     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
149     if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS)
150         return EAS_FALSE;
151     return (state < EAS_STATE_OPEN);
152 }
153 
154 /*----------------------------------------------------------------------------
155  * EAS_IntSetStrmParam()
156  *----------------------------------------------------------------------------
157  * This routine sets common parameters like transpose, volume, etc.
158  * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
159  * fails, it attempts to get the synth handle from the parser and
160  * set the parameter directly on the synth. This eliminates duplicate
161  * code in the parser.
162  *----------------------------------------------------------------------------
163 */
EAS_IntSetStrmParam(S_EAS_DATA * pEASData,EAS_HANDLE pStream,EAS_INT param,EAS_I32 value)164 EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value)
165 {
166     S_SYNTH *pSynth;
167 
168     /* try to set the parameter using stream interface */
169     if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS)
170         return EAS_SUCCESS;
171 
172     /* get a pointer to the synth object and set it directly */
173     /*lint -e{740} we are cheating by passing a pointer through this interface */
174     if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
175         return EAS_ERROR_INVALID_PARAMETER;
176 
177     if (pSynth == NULL)
178         return EAS_ERROR_INVALID_PARAMETER;
179 
180     switch (param)
181     {
182 
183 #ifdef DLS_SYNTHESIZER
184         case PARSER_DATA_DLS_COLLECTION:
185             {
186                 EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value);
187                 if (result == EAS_SUCCESS)
188                 {
189                     DLSAddRef((S_DLS*) value);
190                     VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth);
191                 }
192                 return result;
193             }
194 #endif
195 
196         case PARSER_DATA_EAS_LIBRARY:
197             return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value);
198 
199         case PARSER_DATA_POLYPHONY:
200             return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value);
201 
202         case PARSER_DATA_PRIORITY:
203             return VMSetPriority(pEASData->pVoiceMgr, pSynth, value);
204 
205         case PARSER_DATA_TRANSPOSITION:
206             VMSetTranposition(pSynth, value);
207             break;
208 
209         case PARSER_DATA_VOLUME:
210             VMSetVolume(pSynth, (EAS_U16) value);
211             break;
212 
213         default:
214             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ }
215             return EAS_ERROR_INVALID_PARAMETER;
216     }
217 
218     return EAS_SUCCESS;
219 }
220 
221 /*----------------------------------------------------------------------------
222  * EAS_AllocateStream()
223  *----------------------------------------------------------------------------
224  * Purpose:
225  * Allocates a stream handle
226  *
227  * Inputs:
228  *
229  * Outputs:
230  *
231  *----------------------------------------------------------------------------
232 */
EAS_AllocateStream(EAS_DATA_HANDLE pEASData)233 static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData)
234 {
235     EAS_INT streamNum;
236 
237     /* check for static allocation, only one stream allowed */
238     if (pEASData->staticMemoryModel)
239     {
240         if (pEASData->streams[0].handle != NULL)
241         {
242             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ }
243             return -1;
244         }
245         return 0;
246     }
247 
248     /* dynamic model */
249     for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
250         if (pEASData->streams[streamNum].handle == NULL)
251             break;
252     if (streamNum == MAX_NUMBER_STREAMS)
253     {
254         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ }
255         return -1;
256     }
257     return streamNum;
258 }
259 
260 /*----------------------------------------------------------------------------
261  * EAS_InitStream()
262  *----------------------------------------------------------------------------
263  * Purpose:
264  * Initialize a stream
265  *
266  * Inputs:
267  *
268  * Outputs:
269  *
270  *----------------------------------------------------------------------------
271 */
EAS_InitStream(S_EAS_STREAM * pStream,EAS_VOID_PTR pParserModule,EAS_VOID_PTR streamHandle)272 static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle)
273 {
274     pStream->pParserModule = pParserModule;
275     pStream->handle = streamHandle;
276     pStream->time = 0;
277     pStream->frameLength = AUDIO_FRAME_LENGTH;
278     pStream->repeatCount = 0;
279     pStream->volume = DEFAULT_STREAM_VOLUME;
280     pStream->streamFlags = 0;
281 }
282 
283 /*----------------------------------------------------------------------------
284  * EAS_Config()
285  *----------------------------------------------------------------------------
286  * Purpose:
287  * Returns a pointer to a structure containing the configuration options
288  * in this library build.
289  *
290  * Inputs:
291  *
292  * Outputs:
293  *
294  *----------------------------------------------------------------------------
295 */
EAS_Config(void)296 EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void)
297 {
298     return &easLibConfig;
299 }
300 
301 /*----------------------------------------------------------------------------
302  * EAS_Init()
303  *----------------------------------------------------------------------------
304  * Purpose:
305  * Initialize the synthesizer library
306  *
307  * Inputs:
308  *  ppEASData       - pointer to data handle variable for this instance
309  *
310  * Outputs:
311  *
312  *----------------------------------------------------------------------------
313 */
EAS_Init(EAS_DATA_HANDLE * ppEASData)314 EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData)
315 {
316     EAS_HW_DATA_HANDLE pHWInstData;
317     EAS_RESULT result;
318     S_EAS_DATA *pEASData;
319     EAS_INT module;
320     EAS_BOOL staticMemoryModel;
321 
322     /* get the memory model */
323     staticMemoryModel = EAS_CMStaticMemoryModel();
324 
325     /* initialize the host wrapper interface */
326     *ppEASData = NULL;
327     if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS)
328         return result;
329 
330     /* check Configuration Module for S_EAS_DATA allocation */
331     if (staticMemoryModel)
332         pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA);
333     else
334         pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA));
335     if (!pEASData)
336     {
337         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ }
338         return EAS_ERROR_MALLOC_FAILED;
339     }
340 
341     /* initialize some data */
342     EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA));
343     pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel;
344     pEASData->hwInstData = pHWInstData;
345     pEASData->renderTime = 0;
346 
347     /* set header search flag */
348 #ifdef FILE_HEADER_SEARCH
349     pEASData->searchHeaderFlag = EAS_TRUE;
350 #endif
351 
352     /* initalize parameters */
353     EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME);
354 
355 #ifdef _METRICS_ENABLED
356     /* initalize the metrics module */
357     pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS);
358     if (pEASData->pMetricsModule != NULL)
359     {
360         if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS)
361         {
362             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ }
363             return result;
364         }
365     }
366 #endif
367 
368     /* initailize the voice manager & synthesizer */
369     if ((result = VMInitialize(pEASData)) != EAS_SUCCESS)
370         return result;
371 
372     /* initialize mix engine */
373     if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS)
374     {
375         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ }
376         return result;
377     }
378 
379     /* initialize effects modules */
380     for (module = 0; module < NUM_EFFECTS_MODULES; module++)
381     {
382         pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module);
383         if (pEASData->effectsModules[module].effect != NULL)
384         {
385             if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS)
386             {
387                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ }
388                 return result;
389             }
390         }
391     }
392 
393     /* initialize PCM engine */
394     if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS)
395     {
396         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ }
397         return result;
398     }
399 
400     /* return instance data pointer to host */
401     *ppEASData = pEASData;
402 
403     return EAS_SUCCESS;
404 }
405 
406 /*----------------------------------------------------------------------------
407  * EAS_Shutdown()
408  *----------------------------------------------------------------------------
409  * Purpose:
410  * Shuts down the library. Deallocates any memory associated with the
411  * synthesizer (dynamic memory model only)
412  *
413  * Inputs:
414  *  pEASData        - handle to data for this instance
415  *
416  * Outputs:
417  *
418  *----------------------------------------------------------------------------
419 */
EAS_Shutdown(EAS_DATA_HANDLE pEASData)420 EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData)
421 {
422     /* check for NULL handle */
423     if (!pEASData)
424         return EAS_ERROR_HANDLE_INTEGRITY;
425 
426     /* establish pointers */
427     EAS_HW_DATA_HANDLE hwInstData = pEASData->hwInstData;
428 
429     /* if there are streams open, close them */
430     EAS_RESULT reportResult = EAS_SUCCESS;
431 
432     EAS_RESULT result;
433     EAS_INT i;
434     for (i = 0; i < MAX_NUMBER_STREAMS; i++)
435     {
436         if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle)
437         {
438             if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS)
439             {
440                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ }
441                 reportResult = result;
442             }
443         }
444     }
445 
446     /* shutdown PCM engine */
447     if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS)
448     {
449         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ }
450         if (reportResult == EAS_SUCCESS)
451             reportResult = result;
452     }
453 
454     /* shutdown mix engine */
455     if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS)
456     {
457         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ }
458         if (reportResult == EAS_SUCCESS)
459             reportResult = result;
460     }
461 
462     /* shutdown effects modules */
463     for (i = 0; i < NUM_EFFECTS_MODULES; i++)
464     {
465         if (pEASData->effectsModules[i].effect)
466         {
467             if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS)
468             {
469                 { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ }
470                 if (reportResult == EAS_SUCCESS)
471                     reportResult = result;
472             }
473         }
474     }
475 
476     /* shutdown the voice manager & synthesizer */
477     VMShutdown(pEASData);
478 
479 #ifdef _METRICS_ENABLED
480     /* shutdown the metrics module */
481     if (pEASData->pMetricsModule != NULL)
482     {
483         if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS)
484         {
485             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ }
486             if (reportResult == EAS_SUCCESS)
487                 reportResult = result;
488         }
489     }
490 #endif
491 
492     /* release allocated memory */
493     if (!pEASData->staticMemoryModel)
494         EAS_HWFree(hwInstData, pEASData);
495 
496     /* shutdown host wrappers */
497     if (hwInstData)
498     {
499         if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS)
500         {
501             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ }
502             if (reportResult == EAS_SUCCESS)
503                 reportResult = result;
504         }
505     }
506 
507     return reportResult;
508 }
509 
510 #ifdef JET_INTERFACE
511 /*----------------------------------------------------------------------------
512  * EAS_OpenJETStream()
513  *----------------------------------------------------------------------------
514  * Private interface for JET to open an SMF stream with an offset
515  *----------------------------------------------------------------------------
516 */
EAS_OpenJETStream(EAS_DATA_HANDLE pEASData,EAS_FILE_HANDLE fileHandle,EAS_I32 offset,EAS_HANDLE * ppStream)517 EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream)
518 {
519     EAS_RESULT result;
520     EAS_VOID_PTR streamHandle;
521     S_FILE_PARSER_INTERFACE *pParserModule;
522     EAS_INT streamNum;
523 
524     /* allocate a stream */
525     if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
526         return EAS_ERROR_MAX_STREAMS_OPEN;
527 
528     /* check Configuration Module for SMF parser */
529     *ppStream = NULL;
530     streamHandle = NULL;
531     pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0);
532     if (pParserModule == NULL)
533         return EAS_ERROR_UNRECOGNIZED_FORMAT;
534 
535     /* see if SMF parser recognizes the file */
536     if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS)
537     {
538         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
539         return result;
540     }
541 
542     /* parser recognized the file, return the handle */
543     if (streamHandle)
544     {
545         EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
546         *ppStream = &pEASData->streams[streamNum];
547         return EAS_SUCCESS;
548     }
549 
550     return EAS_ERROR_UNRECOGNIZED_FORMAT;
551 }
552 #endif
553 
554 /*----------------------------------------------------------------------------
555  * EAS_OpenFile()
556  *----------------------------------------------------------------------------
557  * Purpose:
558  * Opens a file for audio playback.
559  *
560  * Inputs:
561  * pEASData         - pointer to overall EAS data structure
562  * pHandle          - pointer to file handle
563  *
564  * Outputs:
565  *
566  *
567  * Side Effects:
568  *
569  *----------------------------------------------------------------------------
570 */
EAS_OpenFile(EAS_DATA_HANDLE pEASData,EAS_FILE_LOCATOR locator,EAS_HANDLE * ppStream)571 EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream)
572 {
573     EAS_RESULT result;
574     EAS_FILE_HANDLE fileHandle;
575     EAS_VOID_PTR streamHandle;
576     S_FILE_PARSER_INTERFACE *pParserModule;
577     EAS_INT streamNum;
578     EAS_INT moduleNum;
579 
580     /* open the file */
581     if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
582         return result;
583 
584     /* allocate a stream */
585     if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
586     {
587         /* Closing the opened file as stream allocation failed */
588         EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
589         return EAS_ERROR_MAX_STREAMS_OPEN;
590     }
591     /* check Configuration Module for file parsers */
592     pParserModule = NULL;
593     *ppStream = NULL;
594     streamHandle = NULL;
595     for (moduleNum = 0; ; moduleNum++)
596     {
597         pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum);
598         if (pParserModule == NULL)
599             break;
600 
601         /* see if this parser recognizes it */
602         if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS)
603         {
604             /* Closing the opened file as file type check failed */
605             EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
606 
607             { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
608             return result;
609         }
610 
611         /* parser recognized the file, return the handle */
612         if (streamHandle)
613         {
614 
615             /* save the parser pointer and file handle */
616             EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
617             *ppStream = &pEASData->streams[streamNum];
618             return EAS_SUCCESS;
619         }
620 
621         /* rewind the file for the next parser */
622         if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS)
623         {
624             /* Closing the opened file as file seek failed */
625             EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
626 
627             return result;
628          }
629     }
630 
631     /* no parser was able to recognize the file, close it and return an error */
632     EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
633     { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ }
634     return EAS_ERROR_UNRECOGNIZED_FORMAT;
635 }
636 
637 /*----------------------------------------------------------------------------
638  * EAS_Prepare()
639  *----------------------------------------------------------------------------
640  * Purpose:
641  * Prepares the synthesizer to play the file or stream. Parses the first
642  * frame of data from the file and arms the synthesizer.
643  *
644  * Inputs:
645  * pEASData         - pointer to overall EAS data structure
646  * handle           - file or stream handle
647  *
648  * Outputs:
649  *
650  *
651  * Side Effects:
652  *
653  *----------------------------------------------------------------------------
654 */
EAS_Prepare(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream)655 EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
656 {
657     S_FILE_PARSER_INTERFACE *pParserModule;
658     EAS_STATE state;
659     EAS_RESULT result;
660 
661     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
662     if (pParserModule == NULL)
663         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
664 
665     /* check for valid state */
666     result = pParserModule->pfState(pEASData, pStream->handle, &state);
667     if (result == EAS_SUCCESS)
668     {
669         /* prepare the stream */
670         if (state == EAS_STATE_OPEN)
671         {
672             pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
673             result = (*pParserModule->pfPrepare)(pEASData, pStream->handle);
674 
675             /* set volume */
676             if (result == EAS_SUCCESS)
677                 result = EAS_SetVolume(pEASData, pStream, pStream->volume);
678         }
679         else
680             result = EAS_ERROR_NOT_VALID_IN_THIS_STATE;
681 
682     }
683 
684     return result;
685 }
686 
687 /*----------------------------------------------------------------------------
688  * EAS_Render()
689  *----------------------------------------------------------------------------
690  * Purpose:
691  * Parse the Midi data and render PCM audio data.
692  *
693  * Inputs:
694  *  pEASData        - buffer for internal EAS data
695  *  pOut            - output buffer pointer
696  *  nNumRequested   - requested num samples to generate
697  *  pnNumGenerated  - actual number of samples generated
698  *
699  * Outputs:
700  *  EAS_SUCCESS if PCM data was successfully rendered
701  *
702  *----------------------------------------------------------------------------
703 */
EAS_Render(EAS_DATA_HANDLE pEASData,EAS_PCM * pOut,EAS_I32 numRequested,EAS_I32 * pNumGenerated)704 EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated)
705 {
706     S_FILE_PARSER_INTERFACE *pParserModule;
707     EAS_RESULT result;
708     EAS_I32 voicesRendered;
709     EAS_STATE parserState;
710     EAS_INT streamNum;
711 
712     /* assume no samples generated and reset workload */
713     *pNumGenerated = 0;
714     VMInitWorkload(pEASData->pVoiceMgr);
715 
716     /* no support for other buffer sizes yet */
717     if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES)
718     {
719         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n",
720             (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ }
721         return EAS_BUFFER_SIZE_MISMATCH;
722     }
723 
724 #ifdef _METRICS_ENABLED
725     /* start performance counter */
726     if (pEASData->pMetricsData)
727         (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
728 #endif
729 
730     /* prep the frame buffer, do mix engine prep only if TRUE */
731 #ifdef _SPLIT_ARCHITECTURE
732     if (VMStartFrame(pEASData))
733         EAS_MixEnginePrep(pEASData, numRequested);
734 #else
735     /* prep the mix engine */
736     EAS_MixEnginePrep(pEASData, numRequested);
737 #endif
738 
739     /* save the output buffer pointer */
740     pEASData->pOutputAudioBuffer = pOut;
741 
742 
743 #ifdef _METRICS_ENABLED
744         /* start performance counter */
745         if (pEASData->pMetricsData)
746             (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
747 #endif
748 
749     /* if we haven't finished parsing from last time, do it now */
750     /* need to parse another frame of events before we render again */
751     for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
752     {
753         /* clear the locate flag */
754         pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE;
755 
756         if (pEASData->streams[streamNum].pParserModule)
757         {
758 
759             /* establish pointer to parser module */
760             pParserModule = pEASData->streams[streamNum].pParserModule;
761 
762 #ifdef JET_INTERFACE
763             /* handle pause */
764             if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE)
765             {
766                 if (pParserModule->pfPause)
767                     result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle);
768                 pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE;
769             }
770 #endif
771 
772             /* get current state */
773             if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
774                 return result;
775 
776 #ifdef JET_INTERFACE
777             /* handle resume */
778             if (parserState == EAS_STATE_PAUSED)
779             {
780                 if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME)
781                 {
782                     if (pParserModule->pfResume)
783                         result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle);
784                     pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME;
785                 }
786             }
787 #endif
788 
789             /* if necessary, parse stream */
790             if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0)
791                 if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS)
792                     return result;
793 
794             /* check for an early abort */
795             if ((pEASData->streams[streamNum].streamFlags) == 0)
796             {
797 
798 #ifdef _METRICS_ENABLED
799                 /* stop performance counter */
800                 if (pEASData->pMetricsData)
801                     (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
802 #endif
803 
804                 return EAS_SUCCESS;
805             }
806 
807             /* check for repeat */
808             if (pEASData->streams[streamNum].repeatCount)
809             {
810 
811                 /* check for stopped state */
812                 if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
813                     return result;
814                 if (parserState == EAS_STATE_STOPPED)
815                 {
816 
817                     /* decrement repeat count, unless it is negative */
818                     if (pEASData->streams[streamNum].repeatCount > 0)
819                         pEASData->streams[streamNum].repeatCount--;
820 
821                     /* reset the parser */
822                     if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS)
823                         return result;
824                     pEASData->streams[streamNum].time = 0;
825                 }
826             }
827         }
828     }
829 
830 #ifdef _METRICS_ENABLED
831     /* stop performance counter */
832     if (pEASData->pMetricsData)
833         (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
834 #endif
835 
836 #ifdef _METRICS_ENABLED
837     /* start the render timer */
838     if (pEASData->pMetricsData)
839         (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
840 #endif
841 
842     /* render audio */
843     if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS)
844     {
845         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ }
846         return result;
847     }
848 
849 #ifdef _METRICS_ENABLED
850     /* stop the render timer */
851     if (pEASData->pMetricsData) {
852         (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1);
853         (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
854         (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered);
855         (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered);
856     }
857 #endif
858 
859     //2 Do we really need frameParsed?
860     /* need to parse another frame of events before we render again */
861     for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
862         if (pEASData->streams[streamNum].pParserModule != NULL)
863             pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED;
864 
865 #ifdef _METRICS_ENABLED
866     /* start performance counter */
867     if (pEASData->pMetricsData)
868         (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
869 #endif
870 
871 #ifdef _METRICS_ENABLED
872     /* stop the stream timer */
873     if (pEASData->pMetricsData)
874         (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
875 #endif
876 
877 #ifdef _METRICS_ENABLED
878     /* start the post timer */
879     if (pEASData->pMetricsData)
880         (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
881 #endif
882 
883     /* for split architecture, send DSP vectors.  Do post only if return is TRUE */
884 #ifdef _SPLIT_ARCHITECTURE
885     if (VMEndFrame(pEASData))
886     {
887         /* now do post-processing */
888         EAS_MixEnginePost(pEASData, numRequested);
889         *pNumGenerated = numRequested;
890     }
891 #else
892     /* now do post-processing */
893     EAS_MixEnginePost(pEASData, numRequested);
894     *pNumGenerated = numRequested;
895 #endif
896 
897 #ifdef _METRICS_ENABLED
898     /* stop the post timer */
899     if (pEASData->pMetricsData)
900         (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
901 #endif
902 
903     /* advance render time */
904     pEASData->renderTime += AUDIO_FRAME_LENGTH;
905 
906 #if 0
907     /* dump workload for debug */
908     if (pEASData->pVoiceMgr->workload)
909         { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ }
910 #endif
911 
912 #ifdef _METRICS_ENABLED
913     /* stop performance counter */
914     if (pEASData->pMetricsData)
915     {
916         PERF_TIMER temp;
917         temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
918 
919         /* if max render time, record the number of voices and time */
920         if ((*pEASData->pMetricsModule->pfRecordMaxValue)
921             (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp))
922         {
923             (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered);
924             (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8));
925         }
926     }
927 #endif
928 
929 #ifdef JET_INTERFACE
930     /* let JET to do its thing */
931     if (pEASData->jetHandle != NULL)
932     {
933         result = JET_Process(pEASData);
934         if (result != EAS_SUCCESS)
935             return result;
936     }
937 #endif
938 
939     return EAS_SUCCESS;
940 }
941 
942 #ifdef JET_INTERFACE
943 /*----------------------------------------------------------------------------
944  * EAS_SetTransposition)
945  *----------------------------------------------------------------------------
946  * Purpose:
947  * Sets the key tranposition for the synthesizer. Transposes all
948  * melodic instruments by the specified amount. Range is limited
949  * to +/-12 semitones.
950  *
951  * Inputs:
952  *  pEASData        - handle to data for this instance
953  *  handle          - handle to stream
954  *  transposition   - +/-12 semitones
955  *
956  * Outputs:
957  *
958  * Side Effects:
959  *
960  *----------------------------------------------------------------------------
961 */
EAS_SetTransposition(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_I32 transposition)962 EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition)
963 {
964 
965     /* check range */
966     if ((transposition < -12) || (transposition > 12))
967         return EAS_ERROR_INVALID_PARAMETER;
968 
969     if (!EAS_StreamReady(pEASData, pStream))
970         return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
971     return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition);
972 }
973 #endif
974 
975 /*----------------------------------------------------------------------------
976  * EAS_ParseEvents()
977  *----------------------------------------------------------------------------
978  * Purpose:
979  * Parse events in the current streams until the desired time is reached.
980  *
981  * Inputs:
982  *  pEASData        - buffer for internal EAS data
983  *  endTime         - stop parsing if this time is reached
984  *  parseMode       - play, locate, or metadata
985  *
986  * Outputs:
987  *  EAS_SUCCESS if PCM data was successfully rendered
988  *
989  *----------------------------------------------------------------------------
990 */
EAS_ParseEvents(S_EAS_DATA * pEASData,EAS_HANDLE pStream,EAS_U32 endTime,EAS_INT parseMode)991 static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode)
992 {
993     S_FILE_PARSER_INTERFACE *pParserModule;
994     EAS_RESULT result;
995     EAS_I32 parserState;
996     EAS_BOOL done;
997     EAS_INT yieldCount = YIELD_EVENT_COUNT;
998     EAS_U32 time = 0;
999 
1000     // This constant is the maximum number of events that can be processed in a single time slice.
1001     // A typical ringtone will contain a few events per time slice.
1002     // Extremely dense ringtones might go up to 50 events.
1003     // If we see this many events then the file is probably stuck in an infinite loop
1004     // and should be aborted.
1005     static const EAS_INT MAX_EVENT_COUNT = 100000;
1006     EAS_INT eventCount = 0;
1007 
1008     /* does this parser have a time function? */
1009     pParserModule = pStream->pParserModule;
1010     if (pParserModule->pfTime == NULL)
1011     {
1012         /* check state */
1013         if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
1014             return result;
1015         /* if play state, advance time */
1016         if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING))
1017             pStream->time += pStream->frameLength;
1018         done = EAS_TRUE;
1019     }
1020 
1021     /* assume we're not done, in case we abort out */
1022     else
1023     {
1024         pStream->streamFlags &= ~STREAM_FLAGS_PARSED;
1025         done = EAS_FALSE;
1026     }
1027 
1028     while (!done)
1029     {
1030 
1031         /* check for stopped state */
1032         if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
1033             return result;
1034         if (parserState > EAS_STATE_PLAY)
1035         {
1036             /* save current time if we're not in play mode */
1037             if (parseMode != eParserModePlay)
1038                 pStream->time = time << 8;
1039             done = EAS_TRUE;
1040             break;
1041         }
1042 
1043         /* get the next event time */
1044         if (pParserModule->pfTime)
1045         {
1046             if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS)
1047                 return result;
1048 
1049             /* if next event is within this frame, parse it */
1050             if (time < (endTime >> 8))
1051             {
1052 
1053                 /* parse the next event */
1054                 if (pParserModule->pfEvent) {
1055                     if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode))
1056                             != EAS_SUCCESS) {
1057                         ALOGE("%s() pfEvent returned %ld", __func__, result);
1058                         return result;
1059                     }
1060                 }
1061 
1062                 // An infinite loop within a ringtone file can cause this function
1063                 // to loop forever.  Try to detect that and return an error.
1064                 // Only check when playing. Otherwise a very large file could be rejected
1065                 // when scanning the entire file in a single call to this function.
1066                 // OTA files will only do infinite loops when in eParserModePlay.
1067                 if (++eventCount >= MAX_EVENT_COUNT && parseMode == eParserModePlay) {
1068                     ALOGE("%s() aborting, %d events. Infinite loop in song file?!",
1069                             __func__, eventCount);
1070                     android_errorWriteLog(0x534e4554, "68664359");
1071                     return EAS_ERROR_FILE_POS;
1072                 }
1073             }
1074 
1075             /* no more events in this frame, advance time */
1076             else
1077             {
1078                 pStream->time = endTime;
1079                 done = EAS_TRUE;
1080             }
1081         }
1082 
1083         /* check for max workload exceeded */
1084         if (VMCheckWorkload(pEASData->pVoiceMgr))
1085         {
1086             /* stop even though we may not have parsed
1087              * all the events in this frame. The parser will try to
1088              * catch up on the next frame.
1089              */
1090             break;
1091         }
1092 
1093         /* give host a chance for an early abort */
1094         if (--yieldCount == 0)
1095         {
1096             if (EAS_HWYield(pEASData->hwInstData))
1097                 break;
1098             yieldCount = YIELD_EVENT_COUNT;
1099         }
1100     }
1101 
1102     /* if no early abort, parsing is complete for this frame */
1103     if (done)
1104         pStream->streamFlags |= STREAM_FLAGS_PARSED;
1105 
1106     return EAS_SUCCESS;
1107 }
1108 
1109 /*----------------------------------------------------------------------------
1110  * EAS_ParseMetaData()
1111  *----------------------------------------------------------------------------
1112  * Purpose:
1113  *
1114  *
1115  * Inputs:
1116  * pEASData         - pointer to overall EAS data structure
1117  * handle           - file or stream handle
1118  * playLength       - pointer to variable to store the play length (in msecs)
1119  *
1120  * Outputs:
1121  *
1122  *
1123  * Side Effects:
1124  *                  - resets the parser to the start of the file
1125  *----------------------------------------------------------------------------
1126 */
EAS_ParseMetaData(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_I32 * playLength)1127 EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength)
1128 {
1129     S_FILE_PARSER_INTERFACE *pParserModule;
1130     EAS_RESULT result;
1131     EAS_STATE state;
1132 
1133     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1134     if (pParserModule == NULL)
1135         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1136 
1137     /* check parser state */
1138     if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
1139         return result;
1140     if (state >= EAS_STATE_OPEN)
1141         return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1142 
1143     /* if parser has metadata function, use that */
1144     if (pParserModule->pfGetMetaData != NULL)
1145         return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength);
1146 
1147     /* reset the parser to the beginning */
1148     if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
1149         return result;
1150 
1151     /* parse the file to end */
1152     pStream->time = 0;
1153     VMInitWorkload(pEASData->pVoiceMgr);
1154     if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS)
1155         return result;
1156 
1157     /* get the parser time */
1158     if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS)
1159         return result;
1160 
1161     /* reset the parser to the beginning */
1162     pStream->time = 0;
1163     return (*pParserModule->pfReset)(pEASData, pStream->handle);
1164 }
1165 
1166 /*----------------------------------------------------------------------------
1167  * EAS_CloseFile()
1168  *----------------------------------------------------------------------------
1169  * Purpose:
1170  * Closes an audio file or stream. Playback should have either paused or
1171  * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED).
1172  *
1173  * Inputs:
1174  * pEASData         - pointer to overall EAS data structure
1175  * handle           - file or stream handle
1176  *
1177  * Outputs:
1178  *
1179  *
1180  * Side Effects:
1181  *
1182  *----------------------------------------------------------------------------
1183 */
EAS_CloseFile(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream)1184 EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1185 {
1186     S_FILE_PARSER_INTERFACE *pParserModule;
1187     EAS_RESULT result;
1188 
1189     /* call the close function */
1190     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1191     if (pParserModule == NULL)
1192         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1193 
1194     result = (*pParserModule->pfClose)(pEASData, pStream->handle);
1195 
1196     /* clear the handle and parser interface pointer */
1197     pStream->handle = NULL;
1198     pStream->pParserModule = NULL;
1199     return result;
1200 }
1201 
1202 /*----------------------------------------------------------------------------
1203  * EAS_State()
1204  *----------------------------------------------------------------------------
1205  * Purpose:
1206  * Returns the state of an audio file or stream.
1207  *
1208  * Inputs:
1209  * pEASData         - pointer to overall EAS data structure
1210  * handle           - file or stream handle
1211  *
1212  * Outputs:
1213  *
1214  *
1215  * Side Effects:
1216  *
1217  *----------------------------------------------------------------------------
1218 */
EAS_State(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_STATE * pState)1219 EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState)
1220 {
1221     S_FILE_PARSER_INTERFACE *pParserModule;
1222     EAS_RESULT result;
1223 
1224     /* call the parser to return state */
1225     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1226     if (pParserModule == NULL)
1227         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1228 
1229     if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS)
1230         return result;
1231 
1232     /* if repeat count is set for this parser, mask the stopped state from the application */
1233     if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED))
1234         *pState = EAS_STATE_PLAY;
1235 
1236     /* if we're not paused or pausing, we don't need to hide state from host */
1237     if (*pState != EAS_STATE_PAUSED && *pState != EAS_STATE_PAUSING)
1238         return EAS_SUCCESS;
1239 
1240     /* if stream is about to be paused, report it as paused */
1241     if (pStream->streamFlags & STREAM_FLAGS_PAUSE)
1242     {
1243         if (pStream->streamFlags & STREAM_FLAGS_LOCATE)
1244             *pState = EAS_STATE_PAUSED;
1245         else
1246             *pState = EAS_STATE_PAUSING;
1247     }
1248 
1249     /* if stream is about to resume, report it as playing */
1250     if (pStream->streamFlags & STREAM_FLAGS_RESUME)
1251         *pState = EAS_STATE_PLAY;
1252 
1253     return EAS_SUCCESS;
1254 }
1255 
1256 /*----------------------------------------------------------------------------
1257  * EAS_SetVolume()
1258  *----------------------------------------------------------------------------
1259  * Purpose:
1260  * Set the master gain for the mix engine in 1dB increments
1261  *
1262  * Inputs:
1263  * pEASData         - pointer to overall EAS data structure
1264  * volume           - the desired master gain (100 is max)
1265  * handle           - file or stream handle
1266  *
1267  * Outputs:
1268  *
1269  *
1270  * Side Effects:
1271  * overrides any previously set master volume from sysex
1272  *
1273  *----------------------------------------------------------------------------
1274 */
EAS_SetVolume(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_I32 volume)1275 EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume)
1276 {
1277     EAS_I16 gain;
1278 
1279     /* check range */
1280     if ((volume < 0) || (volume > EAS_MAX_VOLUME))
1281         return EAS_ERROR_PARAMETER_RANGE;
1282 
1283     /* stream volume */
1284     if (pStream != NULL)
1285     {
1286         EAS_I32 gainOffset;
1287         EAS_RESULT result;
1288 
1289         if (!EAS_StreamReady(pEASData, pStream))
1290             return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1291 
1292         /* get gain offset */
1293         pStream->volume = (EAS_U8) volume;
1294         result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset);
1295         if (result == EAS_SUCCESS)
1296             volume += gainOffset;
1297 
1298         /* set stream volume */
1299         gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
1300 
1301         /* convert to linear scalar */
1302         return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain);
1303     }
1304 
1305     /* master volume */
1306     pEASData->masterVolume = (EAS_U8) volume;
1307 #if (NUM_OUTPUT_CHANNELS == 1)
1308     /* leave 3dB headroom for mono output */
1309     volume -= 3;
1310 #endif
1311 
1312     gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
1313     pEASData->masterGain = gain;
1314     return EAS_SUCCESS;
1315 }
1316 
1317 /*----------------------------------------------------------------------------
1318  * EAS_Locate()
1319  *----------------------------------------------------------------------------
1320  * Purpose:
1321  * Locate into the file associated with the handle.
1322  *
1323  * Inputs:
1324  * pEASData - pointer to overall EAS data structure
1325  * handle           - file handle
1326  * milliseconds     - playback offset from start of file in milliseconds
1327  *
1328  * Outputs:
1329  *
1330  *
1331  * Side Effects:
1332  * the actual offset will be quantized to the closest update period, typically
1333  * a resolution of 5.9ms. Notes that are started prior to this time will not
1334  * sound. Any notes currently playing will be shut off.
1335  *
1336  *----------------------------------------------------------------------------
1337 */
EAS_Locate(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_I32 milliseconds,EAS_BOOL offset)1338 EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset)
1339 {
1340     S_FILE_PARSER_INTERFACE *pParserModule;
1341     EAS_RESULT result;
1342     EAS_U32 requestedTime;
1343     EAS_STATE state;
1344 
1345     /* get pointer to parser function table */
1346     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1347     if (pParserModule == NULL)
1348         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1349 
1350     if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
1351         return result;
1352     if (state >= EAS_STATE_OPEN)
1353         return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1354 
1355     /* handle offset and limit to start of file */
1356     /*lint -e{704} use shift for performance*/
1357     if (offset)
1358         milliseconds += (EAS_I32) pStream->time >> 8;
1359     if (milliseconds < 0)
1360         milliseconds = 0;
1361 
1362     /* check to see if the request is different from the current time */
1363     requestedTime = (EAS_U32) milliseconds;
1364     if (requestedTime == (pStream->time >> 8))
1365         return EAS_SUCCESS;
1366 
1367     /* set the locate flag */
1368     pStream->streamFlags |= STREAM_FLAGS_LOCATE;
1369 
1370     /* use the parser locate function, if available */
1371     if (pParserModule->pfLocate != NULL)
1372     {
1373         EAS_BOOL parserLocate = EAS_FALSE;
1374         result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate);
1375         if (!parserLocate)
1376         {
1377             if (result == EAS_SUCCESS)
1378                 pStream->time = requestedTime << 8;
1379             return result;
1380         }
1381     }
1382 
1383     /* if we were paused and not going to resume, set pause request flag */
1384     if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
1385         pStream->streamFlags |= STREAM_FLAGS_PAUSE;
1386 
1387     /* reset the synth and parser */
1388     if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
1389         return result;
1390     pStream->time = 0;
1391 
1392     /* locating forward, clear parsed flag and parse data until we get to the requested location */
1393     if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS)
1394         return result;
1395 
1396     return EAS_SUCCESS;
1397 }
1398 
1399 /*----------------------------------------------------------------------------
1400  * EAS_GetLocation()
1401  *----------------------------------------------------------------------------
1402  * Purpose:
1403  * Returns the current playback offset
1404  *
1405  * Inputs:
1406  * pEASData         - pointer to overall EAS data structure
1407  * handle           - file handle
1408  *
1409  * Outputs:
1410  * The offset in milliseconds from the start of the current sequence, quantized
1411  * to the nearest update period. Actual resolution is typically 5.9 ms.
1412  *
1413  * Side Effects:
1414  *
1415  *----------------------------------------------------------------------------
1416 */
1417 /*lint -esym(715, pEASData) reserved for future use */
EAS_GetLocation(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream,EAS_I32 * pTime)1418 EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime)
1419 {
1420     if (!EAS_StreamReady(pEASData, pStream))
1421         return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1422 
1423     *pTime = pStream->time >> 8;
1424     return EAS_SUCCESS;
1425 }
1426 
1427 #ifdef JET_INTERFACE
1428 /*----------------------------------------------------------------------------
1429  * EAS_Pause()
1430  *----------------------------------------------------------------------------
1431  * Purpose:
1432  * Pauses the playback of the data associated with this handle. The audio
1433  * is gracefully ramped down to prevent clicks and pops. It may take several
1434  * buffers of audio before the audio is muted.
1435  *
1436  * Inputs:
1437  * psEASData        - pointer to overall EAS data structure
1438  * handle           - file or stream handle
1439  *
1440  * Outputs:
1441  *
1442  *
1443  * Side Effects:
1444  *
1445  *
1446  *----------------------------------------------------------------------------
1447 */
EAS_Pause(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream)1448 EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1449 {
1450     S_FILE_PARSER_INTERFACE *pParserModule;
1451     EAS_STATE state;
1452     EAS_RESULT result;
1453 
1454     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1455     if (pParserModule == NULL)
1456         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1457 
1458     /* check for valid state */
1459     result = pParserModule->pfState(pEASData, pStream->handle, &state);
1460     if (result == EAS_SUCCESS)
1461     {
1462         if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
1463             return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1464 
1465         /* make sure parser implements pause */
1466         if (pParserModule->pfPause == NULL)
1467             result = EAS_ERROR_NOT_IMPLEMENTED;
1468 
1469         /* clear resume flag */
1470         pStream->streamFlags &= ~STREAM_FLAGS_RESUME;
1471 
1472         /* set pause flag */
1473         pStream->streamFlags |= STREAM_FLAGS_PAUSE;
1474 
1475 #if 0
1476         /* pause the stream */
1477         if (pParserModule->pfPause)
1478             result = pParserModule->pfPause(pEASData, pStream->handle);
1479         else
1480             result = EAS_ERROR_NOT_IMPLEMENTED;
1481 #endif
1482     }
1483 
1484     return result;
1485 }
1486 
1487 /*----------------------------------------------------------------------------
1488  * EAS_Resume()
1489  *----------------------------------------------------------------------------
1490  * Purpose:
1491  * Resumes the playback of the data associated with this handle. The audio
1492  * is gracefully ramped up to prevent clicks and pops.
1493  *
1494  * Inputs:
1495  * psEASData        - pointer to overall EAS data structure
1496  * handle           - file or stream handle
1497  *
1498  * Outputs:
1499  *
1500  *
1501  * Side Effects:
1502  *
1503  *
1504  *----------------------------------------------------------------------------
1505 */
EAS_Resume(EAS_DATA_HANDLE pEASData,EAS_HANDLE pStream)1506 EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1507 {
1508     S_FILE_PARSER_INTERFACE *pParserModule;
1509     EAS_STATE state;
1510     EAS_RESULT result;
1511 
1512     pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1513     if (pParserModule == NULL)
1514         return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1515 
1516     /* check for valid state */
1517     result = pParserModule->pfState(pEASData, pStream->handle, &state);
1518     if (result == EAS_SUCCESS)
1519     {
1520         if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0))
1521             return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1522 
1523         /* make sure parser implements this function */
1524         if (pParserModule->pfResume == NULL)
1525             result = EAS_ERROR_NOT_IMPLEMENTED;
1526 
1527         /* clear pause flag */
1528         pStream->streamFlags &= ~STREAM_FLAGS_PAUSE;
1529 
1530         /* set resume flag */
1531         pStream->streamFlags |= STREAM_FLAGS_RESUME;
1532 
1533 #if 0
1534         /* resume the stream */
1535         if (pParserModule->pfResume)
1536             result = pParserModule->pfResume(pEASData, pStream->handle);
1537         else
1538             result = EAS_ERROR_NOT_IMPLEMENTED;
1539 #endif
1540     }
1541 
1542     return result;
1543 }
1544 #endif
1545 
1546 /*----------------------------------------------------------------------------
1547  * EAS_SetParameter()
1548  *----------------------------------------------------------------------------
1549  * Purpose:
1550  * Set the parameter of a module. See E_MODULES for a list of modules
1551  * and the header files of the modules for a list of parameters.
1552  *
1553  * Inputs:
1554  * psEASData        - pointer to overall EAS data structure
1555  * handle           - file or stream handle
1556  * module           - enumerated module number
1557  * param            - enumerated parameter number
1558  * value            - new parameter value
1559  *
1560  * Outputs:
1561  *
1562  *
1563  * Side Effects:
1564  *
1565  *
1566  *----------------------------------------------------------------------------
1567 */
EAS_SetParameter(EAS_DATA_HANDLE pEASData,EAS_I32 module,EAS_I32 param,EAS_I32 value)1568 EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value)
1569 {
1570 
1571     if (module >= NUM_EFFECTS_MODULES)
1572         return EAS_ERROR_INVALID_MODULE;
1573 
1574     if (pEASData->effectsModules[module].effectData == NULL)
1575         return EAS_ERROR_INVALID_MODULE;
1576 
1577     return (*pEASData->effectsModules[module].effect->pFSetParam)
1578         (pEASData->effectsModules[module].effectData, param, value);
1579 }
1580 
1581 #ifdef _METRICS_ENABLED
1582 /*----------------------------------------------------------------------------
1583  * EAS_MetricsReport()
1584  *----------------------------------------------------------------------------
1585  * Purpose:
1586  * Displays the current metrics through the metrics interface.
1587  *
1588  * Inputs:
1589  * p                - instance data handle
1590  *
1591  * Outputs:
1592  *
1593  *
1594  * Side Effects:
1595  *
1596  *----------------------------------------------------------------------------
1597 */
EAS_MetricsReport(EAS_DATA_HANDLE pEASData)1598 EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData)
1599 {
1600     if (!pEASData->pMetricsModule)
1601         return EAS_ERROR_INVALID_MODULE;
1602 
1603     return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData);
1604 }
1605 
1606 /*----------------------------------------------------------------------------
1607  * EAS_MetricsReset()
1608  *----------------------------------------------------------------------------
1609  * Purpose:
1610  * Resets the metrics.
1611  *
1612  * Inputs:
1613  * p                - instance data handle
1614  *
1615  * Outputs:
1616  *
1617  *
1618  * Side Effects:
1619  *
1620  *----------------------------------------------------------------------------
1621 */
EAS_MetricsReset(EAS_DATA_HANDLE pEASData)1622 EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData)
1623 {
1624 
1625     if (!pEASData->pMetricsModule)
1626         return EAS_ERROR_INVALID_MODULE;
1627 
1628     return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData);
1629 }
1630 #endif
1631 
1632 #ifdef FILE_HEADER_SEARCH
1633 /*----------------------------------------------------------------------------
1634  * EAS_SearchFile
1635  *----------------------------------------------------------------------------
1636  * Search file for specific sequence starting at current file
1637  * position. Returns offset to start of sequence.
1638  *
1639  * Inputs:
1640  * pEASData         - pointer to EAS persistent data object
1641  * fileHandle       - file handle
1642  * searchString     - pointer to search sequence
1643  * len              - length of search sequence
1644  * pOffset          - pointer to variable to store offset to sequence
1645  *
1646  * Returns EAS_EOF if end-of-file is reached
1647  *----------------------------------------------------------------------------
1648 */
EAS_SearchFile(S_EAS_DATA * pEASData,EAS_FILE_HANDLE fileHandle,const EAS_U8 * searchString,EAS_I32 len,EAS_I32 * pOffset)1649 EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset)
1650 {
1651     EAS_RESULT result;
1652     EAS_INT index;
1653     EAS_U8 c;
1654 
1655     *pOffset = -1;
1656     index = 0;
1657     for (;;)
1658     {
1659         result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c);
1660         if (result != EAS_SUCCESS)
1661             return result;
1662         if (c == searchString[index])
1663         {
1664             index++;
1665             if (index == 4)
1666             {
1667                 result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset);
1668                 if (result != EAS_SUCCESS)
1669                     return result;
1670                 *pOffset -= len;
1671                 break;
1672             }
1673         }
1674         else
1675             index = 0;
1676     }
1677     return EAS_SUCCESS;
1678 }
1679 #endif
1680 
1681 
1682