eas_wave.c revision 56c99cd2c2c1e6ab038dac5fced5b92ccf11ff6c
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 */
41const EAS_U32 riffTag = 0x46464952;
42const EAS_U32 waveTag = 0x45564157;
43const EAS_U32 fmtTag = 0x20746d66;
44const 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*/
58static 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*/
79static 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*/
100static 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
132WAVE_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*/
200EAS_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
244EAS_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
291WAVE_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