156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * File: 456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * eas_wave.c 556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Contents and purpose: 756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * This module contains .WAV file functions for the EAS synthesizer 856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * test harness. 956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 1056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Copyright Sonic Network Inc. 2005 117df30109963092559d3760c0661a020f9daf1030The Android Open Source Project 127df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Licensed under the Apache License, Version 2.0 (the "License"); 137df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * you may not use this file except in compliance with the License. 147df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * You may obtain a copy of the License at 157df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * 167df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * http://www.apache.org/licenses/LICENSE-2.0 177df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * 187df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * Unless required by applicable law or agreed to in writing, software 197df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * distributed under the License is distributed on an "AS IS" BASIS, 207df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 217df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * See the License for the specific language governing permissions and 227df30109963092559d3760c0661a020f9daf1030The Android Open Source Project * limitations under the License. 2356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 2456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Revision Control: 2556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * $Revision: 658 $ 2656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $ 2756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 2856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 2956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 3056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* lint complaints about most C library headers, so we use our own during lint step */ 3156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _lint 3256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "lint_stdlib.h" 3356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#else 3456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include <stdio.h> 3556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include <stdlib.h> 3656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 3756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 3856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#include "eas_wave.h" 3956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 4056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/* .WAV file format tags */ 4156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst EAS_U32 riffTag = 0x46464952; 4256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst EAS_U32 waveTag = 0x45564157; 4356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst EAS_U32 fmtTag = 0x20746d66; 4456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksconst EAS_U32 dataTag = 0x61746164; 4556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 4656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 4756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 4856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FlipDWord() 4956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 5056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Endian flip a DWORD for big-endian processors 5156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 5256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 5356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 5456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 5556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 5656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 5756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 5856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FlipDWord (EAS_U32 *pValue) 5956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 6056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U8 *p; 6156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U32 temp; 6256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 6356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks p = (EAS_U8*) pValue; 6456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0]; 6556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *pValue = temp; 6656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 6756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 6856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 6956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FlipWord() 7056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 7156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Endian flip a WORD for big-endian processors 7256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 7356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 7456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 7556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 7656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 7756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 7856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 7956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FlipWord (EAS_U16 *pValue) 8056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 8156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U8 *p; 8256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U16 temp; 8356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 8456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks p = (EAS_U8*) pValue; 8556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks temp = (p[1] << 8) | p[0]; 8656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *pValue = temp; 8756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 8856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 8956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 9056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * FlipWaveHeader() 9156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 9256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Endian flip the wave header for big-endian processors 9356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 9456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 9556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 9656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 9756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 9856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 9956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 10056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparksstatic void FlipWaveHeader (WAVE_HEADER *p) 10156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 10256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 10356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nRiffTag); 10456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nRiffSize); 10556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nWaveTag); 10656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nFmtTag); 10756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nFmtSize); 10856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nDataTag); 10956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->nDataSize); 11056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWord(&p->fc.wFormatTag); 11156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWord(&p->fc.nChannels); 11256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->fc.nSamplesPerSec); 11356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipDWord(&p->fc.nAvgBytesPerSec); 11456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWord(&p->fc.nBlockAlign); 11556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWord(&p->fc.wBitsPerSample); 11656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 11756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} 11856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 11956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 12056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 12156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * WaveFileCreate() 12256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 12356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Opens a wave file for writing and writes the header 12456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 12556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 12656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 12756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 12856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 12956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 13056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 13156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 13256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksWAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample) 13356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 13456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks WAVE_FILE *wFile; 13556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 13656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* allocate memory */ 13756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile = malloc(sizeof(WAVE_FILE)); 13856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!wFile) 13956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 14056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->write = EAS_TRUE; 14156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 14256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* create the file */ 14356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->file = fopen(filename,"wb"); 14456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!wFile->file) 14556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 14656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks free(wFile); 14756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 14856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 14956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 15056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* initialize PCM format .WAV file header */ 15156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nRiffTag = riffTag; 15256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8; 15356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nWaveTag = waveTag; 15456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nFmtTag = fmtTag; 15556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nFmtSize = sizeof(FMT_CHUNK); 15656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 15756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* initalize 'fmt' chunk */ 15856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.wFormatTag = 1; 15956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.nChannels = (EAS_U16) nChannels; 16056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec; 16156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample; 16256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8)); 16356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec; 16456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 16556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* initialize 'data' chunk */ 16656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nDataTag = dataTag; 16756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nDataSize = 0; 16856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 16956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 17056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWaveHeader(&wFile->wh); 17156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 17256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 17356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* write the header */ 17456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1) 17556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 17656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fclose(wFile->file); 17756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks free(wFile); 17856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 17956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 18056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 18156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 18256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWaveHeader(&wFile->wh); 18356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 18456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 18556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* return the file handle */ 18656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return wFile; 18756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} /* end WaveFileCreate */ 18856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 18956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 19056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * WaveFileWrite() 19156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 19256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Writes data to the wave file 19356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 19456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 19556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 19656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 19756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 19856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 19956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 20056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n) 20156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 20256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 count; 20356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 20456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* make sure we have an open file */ 20556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (wFile == NULL) 20656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 20756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return 0; 20856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 20956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 21056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 21156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 21256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 i; 21356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U16 *p; 21456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks p = buffer; 21556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks i = n >> 1; 21656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks while (i--) 21756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWord(p++); 21856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 21956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 22056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 22156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* write the data */ 22256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file); 22356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 22456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* add the number of bytes written */ 22556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nRiffSize += (EAS_U32) count; 22656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->wh.nDataSize += (EAS_U32) count; 22756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 22856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* return the count of bytes written */ 22956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return count; 23056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} /* end WriteWaveHeader */ 23156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 23256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 23356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * WaveFileClose() 23456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 23556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Opens a wave file for writing and writes the header 23656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 23756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 23856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 23956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 24056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 24156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 24256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 24356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 24456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksEAS_BOOL WaveFileClose (WAVE_FILE *wFile) 24556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 24656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 count = 1; 24756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 24856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* return to beginning of file and write the header */ 24956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (wFile->write) 25056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 25156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fseek(wFile->file, 0L, SEEK_SET) == 0) 25256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 25356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 25456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 25556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWaveHeader(&wFile->wh); 25656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 25756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file); 25856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 25956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks FlipWaveHeader(&wFile->wh); 26056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 26156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 26256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 26356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 26456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* close the file */ 26556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fclose(wFile->file) != 0) 26656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks count = 0; 26756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 26856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* free the memory */ 26956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks free(wFile); 27056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 27156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* return the file handle */ 27256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return (count == 1 ? EAS_TRUE : EAS_FALSE); 27356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} /* end WaveFileClose */ 27456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 27556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _WAVE_FILE_READ 27656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#ifdef _BIG_ENDIAN 27756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#error "WaveFileOpen not currently supported on big-endian processors" 27856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 27956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks/*---------------------------------------------------------------------------- 28056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * WaveFileOpen() 28156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 28256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Purpose: Opens a wave file for reading and reads the header 28356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 28456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Inputs: 28556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 28656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * Outputs: 28756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks * 28856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks *---------------------------------------------------------------------------- 28956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks*/ 29056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 29156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave SparksWAVE_FILE *WaveFileOpen (const char *filename) 29256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks{ 29356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks WAVE_FILE *wFile; 29456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks struct 29556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 29656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U32 tag; 29756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U32 size; 29856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } chunk; 29956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_U32 tag; 30056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_I32 startChunkPos; 30156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_INT state; 30256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks EAS_BOOL done; 30356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 30456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* allocate memory */ 30556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile = malloc(sizeof(WAVE_FILE)); 30656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!wFile) 30756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 30856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 30956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* open the file */ 31056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->write = EAS_FALSE; 31156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->file = fopen(filename,"rb"); 31256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (!wFile->file) 31356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 31456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks free(wFile); 31556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 31656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 31756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 31856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* make lint happy */ 31956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks chunk.tag = chunk.size = 0; 32056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks startChunkPos = 0; 32156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 32256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* read the RIFF tag and file size */ 32356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state = 0; 32456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_FALSE; 32556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks while (!done) 32656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 32756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 32856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks switch(state) 32956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 33056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* read the RIFF tag */ 33156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 0: 33256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 33356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 33456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 33556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 33656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (chunk.tag != riffTag) 33756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 33856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 33956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state++; 34056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 34156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 34256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 34356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* read the WAVE tag */ 34456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 1: 34556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fread(&tag, sizeof(tag), 1, wFile->file) != 1) 34656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 34756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 34856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 34956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (tag != waveTag) 35056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 35156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 35256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state++; 35356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 35456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 35556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 35656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* looking for fmt chunk */ 35756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 2: 35856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 35956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 36056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 36156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 36256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks startChunkPos = ftell(wFile->file); 36356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 36456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* not fmt tag, skip it */ 36556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (chunk.tag != fmtTag) 36656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 36756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 36856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state++; 36956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 37056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 37156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 37256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* read fmt chunk */ 37356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 3: 37456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1) 37556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 37656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 37756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 37856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 37956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state++; 38056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 38156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 38256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 38356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* looking for data chunk */ 38456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks case 4: 38556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1) 38656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 38756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 38856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 38956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks startChunkPos = ftell(wFile->file); 39056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 39156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* not data tag, skip it */ 39256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (chunk.tag != dataTag) 39356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET); 39456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks else 39556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 39656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks wFile->dataSize = chunk.size; 39756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks state++; 39856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 39956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 40056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 40156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 40256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 40356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks default: 40456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks done = EAS_TRUE; 40556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks break; 40656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 40756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 40856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 40956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* if not final state, an error occurred */ 41056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks if (state != 5) 41156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks { 41256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks fclose(wFile->file); 41356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks free(wFile); 41456c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return NULL; 41556c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks } 41656c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 41756c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks /* return the file handle */ 41856c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks return wFile; 41956c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks} /* end WaveFileOpen */ 42056c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks#endif 42156c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 42256c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 42356c99cd2c2c1e6ab038dac5fced5b92ccf11ff6cDave Sparks 424