1 /*----------------------------------------------------------------------------
2  *
3  * File:
4  * eas_wave.c
5  *
6  * Contents and purpose:
7  * This module contains .WAV file functions for the EAS synthesizer
8  * test harness.
9  *
10  * Copyright Sonic Network Inc. 2005
11 
12  * Licensed under the Apache License, Version 2.0 (the "License");
13  * you may not use this file except in compliance with the License.
14  * You may obtain a copy of the License at
15  *
16  *      http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  *----------------------------------------------------------------------------
24  * Revision Control:
25  *   $Revision: 658 $
26  *   $Date: 2007-04-24 13:35:49 -0700 (Tue, 24 Apr 2007) $
27  *----------------------------------------------------------------------------
28 */
29 
30 /* lint complaints about most C library headers, so we use our own during lint step */
31 #ifdef _lint
32 #include "lint_stdlib.h"
33 #else
34 #include <stdio.h>
35 #include <stdlib.h>
36 #endif
37 
38 #include "eas_wave.h"
39 
40 /* .WAV file format tags */
41 const EAS_U32 riffTag = 0x46464952;
42 const EAS_U32 waveTag = 0x45564157;
43 const EAS_U32 fmtTag = 0x20746d66;
44 const EAS_U32 dataTag = 0x61746164;
45 
46 #ifdef _BIG_ENDIAN
47 /*----------------------------------------------------------------------------
48  * FlipDWord()
49  *----------------------------------------------------------------------------
50  * Purpose: Endian flip a DWORD for big-endian processors
51  *
52  * Inputs:
53  *
54  * Outputs:
55  *
56  *----------------------------------------------------------------------------
57 */
FlipDWord(EAS_U32 * pValue)58 static void FlipDWord (EAS_U32 *pValue)
59 {
60     EAS_U8 *p;
61     EAS_U32 temp;
62 
63     p = (EAS_U8*) pValue;
64     temp = (((((p[3] << 8) | p[2]) << 8) | p[1]) << 8) | p[0];
65     *pValue = temp;
66 }
67 
68 /*----------------------------------------------------------------------------
69  * FlipWord()
70  *----------------------------------------------------------------------------
71  * Purpose: Endian flip a WORD for big-endian processors
72  *
73  * Inputs:
74  *
75  * Outputs:
76  *
77  *----------------------------------------------------------------------------
78 */
FlipWord(EAS_U16 * pValue)79 static void FlipWord (EAS_U16 *pValue)
80 {
81     EAS_U8 *p;
82     EAS_U16 temp;
83 
84     p = (EAS_U8*) pValue;
85     temp = (p[1] << 8) | p[0];
86     *pValue = temp;
87 }
88 
89 /*----------------------------------------------------------------------------
90  * FlipWaveHeader()
91  *----------------------------------------------------------------------------
92  * Purpose: Endian flip the wave header for big-endian processors
93  *
94  * Inputs:
95  *
96  * Outputs:
97  *
98  *----------------------------------------------------------------------------
99 */
FlipWaveHeader(WAVE_HEADER * p)100 static void FlipWaveHeader (WAVE_HEADER *p)
101 {
102 
103     FlipDWord(&p->nRiffTag);
104     FlipDWord(&p->nRiffSize);
105     FlipDWord(&p->nWaveTag);
106     FlipDWord(&p->nFmtTag);
107     FlipDWord(&p->nFmtSize);
108     FlipDWord(&p->nDataTag);
109     FlipDWord(&p->nDataSize);
110     FlipWord(&p->fc.wFormatTag);
111     FlipWord(&p->fc.nChannels);
112     FlipDWord(&p->fc.nSamplesPerSec);
113     FlipDWord(&p->fc.nAvgBytesPerSec);
114     FlipWord(&p->fc.nBlockAlign);
115     FlipWord(&p->fc.wBitsPerSample);
116 
117 }
118 #endif
119 
120 /*----------------------------------------------------------------------------
121  * WaveFileCreate()
122  *----------------------------------------------------------------------------
123  * Purpose: Opens a wave file for writing and writes the header
124  *
125  * Inputs:
126  *
127  * Outputs:
128  *
129  *----------------------------------------------------------------------------
130 */
131 
WaveFileCreate(const char * filename,EAS_I32 nChannels,EAS_I32 nSamplesPerSec,EAS_I32 wBitsPerSample)132 WAVE_FILE *WaveFileCreate (const char *filename, EAS_I32 nChannels, EAS_I32 nSamplesPerSec, EAS_I32 wBitsPerSample)
133 {
134     WAVE_FILE *wFile;
135 
136     /* allocate memory */
137     wFile = malloc(sizeof(WAVE_FILE));
138     if (!wFile)
139         return NULL;
140     wFile->write = EAS_TRUE;
141 
142     /* create the file */
143     wFile->file = fopen(filename,"wb");
144     if (!wFile->file)
145     {
146         free(wFile);
147         return NULL;
148     }
149 
150     /* initialize PCM format .WAV file header */
151     wFile->wh.nRiffTag = riffTag;
152     wFile->wh.nRiffSize = sizeof(WAVE_HEADER) - 8;
153     wFile->wh.nWaveTag = waveTag;
154     wFile->wh.nFmtTag = fmtTag;
155     wFile->wh.nFmtSize = sizeof(FMT_CHUNK);
156 
157     /* initalize 'fmt' chunk */
158     wFile->wh.fc.wFormatTag = 1;
159     wFile->wh.fc.nChannels = (EAS_U16) nChannels;
160     wFile->wh.fc.nSamplesPerSec = (EAS_U32) nSamplesPerSec;
161     wFile->wh.fc.wBitsPerSample = (EAS_U16) wBitsPerSample;
162     wFile->wh.fc.nBlockAlign = (EAS_U16) (nChannels * (EAS_U16) (wBitsPerSample / 8));
163     wFile->wh.fc.nAvgBytesPerSec = wFile->wh.fc.nBlockAlign * (EAS_U32) nSamplesPerSec;
164 
165     /* initialize 'data' chunk */
166     wFile->wh.nDataTag = dataTag;
167     wFile->wh.nDataSize = 0;
168 
169 #ifdef _BIG_ENDIAN
170     FlipWaveHeader(&wFile->wh);
171 #endif
172 
173     /* write the header */
174     if (fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file) != 1)
175     {
176         fclose(wFile->file);
177         free(wFile);
178         return NULL;
179     }
180 
181 #ifdef _BIG_ENDIAN
182     FlipWaveHeader(&wFile->wh);
183 #endif
184 
185     /* return the file handle */
186     return wFile;
187 } /* end WaveFileCreate */
188 
189 /*----------------------------------------------------------------------------
190  * WaveFileWrite()
191  *----------------------------------------------------------------------------
192  * Purpose: Writes data to the wave file
193  *
194  * Inputs:
195  *
196  * Outputs:
197  *
198  *----------------------------------------------------------------------------
199 */
WaveFileWrite(WAVE_FILE * wFile,void * buffer,EAS_I32 n)200 EAS_I32 WaveFileWrite (WAVE_FILE *wFile, void *buffer, EAS_I32 n)
201 {
202     EAS_I32 count;
203 
204     /* make sure we have an open file */
205     if (wFile == NULL)
206     {
207         return 0;
208     }
209 
210 #ifdef _BIG_ENDIAN
211     {
212         EAS_I32 i;
213         EAS_U16 *p;
214         p = buffer;
215         i = n >> 1;
216         while (i--)
217             FlipWord(p++);
218     }
219 #endif
220 
221     /* write the data */
222     count = (EAS_I32) fwrite(buffer, 1, (size_t) n, wFile->file);
223 
224     /* add the number of bytes written */
225     wFile->wh.nRiffSize += (EAS_U32) count;
226     wFile->wh.nDataSize += (EAS_U32) count;
227 
228     /* return the count of bytes written */
229     return count;
230 } /* end WriteWaveHeader */
231 
232 /*----------------------------------------------------------------------------
233  * WaveFileClose()
234  *----------------------------------------------------------------------------
235  * Purpose: Opens a wave file for writing and writes the header
236  *
237  * Inputs:
238  *
239  * Outputs:
240  *
241  *----------------------------------------------------------------------------
242 */
243 
WaveFileClose(WAVE_FILE * wFile)244 EAS_BOOL WaveFileClose (WAVE_FILE *wFile)
245 {
246     EAS_I32 count = 1;
247 
248     /* return to beginning of file and write the header */
249     if (wFile->write)
250     {
251         if (fseek(wFile->file, 0L, SEEK_SET) == 0)
252         {
253 
254 #ifdef _BIG_ENDIAN
255             FlipWaveHeader(&wFile->wh);
256 #endif
257             count = (EAS_I32) fwrite(&wFile->wh, sizeof(WAVE_HEADER), 1, wFile->file);
258 #ifdef _BIG_ENDIAN
259             FlipWaveHeader(&wFile->wh);
260 #endif
261         }
262     }
263 
264     /* close the file */
265     if (fclose(wFile->file) != 0)
266         count = 0;
267 
268     /* free the memory */
269     free(wFile);
270 
271     /* return the file handle */
272     return (count == 1 ? EAS_TRUE : EAS_FALSE);
273 } /* end WaveFileClose */
274 
275 #ifdef _WAVE_FILE_READ
276 #ifdef _BIG_ENDIAN
277 #error "WaveFileOpen not currently supported on big-endian processors"
278 #endif
279 /*----------------------------------------------------------------------------
280  * WaveFileOpen()
281  *----------------------------------------------------------------------------
282  * Purpose: Opens a wave file for reading and reads the header
283  *
284  * Inputs:
285  *
286  * Outputs:
287  *
288  *----------------------------------------------------------------------------
289 */
290 
WaveFileOpen(const char * filename)291 WAVE_FILE *WaveFileOpen (const char *filename)
292 {
293     WAVE_FILE *wFile;
294     struct
295     {
296         EAS_U32 tag;
297         EAS_U32 size;
298     } chunk;
299     EAS_U32 tag;
300     EAS_I32 startChunkPos;
301     EAS_INT state;
302     EAS_BOOL done;
303 
304     /* allocate memory */
305     wFile = malloc(sizeof(WAVE_FILE));
306     if (!wFile)
307         return NULL;
308 
309     /* open the file */
310     wFile->write = EAS_FALSE;
311     wFile->file = fopen(filename,"rb");
312     if (!wFile->file)
313     {
314         free(wFile);
315         return NULL;
316     }
317 
318     /* make lint happy */
319     chunk.tag = chunk.size = 0;
320     startChunkPos = 0;
321 
322     /* read the RIFF tag and file size */
323     state = 0;
324     done = EAS_FALSE;
325     while (!done)
326     {
327 
328         switch(state)
329         {
330             /* read the RIFF tag */
331             case 0:
332                 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
333                     done = EAS_TRUE;
334                 else
335                 {
336                     if (chunk.tag != riffTag)
337                         done = EAS_TRUE;
338                     else
339                         state++;
340                 }
341                 break;
342 
343             /* read the WAVE tag */
344             case 1:
345                 if (fread(&tag, sizeof(tag), 1, wFile->file) != 1)
346                     done = EAS_TRUE;
347                 else
348                 {
349                     if (tag != waveTag)
350                         done = EAS_TRUE;
351                     else
352                         state++;
353                 }
354                 break;
355 
356             /* looking for fmt chunk */
357             case 2:
358                 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
359                     done = EAS_TRUE;
360                 else
361                 {
362                     startChunkPos = ftell(wFile->file);
363 
364                     /* not fmt tag, skip it */
365                     if (chunk.tag != fmtTag)
366                         fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
367                     else
368                         state++;
369                 }
370                 break;
371 
372             /* read fmt chunk */
373             case 3:
374                 if (fread(&wFile->wh.fc, sizeof(FMT_CHUNK), 1, wFile->file) != 1)
375                     done = EAS_TRUE;
376                 else
377                 {
378                     fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
379                     state++;
380                 }
381                 break;
382 
383             /* looking for data chunk */
384             case 4:
385                 if (fread(&chunk, sizeof(chunk), 1, wFile->file) != 1)
386                     done = EAS_TRUE;
387                 else
388                 {
389                     startChunkPos = ftell(wFile->file);
390 
391                     /* not data tag, skip it */
392                     if (chunk.tag != dataTag)
393                         fseek(wFile->file, startChunkPos + (EAS_I32) chunk.size, SEEK_SET);
394                     else
395                     {
396                         wFile->dataSize = chunk.size;
397                         state++;
398                         done = EAS_TRUE;
399                     }
400                 }
401                 break;
402 
403             default:
404                 done = EAS_TRUE;
405                 break;
406         }
407     }
408 
409     /* if not final state, an error occurred */
410     if (state != 5)
411     {
412         fclose(wFile->file);
413         free(wFile);
414         return NULL;
415     }
416 
417     /* return the file handle */
418     return wFile;
419 } /* end WaveFileOpen */
420 #endif
421 
422 
423 
424