eas_wave.c revision 7df30109963092559d3760c0661a020f9daf1030
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