| /*---------------------------------------------------------------------------- |
| * |
| * File: |
| * eas_wave.c |
| * |
| * Contents and purpose: |
| * This module contains .WAV file functions for the EAS synthesizer |
| * test harness. |
| * |
| * 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: 658 $ |
| * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ |
| *---------------------------------------------------------------------------- |
| */ |
| |
| /* lint complaints about most C library headers, so we use our own during lint step */ |
| #ifdef _lint |
| #include "lint_stdlib.h" |
| #else |
| #include <stdio.h> |
| #include <stdlib.h> |
| #endif |
| |
| #include "eas_wave.h" |
| |
| /* .WAV file format tags */ |
| const EAS_U32 riffTag = 0x46464952; |
| const EAS_U32 waveTag = 0x45564157; |
| const EAS_U32 fmtTag = 0x20746d66; |
| const EAS_U32 dataTag = 0x61746164; |
| |
| #ifdef _BIG_ENDIAN |
| /*---------------------------------------------------------------------------- |
| * FlipDWord() |
| *---------------------------------------------------------------------------- |
| * Purpose: Endian flip a DWORD for big-endian processors |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| static void FlipDWord (EAS_U32 *pValue) |
| { |
| EAS_U8 *p; |
| EAS_U32 temp; |
| |
| p = (EAS_U8*) pValue; |
| temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; |
| *pValue = temp; |
| } |
| |
| /*---------------------------------------------------------------------------- |
| * FlipWord() |
| *---------------------------------------------------------------------------- |
| * Purpose: Endian flip a WORD for big-endian processors |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| static void FlipWord (EAS_U16 *pValue) |
| { |
| EAS_U8 *p; |
| EAS_U16 temp; |
| |
| p = (EAS_U8*) pValue; |
| temp = (p[1] << 8) | p[0]; |
| *pValue = temp; |
| } |
| |
| /*---------------------------------------------------------------------------- |
| * FlipWaveHeader() |
| *---------------------------------------------------------------------------- |
| * Purpose: Endian flip the wave header for big-endian processors |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| static void FlipWaveHeader (WAVE_HEADER *p) |
| { |
| |
| FlipDWord(&p->nRiffTag); |
| FlipDWord(&p->nRiffSize); |
| FlipDWord(&p->nWaveTag); |
| FlipDWord(&p->nFmtTag); |
| FlipDWord(&p->nFmtSize); |
| FlipDWord(&p->nDataTag); |
| FlipDWord(&p->nDataSize); |
| FlipWord(&p->fc.wFormatTag); |
| FlipWord(&p->fc.nChannels); |
| FlipDWord(&p->fc.nSamplesPerSec); |
| FlipDWord(&p->fc.nAvgBytesPerSec); |
| FlipWord(&p->fc.nBlockAlign); |
| FlipWord(&p->fc.wBitsPerSample); |
| |
| } |
| #endif |
| |
| /*---------------------------------------------------------------------------- |
| * WaveFileCreate() |
| *---------------------------------------------------------------------------- |
| * Purpose: Opens a wave file for writing and writes the header |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) |
| { |
| WAVE_FILE *wFile; |
| |
| /* allocate memory */ |
| wFile = malloc(sizeof(WAVE_FILE)); |
| if (!wFile) |
| return NULL; |
| wFile->write = EAS_TRUE; |
| |
| /* create the file */ |
| wFile->file = fopen(filename,"wb"); |
| if (!wFile->file) |
| { |
| free(wFile); |
| return NULL; |
| } |
| |
| /* initialize PCM format .WAV file header */ |
| wFile->wh.nRiffTag = riffTag; |
| wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; |
| wFile->wh.nWaveTag = waveTag; |
| wFile->wh.nFmtTag = fmtTag; |
| wFile->wh.nFmtSize = sizeof(FMT_CHUNK); |
| |
| /* initalize 'fmt' chunk */ |
| wFile->wh.fc.wFormatTag = 1; |
| wFile->wh.fc.nChannels = (EAS_U16) nChannels; |
| wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; |
| wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; |
| wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); |
| wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; |
| |
| /* initialize 'data' chunk */ |
| wFile->wh.nDataTag = dataTag; |
| wFile->wh.nDataSize = 0; |
| |
| #ifdef _BIG_ENDIAN |
| FlipWaveHeader(&wFile->wh); |
| #endif |
| |
| /* write the header */ |
| if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) |
| { |
| fclose(wFile->file); |
| free(wFile); |
| return NULL; |
| } |
| |
| #ifdef _BIG_ENDIAN |
| FlipWaveHeader(&wFile->wh); |
| #endif |
| |
| /* return the file handle */ |
| return wFile; |
| } /* end WaveFileCreate */ |
| |
| /*---------------------------------------------------------------------------- |
| * WaveFileWrite() |
| *---------------------------------------------------------------------------- |
| * Purpose: Writes data to the wave file |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) |
| { |
| EAS_I32 count; |
| |
| /* make sure we have an open file */ |
| if (wFile == NULL) |
| { |
| return 0; |
| } |
| |
| #ifdef _BIG_ENDIAN |
| { |
| EAS_I32 i; |
| EAS_U16 *p; |
| p = buffer; |
| i = n >> 1; |
| while (i--) |
| FlipWord(p++); |
| } |
| #endif |
| |
| /* write the data */ |
| count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); |
| |
| /* add the number of bytes written */ |
| wFile->wh.nRiffSize += (EAS_U32) count; |
| wFile->wh.nDataSize += (EAS_U32) count; |
| |
| /* return the count of bytes written */ |
| return count; |
| } /* end WriteWaveHeader */ |
| |
| /*---------------------------------------------------------------------------- |
| * WaveFileClose() |
| *---------------------------------------------------------------------------- |
| * Purpose: Opens a wave file for writing and writes the header |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| EAS_BOOL WaveFileClose (WAVE_FILE *wFile) |
| { |
| EAS_I32 count = 1; |
| |
| /* return to beginning of file and write the header */ |
| if (wFile->write) |
| { |
| if (fseek(wFile->file, 0L, SEEK_SET) == 0) |
| { |
| |
| #ifdef _BIG_ENDIAN |
| FlipWaveHeader(&wFile->wh); |
| #endif |
| count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); |
| #ifdef _BIG_ENDIAN |
| FlipWaveHeader(&wFile->wh); |
| #endif |
| } |
| } |
| |
| /* close the file */ |
| if (fclose(wFile->file) != 0) |
| count = 0; |
| |
| /* free the memory */ |
| free(wFile); |
| |
| /* return the file handle */ |
| return (count == 1 ? EAS_TRUE : EAS_FALSE); |
| } /* end WaveFileClose */ |
| |
| #ifdef _WAVE_FILE_READ |
| #ifdef _BIG_ENDIAN |
| #error "WaveFileOpen not currently supported on big-endian processors" |
| #endif |
| /*---------------------------------------------------------------------------- |
| * WaveFileOpen() |
| *---------------------------------------------------------------------------- |
| * Purpose: Opens a wave file for reading and reads the header |
| * |
| * Inputs: |
| * |
| * Outputs: |
| * |
| *---------------------------------------------------------------------------- |
| */ |
| |
| WAVE_FILE *WaveFileOpen (const char *filename) |
| { |
| WAVE_FILE *wFile; |
| struct |
| { |
| EAS_U32 tag; |
| EAS_U32 size; |
| } chunk; |
| EAS_U32 tag; |
| EAS_I32 startChunkPos; |
| EAS_INT state; |
| EAS_BOOL done; |
| |
| /* allocate memory */ |
| wFile = malloc(sizeof(WAVE_FILE)); |
| if (!wFile) |
| return NULL; |
| |
| /* open the file */ |
| wFile->write = EAS_FALSE; |
| wFile->file = fopen(filename,"rb"); |
| if (!wFile->file) |
| { |
| free(wFile); |
| return NULL; |
| } |
| |
| /* make lint happy */ |
| chunk.tag = chunk.size = 0; |
| startChunkPos = 0; |
| |
| /* read the RIFF tag and file size */ |
| state = 0; |
| done = EAS_FALSE; |
| while (!done) |
| { |
| |
| switch(state) |
| { |
| /* read the RIFF tag */ |
| case 0: |
| if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) |
| done = EAS_TRUE; |
| else |
| { |
| if (chunk.tag != riffTag) |
| done = EAS_TRUE; |
| else |
| state++; |
| } |
| break; |
| |
| /* read the WAVE tag */ |
| case 1: |
| if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) |
| done = EAS_TRUE; |
| else |
| { |
| if (tag != waveTag) |
| done = EAS_TRUE; |
| else |
| state++; |
| } |
| break; |
| |
| /* looking for fmt chunk */ |
| case 2: |
| if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) |
| done = EAS_TRUE; |
| else |
| { |
| startChunkPos = ftell(wFile->file); |
| |
| /* not fmt tag, skip it */ |
| if (chunk.tag != fmtTag) |
| fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); |
| else |
| state++; |
| } |
| break; |
| |
| /* read fmt chunk */ |
| case 3: |
| if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) |
| done = EAS_TRUE; |
| else |
| { |
| fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); |
| state++; |
| } |
| break; |
| |
| /* looking for data chunk */ |
| case 4: |
| if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) |
| done = EAS_TRUE; |
| else |
| { |
| startChunkPos = ftell(wFile->file); |
| |
| /* not data tag, skip it */ |
| if (chunk.tag != dataTag) |
| fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); |
| else |
| { |
| wFile->dataSize = chunk.size; |
| state++; |
| done = EAS_TRUE; |
| } |
| } |
| break; |
| |
| default: |
| done = EAS_TRUE; |
| break; |
| } |
| } |
| |
| /* if not final state, an error occurred */ |
| if (state != 5) |
| { |
| fclose(wFile->file); |
| free(wFile); |
| return NULL; |
| } |
| |
| /* return the file handle */ |
| return wFile; |
| } /* end WaveFileOpen */ |
| #endif |
| |
| |
| |