annotate src/libsndfile-1.0.27/src/w64.c @ 169:223a55898ab9 tip default

Add null config files
author Chris Cannam <cannam@all-day-breakfast.com>
date Mon, 02 Mar 2020 14:03:47 +0000
parents cd6cdf86811e
children
rev   line source
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