1 /*--------------------------------------------------------------------------*
2 Project: Revolution SOUNDFILE dynamic link library
3 File: Wavfile.c
4
5 Copyright (C)2001-2009 Nintendo All Rights Reserved.
6
7 These coded instructions, statements, and computer programs contain
8 proprietary information of Nintendo of America Inc. and/or Nintendo
9 Company Ltd., and are protected by Federal copyright law. They may
10 not be disclosed to third parties or copied or duplicated in any form,
11 in whole or in part, without the prior written consent of Nintendo.
12
13 $Log: Wavfile.c,v $
14 Revision 1.4 2009/03/31 00:16:45 aka
15 Copied from SDK_3_2_DEV_BRANCH.
16
17 Revision 1.2.40.2 2009/03/31 00:14:43 aka
18 Revised CVS log.
19
20 Revision 1.2.40.1 2009/03/30 04:39:30 aka
21 Added supporting a wav file with loop information.
22 Cleaned up.
23
24 Revision 1.2 2006/02/09 06:51:39 aka
25 Changed copyright.
26
27 *--------------------------------------------------------------------------*/
28
29 #include <stdio.h>
30 #include <stdlib.h>
31 #include "Wavfile.h"
32
33
34 u32 * str_riff = (u32 *)"RIFF";
35 u32 * str_wave = (u32 *)"WAVE";
36 u32 * str_fmt = (u32 *)"fmt ";
37 u32 * str_data = (u32 *)"data";
38 u32 * str_smpl = (u32 *)"smpl";
39
40
41 /*---------------------------------------------------------------------------*
42 Name: wavCreateHeader
43
44 Description: create a Wave file header.
45
46 Arguments: wc pointer of a WAVECHUNK structure.
47 channels num of channels.
48 samples num of samples.
49 bitPerSample bit width per a sample.
50 sampleRate sampling frequency.
51 loopEnd end samlpe number of a loop.
52
53 Returns: none.
54 *---------------------------------------------------------------------------*/
55
wavCreateHeader(WAVECHUNK * wc,int channels,int samples,int bitsPerSample,int sampleRate,int loopEnd)56 void wavCreateHeader
57 (
58 WAVECHUNK *wc,
59 int channels,
60 int samples,
61 int bitsPerSample,
62 int sampleRate,
63 int loopEnd
64 )
65 {
66 u32 datasize, riffchunksize;
67 u16 blocksize;
68
69 *((u32*)(wc->chunkId)) = *str_riff;
70 *((u32*)(wc->formType)) = *str_wave;
71 *((u32*)(wc->fmt.chunkId)) = *str_fmt;
72 *((u32*)(wc->data.chunkId)) = *str_data;
73
74 blocksize = channels * ( bitsPerSample / 8 );
75 datasize = blocksize * samples;
76 riffchunksize = datasize + 36;
77
78 if (loopEnd)
79 {
80 riffchunksize += sizeof(SMPLCHUNK) + sizeof(SMPLLOOP);
81 }
82
83 wc->chunkSize = riffchunksize;
84
85 wc->fmt.chunkSize = 16;
86 wc->fmt.waveFormatType = 1;
87 wc->fmt.channel = channels;
88 wc->fmt.samplesPerSec = sampleRate;
89 wc->fmt.bytesPerSec = sampleRate * blocksize;
90 wc->fmt.blockSize = blocksize;
91 wc->fmt.bitsPerSample = bitsPerSample;
92
93 wc->data.chunkSize = datasize;
94
95 return;
96 }
97
98
99 /*---------------------------------------------------------------------------*
100 Name: wavWriteHeader
101
102 Description: output a Wave file header.
103
104 Arguments: wc pointer of a WAVECHUNK structure.
105 outfile pointer of a FILE object.
106
107 Returns: none.
108 *---------------------------------------------------------------------------*/
109
wavWriteHeader(WAVECHUNK * wc,FILE * outfile)110 void wavWriteHeader
111 (
112 WAVECHUNK *wc,
113 FILE *outfile
114 )
115 {
116 fwrite(wc, 1, sizeof(WAVECHUNK), outfile);
117
118 return;
119 }
120
121
122 /*---------------------------------------------------------------------------*
123 Name: wavCreateSmplChunk
124
125 Description: create a SMPL chunk.
126
127 Arguments: wc pointer of a WAVECHUNK structure.
128 sc pointer of a SMPLCHUNK structure.
129 sl pointer of a SMPLLOOP structure.
130 loopStart position of loop start
131 loopEnd position of loop end
132
133 Returns: none.
134 *---------------------------------------------------------------------------*/
135
wavCreateSmplChunk(WAVECHUNK * wc,SMPLCHUNK * sc,SMPLLOOP * sl,u32 loopStart,u32 loopEnd)136 void wavCreateSmplChunk
137 (
138 WAVECHUNK *wc,
139 SMPLCHUNK *sc,
140 SMPLLOOP *sl,
141 u32 loopStart,
142 u32 loopEnd
143 )
144 {
145 *((u32*)(sc->chunkId)) = *str_smpl;
146
147 sc->chunkSize = sizeof(SMPLCHUNK) + sizeof(SMPLLOOP) - 8;
148 sc->manufacturer = 0; // (ignore)
149 sc->product = 0; // (ignore)
150 sc->samplePeriod = 0; // (ignore)
151 sc->midiUnityNote = 0; // (ignore)
152 sc->midiPitchFraction = 0; // (ignore)
153 sc->smpteFormat = 0; // (ignore)
154 sc->smpteOffset = 0; // (ignore)
155 sc->sampleLoops = 1; // only 1 loop
156 sc->samplerData = 0; // (ignore)
157
158 sl->id = 0; // (ignore)
159 sl->type = 0; // forward loop
160 sl->start = loopStart; // loop start
161 sl->end = loopEnd - 1; // loop end
162 sl->fraction = 0; // (ignore)
163 sl->playCount = 0; // infinte loop
164 }
165
166
167 /*---------------------------------------------------------------------------*
168 Name: wavWriteSmplChunk
169
170 Description: output a SMPL chunk.
171
172 Arguments: sc pointer of a SMPLCHUNK structure.
173 sl pointer of a SMPLLOOP structure.
174 outfile pointer of a FILE object.
175
176 Returns: none.
177 *---------------------------------------------------------------------------*/
178
wavWriteSmplChunk(SMPLCHUNK * sc,SMPLLOOP * sl,FILE * outfile)179 void wavWriteSmplChunk(SMPLCHUNK *sc, SMPLLOOP *sl, FILE *outfile)
180 {
181 fwrite(sc, 1, sizeof(SMPLCHUNK), outfile);
182 fwrite(sl, 1, sizeof(SMPLLOOP), outfile);
183 }
184
185
186 /*---------------------------------------------------------------------------*
187 Name: wavReadHeader
188
189 Description: get & parse a Wave file header.
190
191 Arguments: wc pointer of a WAVECHUNK structure.
192 li pointer of a LOOPINFO structure.
193 infile pointer of a FILE object.
194
195 Returns: TRUE OK.
196 FALSE invalid file.
197 *---------------------------------------------------------------------------*/
198
wavReadHeader(WAVECHUNK * wc,LOOPINFO * li,FILE * infile)199 int wavReadHeader
200 (
201 WAVECHUNK *wc,
202 LOOPINFO *li,
203 FILE *infile
204 )
205 {
206 u32 d, riffchunksize, size;
207 int state;
208 int remaining;
209 int top;
210 SMPLCHUNK smpl;
211 SMPLLOOP loop;
212
213 state = 0;
214
215 if (0 != fseek(infile, 0, SEEK_SET))
216 {
217 return FALSE;
218 }
219
220 // check chunk ID = "RIFF"
221 fread(&d, 1, sizeof(u32), infile);
222
223 if (d != *str_riff)
224 {
225 return FALSE;
226 }
227
228 *(u32*)(wc->chunkId) = d;
229
230 // get chunk size
231 fread(&riffchunksize, 1, sizeof(u32), infile);
232 wc->chunkSize = riffchunksize;
233
234 // check RIFF type = "WAVE"
235 fread(&d, 1, sizeof(u32), infile);
236
237 if (d != *str_wave)
238 {
239 return FALSE;
240 }
241
242 *(u32*)(wc->formType) = d;
243
244 riffchunksize -= 4;
245
246 // check chunks
247 while (riffchunksize > 8)
248 {
249 // get chunk ID
250 fread(&d, 1, sizeof(u32), infile);
251
252 // get chunk size
253 fread(&size, 1, sizeof(u32), infile);
254
255 // check chunk ID
256 if (d == *str_fmt)
257 {
258 // fmt chunk
259
260 *(u32*)(wc->fmt.chunkId) = d;
261 wc->fmt.chunkSize = size;
262
263 state++;
264
265 fread(&wc->fmt.waveFormatType, 1, sizeof(FMTCHUNK) - 8, infile);
266
267 remaining = size - (sizeof(FMTCHUNK) - 8);
268
269 if (remaining > 0)
270 {
271 fseek(infile, remaining, SEEK_CUR);
272 }
273 }
274
275 else if (d == *str_data)
276 {
277 // data chunk
278
279 *(u32*)(wc->data.chunkId) = d;
280 wc->data.chunkSize = size;
281
282 state++;
283 top = ftell(infile);
284
285 fseek(infile, size, SEEK_CUR);
286 }
287
288 else if (d == *str_smpl)
289 {
290 // smpl chunk
291
292 fread(&smpl.manufacturer, 1, sizeof(SMPLCHUNK) - 8, infile);
293
294 remaining = size - (sizeof(SMPLCHUNK) - 8);
295
296 if (smpl.sampleLoops)
297 {
298 fread(&loop, 1, sizeof(SMPLLOOP), infile);
299
300 remaining -= sizeof(SMPLLOOP);
301 }
302
303 if (remaining > 0)
304 {
305 fseek(infile, remaining, SEEK_CUR);
306 }
307 }
308
309 else
310 {
311 // other chunks
312
313 fseek(infile, size, SEEK_CUR);
314 }
315
316 riffchunksize -= (2 * sizeof(u32)) + size;
317 }
318
319 if (riffchunksize < 0)
320 {
321 return FALSE;
322 }
323
324 if (state != 2)
325 {
326 return FALSE;
327 }
328
329 // fill LOOPINFO
330 li->start = 0;
331 li->end = 0;
332 if (smpl.sampleLoops && !loop.type)
333 {
334 li->start = loop.start;
335 li->end = loop.end + 1; // adjust to AIFF
336 }
337
338 // return to the top of samples
339 fseek(infile, top, SEEK_SET);
340
341 return TRUE;
342 }
343
344
345 /*---------------------------------------------------------------------------*
346 Name: wavGetSamples
347
348 Description: return num of samples.
349
350 Arguments: wc pointer of a WAVECHUNK structure.
351
352 Returns: num of samples.
353 *---------------------------------------------------------------------------*/
354
wavGetSamples(WAVECHUNK * wc)355 u32 wavGetSamples(WAVECHUNK *wc)
356 {
357 u32 a, bps;
358
359 bps = wc->fmt.channel * wc->fmt.bitsPerSample / 8;
360 a = wc->data.chunkSize / bps;
361
362 return a;
363 }
364
365
366 /*---------------------------------------------------------------------------*
367 Name: wavGetChannels
368
369 Description: return num of channels.
370
371 Arguments: wc pointer of a WAVECHUNK structure.
372
373 Returns: num of channels.
374 *---------------------------------------------------------------------------*/
375
wavGetChannels(WAVECHUNK * wc)376 u32 wavGetChannels(WAVECHUNK *wc)
377 {
378 return (u32)wc->fmt.channel;
379 }
380
381
382 /*---------------------------------------------------------------------------*
383 Name: wavGetBitsPerSample
384
385 Description: return bit width per a sample.
386
387 Arguments: wc pointer of a WAVECHUNK structure.
388
389 Returns: bit width per a sample.
390 *---------------------------------------------------------------------------*/
391
wavGetBitsPerSample(WAVECHUNK * wc)392 u32 wavGetBitsPerSample(WAVECHUNK *wc)
393 {
394 return (u32)wc->fmt.bitsPerSample;
395 }
396
397
398 /*---------------------------------------------------------------------------*
399 Name: wavGetSampleRate
400
401 Description: return num of samples per 1 sec.
402
403 Arguments: wc pointer of a WAVECHUNK structure.
404
405 Returns: num of samples per sec.
406 *---------------------------------------------------------------------------*/
407
wavGetSampleRate(WAVECHUNK * wc)408 u32 wavGetSampleRate(WAVECHUNK *wc)
409 {
410 return (u32)wc->fmt.samplesPerSec;
411 }
412