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