1 /* Copyright (C) 2002 Jean-Marc Valin
2    File: wav_io.c
3    Routines to handle wav (RIFF) headers
4 
5    Redistribution and use in source and binary forms, with or without
6    modification, are permitted provided that the following conditions
7    are met:
8 
9    - Redistributions of source code must retain the above copyright
10    notice, this list of conditions and the following disclaimer.
11 
12    - Redistributions in binary form must reproduce the above copyright
13    notice, this list of conditions and the following disclaimer in the
14    documentation and/or other materials provided with the distribution.
15 
16    - Neither the name of the Xiph.org Foundation nor the names of its
17    contributors may be used to endorse or promote products derived from
18    this software without specific prior written permission.
19 
20    THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21    ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22    LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23    A PARTICULAR PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR
24    CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL,
25    EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO,
26    PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
27    PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
28    LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
29    NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS
30    SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31 */
32 
33 #ifdef HAVE_CONFIG_H
34 # include "config.h"
35 #endif
36 
37 #include <stdio.h>
38 #include <string.h>
39 #include "celt_types.h"
40 #include "wav_io.h"
41 
42 
read_wav_header(FILE * file,int * rate,int * channels,int * format,celt_int32 * size)43 int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32 *size)
44 {
45    char ch[5];
46    celt_int32 itmp;
47    celt_int16 stmp;
48    celt_int32 bpersec;
49    celt_int16 balign;
50    int skip_bytes;
51    int i;
52 
53    ch[4]=0;
54 #if 0
55    fread(ch, 1, 4, file);
56    if (strcmp(ch, "RIFF")!=0)
57    {
58       fseek(file, 0, SEEK_SET);
59       return 0;
60    }
61 
62    fread(&itmp, 4, 1, file);
63    *size = le_int(itmp-36);
64 
65    fread(ch, 1, 4, file);
66    if (strcmp(ch, "WAVE")!=0)
67    {
68       fprintf (stderr, "RIFF file is not a WAVE file\n");
69       return -1;
70    }
71 #endif
72    fread(ch, 1, 4, file);
73    while (strcmp(ch, "fmt ")!=0)
74    {
75       fread(&itmp, 4, 1, file);
76       itmp = le_int(itmp);
77       /*fprintf (stderr, "skip=%d\n", itmp);*/
78       /*strange way of seeking, but it works even for pipes*/
79       for (i=0;i<itmp;i++)
80          fgetc(file);
81       /*fseek(file, itmp, SEEK_CUR);*/
82       fread(ch, 1, 4, file);
83       if (feof(file))
84       {
85          fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n");
86          return -1;
87       }
88    }
89    /*if (strcmp(ch, "fmt ")!=0)
90    {
91       fprintf (stderr, "Corrupted WAVE file: no \"fmt \"\n");
92       return -1;
93       }*/
94 
95    fread(&itmp, 4, 1, file);
96    itmp = le_int(itmp);
97    skip_bytes=itmp-16;
98    /*fprintf (stderr, "skip=%d\n", skip_bytes);*/
99 
100    fread(&stmp, 2, 1, file);
101    stmp = le_short(stmp);
102    if (stmp!=1)
103    {
104       fprintf (stderr, "Only PCM encoding is supported\n");
105       return -1;
106    }
107 
108    fread(&stmp, 2, 1, file);
109    stmp = le_short(stmp);
110    *channels = stmp;
111 
112    if (stmp>2)
113    {
114       fprintf (stderr, "Only mono and (intensity) stereo supported\n");
115       return -1;
116    }
117 
118    fread(&itmp, 4, 1, file);
119    itmp = le_int(itmp);
120    *rate = itmp;
121 
122    fread(&itmp, 4, 1, file);
123    bpersec = le_int(itmp);
124 
125    fread(&stmp, 2, 1, file);
126    balign = le_short(stmp);
127 
128    fread(&stmp, 2, 1, file);
129    stmp = le_short(stmp);
130    if (stmp!=16 && stmp!=8)
131    {
132       fprintf (stderr, "Only 8/16-bit linear supported\n");
133       return -1;
134    }
135    *format=stmp;
136 
137    if (bpersec!=*rate**channels*stmp/8)
138    {
139       fprintf (stderr, "Corrupted header: ByteRate mismatch\n");
140       return -1;
141    }
142 
143    if (balign!=*channels*stmp/8)
144    {
145       fprintf (stderr, "Corrupted header: BlockAlign mismatch\n");
146       return -1;
147    }
148 
149 
150    /*strange way of seeking, but it works even for pipes*/
151    if (skip_bytes>0)
152       for (i=0;i<skip_bytes;i++)
153          fgetc(file);
154 
155    /*fseek(file, skip_bytes, SEEK_CUR);*/
156 
157    fread(ch, 1, 4, file);
158    while (strcmp(ch, "data")!=0)
159    {
160       fread(&itmp, 4, 1, file);
161       itmp = le_int(itmp);
162       /*strange way of seeking, but it works even for pipes*/
163       for (i=0;i<itmp;i++)
164          fgetc(file);
165       /*fseek(file, itmp, SEEK_CUR);*/
166       fread(ch, 1, 4, file);
167       if (feof(file))
168       {
169          fprintf (stderr, "Corrupted WAVE file: no \"data\"\n");
170          return -1;
171       }
172    }
173 
174    /*Ignore this for now*/
175    fread(&itmp, 4, 1, file);
176    itmp = le_int(itmp);
177 
178    *size=itmp;
179 
180    return 1;
181 }
182 
183 
184 
write_wav_header(FILE * file,int rate,int channels,int format,int size)185 void write_wav_header(FILE *file, int rate, int channels, int format, int size)
186 {
187    char ch[5];
188    celt_int32 itmp;
189    celt_int16 stmp;
190 
191    ch[4]=0;
192 
193    fprintf (file, "RIFF");
194 
195    itmp = 0x7fffffff;
196    fwrite(&itmp, 4, 1, file);
197 
198    fprintf (file, "WAVEfmt ");
199 
200    itmp = le_int(16);
201    fwrite(&itmp, 4, 1, file);
202 
203    stmp = le_short(1);
204    fwrite(&stmp, 2, 1, file);
205 
206    stmp = le_short(channels);
207    fwrite(&stmp, 2, 1, file);
208 
209    itmp = le_int(rate);
210    fwrite(&itmp, 4, 1, file);
211 
212    itmp = le_int(rate*channels*2);
213    fwrite(&itmp, 4, 1, file);
214 
215    stmp = le_short(2*channels);
216    fwrite(&stmp, 2, 1, file);
217 
218    stmp = le_short(16);
219    fwrite(&stmp, 2, 1, file);
220 
221    fprintf (file, "data");
222 
223    itmp = le_int(0x7fffffff);
224    fwrite(&itmp, 4, 1, file);
225 
226 
227 }
228