cannam@125
|
1 /*
|
cannam@125
|
2 ** Copyright (C) 1999-2016 Erik de Castro Lopo <erikd@mega-nerd.com>
|
cannam@125
|
3 **
|
cannam@125
|
4 ** This program is free software; you can redistribute it and/or modify
|
cannam@125
|
5 ** it under the terms of the GNU Lesser General Public License as published by
|
cannam@125
|
6 ** the Free Software Foundation; either version 2.1 of the License, or
|
cannam@125
|
7 ** (at your option) any later version.
|
cannam@125
|
8 **
|
cannam@125
|
9 ** This program is distributed in the hope that it will be useful,
|
cannam@125
|
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
|
cannam@125
|
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
cannam@125
|
12 ** GNU Lesser General Public License for more details.
|
cannam@125
|
13 **
|
cannam@125
|
14 ** You should have received a copy of the GNU Lesser General Public License
|
cannam@125
|
15 ** along with this program; if not, write to the Free Software
|
cannam@125
|
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
|
cannam@125
|
17 */
|
cannam@125
|
18
|
cannam@125
|
19 #include "sfconfig.h"
|
cannam@125
|
20
|
cannam@125
|
21 #include <stdio.h>
|
cannam@125
|
22 #include <string.h>
|
cannam@125
|
23 #include <ctype.h>
|
cannam@125
|
24 #include <time.h>
|
cannam@125
|
25
|
cannam@125
|
26 #include "sndfile.h"
|
cannam@125
|
27 #include "sfendian.h"
|
cannam@125
|
28 #include "common.h"
|
cannam@125
|
29 #include "wavlike.h"
|
cannam@125
|
30
|
cannam@125
|
31 /*------------------------------------------------------------------------------
|
cannam@125
|
32 ** W64 files use 16 byte markers as opposed to the four byte marker of
|
cannam@125
|
33 ** WAV files.
|
cannam@125
|
34 ** For comparison purposes, an integer is required, so make an integer
|
cannam@125
|
35 ** hash for the 16 bytes using MAKE_HASH16 macro, but also create a 16
|
cannam@125
|
36 ** byte array containing the complete 16 bytes required when writing the
|
cannam@125
|
37 ** header.
|
cannam@125
|
38 */
|
cannam@125
|
39
|
cannam@125
|
40 #define MAKE_HASH16(x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \
|
cannam@125
|
41 ( (x0) ^ ((x1) << 1) ^ ((x2) << 2) ^ ((x3) << 3) ^ \
|
cannam@125
|
42 ((x4) << 4) ^ ((x5) << 5) ^ ((x6) << 6) ^ ((x7) << 7) ^ \
|
cannam@125
|
43 ((x8) << 8) ^ ((x9) << 9) ^ ((xa) << 10) ^ ((xb) << 11) ^ \
|
cannam@125
|
44 ((xc) << 12) ^ ((xd) << 13) ^ ((xe) << 14) ^ ((xf) << 15) )
|
cannam@125
|
45
|
cannam@125
|
46 #define MAKE_MARKER16(name, x0, x1, x2, x3, x4, x5, x6, x7, x8, x9, xa, xb, xc, xd, xe, xf) \
|
cannam@125
|
47 static unsigned char name [16] = { (x0), (x1), (x2), (x3), (x4), (x5), \
|
cannam@125
|
48 (x6), (x7), (x8), (x9), (xa), (xb), (xc), (xd), (xe), (xf) }
|
cannam@125
|
49
|
cannam@125
|
50 #define riff_HASH16 MAKE_HASH16 ('r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, \
|
cannam@125
|
51 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
|
cannam@125
|
52
|
cannam@125
|
53 #define wave_HASH16 MAKE_HASH16 ('w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, \
|
cannam@125
|
54 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
55
|
cannam@125
|
56 #define fmt_HASH16 MAKE_HASH16 ('f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, \
|
cannam@125
|
57 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
58
|
cannam@125
|
59 #define fact_HASH16 MAKE_HASH16 ('f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, \
|
cannam@125
|
60 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
61
|
cannam@125
|
62 #define data_HASH16 MAKE_HASH16 ('d', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, \
|
cannam@125
|
63 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
64
|
cannam@125
|
65 #define ACID_HASH16 MAKE_HASH16 (0x6D, 0x07, 0x1C, 0xEA, 0xA3, 0xEF, 0x78, 0x4C, \
|
cannam@125
|
66 0x90, 0x57, 0x7F, 0x79, 0xEE, 0x25, 0x2A, 0xAE)
|
cannam@125
|
67
|
cannam@125
|
68 #define levl_HASH16 MAKE_HASH16 (0x6c, 0x65, 0x76, 0x6c, 0xf3, 0xac, 0xd3, 0x11, \
|
cannam@125
|
69 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
70
|
cannam@125
|
71 #define list_HASH16 MAKE_HASH16 (0x6C, 0x69, 0x73, 0x74, 0x2F, 0x91, 0xCF, 0x11, \
|
cannam@125
|
72 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
|
cannam@125
|
73
|
cannam@125
|
74 #define junk_HASH16 MAKE_HASH16 (0x6A, 0x75, 0x6E, 0x6b, 0xF3, 0xAC, 0xD3, 0x11, \
|
cannam@125
|
75 0x8C, 0xD1, 0x00, 0xC0, 0x4f, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
76
|
cannam@125
|
77 #define bext_HASH16 MAKE_HASH16 (0x62, 0x65, 0x78, 0x74, 0xf3, 0xac, 0xd3, 0xaa, \
|
cannam@125
|
78 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
79
|
cannam@125
|
80 #define MARKER_HASH16 MAKE_HASH16 (0x56, 0x62, 0xf7, 0xab, 0x2d, 0x39, 0xd2, 0x11, \
|
cannam@125
|
81 0x86, 0xc7, 0x00, 0xc0, 0x4f, 0x8e, 0xdb, 0x8a)
|
cannam@125
|
82
|
cannam@125
|
83 #define SUMLIST_HASH16 MAKE_HASH16 (0xBC, 0x94, 0x5F, 0x92, 0x5A, 0x52, 0xD2, 0x11, \
|
cannam@125
|
84 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
|
cannam@125
|
85
|
cannam@125
|
86
|
cannam@125
|
87 MAKE_MARKER16 (riff_MARKER16, 'r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11,
|
cannam@125
|
88 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) ;
|
cannam@125
|
89
|
cannam@125
|
90
|
cannam@125
|
91 MAKE_MARKER16 (wave_MARKER16, 'w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11,
|
cannam@125
|
92 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
|
cannam@125
|
93
|
cannam@125
|
94 MAKE_MARKER16 (fmt_MARKER16, 'f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11,
|
cannam@125
|
95 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
|
cannam@125
|
96
|
cannam@125
|
97 MAKE_MARKER16 (fact_MARKER16, 'f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11,
|
cannam@125
|
98 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
|
cannam@125
|
99
|
cannam@125
|
100 MAKE_MARKER16 (data_MARKER16, 'd', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11,
|
cannam@125
|
101 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
|
cannam@125
|
102
|
cannam@125
|
103 enum
|
cannam@125
|
104 { HAVE_riff = 0x01,
|
cannam@125
|
105 HAVE_wave = 0x02,
|
cannam@125
|
106 HAVE_fmt = 0x04,
|
cannam@125
|
107 HAVE_fact = 0x08,
|
cannam@125
|
108 HAVE_data = 0x20
|
cannam@125
|
109 } ;
|
cannam@125
|
110
|
cannam@125
|
111 /*------------------------------------------------------------------------------
|
cannam@125
|
112 * Private static functions.
|
cannam@125
|
113 */
|
cannam@125
|
114
|
cannam@125
|
115 static int w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock) ;
|
cannam@125
|
116 static int w64_write_header (SF_PRIVATE *psf, int calc_length) ;
|
cannam@125
|
117 static int w64_close (SF_PRIVATE *psf) ;
|
cannam@125
|
118
|
cannam@125
|
119 /*------------------------------------------------------------------------------
|
cannam@125
|
120 ** Public function.
|
cannam@125
|
121 */
|
cannam@125
|
122
|
cannam@125
|
123 int
|
cannam@125
|
124 w64_open (SF_PRIVATE *psf)
|
cannam@125
|
125 { WAVLIKE_PRIVATE * wpriv ;
|
cannam@125
|
126 int subformat, error, blockalign = 0, framesperblock = 0 ;
|
cannam@125
|
127
|
cannam@125
|
128 if ((wpriv = calloc (1, sizeof (WAVLIKE_PRIVATE))) == NULL)
|
cannam@125
|
129 return SFE_MALLOC_FAILED ;
|
cannam@125
|
130 psf->container_data = wpriv ;
|
cannam@125
|
131
|
cannam@125
|
132 if (psf->file.mode == SFM_READ || (psf->file.mode == SFM_RDWR &&psf->filelength > 0))
|
cannam@125
|
133 { if ((error = w64_read_header (psf, &blockalign, &framesperblock)))
|
cannam@125
|
134 return error ;
|
cannam@125
|
135 } ;
|
cannam@125
|
136
|
cannam@125
|
137 if ((SF_CONTAINER (psf->sf.format)) != SF_FORMAT_W64)
|
cannam@125
|
138 return SFE_BAD_OPEN_FORMAT ;
|
cannam@125
|
139
|
cannam@125
|
140 subformat = SF_CODEC (psf->sf.format) ;
|
cannam@125
|
141
|
cannam@125
|
142 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
cannam@125
|
143 { if (psf->is_pipe)
|
cannam@125
|
144 return SFE_NO_PIPE_WRITE ;
|
cannam@125
|
145
|
cannam@125
|
146 psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */
|
cannam@125
|
147
|
cannam@125
|
148 psf->blockwidth = psf->bytewidth * psf->sf.channels ;
|
cannam@125
|
149
|
cannam@125
|
150 if (subformat == SF_FORMAT_IMA_ADPCM || subformat == SF_FORMAT_MS_ADPCM)
|
cannam@125
|
151 { blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
|
cannam@125
|
152 framesperblock = -1 ;
|
cannam@125
|
153
|
cannam@125
|
154 /*
|
cannam@125
|
155 ** At this point we don't know the file length so set it stupidly high, but not
|
cannam@125
|
156 ** so high that it triggers undefined behaviour whan something is added to it.
|
cannam@125
|
157 */
|
cannam@125
|
158 psf->filelength = SF_COUNT_MAX - 10000 ;
|
cannam@125
|
159 psf->datalength = psf->filelength ;
|
cannam@125
|
160 if (psf->sf.frames <= 0)
|
cannam@125
|
161 psf->sf.frames = (psf->blockwidth) ? psf->filelength / psf->blockwidth : psf->filelength ;
|
cannam@125
|
162 } ;
|
cannam@125
|
163
|
cannam@125
|
164 if ((error = w64_write_header (psf, SF_FALSE)))
|
cannam@125
|
165 return error ;
|
cannam@125
|
166
|
cannam@125
|
167 psf->write_header = w64_write_header ;
|
cannam@125
|
168 } ;
|
cannam@125
|
169
|
cannam@125
|
170 psf->container_close = w64_close ;
|
cannam@125
|
171
|
cannam@125
|
172 switch (subformat)
|
cannam@125
|
173 { case SF_FORMAT_PCM_U8 :
|
cannam@125
|
174 error = pcm_init (psf) ;
|
cannam@125
|
175 break ;
|
cannam@125
|
176
|
cannam@125
|
177 case SF_FORMAT_PCM_16 :
|
cannam@125
|
178 case SF_FORMAT_PCM_24 :
|
cannam@125
|
179 case SF_FORMAT_PCM_32 :
|
cannam@125
|
180 error = pcm_init (psf) ;
|
cannam@125
|
181 break ;
|
cannam@125
|
182
|
cannam@125
|
183 case SF_FORMAT_ULAW :
|
cannam@125
|
184 error = ulaw_init (psf) ;
|
cannam@125
|
185 break ;
|
cannam@125
|
186
|
cannam@125
|
187 case SF_FORMAT_ALAW :
|
cannam@125
|
188 error = alaw_init (psf) ;
|
cannam@125
|
189 break ;
|
cannam@125
|
190
|
cannam@125
|
191 /* Lite remove start */
|
cannam@125
|
192 case SF_FORMAT_FLOAT :
|
cannam@125
|
193 error = float32_init (psf) ;
|
cannam@125
|
194 break ;
|
cannam@125
|
195
|
cannam@125
|
196 case SF_FORMAT_DOUBLE :
|
cannam@125
|
197 error = double64_init (psf) ;
|
cannam@125
|
198 break ;
|
cannam@125
|
199
|
cannam@125
|
200 case SF_FORMAT_IMA_ADPCM :
|
cannam@125
|
201 error = wavlike_ima_init (psf, blockalign, framesperblock) ;
|
cannam@125
|
202 break ;
|
cannam@125
|
203
|
cannam@125
|
204 case SF_FORMAT_MS_ADPCM :
|
cannam@125
|
205 error = wavlike_msadpcm_init (psf, blockalign, framesperblock) ;
|
cannam@125
|
206 break ;
|
cannam@125
|
207 /* Lite remove end */
|
cannam@125
|
208
|
cannam@125
|
209 case SF_FORMAT_GSM610 :
|
cannam@125
|
210 error = gsm610_init (psf) ;
|
cannam@125
|
211 break ;
|
cannam@125
|
212
|
cannam@125
|
213 default : return SFE_UNIMPLEMENTED ;
|
cannam@125
|
214 } ;
|
cannam@125
|
215
|
cannam@125
|
216 return error ;
|
cannam@125
|
217 } /* w64_open */
|
cannam@125
|
218
|
cannam@125
|
219 /*=========================================================================
|
cannam@125
|
220 ** Private functions.
|
cannam@125
|
221 */
|
cannam@125
|
222
|
cannam@125
|
223 static int
|
cannam@125
|
224 w64_read_header (SF_PRIVATE *psf, int *blockalign, int *framesperblock)
|
cannam@125
|
225 { WAVLIKE_PRIVATE *wpriv ;
|
cannam@125
|
226 WAV_FMT *wav_fmt ;
|
cannam@125
|
227 int dword = 0, marker, format = 0 ;
|
cannam@125
|
228 sf_count_t chunk_size, bytesread = 0 ;
|
cannam@125
|
229 int parsestage = 0, error, done = 0 ;
|
cannam@125
|
230
|
cannam@125
|
231 if ((wpriv = psf->container_data) == NULL)
|
cannam@125
|
232 return SFE_INTERNAL ;
|
cannam@125
|
233 wav_fmt = &wpriv->wav_fmt ;
|
cannam@125
|
234
|
cannam@125
|
235 /* Set position to start of file to begin reading header. */
|
cannam@125
|
236 psf_binheader_readf (psf, "p", 0) ;
|
cannam@125
|
237
|
cannam@125
|
238 while (! done)
|
cannam@125
|
239 { /* Each new chunk must start on an 8 byte boundary, so jump if needed. */
|
cannam@125
|
240 if (psf->headindex & 0x7)
|
cannam@125
|
241 psf_binheader_readf (psf, "j", 8 - (psf->headindex & 0x7)) ;
|
cannam@125
|
242
|
cannam@125
|
243 /* Generate hash of 16 byte marker. */
|
cannam@125
|
244 marker = chunk_size = 0 ;
|
cannam@125
|
245 bytesread = psf_binheader_readf (psf, "eh8", &marker, &chunk_size) ;
|
cannam@125
|
246 if (bytesread == 0)
|
cannam@125
|
247 break ;
|
cannam@125
|
248 switch (marker)
|
cannam@125
|
249 { case riff_HASH16 :
|
cannam@125
|
250 if (parsestage)
|
cannam@125
|
251 return SFE_W64_NO_RIFF ;
|
cannam@125
|
252
|
cannam@125
|
253 if (psf->filelength != chunk_size)
|
cannam@125
|
254 psf_log_printf (psf, "riff : %D (should be %D)\n", chunk_size, psf->filelength) ;
|
cannam@125
|
255 else
|
cannam@125
|
256 psf_log_printf (psf, "riff : %D\n", chunk_size) ;
|
cannam@125
|
257
|
cannam@125
|
258 parsestage |= HAVE_riff ;
|
cannam@125
|
259
|
cannam@125
|
260 bytesread += psf_binheader_readf (psf, "h", &marker) ;
|
cannam@125
|
261 if (marker == wave_HASH16)
|
cannam@125
|
262 { if ((parsestage & HAVE_riff) != HAVE_riff)
|
cannam@125
|
263 return SFE_W64_NO_WAVE ;
|
cannam@125
|
264 psf_log_printf (psf, "wave\n") ;
|
cannam@125
|
265 parsestage |= HAVE_wave ;
|
cannam@125
|
266 } ;
|
cannam@125
|
267 chunk_size = 0 ;
|
cannam@125
|
268 break ;
|
cannam@125
|
269
|
cannam@125
|
270 case ACID_HASH16:
|
cannam@125
|
271 psf_log_printf (psf, "Looks like an ACID file. Exiting.\n") ;
|
cannam@125
|
272 return SFE_UNIMPLEMENTED ;
|
cannam@125
|
273
|
cannam@125
|
274 case fmt_HASH16 :
|
cannam@125
|
275 if ((parsestage & (HAVE_riff | HAVE_wave)) != (HAVE_riff | HAVE_wave))
|
cannam@125
|
276 return SFE_WAV_NO_FMT ;
|
cannam@125
|
277
|
cannam@125
|
278 psf_log_printf (psf, " fmt : %D\n", chunk_size) ;
|
cannam@125
|
279
|
cannam@125
|
280 /* size of 16 byte marker and 8 byte chunk_size value. */
|
cannam@125
|
281 chunk_size -= 24 ;
|
cannam@125
|
282
|
cannam@125
|
283 if ((error = wavlike_read_fmt_chunk (psf, (int) chunk_size)))
|
cannam@125
|
284 return error ;
|
cannam@125
|
285
|
cannam@125
|
286 if (chunk_size % 8)
|
cannam@125
|
287 psf_binheader_readf (psf, "j", 8 - (chunk_size % 8)) ;
|
cannam@125
|
288
|
cannam@125
|
289 format = wav_fmt->format ;
|
cannam@125
|
290 parsestage |= HAVE_fmt ;
|
cannam@125
|
291 chunk_size = 0 ;
|
cannam@125
|
292 break ;
|
cannam@125
|
293
|
cannam@125
|
294 case fact_HASH16:
|
cannam@125
|
295 { sf_count_t frames ;
|
cannam@125
|
296
|
cannam@125
|
297 psf_binheader_readf (psf, "e8", &frames) ;
|
cannam@125
|
298 psf_log_printf (psf, "fact : %D\n frames : %D\n",
|
cannam@125
|
299 chunk_size, frames) ;
|
cannam@125
|
300 } ;
|
cannam@125
|
301 chunk_size = 0 ;
|
cannam@125
|
302 break ;
|
cannam@125
|
303
|
cannam@125
|
304
|
cannam@125
|
305 case data_HASH16 :
|
cannam@125
|
306 if ((parsestage & (HAVE_riff | HAVE_wave | HAVE_fmt)) != (HAVE_riff | HAVE_wave | HAVE_fmt))
|
cannam@125
|
307 return SFE_W64_NO_DATA ;
|
cannam@125
|
308
|
cannam@125
|
309 psf->dataoffset = psf_ftell (psf) ;
|
cannam@125
|
310 psf->datalength = SF_MIN (chunk_size - 24, psf->filelength - psf->dataoffset) ;
|
cannam@125
|
311
|
cannam@125
|
312 if (chunk_size % 8)
|
cannam@125
|
313 chunk_size += 8 - (chunk_size % 8) ;
|
cannam@125
|
314
|
cannam@125
|
315 psf_log_printf (psf, "data : %D\n", chunk_size) ;
|
cannam@125
|
316
|
cannam@125
|
317 parsestage |= HAVE_data ;
|
cannam@125
|
318
|
cannam@125
|
319 if (! psf->sf.seekable)
|
cannam@125
|
320 break ;
|
cannam@125
|
321
|
cannam@125
|
322 /* Seek past data and continue reading header. */
|
cannam@125
|
323 psf_fseek (psf, chunk_size, SEEK_CUR) ;
|
cannam@125
|
324 chunk_size = 0 ;
|
cannam@125
|
325 break ;
|
cannam@125
|
326
|
cannam@125
|
327 case levl_HASH16 :
|
cannam@125
|
328 psf_log_printf (psf, "levl : %D\n", chunk_size) ;
|
cannam@125
|
329 chunk_size -= 24 ;
|
cannam@125
|
330 break ;
|
cannam@125
|
331
|
cannam@125
|
332 case list_HASH16 :
|
cannam@125
|
333 psf_log_printf (psf, "list : %D\n", chunk_size) ;
|
cannam@125
|
334 chunk_size -= 24 ;
|
cannam@125
|
335 break ;
|
cannam@125
|
336
|
cannam@125
|
337 case junk_HASH16 :
|
cannam@125
|
338 psf_log_printf (psf, "junk : %D\n", chunk_size) ;
|
cannam@125
|
339 chunk_size -= 24 ;
|
cannam@125
|
340 break ;
|
cannam@125
|
341
|
cannam@125
|
342 case bext_HASH16 :
|
cannam@125
|
343 psf_log_printf (psf, "bext : %D\n", chunk_size) ;
|
cannam@125
|
344 chunk_size -= 24 ;
|
cannam@125
|
345 break ;
|
cannam@125
|
346
|
cannam@125
|
347 case MARKER_HASH16 :
|
cannam@125
|
348 psf_log_printf (psf, "marker : %D\n", chunk_size) ;
|
cannam@125
|
349 chunk_size -= 24 ;
|
cannam@125
|
350 break ;
|
cannam@125
|
351
|
cannam@125
|
352 case SUMLIST_HASH16 :
|
cannam@125
|
353 psf_log_printf (psf, "summary list : %D\n", chunk_size) ;
|
cannam@125
|
354 chunk_size -= 24 ;
|
cannam@125
|
355 break ;
|
cannam@125
|
356
|
cannam@125
|
357 default :
|
cannam@125
|
358 psf_log_printf (psf, "*** Unknown chunk marker (%X) at position %D with length %D. Exiting parser.\n", marker, psf_ftell (psf) - 8, chunk_size) ;
|
cannam@125
|
359 done = SF_TRUE ;
|
cannam@125
|
360 break ;
|
cannam@125
|
361 } ; /* switch (dword) */
|
cannam@125
|
362
|
cannam@125
|
363 if (chunk_size >= psf->filelength)
|
cannam@125
|
364 { psf_log_printf (psf, "*** Chunk size %u > file length %D. Exiting parser.\n", chunk_size, psf->filelength) ;
|
cannam@125
|
365 break ;
|
cannam@125
|
366 } ;
|
cannam@125
|
367
|
cannam@125
|
368 if (psf->sf.seekable == 0 && (parsestage & HAVE_data))
|
cannam@125
|
369 break ;
|
cannam@125
|
370
|
cannam@125
|
371 if (psf_ftell (psf) >= (psf->filelength - (2 * SIGNED_SIZEOF (dword))))
|
cannam@125
|
372 break ;
|
cannam@125
|
373
|
cannam@125
|
374 if (chunk_size > 0 && chunk_size < 0xffff0000)
|
cannam@125
|
375 { dword = chunk_size ;
|
cannam@125
|
376 psf_binheader_readf (psf, "j", dword - 24) ;
|
cannam@125
|
377 } ;
|
cannam@125
|
378 } ; /* while (1) */
|
cannam@125
|
379
|
cannam@125
|
380 if (psf->dataoffset <= 0)
|
cannam@125
|
381 return SFE_W64_NO_DATA ;
|
cannam@125
|
382
|
cannam@125
|
383 if (psf->sf.channels < 1)
|
cannam@125
|
384 return SFE_CHANNEL_COUNT_ZERO ;
|
cannam@125
|
385
|
cannam@125
|
386 if (psf->sf.channels >= SF_MAX_CHANNELS)
|
cannam@125
|
387 return SFE_CHANNEL_COUNT ;
|
cannam@125
|
388
|
cannam@125
|
389 psf->endian = SF_ENDIAN_LITTLE ; /* All W64 files are little endian. */
|
cannam@125
|
390
|
cannam@125
|
391 if (psf_ftell (psf) != psf->dataoffset)
|
cannam@125
|
392 psf_fseek (psf, psf->dataoffset, SEEK_SET) ;
|
cannam@125
|
393
|
cannam@125
|
394 if (psf->blockwidth)
|
cannam@125
|
395 { if (psf->filelength - psf->dataoffset < psf->datalength)
|
cannam@125
|
396 psf->sf.frames = (psf->filelength - psf->dataoffset) / psf->blockwidth ;
|
cannam@125
|
397 else
|
cannam@125
|
398 psf->sf.frames = psf->datalength / psf->blockwidth ;
|
cannam@125
|
399 } ;
|
cannam@125
|
400
|
cannam@125
|
401 switch (format)
|
cannam@125
|
402 { case WAVE_FORMAT_PCM :
|
cannam@125
|
403 case WAVE_FORMAT_EXTENSIBLE :
|
cannam@125
|
404 /* extensible might be FLOAT, MULAW, etc as well! */
|
cannam@125
|
405 psf->sf.format = SF_FORMAT_W64 | u_bitwidth_to_subformat (psf->bytewidth * 8) ;
|
cannam@125
|
406 break ;
|
cannam@125
|
407
|
cannam@125
|
408 case WAVE_FORMAT_MULAW :
|
cannam@125
|
409 psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ULAW) ;
|
cannam@125
|
410 break ;
|
cannam@125
|
411
|
cannam@125
|
412 case WAVE_FORMAT_ALAW :
|
cannam@125
|
413 psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_ALAW) ;
|
cannam@125
|
414 break ;
|
cannam@125
|
415
|
cannam@125
|
416 case WAVE_FORMAT_MS_ADPCM :
|
cannam@125
|
417 psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_MS_ADPCM) ;
|
cannam@125
|
418 *blockalign = wav_fmt->msadpcm.blockalign ;
|
cannam@125
|
419 *framesperblock = wav_fmt->msadpcm.samplesperblock ;
|
cannam@125
|
420 break ;
|
cannam@125
|
421
|
cannam@125
|
422 case WAVE_FORMAT_IMA_ADPCM :
|
cannam@125
|
423 psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_IMA_ADPCM) ;
|
cannam@125
|
424 *blockalign = wav_fmt->ima.blockalign ;
|
cannam@125
|
425 *framesperblock = wav_fmt->ima.samplesperblock ;
|
cannam@125
|
426 break ;
|
cannam@125
|
427
|
cannam@125
|
428 case WAVE_FORMAT_GSM610 :
|
cannam@125
|
429 psf->sf.format = (SF_FORMAT_W64 | SF_FORMAT_GSM610) ;
|
cannam@125
|
430 break ;
|
cannam@125
|
431
|
cannam@125
|
432 case WAVE_FORMAT_IEEE_FLOAT :
|
cannam@125
|
433 psf->sf.format = SF_FORMAT_W64 ;
|
cannam@125
|
434 psf->sf.format |= (psf->bytewidth == 8) ? SF_FORMAT_DOUBLE : SF_FORMAT_FLOAT ;
|
cannam@125
|
435 break ;
|
cannam@125
|
436
|
cannam@125
|
437 default : return SFE_UNIMPLEMENTED ;
|
cannam@125
|
438 } ;
|
cannam@125
|
439
|
cannam@125
|
440 return 0 ;
|
cannam@125
|
441 } /* w64_read_header */
|
cannam@125
|
442
|
cannam@125
|
443 static int
|
cannam@125
|
444 w64_write_header (SF_PRIVATE *psf, int calc_length)
|
cannam@125
|
445 { sf_count_t fmt_size, current ;
|
cannam@125
|
446 size_t fmt_pad = 0 ;
|
cannam@125
|
447 int subformat, add_fact_chunk = SF_FALSE ;
|
cannam@125
|
448
|
cannam@125
|
449 current = psf_ftell (psf) ;
|
cannam@125
|
450
|
cannam@125
|
451 if (calc_length)
|
cannam@125
|
452 { psf->filelength = psf_get_filelen (psf) ;
|
cannam@125
|
453
|
cannam@125
|
454 psf->datalength = psf->filelength - psf->dataoffset ;
|
cannam@125
|
455 if (psf->dataend)
|
cannam@125
|
456 psf->datalength -= psf->filelength - psf->dataend ;
|
cannam@125
|
457
|
cannam@125
|
458 if (psf->bytewidth)
|
cannam@125
|
459 psf->sf.frames = psf->datalength / (psf->bytewidth * psf->sf.channels) ;
|
cannam@125
|
460 } ;
|
cannam@125
|
461
|
cannam@125
|
462 /* Reset the current header length to zero. */
|
cannam@125
|
463 psf->header [0] = 0 ;
|
cannam@125
|
464 psf->headindex = 0 ;
|
cannam@125
|
465 psf_fseek (psf, 0, SEEK_SET) ;
|
cannam@125
|
466
|
cannam@125
|
467 /* riff marker, length, wave and 'fmt ' markers. */
|
cannam@125
|
468 psf_binheader_writef (psf, "eh8hh", riff_MARKER16, psf->filelength, wave_MARKER16, fmt_MARKER16) ;
|
cannam@125
|
469
|
cannam@125
|
470 subformat = SF_CODEC (psf->sf.format) ;
|
cannam@125
|
471
|
cannam@125
|
472 switch (subformat)
|
cannam@125
|
473 { case SF_FORMAT_PCM_U8 :
|
cannam@125
|
474 case SF_FORMAT_PCM_16 :
|
cannam@125
|
475 case SF_FORMAT_PCM_24 :
|
cannam@125
|
476 case SF_FORMAT_PCM_32 :
|
cannam@125
|
477 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
|
cannam@125
|
478 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
479 fmt_size += fmt_pad ;
|
cannam@125
|
480
|
cannam@125
|
481 /* fmt : format, channels, samplerate */
|
cannam@125
|
482 psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_PCM, psf->sf.channels, psf->sf.samplerate) ;
|
cannam@125
|
483 /* fmt : bytespersec */
|
cannam@125
|
484 psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
|
cannam@125
|
485 /* fmt : blockalign, bitwidth */
|
cannam@125
|
486 psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ;
|
cannam@125
|
487 break ;
|
cannam@125
|
488
|
cannam@125
|
489 case SF_FORMAT_FLOAT :
|
cannam@125
|
490 case SF_FORMAT_DOUBLE :
|
cannam@125
|
491 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
|
cannam@125
|
492 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
493 fmt_size += fmt_pad ;
|
cannam@125
|
494
|
cannam@125
|
495 /* fmt : format, channels, samplerate */
|
cannam@125
|
496 psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_IEEE_FLOAT, psf->sf.channels, psf->sf.samplerate) ;
|
cannam@125
|
497 /* fmt : bytespersec */
|
cannam@125
|
498 psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
|
cannam@125
|
499 /* fmt : blockalign, bitwidth */
|
cannam@125
|
500 psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, psf->bytewidth * 8) ;
|
cannam@125
|
501
|
cannam@125
|
502 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
503 break ;
|
cannam@125
|
504
|
cannam@125
|
505 case SF_FORMAT_ULAW :
|
cannam@125
|
506 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
|
cannam@125
|
507 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
508 fmt_size += fmt_pad ;
|
cannam@125
|
509
|
cannam@125
|
510 /* fmt : format, channels, samplerate */
|
cannam@125
|
511 psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_MULAW, psf->sf.channels, psf->sf.samplerate) ;
|
cannam@125
|
512 /* fmt : bytespersec */
|
cannam@125
|
513 psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
|
cannam@125
|
514 /* fmt : blockalign, bitwidth */
|
cannam@125
|
515 psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ;
|
cannam@125
|
516
|
cannam@125
|
517 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
518 break ;
|
cannam@125
|
519
|
cannam@125
|
520 case SF_FORMAT_ALAW :
|
cannam@125
|
521 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
|
cannam@125
|
522 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
523 fmt_size += fmt_pad ;
|
cannam@125
|
524
|
cannam@125
|
525 /* fmt : format, channels, samplerate */
|
cannam@125
|
526 psf_binheader_writef (psf, "e8224", fmt_size, WAVE_FORMAT_ALAW, psf->sf.channels, psf->sf.samplerate) ;
|
cannam@125
|
527 /* fmt : bytespersec */
|
cannam@125
|
528 psf_binheader_writef (psf, "e4", psf->sf.samplerate * psf->bytewidth * psf->sf.channels) ;
|
cannam@125
|
529 /* fmt : blockalign, bitwidth */
|
cannam@125
|
530 psf_binheader_writef (psf, "e22", psf->bytewidth * psf->sf.channels, 8) ;
|
cannam@125
|
531
|
cannam@125
|
532 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
533 break ;
|
cannam@125
|
534
|
cannam@125
|
535 /* Lite remove start */
|
cannam@125
|
536 case SF_FORMAT_IMA_ADPCM :
|
cannam@125
|
537 { int blockalign, framesperblock, bytespersec ;
|
cannam@125
|
538
|
cannam@125
|
539 blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
|
cannam@125
|
540 framesperblock = 2 * (blockalign - 4 * psf->sf.channels) / psf->sf.channels + 1 ;
|
cannam@125
|
541 bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ;
|
cannam@125
|
542
|
cannam@125
|
543 /* fmt chunk. */
|
cannam@125
|
544 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
|
cannam@125
|
545 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
546 fmt_size += fmt_pad ;
|
cannam@125
|
547
|
cannam@125
|
548 /* fmt : size, WAV format type, channels. */
|
cannam@125
|
549 psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_IMA_ADPCM, psf->sf.channels) ;
|
cannam@125
|
550
|
cannam@125
|
551 /* fmt : samplerate, bytespersec. */
|
cannam@125
|
552 psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
|
cannam@125
|
553
|
cannam@125
|
554 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
|
cannam@125
|
555 psf_binheader_writef (psf, "e2222", blockalign, 4, 2, framesperblock) ;
|
cannam@125
|
556 } ;
|
cannam@125
|
557
|
cannam@125
|
558 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
559 break ;
|
cannam@125
|
560
|
cannam@125
|
561 case SF_FORMAT_MS_ADPCM :
|
cannam@125
|
562 { int blockalign, framesperblock, bytespersec, extrabytes ;
|
cannam@125
|
563
|
cannam@125
|
564 blockalign = wavlike_srate2blocksize (psf->sf.samplerate * psf->sf.channels) ;
|
cannam@125
|
565 framesperblock = 2 + 2 * (blockalign - 7 * psf->sf.channels) / psf->sf.channels ;
|
cannam@125
|
566 bytespersec = (psf->sf.samplerate * blockalign) / framesperblock ;
|
cannam@125
|
567
|
cannam@125
|
568 /* fmt chunk. */
|
cannam@125
|
569 extrabytes = 2 + 2 + WAVLIKE_MSADPCM_ADAPT_COEFF_COUNT * (2 + 2) ;
|
cannam@125
|
570 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes ;
|
cannam@125
|
571 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
572 fmt_size += fmt_pad ;
|
cannam@125
|
573
|
cannam@125
|
574 /* fmt : size, W64 format type, channels. */
|
cannam@125
|
575 psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_MS_ADPCM, psf->sf.channels) ;
|
cannam@125
|
576
|
cannam@125
|
577 /* fmt : samplerate, bytespersec. */
|
cannam@125
|
578 psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
|
cannam@125
|
579
|
cannam@125
|
580 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
|
cannam@125
|
581 psf_binheader_writef (psf, "e22222", blockalign, 4, extrabytes, framesperblock, 7) ;
|
cannam@125
|
582
|
cannam@125
|
583 wavlike_msadpcm_write_adapt_coeffs (psf) ;
|
cannam@125
|
584 } ;
|
cannam@125
|
585
|
cannam@125
|
586 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
587 break ;
|
cannam@125
|
588 /* Lite remove end */
|
cannam@125
|
589
|
cannam@125
|
590 case SF_FORMAT_GSM610 :
|
cannam@125
|
591 { int bytespersec ;
|
cannam@125
|
592
|
cannam@125
|
593 bytespersec = (psf->sf.samplerate * WAVLIKE_GSM610_BLOCKSIZE) / WAVLIKE_GSM610_SAMPLES ;
|
cannam@125
|
594
|
cannam@125
|
595 /* fmt chunk. */
|
cannam@125
|
596 fmt_size = 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
|
cannam@125
|
597 fmt_pad = (size_t) ((fmt_size & 0x7) ? 8 - (fmt_size & 0x7) : 0) ;
|
cannam@125
|
598 fmt_size += fmt_pad ;
|
cannam@125
|
599
|
cannam@125
|
600 /* fmt : size, WAV format type, channels. */
|
cannam@125
|
601 psf_binheader_writef (psf, "e822", fmt_size, WAVE_FORMAT_GSM610, psf->sf.channels) ;
|
cannam@125
|
602
|
cannam@125
|
603 /* fmt : samplerate, bytespersec. */
|
cannam@125
|
604 psf_binheader_writef (psf, "e44", psf->sf.samplerate, bytespersec) ;
|
cannam@125
|
605
|
cannam@125
|
606 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
|
cannam@125
|
607 psf_binheader_writef (psf, "e2222", WAVLIKE_GSM610_BLOCKSIZE, 0, 2, WAVLIKE_GSM610_SAMPLES) ;
|
cannam@125
|
608 } ;
|
cannam@125
|
609
|
cannam@125
|
610 add_fact_chunk = SF_TRUE ;
|
cannam@125
|
611 break ;
|
cannam@125
|
612
|
cannam@125
|
613 default : return SFE_UNIMPLEMENTED ;
|
cannam@125
|
614 } ;
|
cannam@125
|
615
|
cannam@125
|
616 /* Pad to 8 bytes with zeros. */
|
cannam@125
|
617 if (fmt_pad > 0)
|
cannam@125
|
618 psf_binheader_writef (psf, "z", fmt_pad) ;
|
cannam@125
|
619
|
cannam@125
|
620 if (add_fact_chunk)
|
cannam@125
|
621 psf_binheader_writef (psf, "eh88", fact_MARKER16, (sf_count_t) (16 + 8 + 8), psf->sf.frames) ;
|
cannam@125
|
622
|
cannam@125
|
623 psf_binheader_writef (psf, "eh8", data_MARKER16, psf->datalength + 24) ;
|
cannam@125
|
624 psf_fwrite (psf->header, psf->headindex, 1, psf) ;
|
cannam@125
|
625
|
cannam@125
|
626 if (psf->error)
|
cannam@125
|
627 return psf->error ;
|
cannam@125
|
628
|
cannam@125
|
629 psf->dataoffset = psf->headindex ;
|
cannam@125
|
630
|
cannam@125
|
631 if (current > 0)
|
cannam@125
|
632 psf_fseek (psf, current, SEEK_SET) ;
|
cannam@125
|
633
|
cannam@125
|
634 return psf->error ;
|
cannam@125
|
635 } /* w64_write_header */
|
cannam@125
|
636
|
cannam@125
|
637 static int
|
cannam@125
|
638 w64_close (SF_PRIVATE *psf)
|
cannam@125
|
639 {
|
cannam@125
|
640 if (psf->file.mode == SFM_WRITE || psf->file.mode == SFM_RDWR)
|
cannam@125
|
641 w64_write_header (psf, SF_TRUE) ;
|
cannam@125
|
642
|
cannam@125
|
643 return 0 ;
|
cannam@125
|
644 } /* w64_close */
|
cannam@125
|
645
|