eas_public.c revision a8c89077d78769bf4840fa91609edc51fe2fa02d
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#include "eas_synthcfg.h"
31#include "eas.h"
32#include "eas_config.h"
33#include "eas_host.h"
34#include "eas_report.h"
35#include "eas_data.h"
36#include "eas_parser.h"
37#include "eas_pcm.h"
38#include "eas_midi.h"
39#include "eas_mixer.h"
40#include "eas_build.h"
41#include "eas_vm_protos.h"
42#include "eas_math.h"
43
44#ifdef JET_INTERFACE
45#include "jet_data.h"
46#endif
47
48#ifdef DLS_SYNTHESIZER
49#include "eas_mdls.h"
50#endif
51
52/* number of events to parse before calling EAS_HWYield function */
53#define YIELD_EVENT_COUNT       10
54
55/*----------------------------------------------------------------------------
56 * easLibConfig
57 *
58 * This structure is available through the EAS public interface to allow
59 * the user to check the configuration of the library.
60 *----------------------------------------------------------------------------
61*/
62static const S_EAS_LIB_CONFIG easLibConfig =
63{
64    LIB_VERSION,
65#ifdef _CHECKED_BUILD
66    EAS_TRUE,
67#else
68    EAS_FALSE,
69#endif
70    MAX_SYNTH_VOICES,
71    NUM_OUTPUT_CHANNELS,
72    _OUTPUT_SAMPLE_RATE,
73    BUFFER_SIZE_IN_MONO_SAMPLES,
74#ifdef _FILTER_ENABLED
75    EAS_TRUE,
76#else
77    EAS_FALSE,
78#endif
79    _BUILD_TIME_,
80    _BUILD_VERSION_
81};
82
83/* local prototypes */
84static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode);
85
86/*----------------------------------------------------------------------------
87 * EAS_SetStreamParameter
88 *----------------------------------------------------------------------------
89 * Sets the specified parameter in the stream. Allows access to
90 * customizable settings within the individual file parsers.
91 *----------------------------------------------------------------------------
92 * pEASData         - pointer to EAS persistent data object
93 * pStream          - stream handle
94 * param            - enumerated parameter (see eas_parser.h)
95 * value            - new value
96 *----------------------------------------------------------------------------
97*/
98EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value)
99{
100    S_FILE_PARSER_INTERFACE *pParserModule;
101
102    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
103    if (pParserModule->pfSetData)
104        return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value);
105    return EAS_ERROR_FEATURE_NOT_AVAILABLE;
106}
107
108/*----------------------------------------------------------------------------
109 * EAS_GetStreamParameter
110 *----------------------------------------------------------------------------
111 * Sets the specified parameter in the stream. Allows access to
112 * customizable settings within the individual file parsers.
113 *----------------------------------------------------------------------------
114 * pEASData         - pointer to EAS persistent data object
115 * pStream          - stream handle
116 * param            - enumerated parameter (see eas_parser.h)
117 * pValue           - pointer to variable to receive current setting
118 *----------------------------------------------------------------------------
119*/
120EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue)
121{
122    S_FILE_PARSER_INTERFACE *pParserModule;
123
124    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
125    if (pParserModule->pfGetData)
126        return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue);
127    return EAS_ERROR_FEATURE_NOT_AVAILABLE;
128}
129
130/*----------------------------------------------------------------------------
131 * EAS_StreamReady()
132 *----------------------------------------------------------------------------
133 * This routine sets common parameters like transpose, volume, etc.
134 * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
135 * fails, it attempts to get the synth handle from the parser and
136 * set the parameter directly on the synth. This eliminates duplicate
137 * code in the parser.
138 *----------------------------------------------------------------------------
139*/
140EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream)
141{
142    S_FILE_PARSER_INTERFACE *pParserModule;
143    EAS_STATE state;
144
145    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
146    if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS)
147        return EAS_FALSE;
148    return (state < EAS_STATE_OPEN);
149}
150
151/*----------------------------------------------------------------------------
152 * EAS_IntSetStrmParam()
153 *----------------------------------------------------------------------------
154 * This routine sets common parameters like transpose, volume, etc.
155 * First, it attempts to use the parser EAS_SetStreamParameter interface. If that
156 * fails, it attempts to get the synth handle from the parser and
157 * set the parameter directly on the synth. This eliminates duplicate
158 * code in the parser.
159 *----------------------------------------------------------------------------
160*/
161EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value)
162{
163    S_SYNTH *pSynth;
164
165    /* try to set the parameter using stream interface */
166    if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS)
167        return EAS_SUCCESS;
168
169    /* get a pointer to the synth object and set it directly */
170    /*lint -e{740} we are cheating by passing a pointer through this interface */
171    if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
172        return EAS_ERROR_INVALID_PARAMETER;
173
174    if (pSynth == NULL)
175        return EAS_ERROR_INVALID_PARAMETER;
176
177    switch (param)
178    {
179
180#ifdef DLS_SYNTHESIZER
181        case PARSER_DATA_DLS_COLLECTION:
182            {
183                EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value);
184                if (result == EAS_SUCCESS)
185                {
186                    DLSAddRef((S_DLS*) value);
187                    VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth);
188                }
189                return result;
190            }
191#endif
192
193        case PARSER_DATA_EAS_LIBRARY:
194            return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value);
195
196        case PARSER_DATA_POLYPHONY:
197            return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value);
198
199        case PARSER_DATA_PRIORITY:
200            return VMSetPriority(pEASData->pVoiceMgr, pSynth, value);
201
202        case PARSER_DATA_TRANSPOSITION:
203            VMSetTranposition(pSynth, value);
204            break;
205
206        case PARSER_DATA_VOLUME:
207            VMSetVolume(pSynth, (EAS_U16) value);
208            break;
209
210        default:
211            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ }
212            return EAS_ERROR_INVALID_PARAMETER;
213    }
214
215    return EAS_SUCCESS;
216}
217
218/*----------------------------------------------------------------------------
219 * EAS_IntGetStrmParam()
220 *----------------------------------------------------------------------------
221 * This routine gets common parameters like transpose, volume, etc.
222 * First, it attempts to use the parser EAS_GetStreamParameter interface. If that
223 * fails, it attempts to get the synth handle from the parser and
224 * get the parameter directly on the synth.
225 *----------------------------------------------------------------------------
226*/
227EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue)
228{
229    S_SYNTH *pSynth;
230
231    /* try to set the parameter */
232    if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS)
233        return EAS_SUCCESS;
234
235    /* get a pointer to the synth object and retrieve data directly */
236    /*lint -e{740} we are cheating by passing a pointer through this interface */
237    if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
238        return EAS_ERROR_INVALID_PARAMETER;
239
240    if (pSynth == NULL)
241        return EAS_ERROR_INVALID_PARAMETER;
242
243    switch (param)
244    {
245        case PARSER_DATA_POLYPHONY:
246            return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue);
247
248        case PARSER_DATA_PRIORITY:
249            return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue);
250
251        case PARSER_DATA_TRANSPOSITION:
252            VMGetTranposition(pSynth, pValue);
253            break;
254
255        case PARSER_DATA_NOTE_COUNT:
256            *pValue = VMGetNoteCount(pSynth);
257            break;
258
259        default:
260            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ }
261            return EAS_ERROR_INVALID_PARAMETER;
262    }
263
264    return EAS_SUCCESS;
265}
266
267/*----------------------------------------------------------------------------
268 * EAS_AllocateStream()
269 *----------------------------------------------------------------------------
270 * Purpose:
271 * Allocates a stream handle
272 *
273 * Inputs:
274 *
275 * Outputs:
276 *
277 *----------------------------------------------------------------------------
278*/
279static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData)
280{
281    EAS_INT streamNum;
282
283    /* check for static allocation, only one stream allowed */
284    if (pEASData->staticMemoryModel)
285    {
286        if (pEASData->streams[0].handle != NULL)
287        {
288            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ }
289            return -1;
290        }
291        return 0;
292    }
293
294    /* dynamic model */
295    for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
296        if (pEASData->streams[streamNum].handle == NULL)
297            break;
298    if (streamNum == MAX_NUMBER_STREAMS)
299    {
300        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ }
301        return -1;
302    }
303    return streamNum;
304}
305
306/*----------------------------------------------------------------------------
307 * EAS_InitStream()
308 *----------------------------------------------------------------------------
309 * Purpose:
310 * Initialize a stream
311 *
312 * Inputs:
313 *
314 * Outputs:
315 *
316 *----------------------------------------------------------------------------
317*/
318static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle)
319{
320    pStream->pParserModule = pParserModule;
321    pStream->handle = streamHandle;
322    pStream->time = 0;
323    pStream->frameLength = AUDIO_FRAME_LENGTH;
324    pStream->repeatCount = 0;
325    pStream->volume = DEFAULT_STREAM_VOLUME;
326    pStream->streamFlags = 0;
327}
328
329/*----------------------------------------------------------------------------
330 * EAS_Config()
331 *----------------------------------------------------------------------------
332 * Purpose:
333 * Returns a pointer to a structure containing the configuration options
334 * in this library build.
335 *
336 * Inputs:
337 *
338 * Outputs:
339 *
340 *----------------------------------------------------------------------------
341*/
342EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void)
343{
344    return &easLibConfig;
345}
346
347/*----------------------------------------------------------------------------
348 * EAS_Init()
349 *----------------------------------------------------------------------------
350 * Purpose:
351 * Initialize the synthesizer library
352 *
353 * Inputs:
354 *  ppEASData       - pointer to data handle variable for this instance
355 *
356 * Outputs:
357 *
358 *----------------------------------------------------------------------------
359*/
360EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData)
361{
362    EAS_HW_DATA_HANDLE pHWInstData;
363    EAS_RESULT result;
364    S_EAS_DATA *pEASData;
365    EAS_INT module;
366    EAS_BOOL staticMemoryModel;
367
368    /* get the memory model */
369    staticMemoryModel = EAS_CMStaticMemoryModel();
370
371    /* initialize the host wrapper interface */
372    *ppEASData = NULL;
373    if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS)
374        return result;
375
376    /* check Configuration Module for S_EAS_DATA allocation */
377    if (staticMemoryModel)
378        pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA);
379    else
380        pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA));
381    if (!pEASData)
382    {
383        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ }
384        return EAS_ERROR_MALLOC_FAILED;
385    }
386
387    /* initialize some data */
388    EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA));
389    pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel;
390    pEASData->hwInstData = pHWInstData;
391    pEASData->renderTime = 0;
392
393    /* set header search flag */
394#ifdef FILE_HEADER_SEARCH
395    pEASData->searchHeaderFlag = EAS_TRUE;
396#endif
397
398    /* initalize parameters */
399    EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME);
400
401#ifdef _METRICS_ENABLED
402    /* initalize the metrics module */
403    pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS);
404    if (pEASData->pMetricsModule != NULL)
405    {
406        if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS)
407        {
408            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ }
409            return result;
410        }
411    }
412#endif
413
414    /* initailize the voice manager & synthesizer */
415    if ((result = VMInitialize(pEASData)) != EAS_SUCCESS)
416        return result;
417
418    /* initialize mix engine */
419    if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS)
420    {
421        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ }
422        return result;
423    }
424
425    /* initialize effects modules */
426    for (module = 0; module < NUM_EFFECTS_MODULES; module++)
427    {
428        pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module);
429        if (pEASData->effectsModules[module].effect != NULL)
430        {
431            if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS)
432            {
433                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ }
434                return result;
435            }
436        }
437    }
438
439    /* initialize PCM engine */
440    if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS)
441    {
442        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ }
443        return result;
444    }
445
446    /* return instance data pointer to host */
447    *ppEASData = pEASData;
448
449    return EAS_SUCCESS;
450}
451
452/*----------------------------------------------------------------------------
453 * EAS_Shutdown()
454 *----------------------------------------------------------------------------
455 * Purpose:
456 * Shuts down the library. Deallocates any memory associated with the
457 * synthesizer (dynamic memory model only)
458 *
459 * Inputs:
460 *  pEASData        - handle to data for this instance
461 *
462 * Outputs:
463 *
464 *----------------------------------------------------------------------------
465*/
466EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData)
467{
468    EAS_HW_DATA_HANDLE hwInstData;
469    EAS_RESULT result, reportResult;
470    EAS_INT i;
471
472    /* establish pointers */
473    hwInstData = pEASData->hwInstData;
474
475    /* check for NULL handle */
476    if (!pEASData)
477        return EAS_ERROR_HANDLE_INTEGRITY;
478
479    /* if there are streams open, close them */
480    reportResult = EAS_SUCCESS;
481    for (i = 0; i < MAX_NUMBER_STREAMS; i++)
482    {
483        if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle)
484        {
485            if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS)
486            {
487                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ }
488                reportResult = result;
489            }
490        }
491    }
492
493    /* shutdown PCM engine */
494    if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS)
495    {
496        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ }
497        if (reportResult == EAS_SUCCESS)
498            reportResult = result;
499    }
500
501    /* shutdown mix engine */
502    if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS)
503    {
504        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ }
505        if (reportResult == EAS_SUCCESS)
506            reportResult = result;
507    }
508
509    /* shutdown effects modules */
510    for (i = 0; i < NUM_EFFECTS_MODULES; i++)
511    {
512        if (pEASData->effectsModules[i].effect)
513        {
514            if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS)
515            {
516                { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ }
517                if (reportResult == EAS_SUCCESS)
518                    reportResult = result;
519            }
520        }
521    }
522
523    /* shutdown the voice manager & synthesizer */
524    VMShutdown(pEASData);
525
526#ifdef _METRICS_ENABLED
527    /* shutdown the metrics module */
528    if (pEASData->pMetricsModule != NULL)
529    {
530        if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS)
531        {
532            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ }
533            if (reportResult == EAS_SUCCESS)
534                reportResult = result;
535        }
536    }
537#endif
538
539    /* release allocated memory */
540    if (!pEASData->staticMemoryModel)
541        EAS_HWFree(hwInstData, pEASData);
542
543    /* shutdown host wrappers */
544    if (hwInstData)
545    {
546        if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS)
547        {
548            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ }
549            if (reportResult == EAS_SUCCESS)
550                reportResult = result;
551        }
552    }
553
554    return reportResult;
555}
556
557#ifdef JET_INTERFACE
558/*----------------------------------------------------------------------------
559 * EAS_OpenJETStream()
560 *----------------------------------------------------------------------------
561 * Private interface for JET to open an SMF stream with an offset
562 *----------------------------------------------------------------------------
563*/
564EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream)
565{
566    EAS_RESULT result;
567    EAS_VOID_PTR streamHandle;
568    S_FILE_PARSER_INTERFACE *pParserModule;
569    EAS_INT streamNum;
570
571    /* allocate a stream */
572    if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
573        return EAS_ERROR_MAX_STREAMS_OPEN;
574
575    /* check Configuration Module for SMF parser */
576    *ppStream = NULL;
577    streamHandle = NULL;
578    pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0);
579    if (pParserModule == NULL)
580        return EAS_ERROR_UNRECOGNIZED_FORMAT;
581
582    /* see if SMF parser recognizes the file */
583    if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS)
584    {
585        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
586        return result;
587    }
588
589    /* parser recognized the file, return the handle */
590    if (streamHandle)
591    {
592        EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
593        *ppStream = &pEASData->streams[streamNum];
594        return EAS_SUCCESS;
595    }
596
597    return EAS_ERROR_UNRECOGNIZED_FORMAT;
598}
599#endif
600
601/*----------------------------------------------------------------------------
602 * EAS_OpenFile()
603 *----------------------------------------------------------------------------
604 * Purpose:
605 * Opens a file for audio playback.
606 *
607 * Inputs:
608 * pEASData         - pointer to overall EAS data structure
609 * pHandle          - pointer to file handle
610 *
611 * Outputs:
612 *
613 *
614 * Side Effects:
615 *
616 *----------------------------------------------------------------------------
617*/
618EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream)
619{
620    EAS_RESULT result;
621    EAS_FILE_HANDLE fileHandle;
622    EAS_VOID_PTR streamHandle;
623    S_FILE_PARSER_INTERFACE *pParserModule;
624    EAS_INT streamNum;
625    EAS_INT moduleNum;
626
627    /* open the file */
628    if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
629        return result;
630
631    /* allocate a stream */
632    if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
633        return EAS_ERROR_MAX_STREAMS_OPEN;
634
635    /* check Configuration Module for file parsers */
636    pParserModule = NULL;
637    *ppStream = NULL;
638    streamHandle = NULL;
639    for (moduleNum = 0; ; moduleNum++)
640    {
641        pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum);
642        if (pParserModule == NULL)
643            break;
644
645        /* see if this parser recognizes it */
646        if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS)
647        {
648            { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
649            return result;
650        }
651
652        /* parser recognized the file, return the handle */
653        if (streamHandle)
654        {
655
656            /* save the parser pointer and file handle */
657            EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
658            *ppStream = &pEASData->streams[streamNum];
659            return EAS_SUCCESS;
660        }
661
662        /* rewind the file for the next parser */
663        if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS)
664            return result;
665    }
666
667    /* no parser was able to recognize the file, close it and return an error */
668    EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
669    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ }
670    return EAS_ERROR_UNRECOGNIZED_FORMAT;
671}
672
673#ifdef MMAPI_SUPPORT
674/*----------------------------------------------------------------------------
675 * EAS_MMAPIToneControl()
676 *----------------------------------------------------------------------------
677 * Purpose:
678 * Opens a ToneControl file for audio playback.
679 *
680 * Inputs:
681 * pEASData         - pointer to overall EAS data structure
682 * pHandle          - pointer to file handle
683 *
684 * Outputs:
685 *
686 *
687 * Side Effects:
688 *
689 *----------------------------------------------------------------------------
690*/
691EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream)
692{
693    EAS_RESULT result;
694    EAS_FILE_HANDLE fileHandle;
695    EAS_VOID_PTR streamHandle;
696    S_FILE_PARSER_INTERFACE *pParserModule;
697    EAS_INT streamNum;
698
699    /* check if the tone control parser is available */
700    *ppStream = NULL;
701    streamHandle = NULL;
702    pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL);
703    if (pParserModule == NULL)
704    {
705        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ }
706        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
707    }
708
709    /* open the file */
710    if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
711        return result;
712
713    /* allocate a stream */
714    if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
715        return EAS_ERROR_MAX_STREAMS_OPEN;
716
717    /* see if ToneControl parser recognizes it */
718    if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS)
719    {
720        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ }
721        return result;
722    }
723
724    /* parser accepted the file, return the handle */
725    if (streamHandle)
726    {
727
728        /* save the parser pointer and file handle */
729        EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle);
730        *ppStream = &pEASData->streams[streamNum];
731        return EAS_SUCCESS;
732    }
733
734    /* parser did not recognize the file, close it and return an error */
735    EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
736    { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ }
737    return EAS_ERROR_UNRECOGNIZED_FORMAT;
738}
739
740/*----------------------------------------------------------------------------
741 * EAS_GetWaveFmtChunk
742 *----------------------------------------------------------------------------
743 * Helper function to retrieve WAVE file fmt chunk for MMAPI
744 *----------------------------------------------------------------------------
745 * pEASData         - pointer to EAS persistent data object
746 * pStream          - stream handle
747 * pFmtChunk        - pointer to variable to receive current setting
748 *----------------------------------------------------------------------------
749*/
750EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk)
751{
752    EAS_RESULT result;
753    EAS_I32 value;
754
755    if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS)
756        return result;
757    *ppFmtChunk = (EAS_VOID_PTR) value;
758    return EAS_SUCCESS;
759}
760#endif
761
762/*----------------------------------------------------------------------------
763 * EAS_GetFileType
764 *----------------------------------------------------------------------------
765 * Returns the file type (see eas_types.h for enumerations)
766 *----------------------------------------------------------------------------
767 * pEASData         - pointer to EAS persistent data object
768 * pStream          - stream handle
769 * pFileType        - pointer to variable to receive file type
770 *----------------------------------------------------------------------------
771*/
772EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType)
773{
774    if (!EAS_StreamReady (pEASData, pStream))
775        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
776    return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType);
777}
778
779/*----------------------------------------------------------------------------
780 * EAS_Prepare()
781 *----------------------------------------------------------------------------
782 * Purpose:
783 * Prepares the synthesizer to play the file or stream. Parses the first
784 * frame of data from the file and arms the synthesizer.
785 *
786 * Inputs:
787 * pEASData         - pointer to overall EAS data structure
788 * handle           - file or stream handle
789 *
790 * Outputs:
791 *
792 *
793 * Side Effects:
794 *
795 *----------------------------------------------------------------------------
796*/
797EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
798{
799    S_FILE_PARSER_INTERFACE *pParserModule;
800    EAS_STATE state;
801    EAS_RESULT result;
802
803    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
804    if (pParserModule == NULL)
805        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
806
807    /* check for valid state */
808    result = pParserModule->pfState(pEASData, pStream->handle, &state);
809    if (result == EAS_SUCCESS)
810    {
811        /* prepare the stream */
812        if (state == EAS_STATE_OPEN)
813        {
814            pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
815            result = (*pParserModule->pfPrepare)(pEASData, pStream->handle);
816
817            /* set volume */
818            if (result == EAS_SUCCESS)
819                result = EAS_SetVolume(pEASData, pStream, pStream->volume);
820        }
821        else
822            result = EAS_ERROR_NOT_VALID_IN_THIS_STATE;
823
824    }
825
826    return result;
827}
828
829/*----------------------------------------------------------------------------
830 * EAS_Render()
831 *----------------------------------------------------------------------------
832 * Purpose:
833 * Parse the Midi data and render PCM audio data.
834 *
835 * Inputs:
836 *  pEASData        - buffer for internal EAS data
837 *  pOut            - output buffer pointer
838 *  nNumRequested   - requested num samples to generate
839 *  pnNumGenerated  - actual number of samples generated
840 *
841 * Outputs:
842 *  EAS_SUCCESS if PCM data was successfully rendered
843 *
844 *----------------------------------------------------------------------------
845*/
846EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated)
847{
848    S_FILE_PARSER_INTERFACE *pParserModule;
849    EAS_RESULT result;
850    EAS_I32 voicesRendered;
851    EAS_STATE parserState;
852    EAS_INT streamNum;
853
854    /* assume no samples generated and reset workload */
855    *pNumGenerated = 0;
856    VMInitWorkload(pEASData->pVoiceMgr);
857
858    /* no support for other buffer sizes yet */
859    if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES)
860    {
861        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n",
862            (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ }
863        return EAS_BUFFER_SIZE_MISMATCH;
864    }
865
866#ifdef _METRICS_ENABLED
867    /* start performance counter */
868    if (pEASData->pMetricsData)
869        (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
870#endif
871
872    /* prep the frame buffer, do mix engine prep only if TRUE */
873#ifdef _SPLIT_ARCHITECTURE
874    if (VMStartFrame(pEASData))
875        EAS_MixEnginePrep(pEASData, numRequested);
876#else
877    /* prep the mix engine */
878    EAS_MixEnginePrep(pEASData, numRequested);
879#endif
880
881    /* save the output buffer pointer */
882    pEASData->pOutputAudioBuffer = pOut;
883
884
885#ifdef _METRICS_ENABLED
886        /* start performance counter */
887        if (pEASData->pMetricsData)
888            (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
889#endif
890
891    /* if we haven't finished parsing from last time, do it now */
892    /* need to parse another frame of events before we render again */
893    for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
894    {
895        /* clear the locate flag */
896        pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE;
897
898        if (pEASData->streams[streamNum].pParserModule)
899        {
900
901            /* establish pointer to parser module */
902            pParserModule = pEASData->streams[streamNum].pParserModule;
903
904            /* handle pause */
905            if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE)
906            {
907                if (pParserModule->pfPause)
908                    result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle);
909                pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE;
910            }
911
912            /* get current state */
913            if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
914                return result;
915
916            /* handle resume */
917            if (parserState == EAS_STATE_PAUSED)
918            {
919                if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME)
920                {
921                    if (pParserModule->pfResume)
922                        result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle);
923                    pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME;
924                }
925            }
926
927            /* if necessary, parse stream */
928            if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0)
929                if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS)
930                    return result;
931
932            /* check for an early abort */
933            if ((pEASData->streams[streamNum].streamFlags) == 0)
934            {
935
936#ifdef _METRICS_ENABLED
937                /* stop performance counter */
938                if (pEASData->pMetricsData)
939                    (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
940#endif
941
942                return EAS_SUCCESS;
943            }
944
945            /* check for repeat */
946            if (pEASData->streams[streamNum].repeatCount)
947            {
948
949                /* check for stopped state */
950                if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS)
951                    return result;
952                if (parserState == EAS_STATE_STOPPED)
953                {
954
955                    /* decrement repeat count, unless it is negative */
956                    if (pEASData->streams[streamNum].repeatCount > 0)
957                        pEASData->streams[streamNum].repeatCount--;
958
959                    /* reset the parser */
960                    if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS)
961                        return result;
962                    pEASData->streams[streamNum].time = 0;
963                }
964            }
965        }
966    }
967
968#ifdef _METRICS_ENABLED
969    /* stop performance counter */
970    if (pEASData->pMetricsData)
971        (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME);
972#endif
973
974#ifdef _METRICS_ENABLED
975    /* start the render timer */
976    if (pEASData->pMetricsData)
977        (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
978#endif
979
980    /* render audio */
981    if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS)
982    {
983        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ }
984        return result;
985    }
986
987#ifdef _METRICS_ENABLED
988    /* stop the render timer */
989    if (pEASData->pMetricsData) {
990        (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1);
991        (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME);
992        (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered);
993        (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered);
994    }
995#endif
996
997    //2 Do we really need frameParsed?
998    /* need to parse another frame of events before we render again */
999    for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++)
1000        if (pEASData->streams[streamNum].pParserModule != NULL)
1001            pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED;
1002
1003#ifdef _METRICS_ENABLED
1004    /* start performance counter */
1005    if (pEASData->pMetricsData)
1006        (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
1007#endif
1008
1009    /* render PCM audio */
1010    if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS)
1011    {
1012        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ }
1013        return result;
1014    }
1015
1016#ifdef _METRICS_ENABLED
1017    /* stop the stream timer */
1018    if (pEASData->pMetricsData)
1019        (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME);
1020#endif
1021
1022#ifdef _METRICS_ENABLED
1023    /* start the post timer */
1024    if (pEASData->pMetricsData)
1025        (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
1026#endif
1027
1028    /* for split architecture, send DSP vectors.  Do post only if return is TRUE */
1029#ifdef _SPLIT_ARCHITECTURE
1030    if (VMEndFrame(pEASData))
1031    {
1032        /* now do post-processing */
1033        EAS_MixEnginePost(pEASData, numRequested);
1034        *pNumGenerated = numRequested;
1035    }
1036#else
1037    /* now do post-processing */
1038    EAS_MixEnginePost(pEASData, numRequested);
1039    *pNumGenerated = numRequested;
1040#endif
1041
1042#ifdef _METRICS_ENABLED
1043    /* stop the post timer */
1044    if (pEASData->pMetricsData)
1045        (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME);
1046#endif
1047
1048    /* advance render time */
1049    pEASData->renderTime += AUDIO_FRAME_LENGTH;
1050
1051#if 0
1052    /* dump workload for debug */
1053    if (pEASData->pVoiceMgr->workload)
1054        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ }
1055#endif
1056
1057#ifdef _METRICS_ENABLED
1058    /* stop performance counter */
1059    if (pEASData->pMetricsData)
1060    {
1061        PERF_TIMER temp;
1062        temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME);
1063
1064        /* if max render time, record the number of voices and time */
1065        if ((*pEASData->pMetricsModule->pfRecordMaxValue)
1066            (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp))
1067        {
1068            (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered);
1069            (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8));
1070        }
1071    }
1072#endif
1073
1074#ifdef JET_INTERFACE
1075    /* let JET to do its thing */
1076    if (pEASData->jetHandle != NULL)
1077    {
1078        result = JET_Process(pEASData);
1079        if (result != EAS_SUCCESS)
1080            return result;
1081    }
1082#endif
1083
1084    return EAS_SUCCESS;
1085}
1086
1087/*----------------------------------------------------------------------------
1088 * EAS_SetRepeat()
1089 *----------------------------------------------------------------------------
1090 * Purpose:
1091 * Set the selected stream to repeat.
1092 *
1093 * Inputs:
1094 *  pEASData        - handle to data for this instance
1095 *  handle          - handle to stream
1096 *  repeatCount     - repeat count
1097 *
1098 * Outputs:
1099 *
1100 * Side Effects:
1101 *
1102 * Notes:
1103 *  0 = no repeat
1104 *  1 = repeat once, i.e. play through twice
1105 *  -1 = repeat forever
1106 *----------------------------------------------------------------------------
1107*/
1108/*lint -esym(715, pEASData) reserved for future use */
1109EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount)
1110{
1111    pStream->repeatCount = repeatCount;
1112    return EAS_SUCCESS;
1113}
1114
1115/*----------------------------------------------------------------------------
1116 * EAS_GetRepeat()
1117 *----------------------------------------------------------------------------
1118 * Purpose:
1119 * Gets the current repeat count for the selected stream.
1120 *
1121 * Inputs:
1122 *  pEASData        - handle to data for this instance
1123 *  handle          - handle to stream
1124 *  pRrepeatCount   - pointer to variable to hold repeat count
1125 *
1126 * Outputs:
1127 *
1128 * Side Effects:
1129 *
1130 * Notes:
1131 *  0 = no repeat
1132 *  1 = repeat once, i.e. play through twice
1133 *  -1 = repeat forever
1134 *----------------------------------------------------------------------------
1135*/
1136/*lint -esym(715, pEASData) reserved for future use */
1137EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount)
1138{
1139    *pRepeatCount = pStream->repeatCount;
1140    return EAS_SUCCESS;
1141}
1142
1143/*----------------------------------------------------------------------------
1144 * EAS_SetPlaybackRate()
1145 *----------------------------------------------------------------------------
1146 * Purpose:
1147 * Sets the playback rate.
1148 *
1149 * Inputs:
1150 *  pEASData        - handle to data for this instance
1151 *  handle          - handle to stream
1152 *  rate            - rate (28-bit fractional amount)
1153 *
1154 * Outputs:
1155 *
1156 * Side Effects:
1157 *
1158 *----------------------------------------------------------------------------
1159*/
1160/*lint -esym(715, pEASData) reserved for future use */
1161EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate)
1162{
1163
1164    /* check range */
1165    if ((rate < (1 << 27)) || (rate > (1 << 29)))
1166        return EAS_ERROR_INVALID_PARAMETER;
1167
1168    /* calculate new frame length
1169     *
1170     * NOTE: The maximum frame length we can accomodate based on a
1171     * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a
1172     * longer frame length or a higher maximum rate, the fixed point
1173     * divide below will need to be adjusted
1174     */
1175    pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20;
1176
1177    /* notify stream of new playback rate */
1178    EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate);
1179    return EAS_SUCCESS;
1180}
1181
1182/*----------------------------------------------------------------------------
1183 * EAS_SetTransposition)
1184 *----------------------------------------------------------------------------
1185 * Purpose:
1186 * Sets the key tranposition for the synthesizer. Transposes all
1187 * melodic instruments by the specified amount. Range is limited
1188 * to +/-12 semitones.
1189 *
1190 * Inputs:
1191 *  pEASData        - handle to data for this instance
1192 *  handle          - handle to stream
1193 *  transposition   - +/-12 semitones
1194 *
1195 * Outputs:
1196 *
1197 * Side Effects:
1198 *
1199 *----------------------------------------------------------------------------
1200*/
1201EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition)
1202{
1203
1204    /* check range */
1205    if ((transposition < -12) || (transposition > 12))
1206        return EAS_ERROR_INVALID_PARAMETER;
1207
1208    if (!EAS_StreamReady(pEASData, pStream))
1209        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1210    return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition);
1211}
1212
1213/*----------------------------------------------------------------------------
1214 * EAS_ParseEvents()
1215 *----------------------------------------------------------------------------
1216 * Purpose:
1217 * Parse events in the current streams until the desired time is reached.
1218 *
1219 * Inputs:
1220 *  pEASData        - buffer for internal EAS data
1221 *  endTime         - stop parsing if this time is reached
1222 *  parseMode       - play, locate, or metadata
1223 *
1224 * Outputs:
1225 *  EAS_SUCCESS if PCM data was successfully rendered
1226 *
1227 *----------------------------------------------------------------------------
1228*/
1229static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode)
1230{
1231    S_FILE_PARSER_INTERFACE *pParserModule;
1232    EAS_RESULT result;
1233    EAS_I32 parserState;
1234    EAS_BOOL done;
1235    EAS_INT yieldCount = YIELD_EVENT_COUNT;
1236    EAS_U32 time = 0;
1237
1238    /* does this parser have a time function? */
1239    pParserModule = pStream->pParserModule;
1240    if (pParserModule->pfTime == NULL)
1241    {
1242        /* check state */
1243        if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
1244            return result;
1245        /* if play state, advance time */
1246        if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING))
1247            pStream->time += pStream->frameLength;
1248        done = EAS_TRUE;
1249    }
1250
1251    /* assume we're not done, in case we abort out */
1252    else
1253    {
1254        pStream->streamFlags &= ~STREAM_FLAGS_PARSED;
1255        done = EAS_FALSE;
1256    }
1257
1258    while (!done)
1259    {
1260
1261        /* check for stopped state */
1262        if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS)
1263            return result;
1264        if (parserState > EAS_STATE_PLAY)
1265        {
1266            /* save current time if we're not in play mode */
1267            if (parseMode != eParserModePlay)
1268                pStream->time = time << 8;
1269            done = EAS_TRUE;
1270            break;
1271        }
1272
1273        /* get the next event time */
1274        if (pParserModule->pfTime)
1275        {
1276            if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS)
1277                return result;
1278
1279            /* if next event is within this frame, parse it */
1280            if (time < (endTime >> 8))
1281            {
1282
1283                /* parse the next event */
1284                if (pParserModule->pfEvent)
1285                    if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS)
1286                        return result;
1287            }
1288
1289            /* no more events in this frame, advance time */
1290            else
1291            {
1292                pStream->time = endTime;
1293                done = EAS_TRUE;
1294            }
1295        }
1296
1297        /* check for max workload exceeded */
1298        if (VMCheckWorkload(pEASData->pVoiceMgr))
1299        {
1300            /* stop even though we may not have parsed
1301             * all the events in this frame. The parser will try to
1302             * catch up on the next frame.
1303             */
1304            break;
1305        }
1306
1307        /* give host a chance for an early abort */
1308        if (--yieldCount == 0)
1309        {
1310            if (EAS_HWYield(pEASData->hwInstData))
1311                break;
1312            yieldCount = YIELD_EVENT_COUNT;
1313        }
1314    }
1315
1316    /* if no early abort, parsing is complete for this frame */
1317    if (done)
1318        pStream->streamFlags |= STREAM_FLAGS_PARSED;
1319
1320    return EAS_SUCCESS;
1321}
1322
1323/*----------------------------------------------------------------------------
1324 * EAS_ParseMetaData()
1325 *----------------------------------------------------------------------------
1326 * Purpose:
1327 *
1328 *
1329 * Inputs:
1330 * pEASData         - pointer to overall EAS data structure
1331 * handle           - file or stream handle
1332 * playLength       - pointer to variable to store the play length (in msecs)
1333 *
1334 * Outputs:
1335 *
1336 *
1337 * Side Effects:
1338 *                  - resets the parser to the start of the file
1339 *----------------------------------------------------------------------------
1340*/
1341EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength)
1342{
1343    S_FILE_PARSER_INTERFACE *pParserModule;
1344    EAS_RESULT result;
1345    EAS_STATE state;
1346
1347    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1348    if (pParserModule == NULL)
1349        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1350
1351    /* check parser state */
1352    if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
1353        return result;
1354    if (state >= EAS_STATE_OPEN)
1355        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1356
1357    /* if parser has metadata function, use that */
1358    if (pParserModule->pfGetMetaData != NULL)
1359        return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength);
1360
1361    /* reset the parser to the beginning */
1362    if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
1363        return result;
1364
1365    /* parse the file to end */
1366    pStream->time = 0;
1367    VMInitWorkload(pEASData->pVoiceMgr);
1368    if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS)
1369        return result;
1370
1371    /* get the parser time */
1372    if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS)
1373        return result;
1374
1375    /* reset the parser to the beginning */
1376    pStream->time = 0;
1377    return (*pParserModule->pfReset)(pEASData, pStream->handle);
1378}
1379
1380/*----------------------------------------------------------------------------
1381 * EAS_RegisterMetaDataCallback()
1382 *----------------------------------------------------------------------------
1383 * Purpose:
1384 * Registers a metadata callback function for parsed metadata.
1385 *
1386 * Inputs:
1387 * pEASData         - pointer to overall EAS data structure
1388 * handle           - file or stream handle
1389 * cbFunc           - pointer to host callback function
1390 * metaDataBuffer   - pointer to metadata buffer
1391 * metaDataBufSize  - maximum size of the metadata buffer
1392 *
1393 * Outputs:
1394 *
1395 *
1396 * Side Effects:
1397 *
1398 *----------------------------------------------------------------------------
1399*/
1400EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback (
1401    EAS_DATA_HANDLE pEASData,
1402    EAS_HANDLE pStream,
1403    EAS_METADATA_CBFUNC cbFunc,
1404    char *metaDataBuffer,
1405    EAS_I32 metaDataBufSize,
1406    EAS_VOID_PTR pUserData)
1407{
1408    S_METADATA_CB metadata;
1409
1410    if (!EAS_StreamReady(pEASData, pStream))
1411        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1412
1413    /* register callback function */
1414    metadata.callback = cbFunc;
1415    metadata.buffer = metaDataBuffer;
1416    metadata.bufferSize = metaDataBufSize;
1417    metadata.pUserData = pUserData;
1418    return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata);
1419}
1420
1421/*----------------------------------------------------------------------------
1422 * EAS_GetNoteCount ()
1423 *----------------------------------------------------------------------------
1424 * Returns the total number of notes played in this stream
1425 *----------------------------------------------------------------------------
1426*/
1427EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount)
1428{
1429    if (!EAS_StreamReady(pEASData, pStream))
1430        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1431    return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount);
1432}
1433
1434/*----------------------------------------------------------------------------
1435 * EAS_CloseFile()
1436 *----------------------------------------------------------------------------
1437 * Purpose:
1438 * Closes an audio file or stream. Playback should have either paused or
1439 * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED).
1440 *
1441 * Inputs:
1442 * pEASData         - pointer to overall EAS data structure
1443 * handle           - file or stream handle
1444 *
1445 * Outputs:
1446 *
1447 *
1448 * Side Effects:
1449 *
1450 *----------------------------------------------------------------------------
1451*/
1452EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1453{
1454    S_FILE_PARSER_INTERFACE *pParserModule;
1455    EAS_RESULT result;
1456
1457    /* call the close function */
1458    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1459    if (pParserModule == NULL)
1460        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1461
1462    result = (*pParserModule->pfClose)(pEASData, pStream->handle);
1463
1464    /* clear the handle and parser interface pointer */
1465    pStream->handle = NULL;
1466    pStream->pParserModule = NULL;
1467    return result;
1468}
1469
1470/*----------------------------------------------------------------------------
1471 * EAS_OpenMIDIStream()
1472 *----------------------------------------------------------------------------
1473 * Purpose:
1474 * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer
1475 *
1476 * Inputs:
1477 * pEASData         - pointer to overall EAS data structure
1478 * pHandle          - pointer to variable to hold file or stream handle
1479 *
1480 * Outputs:
1481 *
1482 *
1483 * Side Effects:
1484 *
1485 *----------------------------------------------------------------------------
1486*/
1487EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle)
1488{
1489    EAS_RESULT result;
1490    S_INTERACTIVE_MIDI *pMIDIStream;
1491    EAS_INT streamNum;
1492
1493    /* initialize some pointers */
1494    *ppStream = NULL;
1495
1496    /* allocate a stream */
1497    if ((streamNum = EAS_AllocateStream(pEASData)) < 0)
1498        return EAS_ERROR_MAX_STREAMS_OPEN;
1499
1500    /* check Configuration Module for S_EAS_DATA allocation */
1501    if (pEASData->staticMemoryModel)
1502        pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA);
1503    else
1504        pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI));
1505
1506    /* allocate dynamic memory */
1507    if (!pMIDIStream)
1508    {
1509        { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ }
1510        return EAS_ERROR_MALLOC_FAILED;
1511    }
1512
1513    /* zero the memory to insure complete initialization */
1514    EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI));
1515    EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream);
1516
1517    /* instantiate a new synthesizer */
1518    if (streamHandle == NULL)
1519    {
1520        result = VMInitMIDI(pEASData, &pMIDIStream->pSynth);
1521    }
1522
1523    /* use an existing synthesizer */
1524    else
1525    {
1526        EAS_I32 value;
1527        result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value);
1528        pMIDIStream->pSynth = (S_SYNTH*) value;
1529        VMIncRefCount(pMIDIStream->pSynth);
1530    }
1531    if (result != EAS_SUCCESS)
1532    {
1533        EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]);
1534        return result;
1535    }
1536
1537    /* initialize the MIDI stream data */
1538    EAS_InitMIDIStream(&pMIDIStream->stream);
1539
1540    *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum];
1541    return EAS_SUCCESS;
1542}
1543
1544/*----------------------------------------------------------------------------
1545 * EAS_WriteMIDIStream()
1546 *----------------------------------------------------------------------------
1547 * Purpose:
1548 * Send data to the MIDI stream device
1549 *
1550 * Inputs:
1551 * pEASData         - pointer to overall EAS data structure
1552 * handle           - stream handle
1553 * pBuffer          - pointer to buffer
1554 * count            - number of bytes to write
1555 *
1556 * Outputs:
1557 *
1558 *
1559 * Side Effects:
1560 *
1561 *----------------------------------------------------------------------------
1562*/
1563EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count)
1564{
1565    S_INTERACTIVE_MIDI *pMIDIStream;
1566    EAS_RESULT result;
1567
1568    pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle;
1569
1570    if (count <= 0)
1571        return EAS_ERROR_PARAMETER_RANGE;
1572
1573    /* send the entire buffer */
1574    while (count--)
1575    {
1576        if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS)
1577            return result;
1578    }
1579    return EAS_SUCCESS;
1580}
1581
1582/*----------------------------------------------------------------------------
1583 * EAS_CloseMIDIStream()
1584 *----------------------------------------------------------------------------
1585 * Purpose:
1586 * Closes a raw MIDI stream
1587 *
1588 * Inputs:
1589 * pEASData         - pointer to overall EAS data structure
1590 * handle           - stream handle
1591 *
1592 * Outputs:
1593 *
1594 *
1595 * Side Effects:
1596 *
1597 *----------------------------------------------------------------------------
1598*/
1599EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1600{
1601    S_INTERACTIVE_MIDI *pMIDIStream;
1602
1603    pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle;
1604
1605    /* close synth */
1606    if (pMIDIStream->pSynth != NULL)
1607    {
1608        VMMIDIShutdown(pEASData, pMIDIStream->pSynth);
1609        pMIDIStream->pSynth = NULL;
1610    }
1611
1612    /* release allocated memory */
1613    if (!pEASData->staticMemoryModel)
1614        EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream);
1615
1616    pStream->handle = NULL;
1617    return EAS_SUCCESS;
1618}
1619
1620/*----------------------------------------------------------------------------
1621 * EAS_State()
1622 *----------------------------------------------------------------------------
1623 * Purpose:
1624 * Returns the state of an audio file or stream.
1625 *
1626 * Inputs:
1627 * pEASData         - pointer to overall EAS data structure
1628 * handle           - file or stream handle
1629 *
1630 * Outputs:
1631 *
1632 *
1633 * Side Effects:
1634 *
1635 *----------------------------------------------------------------------------
1636*/
1637EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState)
1638{
1639    S_FILE_PARSER_INTERFACE *pParserModule;
1640    EAS_RESULT result;
1641
1642    /* call the parser to return state */
1643    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1644    if (pParserModule == NULL)
1645        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1646
1647    if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS)
1648        return result;
1649
1650    /* if repeat count is set for this parser, mask the stopped state from the application */
1651    if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED))
1652        *pState = EAS_STATE_PLAY;
1653
1654    /* if we're not ready or playing, we don't need to hide state from host */
1655    if (*pState > EAS_STATE_PLAY)
1656        return EAS_SUCCESS;
1657
1658    /* if stream is about to be paused, report it as paused */
1659    if (pStream->streamFlags & STREAM_FLAGS_PAUSE)
1660    {
1661        if (pStream->streamFlags & STREAM_FLAGS_LOCATE)
1662            *pState = EAS_STATE_PAUSED;
1663        else
1664            *pState = EAS_STATE_PAUSING;
1665    }
1666
1667    /* if stream is about to resume, report it as playing */
1668    if (pStream->streamFlags & STREAM_FLAGS_RESUME)
1669        *pState = EAS_STATE_PLAY;
1670
1671    return EAS_SUCCESS;
1672}
1673
1674/*----------------------------------------------------------------------------
1675 * EAS_SetPolyphony()
1676 *----------------------------------------------------------------------------
1677 * Purpose:
1678 * Set the polyphony of the stream. A value of 0 allows the stream
1679 * to use all voices (set by EAS_SetSynthPolyphony).
1680 *
1681 * Inputs:
1682 * pEASData         - pointer to overall EAS data structure
1683 * streamHandle     - handle returned by EAS_OpenFile
1684 * polyphonyCount   - the desired polyphony count
1685 *
1686 * Outputs:
1687 *
1688 * Side Effects:
1689 *
1690 *----------------------------------------------------------------------------
1691*/
1692EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount)
1693{
1694    if (!EAS_StreamReady(pEASData, pStream))
1695        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1696    return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount);
1697}
1698
1699/*----------------------------------------------------------------------------
1700 * EAS_GetPolyphony()
1701 *----------------------------------------------------------------------------
1702 * Purpose:
1703 * Returns the current polyphony setting of the stream
1704 *
1705 * Inputs:
1706 * pEASData         - pointer to overall EAS data structure
1707 * streamHandle     - handle returned by EAS_OpenFile
1708 * pPolyphonyCount  - pointer to variable to receive polyphony count
1709 *
1710 * Outputs:
1711 *
1712 * Side Effects:
1713 *
1714 *----------------------------------------------------------------------------
1715*/
1716EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount)
1717{
1718    if (!EAS_StreamReady(pEASData, pStream))
1719        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1720    return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount);
1721}
1722
1723/*----------------------------------------------------------------------------
1724 * EAS_SetSynthPolyphony()
1725 *----------------------------------------------------------------------------
1726 * Purpose:
1727 * Set the polyphony of the synth . Value must be >= 1 and <= the
1728 * maximum number of voices. This function will pin the polyphony
1729 * at those limits
1730 *
1731 * Inputs:
1732 * pEASData         - pointer to overall EAS data structure
1733 * synthNum         - synthesizer number (0 = onboard, 1 = DSP)
1734 * polyphonyCount   - the desired polyphony count
1735 *
1736 * Outputs:
1737 *
1738 * Side Effects:
1739 *
1740 *----------------------------------------------------------------------------
1741*/
1742EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount)
1743{
1744    return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount);
1745}
1746
1747/*----------------------------------------------------------------------------
1748 * EAS_GetSynthPolyphony()
1749 *----------------------------------------------------------------------------
1750 * Purpose:
1751 * Returns the current polyphony setting of the synth
1752 *
1753 * Inputs:
1754 * pEASData         - pointer to overall EAS data structure
1755 * synthNum         - synthesizer number (0 = onboard, 1 = DSP)
1756 * pPolyphonyCount  - pointer to variable to receive polyphony count
1757 *
1758 * Outputs:
1759 *
1760 * Side Effects:
1761 *
1762 *----------------------------------------------------------------------------
1763*/
1764EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount)
1765{
1766    return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount);
1767}
1768
1769/*----------------------------------------------------------------------------
1770 * EAS_SetPriority()
1771 *----------------------------------------------------------------------------
1772 * Purpose:
1773 * Set the priority of the stream. Determines which stream's voices
1774 * are stolen when there are insufficient voices for all notes.
1775 * Value must be in the range of 1-15, lower values are higher
1776 * priority.
1777 *
1778 * Inputs:
1779 * pEASData         - pointer to overall EAS data structure
1780 * streamHandle     - handle returned by EAS_OpenFile
1781 * polyphonyCount   - the desired polyphony count
1782 *
1783 * Outputs:
1784 *
1785 * Side Effects:
1786 *
1787 *----------------------------------------------------------------------------
1788*/
1789EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority)
1790{
1791    if (!EAS_StreamReady(pEASData, pStream))
1792        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1793    return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority);
1794}
1795
1796/*----------------------------------------------------------------------------
1797 * EAS_GetPriority()
1798 *----------------------------------------------------------------------------
1799 * Purpose:
1800 * Returns the current priority setting of the stream
1801 *
1802 * Inputs:
1803 * pEASData         - pointer to overall EAS data structure
1804 * streamHandle     - handle returned by EAS_OpenFile
1805 * pPriority        - pointer to variable to receive priority
1806 *
1807 * Outputs:
1808 *
1809 * Side Effects:
1810 *
1811 *----------------------------------------------------------------------------
1812*/
1813EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority)
1814{
1815    if (!EAS_StreamReady(pEASData, pStream))
1816        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1817    return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority);
1818}
1819
1820/*----------------------------------------------------------------------------
1821 * EAS_SetVolume()
1822 *----------------------------------------------------------------------------
1823 * Purpose:
1824 * Set the master gain for the mix engine in 1dB increments
1825 *
1826 * Inputs:
1827 * pEASData         - pointer to overall EAS data structure
1828 * volume           - the desired master gain (100 is max)
1829 * handle           - file or stream handle
1830 *
1831 * Outputs:
1832 *
1833 *
1834 * Side Effects:
1835 * overrides any previously set master volume from sysex
1836 *
1837 *----------------------------------------------------------------------------
1838*/
1839EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume)
1840{
1841    EAS_I16 gain;
1842
1843    /* check range */
1844    if ((volume < 0) || (volume > EAS_MAX_VOLUME))
1845        return EAS_ERROR_PARAMETER_RANGE;
1846
1847    /* stream volume */
1848    if (pStream != NULL)
1849    {
1850        EAS_I32 gainOffset;
1851        EAS_RESULT result;
1852
1853        if (!EAS_StreamReady(pEASData, pStream))
1854            return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1855
1856        /* get gain offset */
1857        pStream->volume = (EAS_U8) volume;
1858        result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset);
1859        if (result == EAS_SUCCESS)
1860            volume += gainOffset;
1861
1862        /* set stream volume */
1863        gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
1864
1865        /* convert to linear scalar */
1866        return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain);
1867    }
1868
1869    /* master volume */
1870    pEASData->masterVolume = (EAS_U8) volume;
1871#if (NUM_OUTPUT_CHANNELS == 1)
1872    /* leave 3dB headroom for mono output */
1873    volume -= 3;
1874#endif
1875
1876    gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM);
1877    pEASData->masterGain = gain;
1878    return EAS_SUCCESS;
1879}
1880
1881/*----------------------------------------------------------------------------
1882 * EAS_GetVolume()
1883 *----------------------------------------------------------------------------
1884 * Purpose:
1885 * Returns the master volume for the synthesizer. The default volume setting is
1886 * 50. The volume range is 0 to 100;
1887 *
1888 * Inputs:
1889 * pEASData         - pointer to overall EAS data structure
1890 * volume           - the desired master volume
1891 * handle           - file or stream handle
1892 *
1893 * Outputs:
1894 *
1895 *
1896 * Side Effects:
1897 * overrides any previously set master volume from sysex
1898 *
1899 *----------------------------------------------------------------------------
1900*/
1901EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
1902{
1903    if (pStream == NULL)
1904        return pEASData->masterVolume;
1905
1906    if (!EAS_StreamReady(pEASData, pStream))
1907        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1908    return pStream->volume;
1909}
1910
1911/*----------------------------------------------------------------------------
1912 * EAS_SetMaxLoad()
1913 *----------------------------------------------------------------------------
1914 * Purpose:
1915 * Sets the maximum workload the parsers will do in a single call to
1916 * EAS_Render. The units are currently arbitrary, but should correlate
1917 * well to the actual CPU cycles consumed. The primary effect is to
1918 * reduce the occasional peaks in CPU cycles consumed when parsing
1919 * dense parts of a MIDI score.
1920 *
1921 * Inputs:
1922 *  pEASData        - handle to data for this instance
1923 *  maxLoad         - the desired maximum workload
1924 *
1925 * Outputs:
1926 *
1927 * Side Effects:
1928 *
1929 *----------------------------------------------------------------------------
1930*/
1931EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad)
1932{
1933    VMSetWorkload(pEASData->pVoiceMgr, maxLoad);
1934    return EAS_SUCCESS;
1935}
1936
1937/*----------------------------------------------------------------------------
1938 * EAS_SetMaxPCMStreams()
1939 *----------------------------------------------------------------------------
1940 * Sets the maximum number of PCM streams allowed in parsers that
1941 * use PCM streaming.
1942 *
1943 * Inputs:
1944 * pEASData         - pointer to overall EAS data structure
1945 * streamHandle     - handle returned by EAS_OpenFile
1946 * maxNumStreams    - maximum number of PCM streams
1947 *----------------------------------------------------------------------------
1948*/
1949EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams)
1950{
1951    if (!EAS_StreamReady(pEASData, pStream))
1952        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1953    return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams);
1954}
1955
1956/*----------------------------------------------------------------------------
1957 * EAS_Locate()
1958 *----------------------------------------------------------------------------
1959 * Purpose:
1960 * Locate into the file associated with the handle.
1961 *
1962 * Inputs:
1963 * pEASData - pointer to overall EAS data structure
1964 * handle           - file handle
1965 * milliseconds     - playback offset from start of file in milliseconds
1966 *
1967 * Outputs:
1968 *
1969 *
1970 * Side Effects:
1971 * the actual offset will be quantized to the closest update period, typically
1972 * a resolution of 5.9ms. Notes that are started prior to this time will not
1973 * sound. Any notes currently playing will be shut off.
1974 *
1975 *----------------------------------------------------------------------------
1976*/
1977EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset)
1978{
1979    S_FILE_PARSER_INTERFACE *pParserModule;
1980    EAS_RESULT result;
1981    EAS_U32 requestedTime;
1982    EAS_STATE state;
1983
1984    /* get pointer to parser function table */
1985    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
1986    if (pParserModule == NULL)
1987        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
1988
1989    if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS)
1990        return result;
1991    if (state >= EAS_STATE_OPEN)
1992        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
1993
1994    /* handle offset and limit to start of file */
1995    /*lint -e{704} use shift for performance*/
1996    if (offset)
1997        milliseconds += (EAS_I32) pStream->time >> 8;
1998    if (milliseconds < 0)
1999        milliseconds = 0;
2000
2001    /* check to see if the request is different from the current time */
2002    requestedTime = (EAS_U32) milliseconds;
2003    if (requestedTime == (pStream->time >> 8))
2004        return EAS_SUCCESS;
2005
2006    /* set the locate flag */
2007    pStream->streamFlags |= STREAM_FLAGS_LOCATE;
2008
2009    /* use the parser locate function, if available */
2010    if (pParserModule->pfLocate != NULL)
2011    {
2012        EAS_BOOL parserLocate = EAS_FALSE;
2013        result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate);
2014        if (!parserLocate)
2015        {
2016            if (result == EAS_SUCCESS)
2017                pStream->time = requestedTime << 8;
2018            return result;
2019        }
2020    }
2021
2022    /* if we were paused and not going to resume, set pause request flag */
2023    if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
2024        pStream->streamFlags |= STREAM_FLAGS_PAUSE;
2025
2026    /* reset the synth and parser */
2027    if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS)
2028        return result;
2029    pStream->time = 0;
2030
2031    /* locating forward, clear parsed flag and parse data until we get to the requested location */
2032    if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS)
2033        return result;
2034
2035    return EAS_SUCCESS;
2036}
2037
2038/*----------------------------------------------------------------------------
2039 * EAS_GetLocation()
2040 *----------------------------------------------------------------------------
2041 * Purpose:
2042 * Returns the current playback offset
2043 *
2044 * Inputs:
2045 * pEASData         - pointer to overall EAS data structure
2046 * handle           - file handle
2047 *
2048 * Outputs:
2049 * The offset in milliseconds from the start of the current sequence, quantized
2050 * to the nearest update period. Actual resolution is typically 5.9 ms.
2051 *
2052 * Side Effects:
2053 *
2054 *----------------------------------------------------------------------------
2055*/
2056/*lint -esym(715, pEASData) reserved for future use */
2057EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime)
2058{
2059    if (!EAS_StreamReady(pEASData, pStream))
2060        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2061
2062    *pTime = pStream->time >> 8;
2063    return EAS_SUCCESS;
2064}
2065
2066/*----------------------------------------------------------------------------
2067 * EAS_GetRenderTime()
2068 *----------------------------------------------------------------------------
2069 * Purpose:
2070 * Returns the current playback offset
2071 *
2072 * Inputs:
2073 * pEASData         - pointer to overall EAS data structure
2074 *
2075 * Outputs:
2076 * Gets the render time clock in msecs.
2077 *
2078 * Side Effects:
2079 *
2080 *----------------------------------------------------------------------------
2081*/
2082EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime)
2083{
2084    *pTime = pEASData->renderTime >> 8;
2085    return EAS_SUCCESS;
2086}
2087
2088/*----------------------------------------------------------------------------
2089 * EAS_Pause()
2090 *----------------------------------------------------------------------------
2091 * Purpose:
2092 * Pauses the playback of the data associated with this handle. The audio
2093 * is gracefully ramped down to prevent clicks and pops. It may take several
2094 * buffers of audio before the audio is muted.
2095 *
2096 * Inputs:
2097 * psEASData        - pointer to overall EAS data structure
2098 * handle           - file or stream handle
2099 *
2100 * Outputs:
2101 *
2102 *
2103 * Side Effects:
2104 *
2105 *
2106 *----------------------------------------------------------------------------
2107*/
2108EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
2109{
2110    S_FILE_PARSER_INTERFACE *pParserModule;
2111    EAS_STATE state;
2112    EAS_RESULT result;
2113
2114    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
2115    if (pParserModule == NULL)
2116        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
2117
2118    /* check for valid state */
2119    result = pParserModule->pfState(pEASData, pStream->handle, &state);
2120    if (result == EAS_SUCCESS)
2121    {
2122        if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0))
2123            return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2124
2125        /* make sure parser implements pause */
2126        if (pParserModule->pfPause == NULL)
2127            result = EAS_ERROR_NOT_IMPLEMENTED;
2128
2129        /* clear resume flag */
2130        pStream->streamFlags &= ~STREAM_FLAGS_RESUME;
2131
2132        /* set pause flag */
2133        pStream->streamFlags |= STREAM_FLAGS_PAUSE;
2134
2135#if 0
2136        /* pause the stream */
2137        if (pParserModule->pfPause)
2138            result = pParserModule->pfPause(pEASData, pStream->handle);
2139        else
2140            result = EAS_ERROR_NOT_IMPLEMENTED;
2141#endif
2142    }
2143
2144    return result;
2145}
2146
2147/*----------------------------------------------------------------------------
2148 * EAS_Resume()
2149 *----------------------------------------------------------------------------
2150 * Purpose:
2151 * Resumes the playback of the data associated with this handle. The audio
2152 * is gracefully ramped up to prevent clicks and pops.
2153 *
2154 * Inputs:
2155 * psEASData        - pointer to overall EAS data structure
2156 * handle           - file or stream handle
2157 *
2158 * Outputs:
2159 *
2160 *
2161 * Side Effects:
2162 *
2163 *
2164 *----------------------------------------------------------------------------
2165*/
2166EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream)
2167{
2168    S_FILE_PARSER_INTERFACE *pParserModule;
2169    EAS_STATE state;
2170    EAS_RESULT result;
2171
2172    pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule;
2173    if (pParserModule == NULL)
2174        return EAS_ERROR_FEATURE_NOT_AVAILABLE;
2175
2176    /* check for valid state */
2177    result = pParserModule->pfState(pEASData, pStream->handle, &state);
2178    if (result == EAS_SUCCESS)
2179    {
2180        if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0))
2181            return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2182
2183        /* make sure parser implements this function */
2184        if (pParserModule->pfResume == NULL)
2185            result = EAS_ERROR_NOT_IMPLEMENTED;
2186
2187        /* clear pause flag */
2188        pStream->streamFlags &= ~STREAM_FLAGS_PAUSE;
2189
2190        /* set resume flag */
2191        pStream->streamFlags |= STREAM_FLAGS_RESUME;
2192
2193#if 0
2194        /* resume the stream */
2195        if (pParserModule->pfResume)
2196            result = pParserModule->pfResume(pEASData, pStream->handle);
2197        else
2198            result = EAS_ERROR_NOT_IMPLEMENTED;
2199#endif
2200    }
2201
2202    return result;
2203}
2204
2205/*----------------------------------------------------------------------------
2206 * EAS_GetParameter()
2207 *----------------------------------------------------------------------------
2208 * Purpose:
2209 * Set the parameter of a module. See E_MODULES for a list of modules
2210 * and the header files of the modules for a list of parameters.
2211 *
2212 * Inputs:
2213 * psEASData        - pointer to overall EAS data structure
2214 * handle           - file or stream handle
2215 * module           - enumerated module number
2216 * param            - enumerated parameter number
2217 * pValue           - pointer to variable to receive parameter value
2218 *
2219 * Outputs:
2220 *
2221 *
2222 * Side Effects:
2223 *
2224 *
2225 *----------------------------------------------------------------------------
2226*/
2227EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue)
2228{
2229
2230    if (module >= NUM_EFFECTS_MODULES)
2231        return EAS_ERROR_INVALID_MODULE;
2232
2233    if (pEASData->effectsModules[module].effectData == NULL)
2234        return EAS_ERROR_INVALID_MODULE;
2235
2236    return (*pEASData->effectsModules[module].effect->pFGetParam)
2237        (pEASData->effectsModules[module].effectData, param, pValue);
2238}
2239
2240/*----------------------------------------------------------------------------
2241 * EAS_SetParameter()
2242 *----------------------------------------------------------------------------
2243 * Purpose:
2244 * Set the parameter of a module. See E_MODULES for a list of modules
2245 * and the header files of the modules for a list of parameters.
2246 *
2247 * Inputs:
2248 * psEASData        - pointer to overall EAS data structure
2249 * handle           - file or stream handle
2250 * module           - enumerated module number
2251 * param            - enumerated parameter number
2252 * value            - new parameter value
2253 *
2254 * Outputs:
2255 *
2256 *
2257 * Side Effects:
2258 *
2259 *
2260 *----------------------------------------------------------------------------
2261*/
2262EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value)
2263{
2264
2265    if (module >= NUM_EFFECTS_MODULES)
2266        return EAS_ERROR_INVALID_MODULE;
2267
2268    if (pEASData->effectsModules[module].effectData == NULL)
2269        return EAS_ERROR_INVALID_MODULE;
2270
2271    return (*pEASData->effectsModules[module].effect->pFSetParam)
2272        (pEASData->effectsModules[module].effectData, param, value);
2273}
2274
2275#ifdef _METRICS_ENABLED
2276/*----------------------------------------------------------------------------
2277 * EAS_MetricsReport()
2278 *----------------------------------------------------------------------------
2279 * Purpose:
2280 * Displays the current metrics through the metrics interface.
2281 *
2282 * Inputs:
2283 * p                - instance data handle
2284 *
2285 * Outputs:
2286 *
2287 *
2288 * Side Effects:
2289 *
2290 *----------------------------------------------------------------------------
2291*/
2292EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData)
2293{
2294    if (!pEASData->pMetricsModule)
2295        return EAS_ERROR_INVALID_MODULE;
2296
2297    return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData);
2298}
2299
2300/*----------------------------------------------------------------------------
2301 * EAS_MetricsReset()
2302 *----------------------------------------------------------------------------
2303 * Purpose:
2304 * Resets the metrics.
2305 *
2306 * Inputs:
2307 * p                - instance data handle
2308 *
2309 * Outputs:
2310 *
2311 *
2312 * Side Effects:
2313 *
2314 *----------------------------------------------------------------------------
2315*/
2316EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData)
2317{
2318
2319    if (!pEASData->pMetricsModule)
2320        return EAS_ERROR_INVALID_MODULE;
2321
2322    return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData);
2323}
2324#endif
2325
2326/*----------------------------------------------------------------------------
2327 * EAS_SetSoundLibrary()
2328 *----------------------------------------------------------------------------
2329 * Purpose:
2330 * Sets the location of the sound library.
2331 *
2332 * Inputs:
2333 * pEASData             - instance data handle
2334 * pSoundLib            - pointer to sound library
2335 *
2336 * Outputs:
2337 *
2338 *
2339 * Side Effects:
2340 *
2341 *----------------------------------------------------------------------------
2342*/
2343EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib)
2344{
2345    if (pStream)
2346    {
2347        if (!EAS_StreamReady(pEASData, pStream))
2348            return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2349        return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib);
2350    }
2351
2352    return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib);
2353}
2354
2355/*----------------------------------------------------------------------------
2356 * EAS_SetHeaderSearchFlag()
2357 *----------------------------------------------------------------------------
2358 * By default, when EAS_OpenFile is called, the parsers check the
2359 * first few bytes of the file looking for a specific header. Some
2360 * mobile devices may add a header to the start of a file, which
2361 * will prevent the parser from recognizing the file. If the
2362 * searchFlag is set to EAS_TRUE, the parser will search the entire
2363 * file looking for the header. This may enable EAS to recognize
2364 * some files that it would ordinarily reject. The negative is that
2365 * it make take slightly longer to process the EAS_OpenFile request.
2366 *
2367 * Inputs:
2368 * pEASData             - instance data handle
2369 * searchFlag           - search flag (EAS_TRUE or EAS_FALSE)
2370 *----------------------------------------------------------------------------
2371*/
2372EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag)
2373{
2374    pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag;
2375    return EAS_SUCCESS;
2376}
2377
2378/*----------------------------------------------------------------------------
2379 * EAS_SetPlayMode()
2380 *----------------------------------------------------------------------------
2381 * Some file formats support special play modes, such as iMode partial
2382 * play mode. This call can be used to change the play mode. The
2383 * default play mode (usually straight playback) is always zero.
2384 *
2385 * Inputs:
2386 * pEASData             - instance data handle
2387 * handle               - file or stream handle
2388 * playMode             - play mode (see file parser for specifics)
2389 *----------------------------------------------------------------------------
2390*/
2391EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode)
2392{
2393    return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode);
2394}
2395
2396#ifdef DLS_SYNTHESIZER
2397/*----------------------------------------------------------------------------
2398 * EAS_LoadDLSCollection()
2399 *----------------------------------------------------------------------------
2400 * Purpose:
2401 * Sets the location of the sound library.
2402 *
2403 * Inputs:
2404 * pEASData             - instance data handle
2405 * pSoundLib            - pointer to sound library
2406 *
2407 * Outputs:
2408 *
2409 *
2410 * Side Effects:
2411 *
2412 *----------------------------------------------------------------------------
2413*/
2414EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator)
2415{
2416    EAS_FILE_HANDLE fileHandle;
2417    EAS_RESULT result;
2418    EAS_DLSLIB_HANDLE pDLS;
2419
2420    if (pStream != NULL)
2421    {
2422        if (!EAS_StreamReady(pEASData, pStream))
2423            return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2424    }
2425
2426    /* open the file */
2427    if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS)
2428        return result;
2429
2430    /* parse the file */
2431    result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS);
2432    EAS_HWCloseFile(pEASData->hwInstData, fileHandle);
2433
2434    if (result == EAS_SUCCESS)
2435    {
2436
2437        /* if a stream pStream is specified, point it to the DLS collection */
2438        if (pStream)
2439            result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS);
2440
2441        /* global DLS load */
2442        else
2443            result = VMSetGlobalDLSLib(pEASData, pDLS);
2444    }
2445
2446    return result;
2447}
2448#endif
2449
2450#ifdef EXTERNAL_AUDIO
2451/*----------------------------------------------------------------------------
2452 * EAS_RegExtAudioCallback()
2453 *----------------------------------------------------------------------------
2454 * Purpose:
2455 * Registers callback functions for audio events.
2456 *
2457 * Inputs:
2458 * pEASData         - pointer to overall EAS data structure
2459 * handle           - file or stream handle
2460 * cbProgChgFunc    - pointer to host callback function for program change
2461 * cbEventFunc      - pointer to host callback functio for note events
2462 *
2463 * Outputs:
2464 *
2465 *
2466 * Side Effects:
2467 *
2468 *----------------------------------------------------------------------------
2469*/
2470EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData,
2471    EAS_HANDLE pStream,
2472    EAS_VOID_PTR pInstData,
2473    EAS_EXT_PRG_CHG_FUNC cbProgChgFunc,
2474    EAS_EXT_EVENT_FUNC cbEventFunc)
2475{
2476    S_SYNTH *pSynth;
2477
2478    if (!EAS_StreamReady(pEASData, pStream))
2479        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2480
2481    if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
2482        return EAS_ERROR_INVALID_PARAMETER;
2483
2484    if (pSynth == NULL)
2485        return EAS_ERROR_INVALID_PARAMETER;
2486
2487    VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc);
2488    return EAS_SUCCESS;
2489}
2490
2491/*----------------------------------------------------------------------------
2492 * EAS_GetMIDIControllers()
2493 *----------------------------------------------------------------------------
2494 * Purpose:
2495 * Returns the current state of MIDI controllers on the requested channel.
2496 *
2497 * Inputs:
2498 * pEASData         - pointer to overall EAS data structure
2499 * handle           - file or stream handle
2500 * pControl         - pointer to structure to receive data
2501 *
2502 * Outputs:
2503 *
2504 *
2505 * Side Effects:
2506 *
2507 *----------------------------------------------------------------------------
2508*/
2509EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl)
2510{
2511    S_SYNTH *pSynth;
2512
2513    if (!EAS_StreamReady(pEASData, pStream))
2514        return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
2515
2516    if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS)
2517        return EAS_ERROR_INVALID_PARAMETER;
2518
2519    if (pSynth == NULL)
2520        return EAS_ERROR_INVALID_PARAMETER;
2521
2522    VMGetMIDIControllers(pSynth, channel, pControl);
2523    return EAS_SUCCESS;
2524}
2525#endif
2526
2527#ifdef _SPLIT_ARCHITECTURE
2528/*----------------------------------------------------------------------------
2529 * EAS_SetFrameBuffer()
2530 *----------------------------------------------------------------------------
2531 * Purpose:
2532 * Sets the frame buffer pointer passed to the IPC communications functions
2533 *
2534 * Inputs:
2535 * pEASData             - instance data handle
2536 * locator              - file locator
2537 *
2538 * Outputs:
2539 *
2540 *
2541 * Side Effects:
2542 * May overlay instruments in the GM sound set
2543 *
2544 *----------------------------------------------------------------------------
2545*/
2546EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer)
2547{
2548    if (pEASData->pVoiceMgr)
2549        pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer;
2550    return EAS_SUCCESS;
2551}
2552#endif
2553
2554/*----------------------------------------------------------------------------
2555 * EAS_SearchFile
2556 *----------------------------------------------------------------------------
2557 * Search file for specific sequence starting at current file
2558 * position. Returns offset to start of sequence.
2559 *
2560 * Inputs:
2561 * pEASData         - pointer to EAS persistent data object
2562 * fileHandle       - file handle
2563 * searchString     - pointer to search sequence
2564 * len              - length of search sequence
2565 * pOffset          - pointer to variable to store offset to sequence
2566 *
2567 * Returns EAS_EOF if end-of-file is reached
2568 *----------------------------------------------------------------------------
2569*/
2570EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset)
2571{
2572    EAS_RESULT result;
2573    EAS_INT index;
2574    EAS_U8 c;
2575
2576    *pOffset = -1;
2577    index = 0;
2578    for (;;)
2579    {
2580        result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c);
2581        if (result != EAS_SUCCESS)
2582            return result;
2583        if (c == searchString[index])
2584        {
2585            index++;
2586            if (index == 4)
2587            {
2588                result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset);
2589                if (result != EAS_SUCCESS)
2590                    return result;
2591                *pOffset -= len;
2592                break;
2593            }
2594        }
2595        else
2596            index = 0;
2597    }
2598    return EAS_SUCCESS;
2599}
2600
2601
2602