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