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