summaryrefslogtreecommitdiffstats
path: root/arm-fm-22k/lib_src/eas_wavefile.c
diff options
context:
space:
mode:
Diffstat (limited to 'arm-fm-22k/lib_src/eas_wavefile.c')
-rw-r--r--arm-fm-22k/lib_src/eas_wavefile.c1710
1 files changed, 855 insertions, 855 deletions
diff --git a/arm-fm-22k/lib_src/eas_wavefile.c b/arm-fm-22k/lib_src/eas_wavefile.c
index d3f3ba0..f24bde2 100644
--- a/arm-fm-22k/lib_src/eas_wavefile.c
+++ b/arm-fm-22k/lib_src/eas_wavefile.c
@@ -1,12 +1,12 @@
-/*----------------------------------------------------------------------------
- *
- * File:
- * eas_wavefile.c
- *
- * Contents and purpose:
- * This file implements the wave file parser.
- *
- * Copyright Sonic Network Inc. 2005
+/*----------------------------------------------------------------------------
+ *
+ * File:
+ * eas_wavefile.c
+ *
+ * Contents and purpose:
+ * This file implements the wave file parser.
+ *
+ * Copyright Sonic Network Inc. 2005
* Licensed under the Apache License, Version 2.0 (the "License");
* you may not use this file except in compliance with the License.
@@ -19,849 +19,849 @@
* 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: 852 $
- * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $
- *----------------------------------------------------------------------------
-*/
-
-#include "eas_data.h"
-#include "eas_report.h"
-#include "eas_host.h"
-#include "eas_config.h"
-#include "eas_parser.h"
-#include "eas_pcm.h"
-#include "eas_wavefile.h"
-
-/* lint is choking on the ARM math.h file, so we declare the log10 function here */
-extern double log10(double x);
-
-/* increase gain to compensate for loss in mixer */
-#define WAVE_GAIN_OFFSET 6
-
-/* constant for 1200 / log10(2.0) */
-#define PITCH_CENTS_CONVERSION 3986.313714
-
-/*----------------------------------------------------------------------------
- * WAVE file defines
- *----------------------------------------------------------------------------
-*/
-/* RIFF chunks */
-#define CHUNK_TYPE(a,b,c,d) ( \
- ( ((EAS_U32)(a) & 0xFF) << 24 ) \
- + ( ((EAS_U32)(b) & 0xFF) << 16 ) \
- + ( ((EAS_U32)(c) & 0xFF) << 8 ) \
- + ( ((EAS_U32)(d) & 0xFF) ) )
-
-#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F')
-#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E')
-#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ')
-#define CHUNK_DATA CHUNK_TYPE('d','a','t','a')
-#define CHUNK_LIST CHUNK_TYPE('L','I','S','T')
-#define CHUNK_INFO CHUNK_TYPE('I','N','F','O')
-#define CHUNK_INAM CHUNK_TYPE('I','N','A','M')
-#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P')
-#define CHUNK_IART CHUNK_TYPE('I','A','R','T')
-
-/* wave file format identifiers */
-#define WAVE_FORMAT_PCM 0x0001
-#define WAVE_FORMAT_IMA_ADPCM 0x0011
-
-/* file size for streamed file */
-#define FILE_SIZE_STREAMING 0x80000000
-
-/*----------------------------------------------------------------------------
- * prototypes
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset);
-static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
-static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate);
-static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
-static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
-static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
-static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData);
-static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength);
-
-#ifdef MMAPI_SUPPORT
-static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size);
-#endif
-
-/*----------------------------------------------------------------------------
- *
- * EAS_Wave_Parser
- *
- * This structure contains the functional interface for the Wave file parser
- *----------------------------------------------------------------------------
-*/
-const S_FILE_PARSER_INTERFACE EAS_Wave_Parser =
-{
- WaveCheckFileType,
- WavePrepare,
- NULL,
- NULL,
- WaveState,
- WaveClose,
- WaveReset,
- WavePause,
- WaveResume,
- WaveLocate,
- WaveSetData,
- WaveGetData,
- WaveGetMetaData
-};
-
-/*----------------------------------------------------------------------------
- * WaveCheckFileType()
- *----------------------------------------------------------------------------
- * Purpose:
- * Check the file type to see if we can parse it
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset)
-{
- S_WAVE_STATE *pWaveData;
-
- /* zero the memory to insure complete initialization */
- *pHandle = NULL;
-
- /* read the file header */
- if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS)
- {
-
- /* check for static memory allocation */
- if (pEASData->staticMemoryModel)
- pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA);
- else
- pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE));
- if (!pWaveData)
- return EAS_ERROR_MALLOC_FAILED;
- EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE));
-
- /* return a pointer to the instance data */
- pWaveData->fileHandle = fileHandle;
- pWaveData->fileOffset = offset;
- *pHandle = pWaveData;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WavePrepare()
- *----------------------------------------------------------------------------
- * Purpose:
- * Prepare to parse the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
-
- /* validate parser state */
- pWaveData = (S_WAVE_STATE*) pInstData;
- if (pWaveData->streamHandle != NULL)
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-
- /* back to start of file */
- pWaveData->time = 0;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS)
- return result;
-
- /* parse the file header */
- if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS)
- return result;
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveState()
- *----------------------------------------------------------------------------
- * Purpose:
- * Returns the current state of the stream
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * pState - pointer to variable to store state
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- * Notes:
- * This interface is also exposed in the internal library for use by the other modules.
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState)
-{
- S_WAVE_STATE *pWaveData;
-
- /* return current state */
- pWaveData = (S_WAVE_STATE*) pInstData;
- if (pWaveData->streamHandle)
- return EAS_PEState(pEASData, pWaveData->streamHandle, pState);
-
- /* if no stream handle, and time is not zero, we are done */
- if (pWaveData->time > 0)
- *pState = EAS_STATE_STOPPED;
- else
- *pState = EAS_STATE_OPEN;
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveClose()
- *----------------------------------------------------------------------------
- * Purpose:
- * Close the file and clean up
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
-
- pWaveData = (S_WAVE_STATE*) pInstData;
-
- /* close the stream */
- if (pWaveData->streamHandle)
- {
- if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS)
- return result;
- pWaveData->streamHandle = NULL;
- }
-
- /* if using dynamic memory, free it */
- if (!pEASData->staticMemoryModel)
- {
-
-#ifdef MMAPI_SUPPORT
- /* need to free the fmt chunk */
- if (pWaveData->fmtChunk != NULL)
- EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk);
-#endif
-
- /* free the instance data */
- EAS_HWFree(pEASData->hwInstData, pWaveData);
-
- }
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveReset()
- *----------------------------------------------------------------------------
- * Purpose:
- * Reset the sequencer. Used for locating backwards in the file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* reset to first byte of data in the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEReset(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveLocate()
- *----------------------------------------------------------------------------
- * Purpose:
- * Rewind/fast-forward in file.
- *
- * Inputs:
- * pEASData - pointer to overall EAS data structure
- * handle - pointer to file handle
- * time - time (in msecs)
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pParserLocate) reserved for future use */
-static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* reset to first byte of data in the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PELocate(pEASData, streamHandle, time);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WavePause()
- *----------------------------------------------------------------------------
- * Purpose:
- * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback
- * at the end of the next audio frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* pause the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEPause(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveResume()
- *----------------------------------------------------------------------------
- * Purpose:
- * Resume rendering a PCM stream. Sets the gain target back to its
- * previous setting and restarts playback at the end of the next audio
- * frame.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
-{
- EAS_PCM_HANDLE streamHandle;
-
- /* resume the stream */
- streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
- if (streamHandle)
- return EAS_PEResume(pEASData, streamHandle);
- return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
-}
-
-/*----------------------------------------------------------------------------
- * WaveSetData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
-{
- S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData;
-
- switch (param)
- {
- /* set metadata callback */
- case PARSER_DATA_METADATA_CB:
- EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB));
- return EAS_SUCCESS;
-
- case PARSER_DATA_PLAYBACK_RATE:
- value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28)));
- return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value);
-
- case PARSER_DATA_VOLUME:
- return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value);
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-}
-
-/*----------------------------------------------------------------------------
- * WaveGetData()
- *----------------------------------------------------------------------------
- * Purpose:
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-/*lint -esym(715, pEASData) reserved for future use */
-static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
-{
- S_WAVE_STATE *pWaveData;
-
- pWaveData = (S_WAVE_STATE*) pInstData;
- switch (param)
- {
- /* return file type as WAVE */
- case PARSER_DATA_FILE_TYPE:
- *pValue = pWaveData->fileType;
- break;
-
-#ifdef MMAPI_SUPPORT
- /* return pointer to 'fmt' chunk */
- case PARSER_DATA_FORMAT:
- *pValue = (EAS_I32) pWaveData->fmtChunk;
- break;
-#endif
-
- case PARSER_DATA_GAIN_OFFSET:
- *pValue = WAVE_GAIN_OFFSET;
- break;
-
- default:
- return EAS_ERROR_INVALID_PARAMETER;
- }
-
- return EAS_SUCCESS;
-}
-
-/*----------------------------------------------------------------------------
- * WaveParseHeader()
- *----------------------------------------------------------------------------
- * Purpose:
- * Parse the WAVE file header.
- *
- * Inputs:
- * pEASData - pointer to EAS library instance data
- * handle - pointer to S_WAVE_STATE for this stream
- *
- * Outputs:
- *
- *
- * Side Effects:
- *
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData)
-{
- S_PCM_OPEN_PARAMS params;
- EAS_RESULT result;
- EAS_U32 tag;
- EAS_U32 fileSize;
- EAS_U32 size;
- EAS_I32 pos;
- EAS_I32 audioOffset;
- EAS_U16 usTemp;
- EAS_BOOL parseDone;
- EAS_U32 avgBytesPerSec;
-
- /* init some data (and keep lint happy) */
- params.sampleRate = 0;
- params.size = 0;
- audioOffset = 0;
- params.decoder = 0;
- params.blockSize = 0;
- params.pCallbackFunc = NULL;
- params.cbInstData = NULL;
- params.loopSamples = 0;
- params.fileHandle = fileHandle;
- params.volume = 0x7fff;
- params.envData = 0;
- avgBytesPerSec = 8000;
-
- /* check for 'RIFF' tag */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag != CHUNK_RIFF)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get size */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* check for 'WAVE' tag */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag != CHUNK_WAVE)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* this is enough to say we recognize the file */
- if (pWaveData == NULL)
- return EAS_SUCCESS;
-
- /* check for streaming mode */
- pWaveData->flags = 0;
- pWaveData->mediaLength = -1;
- pWaveData->infoChunkPos = -1;
- pWaveData->infoChunkSize = -1;
- if (fileSize== FILE_SIZE_STREAMING)
- {
- pWaveData->flags |= PCM_FLAGS_STREAMING;
- fileSize = 0x7fffffff;
- }
-
- /* find out where we're at */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
- return result;
- fileSize -= 4;
-
- parseDone = EAS_FALSE;
- for (;;)
- {
- /* get tag and size for next chunk */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* process chunk */
- pos += 8;
- switch (tag)
- {
- case CHUNK_FMT:
-
-#ifdef MMAPI_SUPPORT
- if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS)
- return result;
-#endif
-
- /* get audio format */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- if (usTemp == WAVE_FORMAT_PCM)
- {
- params.decoder = EAS_DECODER_PCM;
- pWaveData->fileType = EAS_FILE_WAVE_PCM;
- }
- else if (usTemp == WAVE_FORMAT_IMA_ADPCM)
- {
- params.decoder = EAS_DECODER_IMA_ADPCM;
- pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM;
- }
- else
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get number of channels */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- if (usTemp == 2)
- pWaveData->flags |= PCM_FLAGS_STEREO;
- else if (usTemp != 1)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* get sample rate */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &params.sampleRate, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* get stream rate */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* get block alignment */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
- params.blockSize = usTemp;
-
- /* get bits per sample */
- if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* PCM, must be 8 or 16 bit samples */
- if (params.decoder == EAS_DECODER_PCM)
- {
- if (usTemp == 8)
- pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED;
- else if (usTemp != 16)
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
-
- /* for IMA ADPCM, we only support mono 4-bit ADPCM */
- else
- {
- if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO))
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
- }
-
- break;
-
- case CHUNK_DATA:
- audioOffset = pos;
- if (pWaveData->flags & PCM_FLAGS_STREAMING)
- {
- params.size = 0x7fffffff;
- parseDone = EAS_TRUE;
- }
- else
- {
- params.size = (EAS_I32) size;
- params.loopStart = size;
- /* use more accurate method if possible */
- if (size <= (0x7fffffff / 1000))
- pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec);
- else
- pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000));
- }
- break;
-
- case CHUNK_LIST:
- /* get the list type */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if (tag == CHUNK_INFO)
- {
- pWaveData->infoChunkPos = pos + 4;
- pWaveData->infoChunkSize = (EAS_I32) size - 4;
- }
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- if (parseDone)
- break;
-
- /* subtract header size */
- fileSize -= 8;
-
- /* account for zero-padding on odd length chunks */
- if (size & 1)
- size++;
-
- /* this check works for files with odd length last chunk and no zero-pad */
- if (size >= fileSize)
- {
- if (size > fileSize)
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- /* subtract size of data chunk (including any zero-pad) */
- fileSize -= size;
-
- /* seek to next chunk */
- pos += (EAS_I32) size;
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS)
- return result;
- }
-
- /* check for valid header */
- if ((params.sampleRate == 0) || (params.size == 0))
- return EAS_ERROR_UNRECOGNIZED_FORMAT;
-
- /* save the pertinent information */
- pWaveData->audioOffset = audioOffset;
- params.flags = pWaveData->flags;
-
- /* seek to data */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS)
- return result;
-
- /* open a stream in the PCM engine */
- return EAS_PEOpenStream(pEASData, &params, &pWaveData->streamHandle);
-}
-
-/*----------------------------------------------------------------------------
- * WaveGetMetaData()
- *----------------------------------------------------------------------------
- * Purpose:
- * Process the INFO chunk and return metadata to host
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength)
-{
- S_WAVE_STATE *pWaveData;
- EAS_RESULT result;
- EAS_I32 pos;
- EAS_U32 size;
- EAS_I32 infoSize;
- EAS_U32 tag;
- EAS_I32 restorePos;
- E_EAS_METADATA_TYPE metaType;
- EAS_I32 metaLen;
-
- /* get current position so we can restore it */
- pWaveData = (S_WAVE_STATE*) pInstData;
-
- /* return media length */
- *pMediaLength = pWaveData->mediaLength;
-
- /* did we encounter an INFO chunk? */
- if (pWaveData->infoChunkPos < 0)
- return EAS_SUCCESS;
-
- if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS)
- return result;
-
- /* offset to start of first chunk in INFO chunk */
- pos = pWaveData->infoChunkPos;
- infoSize = pWaveData->infoChunkSize;
-
- /* read all the chunks in the INFO chunk */
- for (;;)
- {
-
- /* seek to next chunk */
- if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS)
- return result;
-
- /* get tag and size for next chunk */
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
- return result;
- if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
- return result;
-
- /* process chunk */
- pos += 8;
- metaType = EAS_METADATA_UNKNOWN;
- switch (tag)
- {
- case CHUNK_INAM:
- metaType = EAS_METADATA_TITLE;
- break;
-
- case CHUNK_IART:
- metaType = EAS_METADATA_AUTHOR;
- break;
-
- case CHUNK_ICOP:
- metaType = EAS_METADATA_COPYRIGHT;
- break;
-
- default:
- { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
- (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
- break;
- }
-
- /* process known metadata */
- if (metaType != EAS_METADATA_UNKNOWN)
- {
- metaLen = pWaveData->metadata.bufferSize - 1;
- if (metaLen > (EAS_I32) size)
- metaLen = (EAS_I32) size;
- if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS)
- return result;
- pWaveData->metadata.buffer[metaLen] = 0;
- pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData);
- }
-
- /* subtract this block */
- if (size & 1)
- size++;
- infoSize -= (EAS_I32) size + 8;
- if (infoSize == 0)
- break;
- pos += (EAS_I32) size;
- }
-
-
- /* restore original position */
- return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos);
-}
-
-#ifdef MMAPI_SUPPORT
-/*----------------------------------------------------------------------------
- * SaveFmtChunk()
- *----------------------------------------------------------------------------
- * Purpose:
- * Save the fmt chunk for the MMAPI library
- *----------------------------------------------------------------------------
-*/
-static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize)
-{
- EAS_RESULT result;
- EAS_I32 pos;
- EAS_I32 count;
-
- /* save current file position */
- if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
- return result;
-
- /* allocate a chunk of memory */
- pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize);
- if (!pWaveData->fmtChunk)
- return EAS_ERROR_MALLOC_FAILED;
-
- /* read the fmt chunk into memory */
- if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS)
- return result;
- if (count != fmtSize)
- return EAS_ERROR_FILE_READ_FAILED;
-
- /* restore file position */
- return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos);
-}
-#endif
-
+ *
+ *----------------------------------------------------------------------------
+ * Revision Control:
+ * $Revision: 852 $
+ * $Date: 2007-09-04 11:43:49 -0700 (Tue, 04 Sep 2007) $
+ *----------------------------------------------------------------------------
+*/
+
+#include "eas_data.h"
+#include "eas_report.h"
+#include "eas_host.h"
+#include "eas_config.h"
+#include "eas_parser.h"
+#include "eas_pcm.h"
+#include "eas_wavefile.h"
+
+/* lint is choking on the ARM math.h file, so we declare the log10 function here */
+extern double log10(double x);
+
+/* increase gain to compensate for loss in mixer */
+#define WAVE_GAIN_OFFSET 6
+
+/* constant for 1200 / log10(2.0) */
+#define PITCH_CENTS_CONVERSION 3986.313714
+
+/*----------------------------------------------------------------------------
+ * WAVE file defines
+ *----------------------------------------------------------------------------
+*/
+/* RIFF chunks */
+#define CHUNK_TYPE(a,b,c,d) ( \
+ ( ((EAS_U32)(a) & 0xFF) << 24 ) \
+ + ( ((EAS_U32)(b) & 0xFF) << 16 ) \
+ + ( ((EAS_U32)(c) & 0xFF) << 8 ) \
+ + ( ((EAS_U32)(d) & 0xFF) ) )
+
+#define CHUNK_RIFF CHUNK_TYPE('R','I','F','F')
+#define CHUNK_WAVE CHUNK_TYPE('W','A','V','E')
+#define CHUNK_FMT CHUNK_TYPE('f','m','t',' ')
+#define CHUNK_DATA CHUNK_TYPE('d','a','t','a')
+#define CHUNK_LIST CHUNK_TYPE('L','I','S','T')
+#define CHUNK_INFO CHUNK_TYPE('I','N','F','O')
+#define CHUNK_INAM CHUNK_TYPE('I','N','A','M')
+#define CHUNK_ICOP CHUNK_TYPE('I','C','O','P')
+#define CHUNK_IART CHUNK_TYPE('I','A','R','T')
+
+/* wave file format identifiers */
+#define WAVE_FORMAT_PCM 0x0001
+#define WAVE_FORMAT_IMA_ADPCM 0x0011
+
+/* file size for streamed file */
+#define FILE_SIZE_STREAMING 0x80000000
+
+/*----------------------------------------------------------------------------
+ * prototypes
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset);
+static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState);
+static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate);
+static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData);
+static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value);
+static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue);
+static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData);
+static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength);
+
+#ifdef MMAPI_SUPPORT
+static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 size);
+#endif
+
+/*----------------------------------------------------------------------------
+ *
+ * EAS_Wave_Parser
+ *
+ * This structure contains the functional interface for the Wave file parser
+ *----------------------------------------------------------------------------
+*/
+const S_FILE_PARSER_INTERFACE EAS_Wave_Parser =
+{
+ WaveCheckFileType,
+ WavePrepare,
+ NULL,
+ NULL,
+ WaveState,
+ WaveClose,
+ WaveReset,
+ WavePause,
+ WaveResume,
+ WaveLocate,
+ WaveSetData,
+ WaveGetData,
+ WaveGetMetaData
+};
+
+/*----------------------------------------------------------------------------
+ * WaveCheckFileType()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Check the file type to see if we can parse it
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveCheckFileType (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, EAS_VOID_PTR *pHandle, EAS_I32 offset)
+{
+ S_WAVE_STATE *pWaveData;
+
+ /* zero the memory to insure complete initialization */
+ *pHandle = NULL;
+
+ /* read the file header */
+ if (WaveParseHeader(pEASData, fileHandle, NULL) == EAS_SUCCESS)
+ {
+
+ /* check for static memory allocation */
+ if (pEASData->staticMemoryModel)
+ pWaveData = EAS_CMEnumData(EAS_CM_WAVE_DATA);
+ else
+ pWaveData = EAS_HWMalloc(pEASData->hwInstData, sizeof(S_WAVE_STATE));
+ if (!pWaveData)
+ return EAS_ERROR_MALLOC_FAILED;
+ EAS_HWMemSet(pWaveData, 0, sizeof(S_WAVE_STATE));
+
+ /* return a pointer to the instance data */
+ pWaveData->fileHandle = fileHandle;
+ pWaveData->fileOffset = offset;
+ *pHandle = pWaveData;
+ }
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * WavePrepare()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Prepare to parse the file.
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WavePrepare (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_WAVE_STATE *pWaveData;
+ EAS_RESULT result;
+
+ /* validate parser state */
+ pWaveData = (S_WAVE_STATE*) pInstData;
+ if (pWaveData->streamHandle != NULL)
+ return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
+
+ /* back to start of file */
+ pWaveData->time = 0;
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->fileOffset)) != EAS_SUCCESS)
+ return result;
+
+ /* parse the file header */
+ if ((result = WaveParseHeader(pEASData, pWaveData->fileHandle, pWaveData)) != EAS_SUCCESS)
+ return result;
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveState()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Returns the current state of the stream
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ * pState - pointer to variable to store state
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ * Notes:
+ * This interface is also exposed in the internal library for use by the other modules.
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveState (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_STATE *pState)
+{
+ S_WAVE_STATE *pWaveData;
+
+ /* return current state */
+ pWaveData = (S_WAVE_STATE*) pInstData;
+ if (pWaveData->streamHandle)
+ return EAS_PEState(pEASData, pWaveData->streamHandle, pState);
+
+ /* if no stream handle, and time is not zero, we are done */
+ if (pWaveData->time > 0)
+ *pState = EAS_STATE_STOPPED;
+ else
+ *pState = EAS_STATE_OPEN;
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveClose()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Close the file and clean up
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveClose (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ S_WAVE_STATE *pWaveData;
+ EAS_RESULT result;
+
+ pWaveData = (S_WAVE_STATE*) pInstData;
+
+ /* close the stream */
+ if (pWaveData->streamHandle)
+ {
+ if ((result = EAS_PEClose(pEASData, pWaveData->streamHandle)) != EAS_SUCCESS)
+ return result;
+ pWaveData->streamHandle = NULL;
+ }
+
+ /* if using dynamic memory, free it */
+ if (!pEASData->staticMemoryModel)
+ {
+
+#ifdef MMAPI_SUPPORT
+ /* need to free the fmt chunk */
+ if (pWaveData->fmtChunk != NULL)
+ EAS_HWFree(pEASData->hwInstData, pWaveData->fmtChunk);
+#endif
+
+ /* free the instance data */
+ EAS_HWFree(pEASData->hwInstData, pWaveData);
+
+ }
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveReset()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Reset the sequencer. Used for locating backwards in the file.
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveReset (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ EAS_PCM_HANDLE streamHandle;
+
+ /* reset to first byte of data in the stream */
+ streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
+ if (streamHandle)
+ return EAS_PEReset(pEASData, streamHandle);
+ return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveLocate()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Rewind/fast-forward in file.
+ *
+ * Inputs:
+ * pEASData - pointer to overall EAS data structure
+ * handle - pointer to file handle
+ * time - time (in msecs)
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pParserLocate) reserved for future use */
+static EAS_RESULT WaveLocate (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 time, EAS_BOOL *pParserLocate)
+{
+ EAS_PCM_HANDLE streamHandle;
+
+ /* reset to first byte of data in the stream */
+ streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
+ if (streamHandle)
+ return EAS_PELocate(pEASData, streamHandle, time);
+ return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
+}
+
+/*----------------------------------------------------------------------------
+ * WavePause()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Mute and stop rendering a PCM stream. Sets the gain target to zero and stops the playback
+ * at the end of the next audio frame.
+ *
+ * Inputs:
+ * pEASData - pointer to EAS library instance data
+ * handle - pointer to S_WAVE_STATE for this stream
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pEASData) reserved for future use */
+static EAS_RESULT WavePause (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ EAS_PCM_HANDLE streamHandle;
+
+ /* pause the stream */
+ streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
+ if (streamHandle)
+ return EAS_PEPause(pEASData, streamHandle);
+ return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveResume()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Resume rendering a PCM stream. Sets the gain target back to its
+ * previous setting and restarts playback at the end of the next audio
+ * frame.
+ *
+ * Inputs:
+ * pEASData - pointer to EAS library instance data
+ * handle - pointer to S_WAVE_STATE for this stream
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pEASData) reserved for future use */
+static EAS_RESULT WaveResume (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData)
+{
+ EAS_PCM_HANDLE streamHandle;
+
+ /* resume the stream */
+ streamHandle = ((S_WAVE_STATE*)pInstData)->streamHandle;
+ if (streamHandle)
+ return EAS_PEResume(pEASData, streamHandle);
+ return EAS_ERROR_NOT_VALID_IN_THIS_STATE;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveSetData()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ * Inputs:
+ * pEASData - pointer to EAS library instance data
+ * handle - pointer to S_WAVE_STATE for this stream
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveSetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 value)
+{
+ S_WAVE_STATE *pWaveData = (S_WAVE_STATE*) pInstData;
+
+ switch (param)
+ {
+ /* set metadata callback */
+ case PARSER_DATA_METADATA_CB:
+ EAS_HWMemCpy(&pWaveData->metadata, (void*) value, sizeof(S_METADATA_CB));
+ return EAS_SUCCESS;
+
+ case PARSER_DATA_PLAYBACK_RATE:
+ value = (EAS_I32) (PITCH_CENTS_CONVERSION * log10((double) value / (double) (1 << 28)));
+ return EAS_PEUpdatePitch(pEASData, pWaveData->streamHandle, (EAS_I16) value);
+
+ case PARSER_DATA_VOLUME:
+ return EAS_PEUpdateVolume(pEASData, pWaveData->streamHandle, (EAS_I16) value);
+
+ default:
+ return EAS_ERROR_INVALID_PARAMETER;
+ }
+}
+
+/*----------------------------------------------------------------------------
+ * WaveGetData()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ *
+ * Inputs:
+ * pEASData - pointer to EAS library instance data
+ * handle - pointer to S_WAVE_STATE for this stream
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+/*lint -esym(715, pEASData) reserved for future use */
+static EAS_RESULT WaveGetData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 param, EAS_I32 *pValue)
+{
+ S_WAVE_STATE *pWaveData;
+
+ pWaveData = (S_WAVE_STATE*) pInstData;
+ switch (param)
+ {
+ /* return file type as WAVE */
+ case PARSER_DATA_FILE_TYPE:
+ *pValue = pWaveData->fileType;
+ break;
+
+#ifdef MMAPI_SUPPORT
+ /* return pointer to 'fmt' chunk */
+ case PARSER_DATA_FORMAT:
+ *pValue = (EAS_I32) pWaveData->fmtChunk;
+ break;
+#endif
+
+ case PARSER_DATA_GAIN_OFFSET:
+ *pValue = WAVE_GAIN_OFFSET;
+ break;
+
+ default:
+ return EAS_ERROR_INVALID_PARAMETER;
+ }
+
+ return EAS_SUCCESS;
+}
+
+/*----------------------------------------------------------------------------
+ * WaveParseHeader()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Parse the WAVE file header.
+ *
+ * Inputs:
+ * pEASData - pointer to EAS library instance data
+ * handle - pointer to S_WAVE_STATE for this stream
+ *
+ * Outputs:
+ *
+ *
+ * Side Effects:
+ *
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveParseHeader (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData)
+{
+ S_PCM_OPEN_PARAMS params;
+ EAS_RESULT result;
+ EAS_U32 tag;
+ EAS_U32 fileSize;
+ EAS_U32 size;
+ EAS_I32 pos;
+ EAS_I32 audioOffset;
+ EAS_U16 usTemp;
+ EAS_BOOL parseDone;
+ EAS_U32 avgBytesPerSec;
+
+ /* init some data (and keep lint happy) */
+ params.sampleRate = 0;
+ params.size = 0;
+ audioOffset = 0;
+ params.decoder = 0;
+ params.blockSize = 0;
+ params.pCallbackFunc = NULL;
+ params.cbInstData = NULL;
+ params.loopSamples = 0;
+ params.fileHandle = fileHandle;
+ params.volume = 0x7fff;
+ params.envData = 0;
+ avgBytesPerSec = 8000;
+
+ /* check for 'RIFF' tag */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
+ return result;
+ if (tag != CHUNK_RIFF)
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+
+ /* get size */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &fileSize, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* check for 'WAVE' tag */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
+ return result;
+ if (tag != CHUNK_WAVE)
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+
+ /* this is enough to say we recognize the file */
+ if (pWaveData == NULL)
+ return EAS_SUCCESS;
+
+ /* check for streaming mode */
+ pWaveData->flags = 0;
+ pWaveData->mediaLength = -1;
+ pWaveData->infoChunkPos = -1;
+ pWaveData->infoChunkSize = -1;
+ if (fileSize== FILE_SIZE_STREAMING)
+ {
+ pWaveData->flags |= PCM_FLAGS_STREAMING;
+ fileSize = 0x7fffffff;
+ }
+
+ /* find out where we're at */
+ if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
+ return result;
+ fileSize -= 4;
+
+ parseDone = EAS_FALSE;
+ for (;;)
+ {
+ /* get tag and size for next chunk */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
+ return result;
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* process chunk */
+ pos += 8;
+ switch (tag)
+ {
+ case CHUNK_FMT:
+
+#ifdef MMAPI_SUPPORT
+ if ((result = SaveFmtChunk(pEASData, fileHandle, pWaveData, (EAS_I32) size)) != EAS_SUCCESS)
+ return result;
+#endif
+
+ /* get audio format */
+ if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
+ return result;
+ if (usTemp == WAVE_FORMAT_PCM)
+ {
+ params.decoder = EAS_DECODER_PCM;
+ pWaveData->fileType = EAS_FILE_WAVE_PCM;
+ }
+ else if (usTemp == WAVE_FORMAT_IMA_ADPCM)
+ {
+ params.decoder = EAS_DECODER_IMA_ADPCM;
+ pWaveData->fileType = EAS_FILE_WAVE_IMA_ADPCM;
+ }
+ else
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+
+ /* get number of channels */
+ if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
+ return result;
+ if (usTemp == 2)
+ pWaveData->flags |= PCM_FLAGS_STEREO;
+ else if (usTemp != 1)
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+
+ /* get sample rate */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &params.sampleRate, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* get stream rate */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &avgBytesPerSec, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* get block alignment */
+ if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
+ return result;
+ params.blockSize = usTemp;
+
+ /* get bits per sample */
+ if ((result = EAS_HWGetWord(pEASData->hwInstData, fileHandle, &usTemp, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* PCM, must be 8 or 16 bit samples */
+ if (params.decoder == EAS_DECODER_PCM)
+ {
+ if (usTemp == 8)
+ pWaveData->flags |= PCM_FLAGS_8_BIT | PCM_FLAGS_UNSIGNED;
+ else if (usTemp != 16)
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+ }
+
+ /* for IMA ADPCM, we only support mono 4-bit ADPCM */
+ else
+ {
+ if ((usTemp != 4) || (pWaveData->flags & PCM_FLAGS_STEREO))
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+ }
+
+ break;
+
+ case CHUNK_DATA:
+ audioOffset = pos;
+ if (pWaveData->flags & PCM_FLAGS_STREAMING)
+ {
+ params.size = 0x7fffffff;
+ parseDone = EAS_TRUE;
+ }
+ else
+ {
+ params.size = (EAS_I32) size;
+ params.loopStart = size;
+ /* use more accurate method if possible */
+ if (size <= (0x7fffffff / 1000))
+ pWaveData->mediaLength = (EAS_I32) ((size * 1000) / avgBytesPerSec);
+ else
+ pWaveData->mediaLength = (EAS_I32) (size / (avgBytesPerSec / 1000));
+ }
+ break;
+
+ case CHUNK_LIST:
+ /* get the list type */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
+ return result;
+ if (tag == CHUNK_INFO)
+ {
+ pWaveData->infoChunkPos = pos + 4;
+ pWaveData->infoChunkSize = (EAS_I32) size - 4;
+ }
+ break;
+
+ default:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
+ (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
+ break;
+ }
+
+ if (parseDone)
+ break;
+
+ /* subtract header size */
+ fileSize -= 8;
+
+ /* account for zero-padding on odd length chunks */
+ if (size & 1)
+ size++;
+
+ /* this check works for files with odd length last chunk and no zero-pad */
+ if (size >= fileSize)
+ {
+ if (size > fileSize)
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: '%c%c%c%c' chunk size exceeds length of file or is not zero-padded\n",
+ (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
+ break;
+ }
+
+ /* subtract size of data chunk (including any zero-pad) */
+ fileSize -= size;
+
+ /* seek to next chunk */
+ pos += (EAS_I32) size;
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos)) != EAS_SUCCESS)
+ return result;
+ }
+
+ /* check for valid header */
+ if ((params.sampleRate == 0) || (params.size == 0))
+ return EAS_ERROR_UNRECOGNIZED_FORMAT;
+
+ /* save the pertinent information */
+ pWaveData->audioOffset = audioOffset;
+ params.flags = pWaveData->flags;
+
+ /* seek to data */
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, fileHandle, audioOffset)) != EAS_SUCCESS)
+ return result;
+
+ /* open a stream in the PCM engine */
+ return EAS_PEOpenStream(pEASData, &params, &pWaveData->streamHandle);
+}
+
+/*----------------------------------------------------------------------------
+ * WaveGetMetaData()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Process the INFO chunk and return metadata to host
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT WaveGetMetaData (S_EAS_DATA *pEASData, EAS_VOID_PTR pInstData, EAS_I32 *pMediaLength)
+{
+ S_WAVE_STATE *pWaveData;
+ EAS_RESULT result;
+ EAS_I32 pos;
+ EAS_U32 size;
+ EAS_I32 infoSize;
+ EAS_U32 tag;
+ EAS_I32 restorePos;
+ E_EAS_METADATA_TYPE metaType;
+ EAS_I32 metaLen;
+
+ /* get current position so we can restore it */
+ pWaveData = (S_WAVE_STATE*) pInstData;
+
+ /* return media length */
+ *pMediaLength = pWaveData->mediaLength;
+
+ /* did we encounter an INFO chunk? */
+ if (pWaveData->infoChunkPos < 0)
+ return EAS_SUCCESS;
+
+ if ((result = EAS_HWFilePos(pEASData->hwInstData, pWaveData->fileHandle, &restorePos)) != EAS_SUCCESS)
+ return result;
+
+ /* offset to start of first chunk in INFO chunk */
+ pos = pWaveData->infoChunkPos;
+ infoSize = pWaveData->infoChunkSize;
+
+ /* read all the chunks in the INFO chunk */
+ for (;;)
+ {
+
+ /* seek to next chunk */
+ if ((result = EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, pos)) != EAS_SUCCESS)
+ return result;
+
+ /* get tag and size for next chunk */
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &tag, EAS_TRUE)) != EAS_FALSE)
+ return result;
+ if ((result = EAS_HWGetDWord(pEASData->hwInstData, pWaveData->fileHandle, &size, EAS_FALSE)) != EAS_FALSE)
+ return result;
+
+ /* process chunk */
+ pos += 8;
+ metaType = EAS_METADATA_UNKNOWN;
+ switch (tag)
+ {
+ case CHUNK_INAM:
+ metaType = EAS_METADATA_TITLE;
+ break;
+
+ case CHUNK_IART:
+ metaType = EAS_METADATA_AUTHOR;
+ break;
+
+ case CHUNK_ICOP:
+ metaType = EAS_METADATA_COPYRIGHT;
+ break;
+
+ default:
+ { /* dpp: EAS_ReportEx(_EAS_SEVERITY_INFO, "WaveParseHeader: %c%c%c%c chunk - %d byte(s) ignored\n",
+ (char) (tag >> 24), (char) (tag >> 16), (char) (tag >> 8), (char) tag, size); */ }
+ break;
+ }
+
+ /* process known metadata */
+ if (metaType != EAS_METADATA_UNKNOWN)
+ {
+ metaLen = pWaveData->metadata.bufferSize - 1;
+ if (metaLen > (EAS_I32) size)
+ metaLen = (EAS_I32) size;
+ if ((result = EAS_HWReadFile(pEASData->hwInstData, pWaveData->fileHandle, pWaveData->metadata.buffer, metaLen, &metaLen)) != EAS_SUCCESS)
+ return result;
+ pWaveData->metadata.buffer[metaLen] = 0;
+ pWaveData->metadata.callback(metaType, pWaveData->metadata.buffer, pWaveData->metadata.pUserData);
+ }
+
+ /* subtract this block */
+ if (size & 1)
+ size++;
+ infoSize -= (EAS_I32) size + 8;
+ if (infoSize == 0)
+ break;
+ pos += (EAS_I32) size;
+ }
+
+
+ /* restore original position */
+ return EAS_HWFileSeek(pEASData->hwInstData, pWaveData->fileHandle, restorePos);
+}
+
+#ifdef MMAPI_SUPPORT
+/*----------------------------------------------------------------------------
+ * SaveFmtChunk()
+ *----------------------------------------------------------------------------
+ * Purpose:
+ * Save the fmt chunk for the MMAPI library
+ *----------------------------------------------------------------------------
+*/
+static EAS_RESULT SaveFmtChunk (S_EAS_DATA *pEASData, EAS_FILE_HANDLE fileHandle, S_WAVE_STATE *pWaveData, EAS_I32 fmtSize)
+{
+ EAS_RESULT result;
+ EAS_I32 pos;
+ EAS_I32 count;
+
+ /* save current file position */
+ if ((result = EAS_HWFilePos(pEASData->hwInstData, fileHandle, &pos)) != EAS_SUCCESS)
+ return result;
+
+ /* allocate a chunk of memory */
+ pWaveData->fmtChunk = EAS_HWMalloc(pEASData->hwInstData, fmtSize);
+ if (!pWaveData->fmtChunk)
+ return EAS_ERROR_MALLOC_FAILED;
+
+ /* read the fmt chunk into memory */
+ if ((result = EAS_HWReadFile(pEASData->hwInstData, fileHandle, pWaveData->fmtChunk, fmtSize, &count)) != EAS_SUCCESS)
+ return result;
+ if (count != fmtSize)
+ return EAS_ERROR_FILE_READ_FAILED;
+
+ /* restore file position */
+ return EAS_HWFileSeek(pEASData->hwInstData, fileHandle, pos);
+}
+#endif
+