1 1.24 mrg /* $NetBSD: wav.c,v 1.24 2024/03/20 20:18:39 mrg Exp $ */ 2 1.3 mrg 3 1.1 mrg /* 4 1.19 mrg * Copyright (c) 2002, 2009, 2013, 2015, 2019, 2024 Matthew R. Green 5 1.1 mrg * All rights reserved. 6 1.1 mrg * 7 1.1 mrg * Redistribution and use in source and binary forms, with or without 8 1.1 mrg * modification, are permitted provided that the following conditions 9 1.1 mrg * are met: 10 1.1 mrg * 1. Redistributions of source code must retain the above copyright 11 1.1 mrg * notice, this list of conditions and the following disclaimer. 12 1.1 mrg * 2. Redistributions in binary form must reproduce the above copyright 13 1.1 mrg * notice, this list of conditions and the following disclaimer in the 14 1.1 mrg * documentation and/or other materials provided with the distribution. 15 1.1 mrg * 16 1.1 mrg * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR 17 1.1 mrg * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES 18 1.1 mrg * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. 19 1.1 mrg * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT, 20 1.1 mrg * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, 21 1.1 mrg * BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 22 1.1 mrg * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED 23 1.1 mrg * AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 24 1.1 mrg * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 25 1.1 mrg * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 26 1.1 mrg * SUCH DAMAGE. 27 1.1 mrg */ 28 1.1 mrg 29 1.1 mrg /* 30 1.1 mrg * WAV support for the audio tools; thanks go to the sox utility for 31 1.1 mrg * clearing up issues with WAV files. 32 1.1 mrg */ 33 1.6 agc #include <sys/cdefs.h> 34 1.6 agc 35 1.6 agc #ifndef lint 36 1.24 mrg __RCSID("$NetBSD: wav.c,v 1.24 2024/03/20 20:18:39 mrg Exp $"); 37 1.6 agc #endif 38 1.6 agc 39 1.1 mrg 40 1.1 mrg #include <sys/types.h> 41 1.1 mrg #include <sys/audioio.h> 42 1.1 mrg #include <sys/ioctl.h> 43 1.1 mrg #include <sys/time.h> 44 1.1 mrg 45 1.1 mrg #include <ctype.h> 46 1.1 mrg #include <err.h> 47 1.1 mrg #include <stdio.h> 48 1.1 mrg #include <stdlib.h> 49 1.1 mrg #include <string.h> 50 1.9 mrg #include <stdint.h> 51 1.11 mrg #include <unistd.h> 52 1.19 mrg #include <stdbool.h> 53 1.1 mrg 54 1.1 mrg #include "libaudio.h" 55 1.11 mrg #include "auconv.h" 56 1.1 mrg 57 1.10 joerg static const struct { 58 1.1 mrg int wenc; 59 1.2 mrg const char *wname; 60 1.1 mrg } wavencs[] = { 61 1.1 mrg { WAVE_FORMAT_UNKNOWN, "Microsoft Official Unknown" }, 62 1.1 mrg { WAVE_FORMAT_PCM, "Microsoft PCM" }, 63 1.1 mrg { WAVE_FORMAT_ADPCM, "Microsoft ADPCM" }, 64 1.15 mrg { WAVE_FORMAT_IEEE_FLOAT,"Microsoft IEEE Floating-Point" }, 65 1.1 mrg { WAVE_FORMAT_ALAW, "Microsoft A-law" }, 66 1.5 wiz { WAVE_FORMAT_MULAW, "Microsoft mu-law" }, 67 1.1 mrg { WAVE_FORMAT_OKI_ADPCM,"OKI ADPCM" }, 68 1.1 mrg { WAVE_FORMAT_DIGISTD, "Digistd format" }, 69 1.1 mrg { WAVE_FORMAT_DIGIFIX, "Digifix format" }, 70 1.1 mrg { -1, "?Unknown?" }, 71 1.1 mrg }; 72 1.1 mrg 73 1.2 mrg const char * 74 1.2 mrg wav_enc_from_val(int encoding) 75 1.1 mrg { 76 1.1 mrg int i; 77 1.1 mrg 78 1.1 mrg for (i = 0; wavencs[i].wenc != -1; i++) 79 1.1 mrg if (wavencs[i].wenc == encoding) 80 1.1 mrg break; 81 1.1 mrg return (wavencs[i].wname); 82 1.1 mrg } 83 1.1 mrg 84 1.1 mrg /* 85 1.1 mrg * sample header is: 86 1.1 mrg * 87 1.1 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ 88 1.1 mrg * 89 1.1 mrg */ 90 1.1 mrg /* 91 1.1 mrg * WAV format helpers 92 1.1 mrg */ 93 1.22 mrg 94 1.23 mrg #define RIFFNAMELEN 4 95 1.23 mrg 96 1.22 mrg static bool 97 1.23 mrg find_riff_chunk(const char *search, size_t *remainp, char **wherep, uint32_t *partlen) 98 1.22 mrg { 99 1.22 mrg wav_audioheaderpart part; 100 1.22 mrg 101 1.22 mrg *partlen = 0; 102 1.22 mrg 103 1.22 mrg #define ADJUST(l) do { \ 104 1.24 mrg if (l > *(remainp)) \ 105 1.22 mrg return false; \ 106 1.22 mrg *(wherep) += (l); \ 107 1.22 mrg *(remainp) -= (l); \ 108 1.22 mrg } while (0) 109 1.22 mrg 110 1.22 mrg while (*remainp >= sizeof part) { 111 1.22 mrg const char *emsg = ""; 112 1.22 mrg uint32_t len; 113 1.22 mrg 114 1.22 mrg memcpy(&part, *wherep, sizeof part); 115 1.22 mrg ADJUST(sizeof part); 116 1.22 mrg len = getle32(part.len); 117 1.22 mrg if (len % 2) { 118 1.22 mrg emsg = " (odd length, adjusted)"; 119 1.22 mrg len += 1; 120 1.22 mrg } 121 1.23 mrg if (strncmp(part.name, search, RIFFNAMELEN) == 0) { 122 1.22 mrg *partlen = len; 123 1.22 mrg if (verbose > 1) 124 1.22 mrg fprintf(stderr, "Found part %.04s length %d%s\n", 125 1.22 mrg part.name, len, emsg); 126 1.22 mrg return true; 127 1.22 mrg } 128 1.22 mrg ADJUST(len); 129 1.22 mrg if (verbose > 1) 130 1.22 mrg fprintf(stderr, "Skipping part %.04s length %d%s\n", 131 1.22 mrg part.name, len, emsg); 132 1.22 mrg } 133 1.22 mrg #undef ADJUST 134 1.22 mrg 135 1.22 mrg return false; 136 1.22 mrg } 137 1.22 mrg 138 1.1 mrg /* 139 1.1 mrg * find a .wav header, etc. returns header length on success 140 1.1 mrg */ 141 1.1 mrg ssize_t 142 1.10 joerg audio_wav_parse_hdr(void *hdr, size_t sz, u_int *enc, u_int *prec, 143 1.13 mrg u_int *sample, u_int *channels, off_t *datasize) 144 1.1 mrg { 145 1.19 mrg char *where = hdr; 146 1.1 mrg wav_audioheaderfmt fmt; 147 1.9 mrg wav_audiohdrextensible ext; 148 1.19 mrg size_t remain = sz; 149 1.7 mrg u_int newenc, newprec; 150 1.19 mrg uint32_t len = 0; 151 1.9 mrg u_int16_t fmttag; 152 1.2 mrg static const char 153 1.23 mrg strfmt[RIFFNAMELEN] = "fmt ", 154 1.23 mrg strRIFF[RIFFNAMELEN] = "RIFF", 155 1.23 mrg strWAVE[RIFFNAMELEN] = "WAVE", 156 1.23 mrg strdata[RIFFNAMELEN] = "data"; 157 1.19 mrg bool found; 158 1.17 gson 159 1.1 mrg if (sz < 32) 160 1.1 mrg return (AUDIO_ENOENT); 161 1.1 mrg 162 1.19 mrg #define ADJUST(l) do { \ 163 1.24 mrg if ((l) > remain) \ 164 1.19 mrg return (AUDIO_ESHORTHDR); \ 165 1.19 mrg where += (l); \ 166 1.19 mrg remain -= (l); \ 167 1.19 mrg } while (0) 168 1.19 mrg 169 1.21 mrg if (memcmp(where, strRIFF, sizeof strRIFF) != 0) 170 1.1 mrg return (AUDIO_ENOENT); 171 1.21 mrg ADJUST(sizeof strRIFF); 172 1.21 mrg /* XXX we ignore the RIFF length here */ 173 1.21 mrg ADJUST(4); 174 1.21 mrg if (memcmp(where, strWAVE, sizeof strWAVE) != 0) 175 1.1 mrg return (AUDIO_ENOENT); 176 1.21 mrg ADJUST(sizeof strWAVE); 177 1.1 mrg 178 1.22 mrg found = find_riff_chunk(strfmt, &remain, &where, &len); 179 1.1 mrg 180 1.1 mrg /* too short ? */ 181 1.19 mrg if (!found || remain <= sizeof fmt) 182 1.1 mrg return (AUDIO_ESHORTHDR); 183 1.1 mrg 184 1.19 mrg memcpy(&fmt, where, sizeof fmt); 185 1.9 mrg fmttag = getle16(fmt.tag); 186 1.9 mrg if (verbose) 187 1.19 mrg printf("WAVE format tag/len: %04x/%u\n", fmttag, len); 188 1.9 mrg 189 1.9 mrg if (fmttag == WAVE_FORMAT_EXTENSIBLE) { 190 1.19 mrg if (len < sizeof(fmt) + sizeof(ext)) { 191 1.19 mrg if (verbose) 192 1.19 mrg fprintf(stderr, "short WAVE ext fmt\n"); 193 1.9 mrg return (AUDIO_ESHORTHDR); 194 1.19 mrg } 195 1.19 mrg if (remain <= sizeof ext + sizeof fmt) { 196 1.19 mrg if (verbose) 197 1.19 mrg fprintf(stderr, "WAVE ext truncated\n"); 198 1.9 mrg return (AUDIO_ESHORTHDR); 199 1.19 mrg } 200 1.19 mrg memcpy(&ext, where + sizeof fmt, sizeof ext); 201 1.14 jdolecek fmttag = getle16(ext.sub_tag); 202 1.19 mrg uint16_t sublen = getle16(ext.len); 203 1.9 mrg if (verbose) 204 1.19 mrg printf("WAVE extensible tag/len: %04x/%u\n", fmttag, sublen); 205 1.19 mrg 206 1.19 mrg /* 207 1.19 mrg * XXXMRG: it may be that part.len (aka sizeof fmt + sizeof ext) 208 1.19 mrg * should equal sizeof fmt + sizeof ext.len + sublen? this block 209 1.19 mrg * is only entered for part.len == 40, where ext.len is expected 210 1.19 mrg * to be 22 (sizeof ext.len = 2, sizeof fmt = 16). 211 1.19 mrg * 212 1.19 mrg * warn about this, but don't consider it an error. 213 1.19 mrg */ 214 1.20 mrg if (getle16(ext.len) != 22 && verbose) { 215 1.20 mrg fprintf(stderr, "warning: WAVE ext.len %u not 22\n", 216 1.20 mrg getle16(ext.len)); 217 1.20 mrg } 218 1.19 mrg } else if (len < sizeof(fmt)) { 219 1.19 mrg if (verbose) 220 1.19 mrg fprintf(stderr, "WAVE fmt unsupported size %u\n", len); 221 1.19 mrg return (AUDIO_EWAVUNSUPP); 222 1.9 mrg } 223 1.19 mrg ADJUST(len); 224 1.9 mrg 225 1.9 mrg switch (fmttag) { 226 1.1 mrg default: 227 1.1 mrg return (AUDIO_EWAVUNSUPP); 228 1.1 mrg 229 1.1 mrg case WAVE_FORMAT_PCM: 230 1.9 mrg case WAVE_FORMAT_ADPCM: 231 1.9 mrg case WAVE_FORMAT_OKI_ADPCM: 232 1.9 mrg case WAVE_FORMAT_IMA_ADPCM: 233 1.9 mrg case WAVE_FORMAT_DIGIFIX: 234 1.9 mrg case WAVE_FORMAT_DIGISTD: 235 1.1 mrg switch (getle16(fmt.bits_per_sample)) { 236 1.1 mrg case 8: 237 1.1 mrg newprec = 8; 238 1.1 mrg break; 239 1.1 mrg case 16: 240 1.1 mrg newprec = 16; 241 1.1 mrg break; 242 1.1 mrg case 24: 243 1.1 mrg newprec = 24; 244 1.1 mrg break; 245 1.1 mrg case 32: 246 1.1 mrg newprec = 32; 247 1.1 mrg break; 248 1.1 mrg default: 249 1.1 mrg return (AUDIO_EWAVBADPCM); 250 1.1 mrg } 251 1.1 mrg if (newprec == 8) 252 1.1 mrg newenc = AUDIO_ENCODING_ULINEAR_LE; 253 1.1 mrg else 254 1.1 mrg newenc = AUDIO_ENCODING_SLINEAR_LE; 255 1.1 mrg break; 256 1.1 mrg case WAVE_FORMAT_ALAW: 257 1.1 mrg newenc = AUDIO_ENCODING_ALAW; 258 1.1 mrg newprec = 8; 259 1.1 mrg break; 260 1.1 mrg case WAVE_FORMAT_MULAW: 261 1.1 mrg newenc = AUDIO_ENCODING_ULAW; 262 1.1 mrg newprec = 8; 263 1.1 mrg break; 264 1.15 mrg case WAVE_FORMAT_IEEE_FLOAT: 265 1.15 mrg switch (getle16(fmt.bits_per_sample)) { 266 1.15 mrg case 32: 267 1.15 mrg newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT32; 268 1.15 mrg newprec = 32; 269 1.15 mrg break; 270 1.15 mrg case 64: 271 1.15 mrg newenc = AUDIO_ENCODING_LIBAUDIO_FLOAT64; 272 1.15 mrg newprec = 32; 273 1.15 mrg break; 274 1.15 mrg default: 275 1.15 mrg return (AUDIO_EWAVBADPCM); 276 1.15 mrg } 277 1.15 mrg break; 278 1.1 mrg } 279 1.1 mrg 280 1.22 mrg found = find_riff_chunk(strdata, &remain, &where, &len); 281 1.19 mrg if (!found) 282 1.22 mrg return (AUDIO_EWAVNODATA); 283 1.1 mrg 284 1.24 mrg if (channels) 285 1.24 mrg *channels = (u_int)getle16(fmt.channels); 286 1.24 mrg if (sample) 287 1.24 mrg *sample = getle32(fmt.sample_rate); 288 1.24 mrg if (enc) 289 1.24 mrg *enc = newenc; 290 1.24 mrg if (prec) 291 1.24 mrg *prec = newprec; 292 1.24 mrg if (datasize) 293 1.24 mrg *datasize = (off_t)len; 294 1.24 mrg return (where - (char *)hdr); 295 1.19 mrg 296 1.19 mrg #undef ADJUST 297 1.1 mrg } 298 1.11 mrg 299 1.11 mrg 300 1.11 mrg /* 301 1.11 mrg * prepare a WAV header for writing; we fill in hdrp, lenp and leftp, 302 1.11 mrg * and expect our caller (wav_write_header()) to use them. 303 1.11 mrg */ 304 1.11 mrg int 305 1.13 mrg wav_prepare_header(struct track_info *ti, void **hdrp, size_t *lenp, int *leftp) 306 1.11 mrg { 307 1.11 mrg /* 308 1.11 mrg * WAV header we write looks like this: 309 1.11 mrg * 310 1.11 mrg * bytes purpose 311 1.11 mrg * 0-3 "RIFF" 312 1.19 mrg * 4-7 RIFF chunk length (file length minus 8) 313 1.11 mrg * 8-15 "WAVEfmt " 314 1.11 mrg * 16-19 format size 315 1.11 mrg * 20-21 format tag 316 1.11 mrg * 22-23 number of channels 317 1.11 mrg * 24-27 sample rate 318 1.11 mrg * 28-31 average bytes per second 319 1.11 mrg * 32-33 block alignment 320 1.11 mrg * 34-35 bits per sample 321 1.11 mrg * 322 1.11 mrg * then for ULAW and ALAW outputs, we have an extended chunk size 323 1.11 mrg * and a WAV "fact" to add: 324 1.11 mrg * 325 1.11 mrg * 36-37 length of extension (== 0) 326 1.11 mrg * 38-41 "fact" 327 1.11 mrg * 42-45 fact size 328 1.11 mrg * 46-49 number of samples written 329 1.11 mrg * 50-53 "data" 330 1.11 mrg * 54-57 data length 331 1.11 mrg * 58- raw audio data 332 1.11 mrg * 333 1.11 mrg * for PCM outputs we have just the data remaining: 334 1.11 mrg * 335 1.11 mrg * 36-39 "data" 336 1.11 mrg * 40-43 data length 337 1.11 mrg * 44- raw audio data 338 1.11 mrg * 339 1.11 mrg * RIFF\^@^C^@WAVEfmt ^P^@^@^@^A^@^B^@D<AC>^@^@^P<B1>^B^@^D^@^P^@data^@^@^C^@^@^@^@^@^@^@^@^@^@ 340 1.11 mrg */ 341 1.11 mrg static char wavheaderbuf[64]; 342 1.11 mrg char *p = wavheaderbuf; 343 1.11 mrg const char *riff = "RIFF", 344 1.11 mrg *wavefmt = "WAVEfmt ", 345 1.11 mrg *fact = "fact", 346 1.11 mrg *data = "data"; 347 1.11 mrg u_int32_t filelen, fmtsz, sps, abps, factsz = 4, nsample, datalen; 348 1.12 christos u_int16_t fmttag, nchan, align, extln = 0; 349 1.11 mrg 350 1.13 mrg if (ti->header_info) 351 1.11 mrg warnx("header information not supported for WAV"); 352 1.11 mrg *leftp = 0; 353 1.11 mrg 354 1.13 mrg switch (ti->precision) { 355 1.11 mrg case 8: 356 1.11 mrg break; 357 1.11 mrg case 16: 358 1.11 mrg break; 359 1.16 mlelstv case 24: 360 1.16 mlelstv break; 361 1.11 mrg case 32: 362 1.11 mrg break; 363 1.11 mrg default: 364 1.11 mrg { 365 1.11 mrg static int warned = 0; 366 1.11 mrg 367 1.11 mrg if (warned == 0) { 368 1.13 mrg warnx("can not support precision of %d", ti->precision); 369 1.11 mrg warned = 1; 370 1.11 mrg } 371 1.11 mrg } 372 1.11 mrg return (-1); 373 1.11 mrg } 374 1.11 mrg 375 1.13 mrg switch (ti->encoding) { 376 1.11 mrg case AUDIO_ENCODING_ULAW: 377 1.11 mrg fmttag = WAVE_FORMAT_MULAW; 378 1.11 mrg fmtsz = 18; 379 1.13 mrg align = ti->channels; 380 1.11 mrg break; 381 1.11 mrg 382 1.11 mrg case AUDIO_ENCODING_ALAW: 383 1.11 mrg fmttag = WAVE_FORMAT_ALAW; 384 1.11 mrg fmtsz = 18; 385 1.13 mrg align = ti->channels; 386 1.11 mrg break; 387 1.11 mrg 388 1.11 mrg /* 389 1.11 mrg * we could try to support RIFX but it seems to be more portable 390 1.11 mrg * to output little-endian data for WAV files. 391 1.11 mrg */ 392 1.11 mrg case AUDIO_ENCODING_ULINEAR_BE: 393 1.11 mrg case AUDIO_ENCODING_SLINEAR_BE: 394 1.11 mrg case AUDIO_ENCODING_ULINEAR_LE: 395 1.11 mrg case AUDIO_ENCODING_SLINEAR_LE: 396 1.11 mrg case AUDIO_ENCODING_PCM16: 397 1.11 mrg 398 1.11 mrg #if BYTE_ORDER == LITTLE_ENDIAN 399 1.11 mrg case AUDIO_ENCODING_ULINEAR: 400 1.11 mrg case AUDIO_ENCODING_SLINEAR: 401 1.11 mrg #endif 402 1.11 mrg fmttag = WAVE_FORMAT_PCM; 403 1.11 mrg fmtsz = 16; 404 1.13 mrg align = ti->channels * (ti->precision / 8); 405 1.11 mrg break; 406 1.11 mrg 407 1.11 mrg default: 408 1.11 mrg #if 0 // move into record.c, and maybe merge.c 409 1.11 mrg { 410 1.11 mrg static int warned = 0; 411 1.11 mrg 412 1.11 mrg if (warned == 0) { 413 1.13 mrg const char *s = wav_enc_from_val(ti->encoding); 414 1.11 mrg 415 1.11 mrg if (s == NULL) 416 1.11 mrg warnx("can not support encoding of %s", s); 417 1.11 mrg else 418 1.13 mrg warnx("can not support encoding of %d", ti->encoding); 419 1.11 mrg warned = 1; 420 1.11 mrg } 421 1.11 mrg } 422 1.11 mrg #endif 423 1.13 mrg ti->format = AUDIO_FORMAT_NONE; 424 1.11 mrg return (-1); 425 1.11 mrg } 426 1.11 mrg 427 1.13 mrg nchan = ti->channels; 428 1.13 mrg sps = ti->sample_rate; 429 1.11 mrg 430 1.11 mrg /* data length */ 431 1.13 mrg if (ti->outfd == STDOUT_FILENO) 432 1.11 mrg datalen = 0; 433 1.13 mrg else if (ti->total_size != -1) 434 1.13 mrg datalen = ti->total_size; 435 1.11 mrg else 436 1.11 mrg datalen = 0; 437 1.11 mrg 438 1.11 mrg /* file length */ 439 1.11 mrg filelen = 4 + (8 + fmtsz) + (8 + datalen); 440 1.11 mrg if (fmttag != WAVE_FORMAT_PCM) 441 1.11 mrg filelen += 8 + factsz; 442 1.11 mrg 443 1.13 mrg abps = (double)align*ti->sample_rate / (double)1 + 0.5; 444 1.11 mrg 445 1.13 mrg nsample = (datalen / ti->precision) / ti->sample_rate; 446 1.18 gson 447 1.11 mrg /* 448 1.11 mrg * now we've calculated the info, write it out! 449 1.11 mrg */ 450 1.11 mrg #define put32(x) do { \ 451 1.11 mrg u_int32_t _f; \ 452 1.11 mrg putle32(_f, (x)); \ 453 1.11 mrg memcpy(p, &_f, 4); \ 454 1.11 mrg } while (0) 455 1.11 mrg #define put16(x) do { \ 456 1.11 mrg u_int16_t _f; \ 457 1.11 mrg putle16(_f, (x)); \ 458 1.11 mrg memcpy(p, &_f, 2); \ 459 1.11 mrg } while (0) 460 1.11 mrg memcpy(p, riff, 4); 461 1.11 mrg p += 4; /* 4 */ 462 1.11 mrg put32(filelen); 463 1.11 mrg p += 4; /* 8 */ 464 1.11 mrg memcpy(p, wavefmt, 8); 465 1.11 mrg p += 8; /* 16 */ 466 1.11 mrg put32(fmtsz); 467 1.11 mrg p += 4; /* 20 */ 468 1.11 mrg put16(fmttag); 469 1.11 mrg p += 2; /* 22 */ 470 1.11 mrg put16(nchan); 471 1.11 mrg p += 2; /* 24 */ 472 1.11 mrg put32(sps); 473 1.11 mrg p += 4; /* 28 */ 474 1.11 mrg put32(abps); 475 1.11 mrg p += 4; /* 32 */ 476 1.11 mrg put16(align); 477 1.11 mrg p += 2; /* 34 */ 478 1.13 mrg put16(ti->precision); 479 1.11 mrg p += 2; /* 36 */ 480 1.11 mrg /* NON PCM formats have an extended chunk; write it */ 481 1.11 mrg if (fmttag != WAVE_FORMAT_PCM) { 482 1.11 mrg put16(extln); 483 1.11 mrg p += 2; /* 38 */ 484 1.11 mrg memcpy(p, fact, 4); 485 1.11 mrg p += 4; /* 42 */ 486 1.11 mrg put32(factsz); 487 1.11 mrg p += 4; /* 46 */ 488 1.11 mrg put32(nsample); 489 1.11 mrg p += 4; /* 50 */ 490 1.11 mrg } 491 1.11 mrg memcpy(p, data, 4); 492 1.11 mrg p += 4; /* 40/54 */ 493 1.11 mrg put32(datalen); 494 1.11 mrg p += 4; /* 44/58 */ 495 1.11 mrg #undef put32 496 1.11 mrg #undef put16 497 1.11 mrg 498 1.11 mrg *hdrp = wavheaderbuf; 499 1.11 mrg *lenp = (p - wavheaderbuf); 500 1.11 mrg 501 1.11 mrg return 0; 502 1.11 mrg } 503 1.11 mrg 504 1.11 mrg write_conv_func 505 1.13 mrg wav_write_get_conv_func(struct track_info *ti) 506 1.11 mrg { 507 1.11 mrg write_conv_func conv_func = NULL; 508 1.11 mrg 509 1.13 mrg switch (ti->encoding) { 510 1.11 mrg 511 1.11 mrg /* 512 1.11 mrg * we could try to support RIFX but it seems to be more portable 513 1.11 mrg * to output little-endian data for WAV files. 514 1.11 mrg */ 515 1.11 mrg case AUDIO_ENCODING_ULINEAR_BE: 516 1.11 mrg #if BYTE_ORDER == BIG_ENDIAN 517 1.11 mrg case AUDIO_ENCODING_ULINEAR: 518 1.11 mrg #endif 519 1.13 mrg if (ti->precision == 16) 520 1.11 mrg conv_func = change_sign16_swap_bytes_be; 521 1.13 mrg else if (ti->precision == 32) 522 1.11 mrg conv_func = change_sign32_swap_bytes_be; 523 1.11 mrg break; 524 1.11 mrg 525 1.11 mrg case AUDIO_ENCODING_SLINEAR_BE: 526 1.11 mrg #if BYTE_ORDER == BIG_ENDIAN 527 1.11 mrg case AUDIO_ENCODING_SLINEAR: 528 1.11 mrg #endif 529 1.13 mrg if (ti->precision == 8) 530 1.11 mrg conv_func = change_sign8; 531 1.13 mrg else if (ti->precision == 16) 532 1.11 mrg conv_func = swap_bytes; 533 1.13 mrg else if (ti->precision == 32) 534 1.11 mrg conv_func = swap_bytes32; 535 1.11 mrg break; 536 1.11 mrg 537 1.11 mrg case AUDIO_ENCODING_ULINEAR_LE: 538 1.11 mrg #if BYTE_ORDER == LITTLE_ENDIAN 539 1.11 mrg case AUDIO_ENCODING_ULINEAR: 540 1.11 mrg #endif 541 1.13 mrg if (ti->precision == 16) 542 1.11 mrg conv_func = change_sign16_le; 543 1.13 mrg else if (ti->precision == 32) 544 1.11 mrg conv_func = change_sign32_le; 545 1.11 mrg break; 546 1.11 mrg 547 1.11 mrg case AUDIO_ENCODING_SLINEAR_LE: 548 1.11 mrg case AUDIO_ENCODING_PCM16: 549 1.11 mrg #if BYTE_ORDER == LITTLE_ENDIAN 550 1.11 mrg case AUDIO_ENCODING_SLINEAR: 551 1.11 mrg #endif 552 1.13 mrg if (ti->precision == 8) 553 1.11 mrg conv_func = change_sign8; 554 1.11 mrg break; 555 1.11 mrg 556 1.11 mrg default: 557 1.13 mrg ti->format = AUDIO_FORMAT_NONE; 558 1.11 mrg } 559 1.11 mrg 560 1.11 mrg return conv_func; 561 1.11 mrg } 562