diff options
Diffstat (limited to 'arm-wt-22k/lib_src/eas_wavefile.c')
-rw-r--r-- | arm-wt-22k/lib_src/eas_wavefile.c | 1710 |
1 files changed, 855 insertions, 855 deletions
diff --git a/arm-wt-22k/lib_src/eas_wavefile.c b/arm-wt-22k/lib_src/eas_wavefile.c index d3f3ba0..f24bde2 100644 --- a/arm-wt-22k/lib_src/eas_wavefile.c +++ b/arm-wt-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, ¶ms.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, ¶ms, &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, ¶ms.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, ¶ms, &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 + |