Fixed the default int32 type which was wrong on amd64 (and added testcase).
[opus.git] / tools / wav_io.c
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
43 int read_wav_header(FILE *file, int *rate, int *channels, int *format, celt_int32_t *size)
44 {
45    char ch[5];
46    celt_int32_t itmp;
47    celt_int16_t stmp;
48    celt_int32_t bpersec;
49    celt_int16_t 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    if (*rate != 8000 && *rate != 16000 && *rate != 11025 && *rate != 22050 && *rate != 32000 && *rate != 44100 && *rate != 48000)
122    {
123       fprintf (stderr, "Only 8 kHz (narrowband) and 16 kHz (wideband) supported (plus 11.025 kHz and 22.05 kHz, but your mileage may vary)\n");
124       return -1;
125    }
126
127    fread(&itmp, 4, 1, file);
128    bpersec = le_int(itmp);
129
130    fread(&stmp, 2, 1, file);
131    balign = le_short(stmp);
132
133    fread(&stmp, 2, 1, file);
134    stmp = le_short(stmp);
135    if (stmp!=16 && stmp!=8)
136    {
137       fprintf (stderr, "Only 8/16-bit linear supported\n");
138       return -1;
139    }
140    *format=stmp;
141
142    if (bpersec!=*rate**channels*stmp/8)
143    {
144       fprintf (stderr, "Corrupted header: ByteRate mismatch\n");
145       return -1;
146    }
147
148    if (balign!=*channels*stmp/8)
149    {
150       fprintf (stderr, "Corrupted header: BlockAlign mismatch\n");
151       return -1;
152    }
153
154    
155    /*strange way of seeking, but it works even for pipes*/
156    if (skip_bytes>0)
157       for (i=0;i<skip_bytes;i++)
158          fgetc(file);
159
160    /*fseek(file, skip_bytes, SEEK_CUR);*/
161
162    fread(ch, 1, 4, file);
163    while (strcmp(ch, "data")!=0)
164    {
165       fread(&itmp, 4, 1, file);
166       itmp = le_int(itmp);
167       /*strange way of seeking, but it works even for pipes*/
168       for (i=0;i<itmp;i++)
169          fgetc(file);
170       /*fseek(file, itmp, SEEK_CUR);*/
171       fread(ch, 1, 4, file);
172       if (feof(file))
173       {
174          fprintf (stderr, "Corrupted WAVE file: no \"data\"\n");
175          return -1;
176       }
177    }
178
179    /*Ignore this for now*/
180    fread(&itmp, 4, 1, file);
181    itmp = le_int(itmp);
182
183    *size=itmp;
184
185    return 1;
186 }
187
188
189
190 void write_wav_header(FILE *file, int rate, int channels, int format, int size)
191 {
192    char ch[5];
193    celt_int32_t itmp;
194    celt_int16_t stmp;
195
196    ch[4]=0;
197
198    fprintf (file, "RIFF");
199
200    itmp = 0x7fffffff;
201    fwrite(&itmp, 4, 1, file);
202
203    fprintf (file, "WAVEfmt ");
204
205    itmp = le_int(16);
206    fwrite(&itmp, 4, 1, file);
207
208    stmp = le_short(1);
209    fwrite(&stmp, 2, 1, file);
210
211    stmp = le_short(channels);
212    fwrite(&stmp, 2, 1, file);
213
214    itmp = le_int(rate);
215    fwrite(&itmp, 4, 1, file);
216
217    itmp = le_int(rate*channels*2);
218    fwrite(&itmp, 4, 1, file);
219
220    stmp = le_short(2*channels);
221    fwrite(&stmp, 2, 1, file);
222
223    stmp = le_short(16);
224    fwrite(&stmp, 2, 1, file);
225
226    fprintf (file, "data");
227
228    itmp = le_int(0x7fffffff);
229    fwrite(&itmp, 4, 1, file);
230
231
232 }