/*---------------------------------------------------------------------------- * * 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. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. * *---------------------------------------------------------------------------- * Revision Control: * $Revision: 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