1 /**
2 * Aften: A/52 audio encoder
3 * Copyright (c) 2006 Justin Ruggles
4 *
5 * This library is free software; you can redistribute it and/or
6 * modify it under the terms of the GNU Lesser General Public
7 * License as published by the Free Software Foundation; either
8 * version 2 of the License, or (at your option) any later version.
9 *
10 * This library is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
13 * Lesser General Public License for more details.
14 *
15 * You should have received a copy of the GNU Lesser General Public
16 * License along with this library; if not, write to the Free Software
17 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA
18 */
19
20 /**
21 * @file wav.c
22 * WAV file format
23 */
24
25 #include "common.h"
26
27 #include <stdlib.h>
28 #include <stdio.h>
29 #include <string.h>
30
31 #include "pcm.h"
32
33 /* chunk id's */
34 #define RIFF_ID 0x46464952
35 #define WAVE_ID 0x45564157
36 #define FMT__ID 0x20746D66
37 #define DATA_ID 0x61746164
38
39 /**
40 * Reads a 4-byte little-endian word from the input stream
41 */
42 static inline uint32_t
read4le(ByteIOContext * io)43 read4le(ByteIOContext *io)
44 {
45 uint32_t x;
46 if(byteio_read(&x, 4, io) != 4)
47 return 0;
48 return le2me_32(x);
49 }
50
51 /**
52 * Reads a 2-byte little-endian word from the input stream
53 */
54 static uint16_t
read2le(ByteIOContext * io)55 read2le(ByteIOContext *io)
56 {
57 uint16_t x;
58 if(byteio_read(&x, 2, io) != 2)
59 return 0;
60 return le2me_16(x);
61 }
62
63 int
pcmfile_probe_wave(uint8_t * data,int size)64 pcmfile_probe_wave(uint8_t *data, int size)
65 {
66 int id;
67
68 if(!data || size < 12)
69 return 0;
70 id = data[0] | (data[1] << 8) | (data[2] << 16) | (data[3] << 24);
71 if(id != RIFF_ID) {
72 return 0;
73 }
74 id = data[8] | (data[9] << 8) | (data[10] << 16) | (data[11] << 24);
75 if(id != WAVE_ID) {
76 return 0;
77 }
78 return 100;
79 }
80
81 int
pcmfile_init_wave(PcmFile * pf)82 pcmfile_init_wave(PcmFile *pf)
83 {
84 int id, found_data, found_fmt, chunksize;
85
86 // read RIFF id. ignore size.
87 id = read4le(&pf->io);
88 pf->filepos += 4;
89 if(id != RIFF_ID) {
90 fprintf(stderr, "invalid RIFF id in wav header\n");
91 return -1;
92 }
93 read4le(&pf->io);
94 pf->filepos += 4;
95
96 // read WAVE id. ignore size.
97 id = read4le(&pf->io);
98 pf->filepos += 4;
99 if(id != WAVE_ID) {
100 fprintf(stderr, "invalid WAVE id in wav header\n");
101 return -1;
102 }
103
104 // read all header chunks. skip unknown chunks.
105 found_data = found_fmt = 0;
106 while(!found_data) {
107 id = read4le(&pf->io);
108 pf->filepos += 4;
109 chunksize = read4le(&pf->io);
110 pf->filepos += 4;
111 switch(id) {
112 case FMT__ID:
113 if(chunksize < 16) {
114 fprintf(stderr, "invalid fmt chunk in wav header\n");
115 return -1;
116 }
117 pf->wav_format = read2le(&pf->io);
118 pf->filepos += 2;
119 if(pf->wav_format == WAVE_FORMAT_IEEEFLOAT) {
120 pf->sample_type = PCM_SAMPLE_TYPE_FLOAT;
121 } else {
122 pf->sample_type = PCM_SAMPLE_TYPE_INT;
123 }
124 pf->channels = read2le(&pf->io);
125 pf->filepos += 2;
126 if(pf->channels == 0) {
127 fprintf(stderr, "invalid number of channels in wav header\n");
128 return -1;
129 }
130 pf->sample_rate = read4le(&pf->io);
131 pf->filepos += 4;
132 if(pf->sample_rate == 0) {
133 fprintf(stderr, "invalid sample rate in wav header\n");
134 return -1;
135 }
136 read4le(&pf->io);
137 pf->filepos += 4;
138 pf->block_align = read2le(&pf->io);
139 pf->filepos += 2;
140 pf->bit_width = read2le(&pf->io);
141 pf->filepos += 2;
142 if(pf->bit_width == 0) {
143 fprintf(stderr, "invalid sample bit width in wav header\n");
144 return -1;
145 }
146 chunksize -= 16;
147
148 // WAVE_FORMAT_EXTENSIBLE data
149 pf->ch_mask = 0;
150 if(pf->wav_format == WAVE_FORMAT_EXTENSIBLE && chunksize >= 10) {
151 read4le(&pf->io); // skip CbSize and ValidBitsPerSample
152 pf->filepos += 4;
153 pf->ch_mask = read4le(&pf->io);
154 pf->filepos += 4;
155 pf->wav_format = read2le(&pf->io);
156 if(pf->wav_format == WAVE_FORMAT_IEEEFLOAT) {
157 pf->sample_type = PCM_SAMPLE_TYPE_FLOAT;
158 } else {
159 pf->sample_type = PCM_SAMPLE_TYPE_INT;
160 }
161 pf->filepos += 2;
162 chunksize -= 10;
163 }
164
165 // override block alignment in header
166 if(pf->wav_format == WAVE_FORMAT_IEEEFLOAT ||
167 pf->wav_format == WAVE_FORMAT_PCM) {
168 pf->block_align = MAX(1, ((pf->bit_width + 7) >> 3) * pf->channels);
169 }
170
171 // make up channel mask if not using WAVE_FORMAT_EXTENSIBLE
172 // or if ch_mask is set to zero (unspecified configuration)
173 // TODO: select default configurations for >6 channels
174 if(pf->ch_mask == 0) {
175 switch(pf->channels) {
176 case 1: pf->ch_mask = 0x04; break;
177 case 2: pf->ch_mask = 0x03; break;
178 case 3: pf->ch_mask = 0x07; break;
179 case 4: pf->ch_mask = 0x107; break;
180 case 5: pf->ch_mask = 0x37; break;
181 case 6: pf->ch_mask = 0x3F; break;
182 }
183 }
184
185 // skip any leftover bytes in fmt chunk
186 if(pcmfile_seek_set(pf, pf->filepos + chunksize)) {
187 fprintf(stderr, "error seeking in wav file\n");
188 return -1;
189 }
190 found_fmt = 1;
191 break;
192 case DATA_ID:
193 if(!found_fmt) return -1;
194 if(chunksize == 0)
195 pf->read_to_eof = 1;
196 pf->data_size = chunksize;
197 pf->data_start = pf->filepos;
198 if(pf->seekable && pf->file_size > 0) {
199 // limit data size to end-of-file
200 if(pf->data_size > 0)
201 pf->data_size = MIN(pf->data_size, pf->file_size - pf->data_start);
202 else
203 pf->data_size = pf->file_size - pf->data_start;
204 }
205 pf->samples = (pf->data_size / pf->block_align);
206 found_data = 1;
207 break;
208 default:
209 // skip unknown chunk
210 if(chunksize > 0 && pcmfile_seek_set(pf, pf->filepos + chunksize)) {
211 fprintf(stderr, "error seeking in wav file\n");
212 return -1;
213 }
214 }
215 }
216
217 // set audio data format based on bit depth and sample type
218 pf->source_format = PCM_SAMPLE_FMT_UNKNOWN;
219 switch(pf->bit_width) {
220 case 8: pf->source_format = PCM_SAMPLE_FMT_U8; break;
221 case 16: pf->source_format = PCM_SAMPLE_FMT_S16; break;
222 case 20: pf->source_format = PCM_SAMPLE_FMT_S20; break;
223 case 24: pf->source_format = PCM_SAMPLE_FMT_S24; break;
224 case 32:
225 if(pf->sample_type == PCM_SAMPLE_TYPE_FLOAT)
226 pf->source_format = PCM_SAMPLE_FMT_FLT;
227 else if(pf->sample_type == PCM_SAMPLE_TYPE_INT)
228 pf->source_format = PCM_SAMPLE_FMT_S32;
229 break;
230 case 64:
231 if(pf->sample_type == PCM_SAMPLE_TYPE_FLOAT) {
232 pf->source_format = PCM_SAMPLE_FMT_DBL;
233 } else {
234 fprintf(stderr, "64-bit integer samples not supported\n");
235 return -1;
236 }
237 break;
238 }
239 pcmfile_set_source(pf, pf->source_format, PCM_BYTE_ORDER_LE);
240
241 return 0;
242 }
243