/*---------------------------------------------------------------------------- * * File: * eas_public.c * * Contents and purpose: * Contains EAS library public interface * * Copyright Sonic Network Inc. 2004 * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *---------------------------------------------------------------------------- * Revision Control: * $Revision: 842 $ * $Date: 2007-08-23 14:32:31 -0700 (Thu, 23 Aug 2007) $ *---------------------------------------------------------------------------- */ #define LOG_TAG "Sonivox" #include "log/log.h" #include "eas_synthcfg.h" #include "eas.h" #include "eas_config.h" #include "eas_host.h" #include "eas_report.h" #include "eas_data.h" #include "eas_parser.h" #include "eas_pcm.h" #include "eas_midi.h" #include "eas_mixer.h" #include "eas_build.h" #include "eas_vm_protos.h" #include "eas_math.h" #ifdef JET_INTERFACE #include "jet_data.h" #endif #ifdef DLS_SYNTHESIZER #include "eas_mdls.h" #endif /* number of events to parse before calling EAS_HWYield function */ #define YIELD_EVENT_COUNT 10 /*---------------------------------------------------------------------------- * easLibConfig * * This structure is available through the EAS public interface to allow * the user to check the configuration of the library. *---------------------------------------------------------------------------- */ static const S_EAS_LIB_CONFIG easLibConfig = { LIB_VERSION, #ifdef _CHECKED_BUILD EAS_TRUE, #else EAS_FALSE, #endif MAX_SYNTH_VOICES, NUM_OUTPUT_CHANNELS, _OUTPUT_SAMPLE_RATE, BUFFER_SIZE_IN_MONO_SAMPLES, #ifdef _FILTER_ENABLED EAS_TRUE, #else EAS_FALSE, #endif _BUILD_TIME_, _BUILD_VERSION_ }; /* local prototypes */ static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, S_EAS_STREAM *pStream, EAS_U32 endTime, EAS_INT parseMode); /*---------------------------------------------------------------------------- * EAS_SetStreamParameter *---------------------------------------------------------------------------- * Sets the specified parameter in the stream. Allows access to * customizable settings within the individual file parsers. *---------------------------------------------------------------------------- * pEASData - pointer to EAS persistent data object * pStream - stream handle * param - enumerated parameter (see eas_parser.h) * value - new value *---------------------------------------------------------------------------- */ EAS_RESULT EAS_SetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 value) { S_FILE_PARSER_INTERFACE *pParserModule; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule->pfSetData) return (*pParserModule->pfSetData)(pEASData, pStream->handle, param, value); return EAS_ERROR_FEATURE_NOT_AVAILABLE; } /*---------------------------------------------------------------------------- * EAS_GetStreamParameter *---------------------------------------------------------------------------- * Sets the specified parameter in the stream. Allows access to * customizable settings within the individual file parsers. *---------------------------------------------------------------------------- * pEASData - pointer to EAS persistent data object * pStream - stream handle * param - enumerated parameter (see eas_parser.h) * pValue - pointer to variable to receive current setting *---------------------------------------------------------------------------- */ EAS_RESULT EAS_GetStreamParameter (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 param, EAS_I32 *pValue) { S_FILE_PARSER_INTERFACE *pParserModule; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule->pfGetData) return (*pParserModule->pfGetData)(pEASData, pStream->handle, param, pValue); return EAS_ERROR_FEATURE_NOT_AVAILABLE; } /*---------------------------------------------------------------------------- * EAS_StreamReady() *---------------------------------------------------------------------------- * This routine sets common parameters like transpose, volume, etc. * First, it attempts to use the parser EAS_SetStreamParameter interface. If that * fails, it attempts to get the synth handle from the parser and * set the parameter directly on the synth. This eliminates duplicate * code in the parser. *---------------------------------------------------------------------------- */ EAS_BOOL EAS_StreamReady (S_EAS_DATA *pEASData, EAS_HANDLE pStream) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_STATE state; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule->pfState(pEASData, pStream->handle, &state) != EAS_SUCCESS) return EAS_FALSE; return (state < EAS_STATE_OPEN); } /*---------------------------------------------------------------------------- * EAS_IntSetStrmParam() *---------------------------------------------------------------------------- * This routine sets common parameters like transpose, volume, etc. * First, it attempts to use the parser EAS_SetStreamParameter interface. If that * fails, it attempts to get the synth handle from the parser and * set the parameter directly on the synth. This eliminates duplicate * code in the parser. *---------------------------------------------------------------------------- */ EAS_RESULT EAS_IntSetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 value) { S_SYNTH *pSynth; /* try to set the parameter using stream interface */ if (EAS_SetStreamParameter(pEASData, pStream, param, value) == EAS_SUCCESS) return EAS_SUCCESS; /* get a pointer to the synth object and set it directly */ /*lint -e{740} we are cheating by passing a pointer through this interface */ if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) return EAS_ERROR_INVALID_PARAMETER; if (pSynth == NULL) return EAS_ERROR_INVALID_PARAMETER; switch (param) { #ifdef DLS_SYNTHESIZER case PARSER_DATA_DLS_COLLECTION: { EAS_RESULT result = VMSetDLSLib(pSynth, (EAS_DLSLIB_HANDLE) value); if (result == EAS_SUCCESS) { DLSAddRef((S_DLS*) value); VMInitializeAllChannels(pEASData->pVoiceMgr, pSynth); } return result; } #endif case PARSER_DATA_EAS_LIBRARY: return VMSetEASLib(pSynth, (EAS_SNDLIB_HANDLE) value); case PARSER_DATA_POLYPHONY: return VMSetPolyphony(pEASData->pVoiceMgr, pSynth, value); case PARSER_DATA_PRIORITY: return VMSetPriority(pEASData->pVoiceMgr, pSynth, value); case PARSER_DATA_TRANSPOSITION: VMSetTranposition(pSynth, value); break; case PARSER_DATA_VOLUME: VMSetVolume(pSynth, (EAS_U16) value); break; default: { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } return EAS_ERROR_INVALID_PARAMETER; } return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_IntGetStrmParam() *---------------------------------------------------------------------------- * This routine gets common parameters like transpose, volume, etc. * First, it attempts to use the parser EAS_GetStreamParameter interface. If that * fails, it attempts to get the synth handle from the parser and * get the parameter directly on the synth. *---------------------------------------------------------------------------- */ EAS_RESULT EAS_IntGetStrmParam (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_INT param, EAS_I32 *pValue) { S_SYNTH *pSynth; /* try to set the parameter */ if (EAS_GetStreamParameter(pEASData, pStream, param, pValue) == EAS_SUCCESS) return EAS_SUCCESS; /* get a pointer to the synth object and retrieve data directly */ /*lint -e{740} we are cheating by passing a pointer through this interface */ if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) return EAS_ERROR_INVALID_PARAMETER; if (pSynth == NULL) return EAS_ERROR_INVALID_PARAMETER; switch (param) { case PARSER_DATA_POLYPHONY: return VMGetPolyphony(pEASData->pVoiceMgr, pSynth, pValue); case PARSER_DATA_PRIORITY: return VMGetPriority(pEASData->pVoiceMgr, pSynth, pValue); case PARSER_DATA_TRANSPOSITION: VMGetTranposition(pSynth, pValue); break; case PARSER_DATA_NOTE_COUNT: *pValue = VMGetNoteCount(pSynth); break; default: { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Invalid paramter %d in call to EAS_IntSetStrmParam", param); */ } return EAS_ERROR_INVALID_PARAMETER; } return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_AllocateStream() *---------------------------------------------------------------------------- * Purpose: * Allocates a stream handle * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ static EAS_INT EAS_AllocateStream (EAS_DATA_HANDLE pEASData) { EAS_INT streamNum; /* check for static allocation, only one stream allowed */ if (pEASData->staticMemoryModel) { if (pEASData->streams[0].handle != NULL) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Attempt to open multiple streams in static model\n"); */ } return -1; } return 0; } /* dynamic model */ for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) if (pEASData->streams[streamNum].handle == NULL) break; if (streamNum == MAX_NUMBER_STREAMS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Exceeded maximum number of open streams\n"); */ } return -1; } return streamNum; } /*---------------------------------------------------------------------------- * EAS_InitStream() *---------------------------------------------------------------------------- * Purpose: * Initialize a stream * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ static void EAS_InitStream (S_EAS_STREAM *pStream, EAS_VOID_PTR pParserModule, EAS_VOID_PTR streamHandle) { pStream->pParserModule = pParserModule; pStream->handle = streamHandle; pStream->time = 0; pStream->frameLength = AUDIO_FRAME_LENGTH; pStream->repeatCount = 0; pStream->volume = DEFAULT_STREAM_VOLUME; pStream->streamFlags = 0; } /*---------------------------------------------------------------------------- * EAS_Config() *---------------------------------------------------------------------------- * Purpose: * Returns a pointer to a structure containing the configuration options * in this library build. * * Inputs: * * Outputs: * *---------------------------------------------------------------------------- */ EAS_PUBLIC const S_EAS_LIB_CONFIG *EAS_Config (void) { return &easLibConfig; } /*---------------------------------------------------------------------------- * EAS_Init() *---------------------------------------------------------------------------- * Purpose: * Initialize the synthesizer library * * Inputs: * ppEASData - pointer to data handle variable for this instance * * Outputs: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Init (EAS_DATA_HANDLE *ppEASData) { EAS_HW_DATA_HANDLE pHWInstData; EAS_RESULT result; S_EAS_DATA *pEASData; EAS_INT module; EAS_BOOL staticMemoryModel; /* get the memory model */ staticMemoryModel = EAS_CMStaticMemoryModel(); /* initialize the host wrapper interface */ *ppEASData = NULL; if ((result = EAS_HWInit(&pHWInstData)) != EAS_SUCCESS) return result; /* check Configuration Module for S_EAS_DATA allocation */ if (staticMemoryModel) pEASData = EAS_CMEnumData(EAS_CM_EAS_DATA); else pEASData = EAS_HWMalloc(pHWInstData, sizeof(S_EAS_DATA)); if (!pEASData) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate EAS library memory\n"); */ } return EAS_ERROR_MALLOC_FAILED; } /* initialize some data */ EAS_HWMemSet(pEASData, 0, sizeof(S_EAS_DATA)); pEASData->staticMemoryModel = (EAS_BOOL8) staticMemoryModel; pEASData->hwInstData = pHWInstData; pEASData->renderTime = 0; /* set header search flag */ #ifdef FILE_HEADER_SEARCH pEASData->searchHeaderFlag = EAS_TRUE; #endif /* initalize parameters */ EAS_SetVolume(pEASData, NULL, DEFAULT_VOLUME); #ifdef _METRICS_ENABLED /* initalize the metrics module */ pEASData->pMetricsModule = EAS_CMEnumOptModules(EAS_MODULE_METRICS); if (pEASData->pMetricsModule != NULL) { if ((result = (*pEASData->pMetricsModule->pfInit)(pEASData, &pEASData->pMetricsData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld initializing metrics module\n", result); */ } return result; } } #endif /* initailize the voice manager & synthesizer */ if ((result = VMInitialize(pEASData)) != EAS_SUCCESS) return result; /* initialize mix engine */ if ((result = EAS_MixEngineInit(pEASData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld starting up mix engine\n", result); */ } return result; } /* initialize effects modules */ for (module = 0; module < NUM_EFFECTS_MODULES; module++) { pEASData->effectsModules[module].effect = EAS_CMEnumFXModules(module); if (pEASData->effectsModules[module].effect != NULL) { if ((result = (*pEASData->effectsModules[module].effect->pfInit)(pEASData, &pEASData->effectsModules[module].effectData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Initialization of effects module %d returned %d\n", module, result); */ } return result; } } } /* initialize PCM engine */ if ((result = EAS_PEInit(pEASData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "EAS_PEInit failed with error code %ld\n", result); */ } return result; } /* return instance data pointer to host */ *ppEASData = pEASData; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_Shutdown() *---------------------------------------------------------------------------- * Purpose: * Shuts down the library. Deallocates any memory associated with the * synthesizer (dynamic memory model only) * * Inputs: * pEASData - handle to data for this instance * * Outputs: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Shutdown (EAS_DATA_HANDLE pEASData) { /* check for NULL handle */ if (!pEASData) return EAS_ERROR_HANDLE_INTEGRITY; /* establish pointers */ EAS_HW_DATA_HANDLE hwInstData = pEASData->hwInstData; /* if there are streams open, close them */ EAS_RESULT reportResult = EAS_SUCCESS; EAS_RESULT result; EAS_INT i; for (i = 0; i < MAX_NUMBER_STREAMS; i++) { if (pEASData->streams[i].pParserModule && pEASData->streams[i].handle) { if ((result = (*((S_FILE_PARSER_INTERFACE*)(pEASData->streams[i].pParserModule))->pfClose)(pEASData, pEASData->streams[i].handle)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down parser module\n", result); */ } reportResult = result; } } } /* shutdown PCM engine */ if ((result = EAS_PEShutdown(pEASData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down PCM engine\n", result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } /* shutdown mix engine */ if ((result = EAS_MixEngineShutdown(pEASData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down mix engine\n", result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } /* shutdown effects modules */ for (i = 0; i < NUM_EFFECTS_MODULES; i++) { if (pEASData->effectsModules[i].effect) { if ((result = (*pEASData->effectsModules[i].effect->pfShutdown)(pEASData, pEASData->effectsModules[i].effectData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Shutdown of effects module %d returned %d\n", i, result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } } } /* shutdown the voice manager & synthesizer */ VMShutdown(pEASData); #ifdef _METRICS_ENABLED /* shutdown the metrics module */ if (pEASData->pMetricsModule != NULL) { if ((result = (*pEASData->pMetricsModule->pfShutdown)(pEASData, pEASData->pMetricsData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down metrics module\n", result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } } #endif /* release allocated memory */ if (!pEASData->staticMemoryModel) EAS_HWFree(hwInstData, pEASData); /* shutdown host wrappers */ if (hwInstData) { if ((result = EAS_HWShutdown(hwInstData)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "Error %ld shutting down host wrappers\n", result); */ } if (reportResult == EAS_SUCCESS) reportResult = result; } } return reportResult; } #ifdef JET_INTERFACE /*---------------------------------------------------------------------------- * EAS_OpenJETStream() *---------------------------------------------------------------------------- * Private interface for JET to open an SMF stream with an offset *---------------------------------------------------------------------------- */ EAS_RESULT EAS_OpenJETStream (EAS_DATA_HANDLE pEASData, EAS_FILE_HANDLE fileHandle, EAS_I32 offset, EAS_HANDLE *ppStream) { EAS_RESULT result; EAS_VOID_PTR streamHandle; S_FILE_PARSER_INTERFACE *pParserModule; EAS_INT streamNum; /* allocate a stream */ if ((streamNum = EAS_AllocateStream(pEASData)) < 0) return EAS_ERROR_MAX_STREAMS_OPEN; /* check Configuration Module for SMF parser */ *ppStream = NULL; streamHandle = NULL; pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(0); if (pParserModule == NULL) return EAS_ERROR_UNRECOGNIZED_FORMAT; /* see if SMF parser recognizes the file */ if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, offset)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } return result; } /* parser recognized the file, return the handle */ if (streamHandle) { EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); *ppStream = &pEASData->streams[streamNum]; return EAS_SUCCESS; } return EAS_ERROR_UNRECOGNIZED_FORMAT; } #endif /*---------------------------------------------------------------------------- * EAS_OpenFile() *---------------------------------------------------------------------------- * Purpose: * Opens a file for audio playback. * * Inputs: * pEASData - pointer to overall EAS data structure * pHandle - pointer to file handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_OpenFile (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) { EAS_RESULT result; EAS_FILE_HANDLE fileHandle; EAS_VOID_PTR streamHandle; S_FILE_PARSER_INTERFACE *pParserModule; EAS_INT streamNum; EAS_INT moduleNum; /* open the file */ if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) return result; /* allocate a stream */ if ((streamNum = EAS_AllocateStream(pEASData)) < 0) { /* Closing the opened file as stream allocation failed */ EAS_HWCloseFile(pEASData->hwInstData, fileHandle); return EAS_ERROR_MAX_STREAMS_OPEN; } /* check Configuration Module for file parsers */ pParserModule = NULL; *ppStream = NULL; streamHandle = NULL; for (moduleNum = 0; ; moduleNum++) { pParserModule = (S_FILE_PARSER_INTERFACE *) EAS_CMEnumModules(moduleNum); if (pParserModule == NULL) break; /* see if this parser recognizes it */ if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) { /* Closing the opened file as file type check failed */ EAS_HWCloseFile(pEASData->hwInstData, fileHandle); { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } return result; } /* parser recognized the file, return the handle */ if (streamHandle) { /* save the parser pointer and file handle */ EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); *ppStream = &pEASData->streams[streamNum]; return EAS_SUCCESS; } /* rewind the file for the next parser */ if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, 0L)) != EAS_SUCCESS) { /* Closing the opened file as file seek failed */ EAS_HWCloseFile(pEASData->hwInstData, fileHandle); return result; } } /* no parser was able to recognize the file, close it and return an error */ EAS_HWCloseFile(pEASData->hwInstData, fileHandle); { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } return EAS_ERROR_UNRECOGNIZED_FORMAT; } #ifdef MMAPI_SUPPORT /*---------------------------------------------------------------------------- * EAS_MMAPIToneControl() *---------------------------------------------------------------------------- * Purpose: * Opens a ToneControl file for audio playback. * * Inputs: * pEASData - pointer to overall EAS data structure * pHandle - pointer to file handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_MMAPIToneControl (EAS_DATA_HANDLE pEASData, EAS_FILE_LOCATOR locator, EAS_HANDLE *ppStream) { EAS_RESULT result; EAS_FILE_HANDLE fileHandle; EAS_VOID_PTR streamHandle; S_FILE_PARSER_INTERFACE *pParserModule; EAS_INT streamNum; /* check if the tone control parser is available */ *ppStream = NULL; streamHandle = NULL; pParserModule = EAS_CMEnumOptModules(EAS_MODULE_MMAPI_TONE_CONTROL); if (pParserModule == NULL) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_MMAPIToneControl: ToneControl parser not available\n"); */ } return EAS_ERROR_FEATURE_NOT_AVAILABLE; } /* open the file */ if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) return result; /* allocate a stream */ if ((streamNum = EAS_AllocateStream(pEASData)) < 0) return EAS_ERROR_MAX_STREAMS_OPEN; /* see if ToneControl parser recognizes it */ if ((result = (*pParserModule->pfCheckFileType)(pEASData, fileHandle, &streamHandle, 0L)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "CheckFileType returned error %ld\n", result); */ } return result; } /* parser accepted the file, return the handle */ if (streamHandle) { /* save the parser pointer and file handle */ EAS_InitStream(&pEASData->streams[streamNum], pParserModule, streamHandle); *ppStream = &pEASData->streams[streamNum]; return EAS_SUCCESS; } /* parser did not recognize the file, close it and return an error */ EAS_HWCloseFile(pEASData->hwInstData, fileHandle); { /* dpp: EAS_ReportEx(_EAS_SEVERITY_WARNING, "No parser recognized the requested file\n"); */ } return EAS_ERROR_UNRECOGNIZED_FORMAT; } /*---------------------------------------------------------------------------- * EAS_GetWaveFmtChunk *---------------------------------------------------------------------------- * Helper function to retrieve WAVE file fmt chunk for MMAPI *---------------------------------------------------------------------------- * pEASData - pointer to EAS persistent data object * pStream - stream handle * pFmtChunk - pointer to variable to receive current setting *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetWaveFmtChunk (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_VOID_PTR *ppFmtChunk) { EAS_RESULT result; EAS_I32 value; if ((result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FORMAT, &value)) != EAS_SUCCESS) return result; *ppFmtChunk = (EAS_VOID_PTR) value; return EAS_SUCCESS; } #endif /*---------------------------------------------------------------------------- * EAS_GetFileType *---------------------------------------------------------------------------- * Returns the file type (see eas_types.h for enumerations) *---------------------------------------------------------------------------- * pEASData - pointer to EAS persistent data object * pStream - stream handle * pFileType - pointer to variable to receive file type *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetFileType (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_I32 *pFileType) { if (!EAS_StreamReady (pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_FILE_TYPE, pFileType); } /*---------------------------------------------------------------------------- * EAS_Prepare() *---------------------------------------------------------------------------- * Purpose: * Prepares the synthesizer to play the file or stream. Parses the first * frame of data from the file and arms the synthesizer. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Prepare (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_STATE state; EAS_RESULT result; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; /* check for valid state */ result = pParserModule->pfState(pEASData, pStream->handle, &state); if (result == EAS_SUCCESS) { /* prepare the stream */ if (state == EAS_STATE_OPEN) { pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; result = (*pParserModule->pfPrepare)(pEASData, pStream->handle); /* set volume */ if (result == EAS_SUCCESS) result = EAS_SetVolume(pEASData, pStream, pStream->volume); } else result = EAS_ERROR_NOT_VALID_IN_THIS_STATE; } return result; } /*---------------------------------------------------------------------------- * EAS_Render() *---------------------------------------------------------------------------- * Purpose: * Parse the Midi data and render PCM audio data. * * Inputs: * pEASData - buffer for internal EAS data * pOut - output buffer pointer * nNumRequested - requested num samples to generate * pnNumGenerated - actual number of samples generated * * Outputs: * EAS_SUCCESS if PCM data was successfully rendered * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Render (EAS_DATA_HANDLE pEASData, EAS_PCM *pOut, EAS_I32 numRequested, EAS_I32 *pNumGenerated) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; EAS_I32 voicesRendered; EAS_STATE parserState; EAS_INT streamNum; /* assume no samples generated and reset workload */ *pNumGenerated = 0; VMInitWorkload(pEASData->pVoiceMgr); /* no support for other buffer sizes yet */ if (numRequested != BUFFER_SIZE_IN_MONO_SAMPLES) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "This library supports only %ld samples in buffer, host requested %ld samples\n", (EAS_I32) BUFFER_SIZE_IN_MONO_SAMPLES, numRequested); */ } return EAS_BUFFER_SIZE_MISMATCH; } #ifdef _METRICS_ENABLED /* start performance counter */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); #endif /* prep the frame buffer, do mix engine prep only if TRUE */ #ifdef _SPLIT_ARCHITECTURE if (VMStartFrame(pEASData)) EAS_MixEnginePrep(pEASData, numRequested); #else /* prep the mix engine */ EAS_MixEnginePrep(pEASData, numRequested); #endif /* save the output buffer pointer */ pEASData->pOutputAudioBuffer = pOut; #ifdef _METRICS_ENABLED /* start performance counter */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); #endif /* if we haven't finished parsing from last time, do it now */ /* need to parse another frame of events before we render again */ for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) { /* clear the locate flag */ pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_LOCATE; if (pEASData->streams[streamNum].pParserModule) { /* establish pointer to parser module */ pParserModule = pEASData->streams[streamNum].pParserModule; /* handle pause */ if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PAUSE) { if (pParserModule->pfPause) result = pParserModule->pfPause(pEASData, pEASData->streams[streamNum].handle); pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PAUSE; } /* get current state */ if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) return result; /* handle resume */ if (parserState == EAS_STATE_PAUSED) { if (pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_RESUME) { if (pParserModule->pfResume) result = pParserModule->pfResume(pEASData, pEASData->streams[streamNum].handle); pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_RESUME; } } /* if necessary, parse stream */ if ((pEASData->streams[streamNum].streamFlags & STREAM_FLAGS_PARSED) == 0) if ((result = EAS_ParseEvents(pEASData, &pEASData->streams[streamNum], pEASData->streams[streamNum].time + pEASData->streams[streamNum].frameLength, eParserModePlay)) != EAS_SUCCESS) return result; /* check for an early abort */ if ((pEASData->streams[streamNum].streamFlags) == 0) { #ifdef _METRICS_ENABLED /* stop performance counter */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); #endif return EAS_SUCCESS; } /* check for repeat */ if (pEASData->streams[streamNum].repeatCount) { /* check for stopped state */ if ((result = (*pParserModule->pfState)(pEASData, pEASData->streams[streamNum].handle, &parserState)) != EAS_SUCCESS) return result; if (parserState == EAS_STATE_STOPPED) { /* decrement repeat count, unless it is negative */ if (pEASData->streams[streamNum].repeatCount > 0) pEASData->streams[streamNum].repeatCount--; /* reset the parser */ if ((result = (*pParserModule->pfReset)(pEASData, pEASData->streams[streamNum].handle)) != EAS_SUCCESS) return result; pEASData->streams[streamNum].time = 0; } } } } #ifdef _METRICS_ENABLED /* stop performance counter */ if (pEASData->pMetricsData) (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_PARSE_TIME); #endif #ifdef _METRICS_ENABLED /* start the render timer */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); #endif /* render audio */ if ((result = VMRender(pEASData->pVoiceMgr, BUFFER_SIZE_IN_MONO_SAMPLES, pEASData->pMixBuffer, &voicesRendered)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "pfRender function returned error %ld\n", result); */ } return result; } #ifdef _METRICS_ENABLED /* stop the render timer */ if (pEASData->pMetricsData) { (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_FRAME_COUNT, 1); (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_RENDER_TIME); (*pEASData->pMetricsModule->pfIncrementCounter)(pEASData->pMetricsData, EAS_PM_TOTAL_VOICE_COUNT, (EAS_U32) voicesRendered); (void)(*pEASData->pMetricsModule->pfRecordMaxValue)(pEASData->pMetricsData, EAS_PM_MAX_VOICES, (EAS_U32) voicesRendered); } #endif //2 Do we really need frameParsed? /* need to parse another frame of events before we render again */ for (streamNum = 0; streamNum < MAX_NUMBER_STREAMS; streamNum++) if (pEASData->streams[streamNum].pParserModule != NULL) pEASData->streams[streamNum].streamFlags &= ~STREAM_FLAGS_PARSED; #ifdef _METRICS_ENABLED /* start performance counter */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); #endif /* render PCM audio */ if ((result = EAS_PERender(pEASData, numRequested)) != EAS_SUCCESS) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_ERROR, "EAS_PERender returned error %ld\n", result); */ } return result; } #ifdef _METRICS_ENABLED /* stop the stream timer */ if (pEASData->pMetricsData) (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_STREAM_TIME); #endif #ifdef _METRICS_ENABLED /* start the post timer */ if (pEASData->pMetricsData) (*pEASData->pMetricsModule->pfStartTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); #endif /* for split architecture, send DSP vectors. Do post only if return is TRUE */ #ifdef _SPLIT_ARCHITECTURE if (VMEndFrame(pEASData)) { /* now do post-processing */ EAS_MixEnginePost(pEASData, numRequested); *pNumGenerated = numRequested; } #else /* now do post-processing */ EAS_MixEnginePost(pEASData, numRequested); *pNumGenerated = numRequested; #endif #ifdef _METRICS_ENABLED /* stop the post timer */ if (pEASData->pMetricsData) (void)(*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_POST_TIME); #endif /* advance render time */ pEASData->renderTime += AUDIO_FRAME_LENGTH; #if 0 /* dump workload for debug */ if (pEASData->pVoiceMgr->workload) { /* dpp: EAS_ReportEx(_EAS_SEVERITY_DETAIL, "Workload = %d\n", pEASData->pVoiceMgr->workload); */ } #endif #ifdef _METRICS_ENABLED /* stop performance counter */ if (pEASData->pMetricsData) { PERF_TIMER temp; temp = (*pEASData->pMetricsModule->pfStopTimer)(pEASData->pMetricsData, EAS_PM_TOTAL_TIME); /* if max render time, record the number of voices and time */ if ((*pEASData->pMetricsModule->pfRecordMaxValue) (pEASData->pMetricsData, EAS_PM_MAX_CYCLES, (EAS_U32) temp)) { (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_VOICES, (EAS_U32) voicesRendered); (*pEASData->pMetricsModule->pfRecordValue)(pEASData->pMetricsData, EAS_PM_MAX_CYCLES_TIME, (EAS_I32) (pEASData->renderTime >> 8)); } } #endif #ifdef JET_INTERFACE /* let JET to do its thing */ if (pEASData->jetHandle != NULL) { result = JET_Process(pEASData); if (result != EAS_SUCCESS) return result; } #endif return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetRepeat() *---------------------------------------------------------------------------- * Purpose: * Set the selected stream to repeat. * * Inputs: * pEASData - handle to data for this instance * handle - handle to stream * repeatCount - repeat count * * Outputs: * * Side Effects: * * Notes: * 0 = no repeat * 1 = repeat once, i.e. play through twice * -1 = repeat forever *---------------------------------------------------------------------------- */ /*lint -esym(715, pEASData) reserved for future use */ EAS_PUBLIC EAS_RESULT EAS_SetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 repeatCount) { pStream->repeatCount = repeatCount; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_GetRepeat() *---------------------------------------------------------------------------- * Purpose: * Gets the current repeat count for the selected stream. * * Inputs: * pEASData - handle to data for this instance * handle - handle to stream * pRrepeatCount - pointer to variable to hold repeat count * * Outputs: * * Side Effects: * * Notes: * 0 = no repeat * 1 = repeat once, i.e. play through twice * -1 = repeat forever *---------------------------------------------------------------------------- */ /*lint -esym(715, pEASData) reserved for future use */ EAS_PUBLIC EAS_RESULT EAS_GetRepeat (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pRepeatCount) { *pRepeatCount = pStream->repeatCount; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetPlaybackRate() *---------------------------------------------------------------------------- * Purpose: * Sets the playback rate. * * Inputs: * pEASData - handle to data for this instance * handle - handle to stream * rate - rate (28-bit fractional amount) * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ /*lint -esym(715, pEASData) reserved for future use */ EAS_PUBLIC EAS_RESULT EAS_SetPlaybackRate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U32 rate) { /* check range */ if ((rate < (1 << 27)) || (rate > (1 << 29))) return EAS_ERROR_INVALID_PARAMETER; /* calculate new frame length * * NOTE: The maximum frame length we can accomodate based on a * maximum rate of 2.0 (2^28) is 2047 (2^13-1). To accomodate a * longer frame length or a higher maximum rate, the fixed point * divide below will need to be adjusted */ pStream->frameLength = (AUDIO_FRAME_LENGTH * (rate >> 8)) >> 20; /* notify stream of new playback rate */ EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_PLAYBACK_RATE, (EAS_I32) rate); return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetTransposition) *---------------------------------------------------------------------------- * Purpose: * Sets the key tranposition for the synthesizer. Transposes all * melodic instruments by the specified amount. Range is limited * to +/-12 semitones. * * Inputs: * pEASData - handle to data for this instance * handle - handle to stream * transposition - +/-12 semitones * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetTransposition (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 transposition) { /* check range */ if ((transposition < -12) || (transposition > 12)) return EAS_ERROR_INVALID_PARAMETER; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_TRANSPOSITION, transposition); } /*---------------------------------------------------------------------------- * EAS_ParseEvents() *---------------------------------------------------------------------------- * Purpose: * Parse events in the current streams until the desired time is reached. * * Inputs: * pEASData - buffer for internal EAS data * endTime - stop parsing if this time is reached * parseMode - play, locate, or metadata * * Outputs: * EAS_SUCCESS if PCM data was successfully rendered * *---------------------------------------------------------------------------- */ static EAS_RESULT EAS_ParseEvents (S_EAS_DATA *pEASData, EAS_HANDLE pStream, EAS_U32 endTime, EAS_INT parseMode) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; EAS_I32 parserState; EAS_BOOL done; EAS_INT yieldCount = YIELD_EVENT_COUNT; EAS_U32 time = 0; // This constant is the maximum number of events that can be processed in a single time slice. // A typical ringtone will contain a few events per time slice. // Extremely dense ringtones might go up to 50 events. // If we see this many events then the file is probably stuck in an infinite loop // and should be aborted. static const EAS_INT MAX_EVENT_COUNT = 100000; EAS_INT eventCount = 0; /* does this parser have a time function? */ pParserModule = pStream->pParserModule; if (pParserModule->pfTime == NULL) { /* check state */ if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) return result; /* if play state, advance time */ if ((parserState >= EAS_STATE_READY) && (parserState <= EAS_STATE_PAUSING)) pStream->time += pStream->frameLength; done = EAS_TRUE; } /* assume we're not done, in case we abort out */ else { pStream->streamFlags &= ~STREAM_FLAGS_PARSED; done = EAS_FALSE; } while (!done) { /* check for stopped state */ if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &parserState)) != EAS_SUCCESS) return result; if (parserState > EAS_STATE_PLAY) { /* save current time if we're not in play mode */ if (parseMode != eParserModePlay) pStream->time = time << 8; done = EAS_TRUE; break; } /* get the next event time */ if (pParserModule->pfTime) { if ((result = (*pParserModule->pfTime)(pEASData, pStream->handle, &time)) != EAS_SUCCESS) return result; /* if next event is within this frame, parse it */ if (time < (endTime >> 8)) { /* parse the next event */ if (pParserModule->pfEvent) { if ((result = (*pParserModule->pfEvent)(pEASData, pStream->handle, parseMode)) != EAS_SUCCESS) { ALOGE("%s() pfEvent returned %ld", __func__, result); return result; } } // An infinite loop within a ringtone file can cause this function // to loop forever. Try to detect that and return an error. // Only check when playing. Otherwise a very large file could be rejected // when scanning the entire file in a single call to this function. // OTA files will only do infinite loops when in eParserModePlay. if (++eventCount >= MAX_EVENT_COUNT && parseMode == eParserModePlay) { ALOGE("%s() aborting, %d events. Infinite loop in song file?!", __func__, eventCount); android_errorWriteLog(0x534e4554, "68664359"); return EAS_ERROR_FILE_POS; } } /* no more events in this frame, advance time */ else { pStream->time = endTime; done = EAS_TRUE; } } /* check for max workload exceeded */ if (VMCheckWorkload(pEASData->pVoiceMgr)) { /* stop even though we may not have parsed * all the events in this frame. The parser will try to * catch up on the next frame. */ break; } /* give host a chance for an early abort */ if (--yieldCount == 0) { if (EAS_HWYield(pEASData->hwInstData)) break; yieldCount = YIELD_EVENT_COUNT; } } /* if no early abort, parsing is complete for this frame */ if (done) pStream->streamFlags |= STREAM_FLAGS_PARSED; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_ParseMetaData() *---------------------------------------------------------------------------- * Purpose: * * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * playLength - pointer to variable to store the play length (in msecs) * * Outputs: * * * Side Effects: * - resets the parser to the start of the file *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_ParseMetaData (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *playLength) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; EAS_STATE state; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; /* check parser state */ if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) return result; if (state >= EAS_STATE_OPEN) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* if parser has metadata function, use that */ if (pParserModule->pfGetMetaData != NULL) return pParserModule->pfGetMetaData(pEASData, pStream->handle, playLength); /* reset the parser to the beginning */ if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) return result; /* parse the file to end */ pStream->time = 0; VMInitWorkload(pEASData->pVoiceMgr); if ((result = EAS_ParseEvents(pEASData, pStream, 0x7fffffff, eParserModeMetaData)) != EAS_SUCCESS) return result; /* get the parser time */ if ((result = EAS_GetLocation(pEASData, pStream, playLength)) != EAS_SUCCESS) return result; /* reset the parser to the beginning */ pStream->time = 0; return (*pParserModule->pfReset)(pEASData, pStream->handle); } /*---------------------------------------------------------------------------- * EAS_RegisterMetaDataCallback() *---------------------------------------------------------------------------- * Purpose: * Registers a metadata callback function for parsed metadata. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * cbFunc - pointer to host callback function * metaDataBuffer - pointer to metadata buffer * metaDataBufSize - maximum size of the metadata buffer * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_RegisterMetaDataCallback ( EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_METADATA_CBFUNC cbFunc, char *metaDataBuffer, EAS_I32 metaDataBufSize, EAS_VOID_PTR pUserData) { S_METADATA_CB metadata; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* register callback function */ metadata.callback = cbFunc; metadata.buffer = metaDataBuffer; metadata.bufferSize = metaDataBufSize; metadata.pUserData = pUserData; return EAS_SetStreamParameter(pEASData, pStream, PARSER_DATA_METADATA_CB, (EAS_I32) &metadata); } /*---------------------------------------------------------------------------- * EAS_GetNoteCount () *---------------------------------------------------------------------------- * Returns the total number of notes played in this stream *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetNoteCount (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pNoteCount) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_NOTE_COUNT, pNoteCount); } /*---------------------------------------------------------------------------- * EAS_CloseFile() *---------------------------------------------------------------------------- * Purpose: * Closes an audio file or stream. Playback should have either paused or * completed (EAS_State returns EAS_PAUSED or EAS_STOPPED). * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_CloseFile (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; /* call the close function */ pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; result = (*pParserModule->pfClose)(pEASData, pStream->handle); /* clear the handle and parser interface pointer */ pStream->handle = NULL; pStream->pParserModule = NULL; return result; } /*---------------------------------------------------------------------------- * EAS_OpenMIDIStream() *---------------------------------------------------------------------------- * Purpose: * Opens a raw MIDI stream allowing the host to route MIDI cable data directly to the synthesizer * * Inputs: * pEASData - pointer to overall EAS data structure * pHandle - pointer to variable to hold file or stream handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_OpenMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE *ppStream, EAS_HANDLE streamHandle) { EAS_RESULT result; S_INTERACTIVE_MIDI *pMIDIStream; EAS_INT streamNum; /* initialize some pointers */ *ppStream = NULL; /* allocate a stream */ if ((streamNum = EAS_AllocateStream(pEASData)) < 0) return EAS_ERROR_MAX_STREAMS_OPEN; /* check Configuration Module for S_EAS_DATA allocation */ if (pEASData->staticMemoryModel) pMIDIStream = EAS_CMEnumData(EAS_CM_MIDI_STREAM_DATA); else pMIDIStream = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_INTERACTIVE_MIDI)); /* allocate dynamic memory */ if (!pMIDIStream) { { /* dpp: EAS_ReportEx(_EAS_SEVERITY_FATAL, "Failed to allocate MIDI stream data\n"); */ } return EAS_ERROR_MALLOC_FAILED; } /* zero the memory to insure complete initialization */ EAS_HWMemSet(pMIDIStream, 0, sizeof(S_INTERACTIVE_MIDI)); EAS_InitStream(&pEASData->streams[streamNum], NULL, pMIDIStream); /* instantiate a new synthesizer */ if (streamHandle == NULL) { result = VMInitMIDI(pEASData, &pMIDIStream->pSynth); } /* use an existing synthesizer */ else { EAS_I32 value; result = EAS_GetStreamParameter(pEASData, streamHandle, PARSER_DATA_SYNTH_HANDLE, &value); pMIDIStream->pSynth = (S_SYNTH*) value; VMIncRefCount(pMIDIStream->pSynth); } if (result != EAS_SUCCESS) { EAS_CloseMIDIStream(pEASData, &pEASData->streams[streamNum]); return result; } /* initialize the MIDI stream data */ EAS_InitMIDIStream(&pMIDIStream->stream); *ppStream = (EAS_HANDLE) &pEASData->streams[streamNum]; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_WriteMIDIStream() *---------------------------------------------------------------------------- * Purpose: * Send data to the MIDI stream device * * Inputs: * pEASData - pointer to overall EAS data structure * handle - stream handle * pBuffer - pointer to buffer * count - number of bytes to write * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_WriteMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 *pBuffer, EAS_I32 count) { S_INTERACTIVE_MIDI *pMIDIStream; EAS_RESULT result; pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; if (count <= 0) return EAS_ERROR_PARAMETER_RANGE; /* send the entire buffer */ while (count--) { if ((result = EAS_ParseMIDIStream(pEASData, pMIDIStream->pSynth, &pMIDIStream->stream, *pBuffer++, eParserModePlay)) != EAS_SUCCESS) return result; } return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_CloseMIDIStream() *---------------------------------------------------------------------------- * Purpose: * Closes a raw MIDI stream * * Inputs: * pEASData - pointer to overall EAS data structure * handle - stream handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_CloseMIDIStream (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { S_INTERACTIVE_MIDI *pMIDIStream; pMIDIStream = (S_INTERACTIVE_MIDI*) pStream->handle; /* close synth */ if (pMIDIStream->pSynth != NULL) { VMMIDIShutdown(pEASData, pMIDIStream->pSynth); pMIDIStream->pSynth = NULL; } /* release allocated memory */ if (!pEASData->staticMemoryModel) EAS_HWFree(((S_EAS_DATA*) pEASData)->hwInstData, pMIDIStream); pStream->handle = NULL; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_State() *---------------------------------------------------------------------------- * Purpose: * Returns the state of an audio file or stream. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_State (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_STATE *pState) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; /* call the parser to return state */ pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, pState)) != EAS_SUCCESS) return result; /* if repeat count is set for this parser, mask the stopped state from the application */ if (pStream->repeatCount && (*pState == EAS_STATE_STOPPED)) *pState = EAS_STATE_PLAY; /* if we're not paused or pausing, we don't need to hide state from host */ if (*pState != EAS_STATE_PAUSED && *pState != EAS_STATE_PAUSING) return EAS_SUCCESS; /* if stream is about to be paused, report it as paused */ if (pStream->streamFlags & STREAM_FLAGS_PAUSE) { if (pStream->streamFlags & STREAM_FLAGS_LOCATE) *pState = EAS_STATE_PAUSED; else *pState = EAS_STATE_PAUSING; } /* if stream is about to resume, report it as playing */ if (pStream->streamFlags & STREAM_FLAGS_RESUME) *pState = EAS_STATE_PLAY; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetPolyphony() *---------------------------------------------------------------------------- * Purpose: * Set the polyphony of the stream. A value of 0 allows the stream * to use all voices (set by EAS_SetSynthPolyphony). * * Inputs: * pEASData - pointer to overall EAS data structure * streamHandle - handle returned by EAS_OpenFile * polyphonyCount - the desired polyphony count * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 polyphonyCount) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, polyphonyCount); } /*---------------------------------------------------------------------------- * EAS_GetPolyphony() *---------------------------------------------------------------------------- * Purpose: * Returns the current polyphony setting of the stream * * Inputs: * pEASData - pointer to overall EAS data structure * streamHandle - handle returned by EAS_OpenFile * pPolyphonyCount - pointer to variable to receive polyphony count * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetPolyphony (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPolyphonyCount) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_POLYPHONY, pPolyphonyCount); } /*---------------------------------------------------------------------------- * EAS_SetSynthPolyphony() *---------------------------------------------------------------------------- * Purpose: * Set the polyphony of the synth . Value must be >= 1 and <= the * maximum number of voices. This function will pin the polyphony * at those limits * * Inputs: * pEASData - pointer to overall EAS data structure * synthNum - synthesizer number (0 = onboard, 1 = DSP) * polyphonyCount - the desired polyphony count * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 polyphonyCount) { return VMSetSynthPolyphony(pEASData->pVoiceMgr, synthNum, polyphonyCount); } /*---------------------------------------------------------------------------- * EAS_GetSynthPolyphony() *---------------------------------------------------------------------------- * Purpose: * Returns the current polyphony setting of the synth * * Inputs: * pEASData - pointer to overall EAS data structure * synthNum - synthesizer number (0 = onboard, 1 = DSP) * pPolyphonyCount - pointer to variable to receive polyphony count * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetSynthPolyphony (EAS_DATA_HANDLE pEASData, EAS_I32 synthNum, EAS_I32 *pPolyphonyCount) { return VMGetSynthPolyphony(pEASData->pVoiceMgr, synthNum, pPolyphonyCount); } /*---------------------------------------------------------------------------- * EAS_SetPriority() *---------------------------------------------------------------------------- * Purpose: * Set the priority of the stream. Determines which stream's voices * are stolen when there are insufficient voices for all notes. * Value must be in the range of 1-15, lower values are higher * priority. * * Inputs: * pEASData - pointer to overall EAS data structure * streamHandle - handle returned by EAS_OpenFile * polyphonyCount - the desired polyphony count * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 priority) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, priority); } /*---------------------------------------------------------------------------- * EAS_GetPriority() *---------------------------------------------------------------------------- * Purpose: * Returns the current priority setting of the stream * * Inputs: * pEASData - pointer to overall EAS data structure * streamHandle - handle returned by EAS_OpenFile * pPriority - pointer to variable to receive priority * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetPriority (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pPriority) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntGetStrmParam(pEASData, pStream, PARSER_DATA_PRIORITY, pPriority); } /*---------------------------------------------------------------------------- * EAS_SetVolume() *---------------------------------------------------------------------------- * Purpose: * Set the master gain for the mix engine in 1dB increments * * Inputs: * pEASData - pointer to overall EAS data structure * volume - the desired master gain (100 is max) * handle - file or stream handle * * Outputs: * * * Side Effects: * overrides any previously set master volume from sysex * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 volume) { EAS_I16 gain; /* check range */ if ((volume < 0) || (volume > EAS_MAX_VOLUME)) return EAS_ERROR_PARAMETER_RANGE; /* stream volume */ if (pStream != NULL) { EAS_I32 gainOffset; EAS_RESULT result; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* get gain offset */ pStream->volume = (EAS_U8) volume; result = EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_GAIN_OFFSET, &gainOffset); if (result == EAS_SUCCESS) volume += gainOffset; /* set stream volume */ gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); /* convert to linear scalar */ return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_VOLUME, gain); } /* master volume */ pEASData->masterVolume = (EAS_U8) volume; #if (NUM_OUTPUT_CHANNELS == 1) /* leave 3dB headroom for mono output */ volume -= 3; #endif gain = EAS_VolumeToGain(volume - STREAM_VOLUME_HEADROOM); pEASData->masterGain = gain; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_GetVolume() *---------------------------------------------------------------------------- * Purpose: * Returns the master volume for the synthesizer. The default volume setting is * 50. The volume range is 0 to 100; * * Inputs: * pEASData - pointer to overall EAS data structure * volume - the desired master volume * handle - file or stream handle * * Outputs: * * * Side Effects: * overrides any previously set master volume from sysex * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_I32 EAS_GetVolume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { if (pStream == NULL) return pEASData->masterVolume; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return pStream->volume; } /*---------------------------------------------------------------------------- * EAS_SetMaxLoad() *---------------------------------------------------------------------------- * Purpose: * Sets the maximum workload the parsers will do in a single call to * EAS_Render. The units are currently arbitrary, but should correlate * well to the actual CPU cycles consumed. The primary effect is to * reduce the occasional peaks in CPU cycles consumed when parsing * dense parts of a MIDI score. * * Inputs: * pEASData - handle to data for this instance * maxLoad - the desired maximum workload * * Outputs: * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetMaxLoad (EAS_DATA_HANDLE pEASData, EAS_I32 maxLoad) { VMSetWorkload(pEASData->pVoiceMgr, maxLoad); return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetMaxPCMStreams() *---------------------------------------------------------------------------- * Sets the maximum number of PCM streams allowed in parsers that * use PCM streaming. * * Inputs: * pEASData - pointer to overall EAS data structure * streamHandle - handle returned by EAS_OpenFile * maxNumStreams - maximum number of PCM streams *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetMaxPCMStreams (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 maxNumStreams) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_MAX_PCM_STREAMS, maxNumStreams); } /*---------------------------------------------------------------------------- * EAS_Locate() *---------------------------------------------------------------------------- * Purpose: * Locate into the file associated with the handle. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file handle * milliseconds - playback offset from start of file in milliseconds * * Outputs: * * * Side Effects: * the actual offset will be quantized to the closest update period, typically * a resolution of 5.9ms. Notes that are started prior to this time will not * sound. Any notes currently playing will be shut off. * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Locate (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 milliseconds, EAS_BOOL offset) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_RESULT result; EAS_U32 requestedTime; EAS_STATE state; /* get pointer to parser function table */ pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; if ((result = (*pParserModule->pfState)(pEASData, pStream->handle, &state)) != EAS_SUCCESS) return result; if (state >= EAS_STATE_OPEN) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* handle offset and limit to start of file */ /*lint -e{704} use shift for performance*/ if (offset) milliseconds += (EAS_I32) pStream->time >> 8; if (milliseconds < 0) milliseconds = 0; /* check to see if the request is different from the current time */ requestedTime = (EAS_U32) milliseconds; if (requestedTime == (pStream->time >> 8)) return EAS_SUCCESS; /* set the locate flag */ pStream->streamFlags |= STREAM_FLAGS_LOCATE; /* use the parser locate function, if available */ if (pParserModule->pfLocate != NULL) { EAS_BOOL parserLocate = EAS_FALSE; result = pParserModule->pfLocate(pEASData, pStream->handle, (EAS_I32) requestedTime, &parserLocate); if (!parserLocate) { if (result == EAS_SUCCESS) pStream->time = requestedTime << 8; return result; } } /* if we were paused and not going to resume, set pause request flag */ if (((state == EAS_STATE_PAUSING) || (state == EAS_STATE_PAUSED)) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) pStream->streamFlags |= STREAM_FLAGS_PAUSE; /* reset the synth and parser */ if ((result = (*pParserModule->pfReset)(pEASData, pStream->handle)) != EAS_SUCCESS) return result; pStream->time = 0; /* locating forward, clear parsed flag and parse data until we get to the requested location */ if ((result = EAS_ParseEvents(pEASData, pStream, requestedTime << 8, eParserModeLocate)) != EAS_SUCCESS) return result; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_GetLocation() *---------------------------------------------------------------------------- * Purpose: * Returns the current playback offset * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file handle * * Outputs: * The offset in milliseconds from the start of the current sequence, quantized * to the nearest update period. Actual resolution is typically 5.9 ms. * * Side Effects: * *---------------------------------------------------------------------------- */ /*lint -esym(715, pEASData) reserved for future use */ EAS_PUBLIC EAS_RESULT EAS_GetLocation (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 *pTime) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; *pTime = pStream->time >> 8; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_GetRenderTime() *---------------------------------------------------------------------------- * Purpose: * Returns the current playback offset * * Inputs: * pEASData - pointer to overall EAS data structure * * Outputs: * Gets the render time clock in msecs. * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetRenderTime (EAS_DATA_HANDLE pEASData, EAS_I32 *pTime) { *pTime = pEASData->renderTime >> 8; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_Pause() *---------------------------------------------------------------------------- * Purpose: * Pauses the playback of the data associated with this handle. The audio * is gracefully ramped down to prevent clicks and pops. It may take several * buffers of audio before the audio is muted. * * Inputs: * psEASData - pointer to overall EAS data structure * handle - file or stream handle * * Outputs: * * * Side Effects: * * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Pause (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_STATE state; EAS_RESULT result; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; /* check for valid state */ result = pParserModule->pfState(pEASData, pStream->handle, &state); if (result == EAS_SUCCESS) { if ((state != EAS_STATE_PLAY) && (state != EAS_STATE_READY) && ((pStream->streamFlags & STREAM_FLAGS_RESUME) == 0)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* make sure parser implements pause */ if (pParserModule->pfPause == NULL) result = EAS_ERROR_NOT_IMPLEMENTED; /* clear resume flag */ pStream->streamFlags &= ~STREAM_FLAGS_RESUME; /* set pause flag */ pStream->streamFlags |= STREAM_FLAGS_PAUSE; #if 0 /* pause the stream */ if (pParserModule->pfPause) result = pParserModule->pfPause(pEASData, pStream->handle); else result = EAS_ERROR_NOT_IMPLEMENTED; #endif } return result; } /*---------------------------------------------------------------------------- * EAS_Resume() *---------------------------------------------------------------------------- * Purpose: * Resumes the playback of the data associated with this handle. The audio * is gracefully ramped up to prevent clicks and pops. * * Inputs: * psEASData - pointer to overall EAS data structure * handle - file or stream handle * * Outputs: * * * Side Effects: * * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_Resume (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream) { S_FILE_PARSER_INTERFACE *pParserModule; EAS_STATE state; EAS_RESULT result; pParserModule = (S_FILE_PARSER_INTERFACE*) pStream->pParserModule; if (pParserModule == NULL) return EAS_ERROR_FEATURE_NOT_AVAILABLE; /* check for valid state */ result = pParserModule->pfState(pEASData, pStream->handle, &state); if (result == EAS_SUCCESS) { if ((state != EAS_STATE_PAUSED) && (state != EAS_STATE_PAUSING) && ((pStream->streamFlags & STREAM_FLAGS_PAUSE) == 0)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; /* make sure parser implements this function */ if (pParserModule->pfResume == NULL) result = EAS_ERROR_NOT_IMPLEMENTED; /* clear pause flag */ pStream->streamFlags &= ~STREAM_FLAGS_PAUSE; /* set resume flag */ pStream->streamFlags |= STREAM_FLAGS_RESUME; #if 0 /* resume the stream */ if (pParserModule->pfResume) result = pParserModule->pfResume(pEASData, pStream->handle); else result = EAS_ERROR_NOT_IMPLEMENTED; #endif } return result; } /*---------------------------------------------------------------------------- * EAS_GetParameter() *---------------------------------------------------------------------------- * Purpose: * Set the parameter of a module. See E_MODULES for a list of modules * and the header files of the modules for a list of parameters. * * Inputs: * psEASData - pointer to overall EAS data structure * handle - file or stream handle * module - enumerated module number * param - enumerated parameter number * pValue - pointer to variable to receive parameter value * * Outputs: * * * Side Effects: * * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 *pValue) { if (module >= NUM_EFFECTS_MODULES) return EAS_ERROR_INVALID_MODULE; if (pEASData->effectsModules[module].effectData == NULL) return EAS_ERROR_INVALID_MODULE; return (*pEASData->effectsModules[module].effect->pFGetParam) (pEASData->effectsModules[module].effectData, param, pValue); } /*---------------------------------------------------------------------------- * EAS_SetParameter() *---------------------------------------------------------------------------- * Purpose: * Set the parameter of a module. See E_MODULES for a list of modules * and the header files of the modules for a list of parameters. * * Inputs: * psEASData - pointer to overall EAS data structure * handle - file or stream handle * module - enumerated module number * param - enumerated parameter number * value - new parameter value * * Outputs: * * * Side Effects: * * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetParameter (EAS_DATA_HANDLE pEASData, EAS_I32 module, EAS_I32 param, EAS_I32 value) { if (module >= NUM_EFFECTS_MODULES) return EAS_ERROR_INVALID_MODULE; if (pEASData->effectsModules[module].effectData == NULL) return EAS_ERROR_INVALID_MODULE; return (*pEASData->effectsModules[module].effect->pFSetParam) (pEASData->effectsModules[module].effectData, param, value); } #ifdef _METRICS_ENABLED /*---------------------------------------------------------------------------- * EAS_MetricsReport() *---------------------------------------------------------------------------- * Purpose: * Displays the current metrics through the metrics interface. * * Inputs: * p - instance data handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_MetricsReport (EAS_DATA_HANDLE pEASData) { if (!pEASData->pMetricsModule) return EAS_ERROR_INVALID_MODULE; return (*pEASData->pMetricsModule->pfReport)(pEASData->pMetricsData); } /*---------------------------------------------------------------------------- * EAS_MetricsReset() *---------------------------------------------------------------------------- * Purpose: * Resets the metrics. * * Inputs: * p - instance data handle * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_MetricsReset (EAS_DATA_HANDLE pEASData) { if (!pEASData->pMetricsModule) return EAS_ERROR_INVALID_MODULE; return (*pEASData->pMetricsModule->pfReset)(pEASData->pMetricsData); } #endif /*---------------------------------------------------------------------------- * EAS_SetSoundLibrary() *---------------------------------------------------------------------------- * Purpose: * Sets the location of the sound library. * * Inputs: * pEASData - instance data handle * pSoundLib - pointer to sound library * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetSoundLibrary (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_SNDLIB_HANDLE pSndLib) { if (pStream) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_EAS_LIBRARY, (EAS_I32) pSndLib); } return VMSetGlobalEASLib(pEASData->pVoiceMgr, pSndLib); } /*---------------------------------------------------------------------------- * EAS_SetHeaderSearchFlag() *---------------------------------------------------------------------------- * By default, when EAS_OpenFile is called, the parsers check the * first few bytes of the file looking for a specific header. Some * mobile devices may add a header to the start of a file, which * will prevent the parser from recognizing the file. If the * searchFlag is set to EAS_TRUE, the parser will search the entire * file looking for the header. This may enable EAS to recognize * some files that it would ordinarily reject. The negative is that * it make take slightly longer to process the EAS_OpenFile request. * * Inputs: * pEASData - instance data handle * searchFlag - search flag (EAS_TRUE or EAS_FALSE) *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetHeaderSearchFlag (EAS_DATA_HANDLE pEASData, EAS_BOOL searchFlag) { pEASData->searchHeaderFlag = (EAS_BOOL8) searchFlag; return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_SetPlayMode() *---------------------------------------------------------------------------- * Some file formats support special play modes, such as iMode partial * play mode. This call can be used to change the play mode. The * default play mode (usually straight playback) is always zero. * * Inputs: * pEASData - instance data handle * handle - file or stream handle * playMode - play mode (see file parser for specifics) *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetPlayMode (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_I32 playMode) { return EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_PLAY_MODE, playMode); } #ifdef DLS_SYNTHESIZER /*---------------------------------------------------------------------------- * EAS_LoadDLSCollection() *---------------------------------------------------------------------------- * Purpose: * Sets the location of the sound library. * * Inputs: * pEASData - instance data handle * pSoundLib - pointer to sound library * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_LoadDLSCollection (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_FILE_LOCATOR locator) { EAS_FILE_HANDLE fileHandle; EAS_RESULT result; EAS_DLSLIB_HANDLE pDLS; if (pStream != NULL) { if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; } /* open the file */ if ((result = EAS_HWOpenFile(pEASData->hwInstData, locator, &fileHandle, EAS_FILE_READ)) != EAS_SUCCESS) return result; /* parse the file */ result = DLSParser(pEASData->hwInstData, fileHandle, 0, &pDLS); EAS_HWCloseFile(pEASData->hwInstData, fileHandle); if (result == EAS_SUCCESS) { /* if a stream pStream is specified, point it to the DLS collection */ if (pStream) result = EAS_IntSetStrmParam(pEASData, pStream, PARSER_DATA_DLS_COLLECTION, (EAS_I32) pDLS); /* global DLS load */ else result = VMSetGlobalDLSLib(pEASData, pDLS); } return result; } #endif #ifdef EXTERNAL_AUDIO /*---------------------------------------------------------------------------- * EAS_RegExtAudioCallback() *---------------------------------------------------------------------------- * Purpose: * Registers callback functions for audio events. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * cbProgChgFunc - pointer to host callback function for program change * cbEventFunc - pointer to host callback functio for note events * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_RegExtAudioCallback (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_VOID_PTR pInstData, EAS_EXT_PRG_CHG_FUNC cbProgChgFunc, EAS_EXT_EVENT_FUNC cbEventFunc) { S_SYNTH *pSynth; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) return EAS_ERROR_INVALID_PARAMETER; if (pSynth == NULL) return EAS_ERROR_INVALID_PARAMETER; VMRegExtAudioCallback(pSynth, pInstData, cbProgChgFunc, cbEventFunc); return EAS_SUCCESS; } /*---------------------------------------------------------------------------- * EAS_GetMIDIControllers() *---------------------------------------------------------------------------- * Purpose: * Returns the current state of MIDI controllers on the requested channel. * * Inputs: * pEASData - pointer to overall EAS data structure * handle - file or stream handle * pControl - pointer to structure to receive data * * Outputs: * * * Side Effects: * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_GetMIDIControllers (EAS_DATA_HANDLE pEASData, EAS_HANDLE pStream, EAS_U8 channel, S_MIDI_CONTROLLERS *pControl) { S_SYNTH *pSynth; if (!EAS_StreamReady(pEASData, pStream)) return EAS_ERROR_NOT_VALID_IN_THIS_STATE; if (EAS_GetStreamParameter(pEASData, pStream, PARSER_DATA_SYNTH_HANDLE, (EAS_I32*) &pSynth) != EAS_SUCCESS) return EAS_ERROR_INVALID_PARAMETER; if (pSynth == NULL) return EAS_ERROR_INVALID_PARAMETER; VMGetMIDIControllers(pSynth, channel, pControl); return EAS_SUCCESS; } #endif #ifdef _SPLIT_ARCHITECTURE /*---------------------------------------------------------------------------- * EAS_SetFrameBuffer() *---------------------------------------------------------------------------- * Purpose: * Sets the frame buffer pointer passed to the IPC communications functions * * Inputs: * pEASData - instance data handle * locator - file locator * * Outputs: * * * Side Effects: * May overlay instruments in the GM sound set * *---------------------------------------------------------------------------- */ EAS_PUBLIC EAS_RESULT EAS_SetFrameBuffer (EAS_DATA_HANDLE pEASData, EAS_FRAME_BUFFER_HANDLE pFrameBuffer) { if (pEASData->pVoiceMgr) pEASData->pVoiceMgr->pFrameBuffer = pFrameBuffer; return EAS_SUCCESS; } #endif /*---------------------------------------------------------------------------- * EAS_SearchFile *---------------------------------------------------------------------------- * Search file for specific sequence starting at current file * position. Returns offset to start of sequence. * * Inputs: * pEASData - pointer to EAS persistent data object * fileHandle - file handle * searchString - pointer to search sequence * len - length of search sequence * pOffset - pointer to variable to store offset to sequence * * Returns EAS_EOF if end-of-file is reached *---------------------------------------------------------------------------- */ EAS_RESULT EAS_SearchFile (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, const EAS_U8 *searchString, EAS_I32 len, EAS_I32 *pOffset) { EAS_RESULT result; EAS_INT index; EAS_U8 c; *pOffset = -1; index = 0; for (;;) { result = EAS_HWGetByte(pEASData->hwInstData, fileHandle, &c); if (result != EAS_SUCCESS) return result; if (c == searchString[index]) { index++; if (index == 4) { result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, pOffset); if (result != EAS_SUCCESS) return result; *pOffset -= len; break; } } else index = 0; } return EAS_SUCCESS; }