2 ** Copyright (C) 1999-2011 Erik de Castro Lopo <erikd@mega-nerd.com>
4 ** This program is free software; you can redistribute it and/or modify
5 ** it under the terms of the GNU Lesser General Public License as published by
6 ** the Free Software Foundation; either version 2.1 of the License, or
7 ** (at your option) any later version.
9 ** This program is distributed in the hope that it will be useful,
10 ** but WITHOUT ANY WARRANTY; without even the implied warranty of
11 ** MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
12 ** GNU Lesser General Public License for more details.
14 ** You should have received a copy of the GNU Lesser General Public License
15 ** along with this program; if not, write to the Free Software
16 ** Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
31 /*------------------------------------------------------------------------------
32 ** W64 files use 16 byte markers as opposed to the four byte marker of
34 ** For comparison purposes, an integer is required, so make an integer
35 ** hash for the 16 bytes using MAKE_HASH16 macro, but also create a 16
36 ** byte array containing the complete 16 bytes required when writing the
40 #define MAKE_HASH16(x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) \
41 ( (x0) ^ ((x1) << 1) ^ ((x2) << 2) ^ ((x3) << 3) ^ \
42 ((x4) << 4) ^ ((x5) << 5) ^ ((x6) << 6) ^ ((x7) << 7) ^ \
43 ((x8) << 8) ^ ((x9) << 9) ^ ((xa) << 10) ^ ((xb) << 11) ^ \
44 ((xc) << 12) ^ ((xd) << 13) ^ ((xe) << 14) ^ ((xf) << 15) )
46 #define MAKE_MARKER16(name,x0,x1,x2,x3,x4,x5,x6,x7,x8,x9,xa,xb,xc,xd,xe,xf) \
47 static unsigned char name [16] = { (x0), (x1), (x2), (x3), (x4), (x5), \
48 (x6), (x7), (x8), (x9), (xa), (xb), (xc), (xd), (xe), (xf) }
50 #define riff_HASH16 MAKE_HASH16 ('r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11, \
51 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
53 #define wave_HASH16 MAKE_HASH16 ('w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11, \
54 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
56 #define fmt_HASH16 MAKE_HASH16 ('f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11, \
57 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
59 #define fact_HASH16 MAKE_HASH16 ('f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11, \
60 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
62 #define data_HASH16 MAKE_HASH16 ('d', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11, \
63 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
65 #define ACID_HASH16 MAKE_HASH16 (0x6D, 0x07, 0x1C, 0xEA, 0xA3, 0xEF, 0x78, 0x4C, \
66 0x90, 0x57, 0x7F, 0x79, 0xEE, 0x25, 0x2A, 0xAE)
68 #define levl_HASH16 MAKE_HASH16 (0x6c, 0x65, 0x76, 0x6c, 0xf3, 0xac, 0xd3, 0x11, \
69 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
71 #define list_HASH16 MAKE_HASH16 (0x6C, 0x69, 0x73, 0x74, 0x2F, 0x91, 0xCF, 0x11, \
72 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00)
74 #define junk_HASH16 MAKE_HASH16 (0x6A, 0x75, 0x6E, 0x6b, 0xF3, 0xAC, 0xD3, 0x11, \
75 0x8C, 0xD1, 0x00, 0xC0, 0x4f, 0x8E, 0xDB, 0x8A)
77 #define bext_MARKER MAKE_HASH16 (0x62, 0x65, 0x78, 0x74, 0xf3, 0xac, 0xd3, 0xaa, \
78 0xd1, 0x8c, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
80 #define MARKER_HASH16 MAKE_HASH16 (0x56, 0x62, 0xf7, 0xab, 0x2d, 0x39, 0xd2, 0x11, \
81 0x86, 0xc7, 0x00, 0xc0, 0x4f, 0x8e, 0xdb, 0x8a)
83 #define SUMLIST_HASH16 MAKE_HASH16 (0xBC, 0x94, 0x5F, 0x92, 0x5A, 0x52, 0xD2, 0x11, \
84 0x86, 0xDC, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A)
87 MAKE_MARKER16 (riff_MARKER16
, 'r', 'i', 'f', 'f', 0x2E, 0x91, 0xCF, 0x11,
88 0xA5, 0xD6, 0x28, 0xDB, 0x04, 0xC1, 0x00, 0x00) ;
91 MAKE_MARKER16 (wave_MARKER16
, 'w', 'a', 'v', 'e', 0xF3, 0xAC, 0xD3, 0x11,
92 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
94 MAKE_MARKER16 (fmt_MARKER16
, 'f', 'm', 't', ' ', 0xF3, 0xAC, 0xD3, 0x11,
95 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
97 MAKE_MARKER16 (fact_MARKER16
, 'f', 'a', 'c', 't', 0xF3, 0xAC, 0xD3, 0x11,
98 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
100 MAKE_MARKER16 (data_MARKER16
, 'd', 'a', 't', 'a', 0xF3, 0xAC, 0xD3, 0x11,
101 0x8C, 0xD1, 0x00, 0xC0, 0x4F, 0x8E, 0xDB, 0x8A) ;
111 /*------------------------------------------------------------------------------
112 * Private static functions.
115 static int w64_read_header (SF_PRIVATE
*psf
, int *blockalign
, int *framesperblock
) ;
116 static int w64_write_header (SF_PRIVATE
*psf
, int calc_length
) ;
117 static int w64_close (SF_PRIVATE
*psf
) ;
119 /*------------------------------------------------------------------------------
124 w64_open (SF_PRIVATE
*psf
)
125 { WAV_PRIVATE
* wpriv
;
126 int subformat
, error
, blockalign
= 0, framesperblock
= 0 ;
128 if ((wpriv
= calloc (1, sizeof (WAV_PRIVATE
))) == NULL
)
129 return SFE_MALLOC_FAILED
;
130 psf
->container_data
= wpriv
;
132 if (psf
->file
.mode
== SFM_READ
|| (psf
->file
.mode
== SFM_RDWR
&&psf
->filelength
> 0))
133 { if ((error
= w64_read_header (psf
, &blockalign
, &framesperblock
)))
137 if ((SF_CONTAINER (psf
->sf
.format
)) != SF_FORMAT_W64
)
138 return SFE_BAD_OPEN_FORMAT
;
140 subformat
= SF_CODEC (psf
->sf
.format
) ;
142 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
144 return SFE_NO_PIPE_WRITE
;
146 psf
->endian
= SF_ENDIAN_LITTLE
; /* All W64 files are little endian. */
148 psf
->blockwidth
= psf
->bytewidth
* psf
->sf
.channels
;
150 if (subformat
== SF_FORMAT_IMA_ADPCM
|| subformat
== SF_FORMAT_MS_ADPCM
)
151 { blockalign
= wav_w64_srate2blocksize (psf
->sf
.samplerate
* psf
->sf
.channels
) ;
152 framesperblock
= -1 ;
154 /* FIXME : This block must go */
155 psf
->filelength
= SF_COUNT_MAX
;
156 psf
->datalength
= psf
->filelength
;
157 if (psf
->sf
.frames
<= 0)
158 psf
->sf
.frames
= (psf
->blockwidth
) ? psf
->filelength
/ psf
->blockwidth
: psf
->filelength
;
159 /* EMXIF : This block must go */
162 if ((error
= w64_write_header (psf
, SF_FALSE
)))
165 psf
->write_header
= w64_write_header
;
168 psf
->container_close
= w64_close
;
171 { case SF_FORMAT_PCM_U8
:
172 error
= pcm_init (psf
) ;
175 case SF_FORMAT_PCM_16
:
176 case SF_FORMAT_PCM_24
:
177 case SF_FORMAT_PCM_32
:
178 error
= pcm_init (psf
) ;
181 case SF_FORMAT_ULAW
:
182 error
= ulaw_init (psf
) ;
185 case SF_FORMAT_ALAW
:
186 error
= alaw_init (psf
) ;
189 /* Lite remove start */
190 case SF_FORMAT_FLOAT
:
191 error
= float32_init (psf
) ;
194 case SF_FORMAT_DOUBLE
:
195 error
= double64_init (psf
) ;
198 case SF_FORMAT_IMA_ADPCM
:
199 error
= wav_w64_ima_init (psf
, blockalign
, framesperblock
) ;
202 case SF_FORMAT_MS_ADPCM
:
203 error
= wav_w64_msadpcm_init (psf
, blockalign
, framesperblock
) ;
205 /* Lite remove end */
207 case SF_FORMAT_GSM610
:
208 error
= gsm610_init (psf
) ;
211 default : return SFE_UNIMPLEMENTED
;
217 /*=========================================================================
218 ** Private functions.
222 w64_read_header (SF_PRIVATE
*psf
, int *blockalign
, int *framesperblock
)
223 { WAV_PRIVATE
*wpriv
;
225 int dword
= 0, marker
, format
= 0 ;
226 sf_count_t chunk_size
, bytesread
= 0 ;
227 int parsestage
= 0, error
, done
= 0 ;
229 if ((wpriv
= psf
->container_data
) == NULL
)
230 return SFE_INTERNAL
;
231 wav_fmt
= &wpriv
->wav_fmt
;
233 /* Set position to start of file to begin reading header. */
234 psf_binheader_readf (psf
, "p", 0) ;
237 { /* Each new chunk must start on an 8 byte boundary, so jump if needed. */
238 if (psf
->headindex
& 0x7)
239 psf_binheader_readf (psf
, "j", 8 - (psf
->headindex
& 0x7)) ;
241 /* Generate hash of 16 byte marker. */
242 bytesread
+= psf_binheader_readf (psf
, "h", &marker
) ;
248 return SFE_W64_NO_RIFF
;
250 bytesread
+= psf_binheader_readf (psf
, "e8", &chunk_size
) ;
252 if (psf
->filelength
!= chunk_size
)
253 psf_log_printf (psf
, "riff : %D (should be %D)\n", chunk_size
, psf
->filelength
) ;
255 psf_log_printf (psf
, "riff : %D\n", chunk_size
) ;
257 parsestage
|= HAVE_riff
;
261 psf_log_printf (psf
, "Looks like an ACID file. Exiting.\n") ;
262 return SFE_UNIMPLEMENTED
;
265 if ((parsestage
& HAVE_riff
) != HAVE_riff
)
266 return SFE_W64_NO_WAVE
;
267 psf_log_printf (psf
, "wave\n") ;
268 parsestage
|= HAVE_wave
;
272 if ((parsestage
& (HAVE_riff
| HAVE_wave
)) != (HAVE_riff
| HAVE_wave
))
273 return SFE_WAV_NO_FMT
;
275 bytesread
+= psf_binheader_readf (psf
, "e8", &chunk_size
) ;
276 psf_log_printf (psf
, " fmt : %D\n", chunk_size
) ;
278 /* size of 16 byte marker and 8 byte chunk_size value. */
281 if ((error
= wav_w64_read_fmt_chunk (psf
, (int) chunk_size
)))
285 psf_binheader_readf (psf
, "j", 8 - (chunk_size
% 8)) ;
287 format
= wav_fmt
->format
;
288 parsestage
|= HAVE_fmt
;
292 { sf_count_t frames
;
294 psf_binheader_readf (psf
, "e88", &chunk_size
, &frames
) ;
295 psf_log_printf (psf
, " fact : %D\n frames : %D\n",
296 chunk_size
, frames
) ;
302 if ((parsestage
& (HAVE_riff
| HAVE_wave
| HAVE_fmt
)) != (HAVE_riff
| HAVE_wave
| HAVE_fmt
))
303 return SFE_W64_NO_DATA
;
305 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
307 psf
->dataoffset
= psf_ftell (psf
) ;
309 psf
->datalength
= chunk_size
- 24 ;
312 chunk_size
+= 8 - (chunk_size
% 8) ;
314 psf_log_printf (psf
, "data : %D\n", chunk_size
) ;
316 parsestage
|= HAVE_data
;
318 if (! psf
->sf
.seekable
)
321 /* Seek past data and continue reading header. */
322 psf_fseek (psf
, chunk_size
, SEEK_CUR
) ;
326 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
327 psf_log_printf (psf
, "levl : %D\n", chunk_size
) ;
329 psf_binheader_readf (psf
, "j", dword
- 24) ;
333 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
334 psf_log_printf (psf
, "list : %D\n", chunk_size
) ;
336 psf_binheader_readf (psf
, "j", dword
- 24) ;
340 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
341 psf_log_printf (psf
, "junk : %D\n", chunk_size
) ;
343 psf_binheader_readf (psf
, "j", dword
- 24) ;
347 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
348 psf_log_printf (psf
, "bext : %D\n", chunk_size
) ;
350 psf_binheader_readf (psf
, "j", dword
- 24) ;
354 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
355 psf_log_printf (psf
, "marker : %D\n", chunk_size
) ;
357 psf_binheader_readf (psf
, "j", dword
- 24) ;
360 case SUMLIST_HASH16
:
361 psf_binheader_readf (psf
, "e8", &chunk_size
) ;
362 psf_log_printf (psf
, "summary list : %D\n", chunk_size
) ;
364 psf_binheader_readf (psf
, "j", dword
- 24) ;
368 psf_log_printf (psf
, "*** Unknown chunk marker : %X. Exiting parser.\n", marker
) ;
371 } ; /* switch (dword) */
373 if (psf
->sf
.seekable
== 0 && (parsestage
& HAVE_data
))
376 if (psf_ftell (psf
) >= (psf
->filelength
- (2 * SIGNED_SIZEOF (dword
))))
380 if (psf
->dataoffset
<= 0)
381 return SFE_W64_NO_DATA
;
383 psf
->endian
= SF_ENDIAN_LITTLE
; /* All W64 files are little endian. */
385 if (psf_ftell (psf
) != psf
->dataoffset
)
386 psf_fseek (psf
, psf
->dataoffset
, SEEK_SET
) ;
389 { if (psf
->filelength
- psf
->dataoffset
< psf
->datalength
)
390 psf
->sf
.frames
= (psf
->filelength
- psf
->dataoffset
) / psf
->blockwidth
;
392 psf
->sf
.frames
= psf
->datalength
/ psf
->blockwidth
;
396 { case WAVE_FORMAT_PCM
:
397 case WAVE_FORMAT_EXTENSIBLE
:
398 /* extensible might be FLOAT, MULAW, etc as well! */
399 psf
->sf
.format
= SF_FORMAT_W64
| u_bitwidth_to_subformat (psf
->bytewidth
* 8) ;
402 case WAVE_FORMAT_MULAW
:
403 psf
->sf
.format
= (SF_FORMAT_W64
| SF_FORMAT_ULAW
) ;
406 case WAVE_FORMAT_ALAW
:
407 psf
->sf
.format
= (SF_FORMAT_W64
| SF_FORMAT_ALAW
) ;
410 case WAVE_FORMAT_MS_ADPCM
:
411 psf
->sf
.format
= (SF_FORMAT_W64
| SF_FORMAT_MS_ADPCM
) ;
412 *blockalign
= wav_fmt
->msadpcm
.blockalign
;
413 *framesperblock
= wav_fmt
->msadpcm
.samplesperblock
;
416 case WAVE_FORMAT_IMA_ADPCM
:
417 psf
->sf
.format
= (SF_FORMAT_W64
| SF_FORMAT_IMA_ADPCM
) ;
418 *blockalign
= wav_fmt
->ima
.blockalign
;
419 *framesperblock
= wav_fmt
->ima
.samplesperblock
;
422 case WAVE_FORMAT_GSM610
:
423 psf
->sf
.format
= (SF_FORMAT_W64
| SF_FORMAT_GSM610
) ;
426 case WAVE_FORMAT_IEEE_FLOAT
:
427 psf
->sf
.format
= SF_FORMAT_W64
;
428 psf
->sf
.format
|= (psf
->bytewidth
== 8) ? SF_FORMAT_DOUBLE
: SF_FORMAT_FLOAT
;
431 default : return SFE_UNIMPLEMENTED
;
435 } /* w64_read_header */
438 w64_write_header (SF_PRIVATE
*psf
, int calc_length
)
439 { sf_count_t fmt_size
, current
;
441 int subformat
, add_fact_chunk
= SF_FALSE
;
443 current
= psf_ftell (psf
) ;
446 { psf
->filelength
= psf_get_filelen (psf
) ;
448 psf
->datalength
= psf
->filelength
- psf
->dataoffset
;
450 psf
->datalength
-= psf
->filelength
- psf
->dataend
;
453 psf
->sf
.frames
= psf
->datalength
/ (psf
->bytewidth
* psf
->sf
.channels
) ;
456 /* Reset the current header length to zero. */
457 psf
->header
[0] = 0 ;
459 psf_fseek (psf
, 0, SEEK_SET
) ;
461 /* riff marker, length, wave and 'fmt ' markers. */
462 psf_binheader_writef (psf
, "eh8hh", riff_MARKER16
, psf
->filelength
, wave_MARKER16
, fmt_MARKER16
) ;
464 subformat
= SF_CODEC (psf
->sf
.format
) ;
467 { case SF_FORMAT_PCM_U8
:
468 case SF_FORMAT_PCM_16
:
469 case SF_FORMAT_PCM_24
:
470 case SF_FORMAT_PCM_32
:
471 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
472 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
473 fmt_size
+= fmt_pad
;
475 /* fmt : format, channels, samplerate */
476 psf_binheader_writef (psf
, "e8224", fmt_size
, WAVE_FORMAT_PCM
, psf
->sf
.channels
, psf
->sf
.samplerate
) ;
477 /* fmt : bytespersec */
478 psf_binheader_writef (psf
, "e4", psf
->sf
.samplerate
* psf
->bytewidth
* psf
->sf
.channels
) ;
479 /* fmt : blockalign, bitwidth */
480 psf_binheader_writef (psf
, "e22", psf
->bytewidth
* psf
->sf
.channels
, psf
->bytewidth
* 8) ;
483 case SF_FORMAT_FLOAT
:
484 case SF_FORMAT_DOUBLE
:
485 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
486 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
487 fmt_size
+= fmt_pad
;
489 /* fmt : format, channels, samplerate */
490 psf_binheader_writef (psf
, "e8224", fmt_size
, WAVE_FORMAT_IEEE_FLOAT
, psf
->sf
.channels
, psf
->sf
.samplerate
) ;
491 /* fmt : bytespersec */
492 psf_binheader_writef (psf
, "e4", psf
->sf
.samplerate
* psf
->bytewidth
* psf
->sf
.channels
) ;
493 /* fmt : blockalign, bitwidth */
494 psf_binheader_writef (psf
, "e22", psf
->bytewidth
* psf
->sf
.channels
, psf
->bytewidth
* 8) ;
496 add_fact_chunk
= SF_TRUE
;
499 case SF_FORMAT_ULAW
:
500 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
501 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
502 fmt_size
+= fmt_pad
;
504 /* fmt : format, channels, samplerate */
505 psf_binheader_writef (psf
, "e8224", fmt_size
, WAVE_FORMAT_MULAW
, psf
->sf
.channels
, psf
->sf
.samplerate
) ;
506 /* fmt : bytespersec */
507 psf_binheader_writef (psf
, "e4", psf
->sf
.samplerate
* psf
->bytewidth
* psf
->sf
.channels
) ;
508 /* fmt : blockalign, bitwidth */
509 psf_binheader_writef (psf
, "e22", psf
->bytewidth
* psf
->sf
.channels
, 8) ;
511 add_fact_chunk
= SF_TRUE
;
514 case SF_FORMAT_ALAW
:
515 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 ;
516 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
517 fmt_size
+= fmt_pad
;
519 /* fmt : format, channels, samplerate */
520 psf_binheader_writef (psf
, "e8224", fmt_size
, WAVE_FORMAT_ALAW
, psf
->sf
.channels
, psf
->sf
.samplerate
) ;
521 /* fmt : bytespersec */
522 psf_binheader_writef (psf
, "e4", psf
->sf
.samplerate
* psf
->bytewidth
* psf
->sf
.channels
) ;
523 /* fmt : blockalign, bitwidth */
524 psf_binheader_writef (psf
, "e22", psf
->bytewidth
* psf
->sf
.channels
, 8) ;
526 add_fact_chunk
= SF_TRUE
;
529 /* Lite remove start */
530 case SF_FORMAT_IMA_ADPCM
:
531 { int blockalign
, framesperblock
, bytespersec
;
533 blockalign
= wav_w64_srate2blocksize (psf
->sf
.samplerate
* psf
->sf
.channels
) ;
534 framesperblock
= 2 * (blockalign
- 4 * psf
->sf
.channels
) / psf
->sf
.channels
+ 1 ;
535 bytespersec
= (psf
->sf
.samplerate
* blockalign
) / framesperblock
;
538 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
539 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
540 fmt_size
+= fmt_pad
;
542 /* fmt : size, WAV format type, channels. */
543 psf_binheader_writef (psf
, "e822", fmt_size
, WAVE_FORMAT_IMA_ADPCM
, psf
->sf
.channels
) ;
545 /* fmt : samplerate, bytespersec. */
546 psf_binheader_writef (psf
, "e44", psf
->sf
.samplerate
, bytespersec
) ;
548 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
549 psf_binheader_writef (psf
, "e2222", blockalign
, 4, 2, framesperblock
) ;
552 add_fact_chunk
= SF_TRUE
;
555 case SF_FORMAT_MS_ADPCM
:
556 { int blockalign
, framesperblock
, bytespersec
, extrabytes
;
558 blockalign
= wav_w64_srate2blocksize (psf
->sf
.samplerate
* psf
->sf
.channels
) ;
559 framesperblock
= 2 + 2 * (blockalign
- 7 * psf
->sf
.channels
) / psf
->sf
.channels
;
560 bytespersec
= (psf
->sf
.samplerate
* blockalign
) / framesperblock
;
563 extrabytes
= 2 + 2 + MSADPCM_ADAPT_COEFF_COUNT
* (2 + 2) ;
564 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + extrabytes
;
565 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
566 fmt_size
+= fmt_pad
;
568 /* fmt : size, W64 format type, channels. */
569 psf_binheader_writef (psf
, "e822", fmt_size
, WAVE_FORMAT_MS_ADPCM
, psf
->sf
.channels
) ;
571 /* fmt : samplerate, bytespersec. */
572 psf_binheader_writef (psf
, "e44", psf
->sf
.samplerate
, bytespersec
) ;
574 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
575 psf_binheader_writef (psf
, "e22222", blockalign
, 4, extrabytes
, framesperblock
, 7) ;
577 msadpcm_write_adapt_coeffs (psf
) ;
580 add_fact_chunk
= SF_TRUE
;
582 /* Lite remove end */
584 case SF_FORMAT_GSM610
:
587 bytespersec
= (psf
->sf
.samplerate
* WAV_W64_GSM610_BLOCKSIZE
) / WAV_W64_GSM610_SAMPLES
;
590 fmt_size
= 24 + 2 + 2 + 4 + 4 + 2 + 2 + 2 + 2 ;
591 fmt_pad
= (size_t) (8 - (fmt_size
& 0x7)) ;
592 fmt_size
+= fmt_pad
;
594 /* fmt : size, WAV format type, channels. */
595 psf_binheader_writef (psf
, "e822", fmt_size
, WAVE_FORMAT_GSM610
, psf
->sf
.channels
) ;
597 /* fmt : samplerate, bytespersec. */
598 psf_binheader_writef (psf
, "e44", psf
->sf
.samplerate
, bytespersec
) ;
600 /* fmt : blockalign, bitwidth, extrabytes, framesperblock. */
601 psf_binheader_writef (psf
, "e2222", WAV_W64_GSM610_BLOCKSIZE
, 0, 2, WAV_W64_GSM610_SAMPLES
) ;
604 add_fact_chunk
= SF_TRUE
;
607 default : return SFE_UNIMPLEMENTED
;
610 /* Pad to 8 bytes with zeros. */
612 psf_binheader_writef (psf
, "z", fmt_pad
) ;
615 psf_binheader_writef (psf
, "eh88", fact_MARKER16
, (sf_count_t
) (16 + 8 + 8), psf
->sf
.frames
) ;
617 psf_binheader_writef (psf
, "eh8", data_MARKER16
, psf
->datalength
+ 24) ;
618 psf_fwrite (psf
->header
, psf
->headindex
, 1, psf
) ;
623 psf
->dataoffset
= psf
->headindex
;
626 psf_fseek (psf
, current
, SEEK_SET
) ;
629 } /* w64_write_header */
632 w64_close (SF_PRIVATE
*psf
)
634 if (psf
->file
.mode
== SFM_WRITE
|| psf
->file
.mode
== SFM_RDWR
)
635 w64_write_header (psf
, SF_TRUE
) ;