1 /* 2 * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org> 3 * 4 * Permission to use, copy, modify, and distribute this software for any 5 * purpose with or without fee is hereby granted, provided that the above 6 * copyright notice and this permission notice appear in all copies. 7 * 8 * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 9 * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 10 * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 11 * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 12 * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 13 * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 14 * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 15 */ 16 17 #include <fcntl.h> 18 #include <string.h> 19 #include <unistd.h> 20 #include "afile.h" 21 #include "utils.h" 22 23 typedef struct { 24 unsigned char ld[4]; 25 } le32_t; 26 27 typedef struct { 28 unsigned char lw[2]; 29 } le16_t; 30 31 typedef struct { 32 unsigned char bd[4]; 33 } be32_t; 34 35 typedef struct { 36 unsigned char bw[2]; 37 } be16_t; 38 39 struct wav_riff { 40 char id[4]; 41 le32_t size; 42 char type[4]; 43 }; 44 45 struct wav_chunk { 46 char id[4]; 47 le32_t size; 48 }; 49 50 struct wav_fmt { 51 #define WAV_FMT_PCM 1 52 #define WAV_FMT_FLOAT 3 53 #define WAV_FMT_ALAW 6 54 #define WAV_FMT_ULAW 7 55 #define WAV_FMT_EXT 0xfffe 56 le16_t fmt; 57 le16_t nch; 58 le32_t rate; 59 le32_t byterate; 60 le16_t blkalign; 61 le16_t bits; 62 #define WAV_FMT_SIZE 16 63 #define WAV_FMT_EXT_SIZE (16 + 24) 64 le16_t extsize; 65 le16_t valbits; 66 le32_t chanmask; 67 le16_t extfmt; 68 char guid[14]; 69 }; 70 71 struct wav_hdr { 72 struct wav_riff riff; /* 00..11 */ 73 struct wav_chunk fmt_hdr; /* 12..20 */ 74 struct wav_fmt fmt; 75 struct wav_chunk data_hdr; 76 }; 77 78 struct aiff_form { 79 char id[4]; 80 be32_t size; 81 char type[4]; 82 }; 83 84 struct aiff_chunk { 85 char id[4]; 86 be32_t size; 87 }; 88 89 struct aiff_comm { 90 struct aiff_commbase { 91 be16_t nch; 92 be32_t nfr; 93 be16_t bits; 94 /* rate in 80-bit floating point */ 95 be16_t rate_ex; 96 be32_t rate_hi; 97 be32_t rate_lo; 98 } base; 99 char comp_id[4]; 100 /* followed by stuff we don't care about */ 101 }; 102 103 struct aiff_data { 104 be32_t offs; 105 be32_t blksz; 106 }; 107 108 struct aiff_hdr { 109 struct aiff_form form; 110 struct aiff_chunk comm_hdr; 111 struct aiff_commbase comm; 112 struct aiff_chunk data_hdr; 113 struct aiff_data data; 114 }; 115 116 struct au_hdr { 117 char id[4]; 118 be32_t offs; 119 be32_t size; 120 #define AU_FMT_PCM8 2 121 #define AU_FMT_PCM16 3 122 #define AU_FMT_PCM24 4 123 #define AU_FMT_PCM32 5 124 #define AU_FMT_FLOAT 6 125 #define AU_FMT_ALAW 0x1b 126 #define AU_FMT_ULAW 1 127 be32_t fmt; 128 be32_t rate; 129 be32_t nch; 130 char desc[8]; 131 /* followed by optional desc[] continuation */ 132 }; 133 134 const char wav_id_riff[4] = {'R', 'I', 'F', 'F'}; 135 const char wav_id_wave[4] = {'W', 'A', 'V', 'E'}; 136 const char wav_id_data[4] = {'d', 'a', 't', 'a'}; 137 const char wav_id_fmt[4] = {'f', 'm', 't', ' '}; 138 const char wav_guid[14] = { 139 0x00, 0x00, 0x00, 0x00, 140 0x10, 0x00, 0x80, 0x00, 141 0x00, 0xAA, 0x00, 0x38, 142 0x9B, 0x71 143 }; 144 145 const char aiff_id_form[4] = {'F', 'O', 'R', 'M'}; 146 const char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'}; 147 const char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'}; 148 const char aiff_id_data[4] = {'S', 'S', 'N', 'D'}; 149 const char aiff_id_comm[4] = {'C', 'O', 'M', 'M'}; 150 const char aiff_id_none[4] = {'N', 'O', 'N', 'E'}; 151 const char aiff_id_fl32[4] = {'f', 'l', '3', '2'}; 152 const char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'}; 153 const char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'}; 154 155 const char au_id[4] = {'.', 's', 'n', 'd'}; 156 157 static inline unsigned int 158 le16_get(le16_t *p) 159 { 160 return p->lw[0] | p->lw[1] << 8; 161 } 162 163 static inline void 164 le16_set(le16_t *p, unsigned int v) 165 { 166 p->lw[0] = v; 167 p->lw[1] = v >> 8; 168 } 169 170 static inline unsigned int 171 le32_get(le32_t *p) 172 { 173 return p->ld[0] | 174 p->ld[1] << 8 | 175 p->ld[2] << 16 | 176 p->ld[3] << 24; 177 } 178 179 static inline void 180 le32_set(le32_t *p, unsigned int v) 181 { 182 p->ld[0] = v; 183 p->ld[1] = v >> 8; 184 p->ld[2] = v >> 16; 185 p->ld[3] = v >> 24; 186 } 187 188 static inline unsigned int 189 be16_get(be16_t *p) 190 { 191 return p->bw[1] | p->bw[0] << 8; 192 } 193 194 static inline void 195 be16_set(be16_t *p, unsigned int v) 196 { 197 p->bw[1] = v; 198 p->bw[0] = v >> 8; 199 } 200 201 static inline unsigned int 202 be32_get(be32_t *p) 203 { 204 return p->bd[3] | 205 p->bd[2] << 8 | 206 p->bd[1] << 16 | 207 p->bd[0] << 24; 208 } 209 210 static inline void 211 be32_set(be32_t *p, unsigned int v) 212 { 213 p->bd[3] = v; 214 p->bd[2] = v >> 8; 215 p->bd[1] = v >> 16; 216 p->bd[0] = v >> 24; 217 } 218 219 static int 220 afile_readhdr(struct afile *f, void *addr, size_t size) 221 { 222 if (lseek(f->fd, 0, SEEK_SET) == -1) { 223 logx(1, "%s: failed to seek to beginning of file", f->path); 224 return 0; 225 } 226 if (read(f->fd, addr, size) != size) { 227 logx(1, "%s: failed to read header", f->path); 228 return 0; 229 } 230 return 1; 231 } 232 233 static int 234 afile_writehdr(struct afile *f, void *addr, size_t size) 235 { 236 if (lseek(f->fd, 0, SEEK_SET) == -1) { 237 logx(1, "%s: failed to seek back to header", f->path); 238 return 0; 239 } 240 if (write(f->fd, addr, size) != size) { 241 logx(1, "%s: failed to write header", f->path); 242 return 0; 243 } 244 f->curpos = f->startpos; 245 return 1; 246 } 247 248 static int 249 afile_checkpar(struct afile *f) 250 { 251 if (f->nch == 0 || f->nch > NCHAN_MAX) { 252 logx(1, "%s: %u: unsupported number of channels", f->path, f->nch); 253 return 0; 254 } 255 if (f->rate < RATE_MIN || f->rate > RATE_MAX) { 256 logx(1, "%s: %u: unsupported rate", f->path, f->rate); 257 return 0; 258 } 259 if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) { 260 logx(1, "%s: %u: unsupported bits per sample", f->path, f->par.bits); 261 return 0; 262 } 263 if (f->par.bits > f->par.bps * 8) { 264 logx(1, "%s: bits larger than bytes-per-sample", f->path); 265 return 0; 266 } 267 if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) { 268 logx(1, "%s: only 32-bit floating points are supported", f->path); 269 return 0; 270 } 271 return 1; 272 } 273 274 static int 275 afile_wav_readfmt(struct afile *f, unsigned int csize) 276 { 277 struct wav_fmt fmt; 278 unsigned int wenc; 279 280 if (csize < WAV_FMT_SIZE) { 281 logx(1, "%s: %u: bogus format chunk size", f->path, csize); 282 return 0; 283 } 284 if (csize > WAV_FMT_EXT_SIZE) 285 csize = WAV_FMT_EXT_SIZE; 286 if (read(f->fd, &fmt, csize) != csize) { 287 logx(1, "%s: failed to read format chunk", f->path); 288 return 0; 289 } 290 wenc = le16_get(&fmt.fmt); 291 f->par.bits = le16_get(&fmt.bits); 292 if (wenc == WAV_FMT_EXT) { 293 if (csize != WAV_FMT_EXT_SIZE) { 294 logx(1, "%s: missing extended format chunk", f->path); 295 return 0; 296 } 297 if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) { 298 logx(1, "%s: unknown format (GUID)", f->path); 299 return 0; 300 } 301 f->par.bps = (f->par.bits + 7) / 8; 302 f->par.bits = le16_get(&fmt.valbits); 303 wenc = le16_get(&fmt.extfmt); 304 } else 305 f->par.bps = (f->par.bits + 7) / 8; 306 f->nch = le16_get(&fmt.nch); 307 f->rate = le32_get(&fmt.rate); 308 f->par.le = 1; 309 f->par.msb = 1; 310 switch (wenc) { 311 case WAV_FMT_PCM: 312 f->fmt = AFILE_FMT_PCM; 313 f->par.sig = (f->par.bits <= 8) ? 0 : 1; 314 break; 315 case WAV_FMT_ALAW: 316 f->fmt = AFILE_FMT_ALAW; 317 f->par.bits = 8; 318 f->par.bps = 1; 319 break; 320 case WAV_FMT_ULAW: 321 f->fmt = AFILE_FMT_ULAW; 322 f->par.bits = 8; 323 f->par.bps = 1; 324 break; 325 case WAV_FMT_FLOAT: 326 f->fmt = AFILE_FMT_FLOAT; 327 break; 328 default: 329 logx(1, "%s: %u: unsupported encoding", f->path, wenc); 330 return 0; 331 } 332 return afile_checkpar(f); 333 } 334 335 static int 336 afile_wav_readhdr(struct afile *f) 337 { 338 struct wav_riff riff; 339 struct wav_chunk chunk; 340 unsigned int csize, rsize, pos = 0; 341 int fmt_done = 0; 342 343 if (!afile_readhdr(f, &riff, sizeof(struct wav_riff))) 344 return 0; 345 if (memcmp(&riff.id, &wav_id_riff, 4) != 0 || 346 memcmp(&riff.type, &wav_id_wave, 4) != 0) { 347 logx(1, "%s: not a .wav file", f->path); 348 return 0; 349 } 350 rsize = le32_get(&riff.size); 351 for (;;) { 352 if (pos + sizeof(struct wav_chunk) > rsize) { 353 logx(1, "%s: missing data chunk", f->path); 354 return 0; 355 } 356 if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) { 357 logx(1, "%s: failed to read chunk header", f->path); 358 return 0; 359 } 360 csize = le32_get(&chunk.size); 361 if (memcmp(chunk.id, wav_id_fmt, 4) == 0) { 362 if (!afile_wav_readfmt(f, csize)) 363 return 0; 364 fmt_done = 1; 365 } else if (memcmp(chunk.id, wav_id_data, 4) == 0) { 366 f->startpos = pos + sizeof(riff) + sizeof(chunk); 367 f->endpos = f->startpos + csize; 368 break; 369 } else { 370 #ifdef DEBUG 371 if (log_level >= 2) { 372 logx(1, "%s: skipped unknown chunk", f->path); 373 } 374 #endif 375 } 376 377 /* 378 * next chunk 379 */ 380 pos += sizeof(struct wav_chunk) + csize; 381 if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) == -1) { 382 logx(1, "%s: failed to seek to chunk", f->path); 383 return 0; 384 } 385 } 386 if (!fmt_done) { 387 logx(1, "%s: missing format chunk", f->path); 388 return 0; 389 } 390 return 1; 391 } 392 393 /* 394 * Write header and seek to start position 395 */ 396 static int 397 afile_wav_writehdr(struct afile *f) 398 { 399 struct wav_hdr hdr; 400 401 memset(&hdr, 0, sizeof(struct wav_hdr)); 402 memcpy(hdr.riff.id, wav_id_riff, 4); 403 memcpy(hdr.riff.type, wav_id_wave, 4); 404 le32_set(&hdr.riff.size, f->endpos - sizeof(hdr.riff)); 405 memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4); 406 le32_set(&hdr.fmt_hdr.size, sizeof(hdr.fmt)); 407 le16_set(&hdr.fmt.fmt, WAV_FMT_EXT); 408 le16_set(&hdr.fmt.nch, f->nch); 409 le32_set(&hdr.fmt.rate, f->rate); 410 le32_set(&hdr.fmt.byterate, f->rate * f->par.bps * f->nch); 411 le16_set(&hdr.fmt.blkalign, f->par.bps * f->nch); 412 le16_set(&hdr.fmt.bits, f->par.bits); 413 le16_set(&hdr.fmt.extsize, 414 WAV_FMT_EXT_SIZE - WAV_FMT_SIZE - sizeof(hdr.fmt.extsize)); 415 le16_set(&hdr.fmt.valbits, f->par.bits); 416 le16_set(&hdr.fmt.extfmt, 1); 417 memcpy(&hdr.fmt.guid, wav_guid, sizeof(hdr.fmt.guid)); 418 memcpy(hdr.data_hdr.id, wav_id_data, 4); 419 le32_set(&hdr.data_hdr.size, f->endpos - f->startpos); 420 return afile_writehdr(f, &hdr, sizeof(struct wav_hdr)); 421 } 422 423 static int 424 afile_aiff_readcomm(struct afile *f, unsigned int csize, 425 int comp, unsigned int *nfr) 426 { 427 struct aiff_comm comm; 428 unsigned int csize_min; 429 unsigned int e, m; 430 431 csize_min = comp ? 432 sizeof(struct aiff_comm) : sizeof(struct aiff_commbase); 433 if (csize < csize_min) { 434 logx(1, "%s: %u: bogus comm chunk size", f->path, csize); 435 return 0; 436 } 437 if (read(f->fd, &comm, csize_min) != csize_min) { 438 logx(1, "%s: failed to read comm chunk", f->path); 439 return 0; 440 } 441 f->nch = be16_get(&comm.base.nch); 442 e = be16_get(&comm.base.rate_ex); 443 m = be32_get(&comm.base.rate_hi); 444 if (e < 0x3fff || e > 0x3fff + 31) { 445 logx(1, "%s: malformed sample rate", f->path); 446 return 0; 447 } 448 f->rate = m >> (0x3fff + 31 - e); 449 if (comp) { 450 if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) { 451 f->fmt = AFILE_FMT_PCM; 452 f->par.bits = be16_get(&comm.base.bits); 453 } else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) { 454 f->fmt = AFILE_FMT_FLOAT; 455 f->par.bits = 32; 456 } else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) { 457 f->fmt = AFILE_FMT_ULAW; 458 f->par.bits = 8; 459 } else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) { 460 f->fmt = AFILE_FMT_ALAW; 461 f->par.bits = 8; 462 } else { 463 logx(1, "%s: unsupported encoding", f->path); 464 return 0; 465 } 466 } else { 467 f->fmt = AFILE_FMT_PCM; 468 f->par.bits = be16_get(&comm.base.bits); 469 } 470 f->par.le = 0; 471 f->par.sig = 1; 472 f->par.msb = 1; 473 f->par.bps = (f->par.bits + 7) / 8; 474 *nfr = be32_get(&comm.base.nfr); 475 return afile_checkpar(f); 476 } 477 478 static int 479 afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs) 480 { 481 struct aiff_data data; 482 483 if (csize < sizeof(struct aiff_data)) { 484 logx(1, "%s: %u: bogus data chunk size", f->path, csize); 485 return 0; 486 } 487 csize = sizeof(struct aiff_data); 488 if (read(f->fd, &data, csize) != csize) { 489 logx(1, "%s: failed to read data chunk", f->path); 490 return 0; 491 } 492 *roffs = csize + be32_get(&data.offs); 493 return 1; 494 } 495 496 static int 497 afile_aiff_readhdr(struct afile *f) 498 { 499 struct aiff_form form; 500 struct aiff_chunk chunk; 501 unsigned int csize, rsize, nfr = 0, pos = 0, offs; 502 int comm_done = 0, comp; 503 504 if (!afile_readhdr(f, &form, sizeof(struct aiff_form))) 505 return 0; 506 if (memcmp(&form.id, &aiff_id_form, 4) != 0) { 507 logx(1, "%s: not an aiff file", f->path); 508 return 0; 509 } 510 if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) { 511 comp = 0; 512 } else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0) 513 comp = 1; 514 else { 515 logx(1, "%s: unsupported aiff file sub-type", f->path); 516 return 0; 517 } 518 rsize = be32_get(&form.size); 519 for (;;) { 520 if (pos + sizeof(struct aiff_chunk) > rsize) { 521 logx(1, "%s: missing data chunk", f->path); 522 return 0; 523 } 524 if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) { 525 logx(1, "%s: failed to read chunk header", f->path); 526 return 0; 527 } 528 csize = be32_get(&chunk.size); 529 if (memcmp(chunk.id, aiff_id_comm, 4) == 0) { 530 if (!afile_aiff_readcomm(f, csize, comp, &nfr)) 531 return 0; 532 comm_done = 1; 533 } else if (memcmp(chunk.id, aiff_id_data, 4) == 0) { 534 if (!afile_aiff_readdata(f, csize, &offs)) 535 return 0; 536 f->startpos = sizeof(form) + pos + 537 sizeof(chunk) + offs; 538 break; 539 } else { 540 #ifdef DEBUG 541 logx(2, "%s: skipped unknown chunk", f->path); 542 #endif 543 } 544 545 /* 546 * The aiff spec says "Each Chunk must contain an even 547 * number of bytes. For those Chunks whose total 548 * contents would yield an odd number of bytes, a zero 549 * pad byte must be added at the end of the Chunk. This 550 * pad byte is not included in ckDataSize, which 551 * indicates the size of the data in the Chunk." 552 */ 553 csize = (csize + 1) & ~1; 554 pos += sizeof(struct aiff_chunk) + csize; 555 556 if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) { 557 logx(1, "%s: failed to seek to chunk", f->path); 558 return 0; 559 } 560 } 561 if (!comm_done) { 562 logx(1, "%s: missing comm chunk", f->path); 563 return 0; 564 } 565 f->endpos = f->startpos + f->par.bps * f->nch * nfr; 566 return 1; 567 } 568 569 /* 570 * Write header and seek to start position 571 */ 572 static int 573 afile_aiff_writehdr(struct afile *f) 574 { 575 struct aiff_hdr hdr; 576 unsigned int bpf; 577 unsigned int e, m; 578 579 /* convert rate to 80-bit float (exponent and fraction part) */ 580 m = f->rate; 581 e = 0x3fff + 31; 582 while ((m & 0x80000000) == 0) { 583 e--; 584 m <<= 1; 585 } 586 587 /* bytes per frame */ 588 bpf = f->nch * f->par.bps; 589 590 memset(&hdr, 0, sizeof(struct aiff_hdr)); 591 memcpy(hdr.form.id, aiff_id_form, 4); 592 memcpy(hdr.form.type, aiff_id_aiff, 4); 593 be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form)); 594 595 memcpy(hdr.comm_hdr.id, aiff_id_comm, 4); 596 be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm)); 597 be16_set(&hdr.comm.nch, f->nch); 598 be16_set(&hdr.comm.bits, f->par.bits); 599 be16_set(&hdr.comm.rate_ex, e); 600 be32_set(&hdr.comm.rate_hi, m); 601 be32_set(&hdr.comm.rate_lo, 0); 602 be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf); 603 604 memcpy(hdr.data_hdr.id, aiff_id_data, 4); 605 be32_set(&hdr.data_hdr.size, f->endpos - f->startpos); 606 be32_set(&hdr.data.offs, 0); 607 be32_set(&hdr.data.blksz, 0); 608 return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr)); 609 } 610 611 static int 612 afile_au_readhdr(struct afile *f) 613 { 614 struct au_hdr hdr; 615 unsigned int fmt; 616 617 if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr))) 618 return 0; 619 if (memcmp(&hdr.id, &au_id, 4) != 0) { 620 logx(1, "%s: not a .au file", f->path); 621 return 0; 622 } 623 f->startpos = be32_get(&hdr.offs); 624 f->endpos = f->startpos + be32_get(&hdr.size); 625 fmt = be32_get(&hdr.fmt); 626 switch (fmt) { 627 case AU_FMT_PCM8: 628 f->fmt = AFILE_FMT_PCM; 629 f->par.bits = 8; 630 break; 631 case AU_FMT_PCM16: 632 f->fmt = AFILE_FMT_PCM; 633 f->par.bits = 16; 634 break; 635 case AU_FMT_PCM24: 636 f->fmt = AFILE_FMT_PCM; 637 f->par.bits = 24; 638 break; 639 case AU_FMT_PCM32: 640 f->fmt = AFILE_FMT_PCM; 641 f->par.bits = 32; 642 break; 643 case AU_FMT_ULAW: 644 f->fmt = AFILE_FMT_ULAW; 645 f->par.bits = 8; 646 break; 647 case AU_FMT_ALAW: 648 f->fmt = AFILE_FMT_ALAW; 649 f->par.bits = 8; 650 break; 651 case AU_FMT_FLOAT: 652 f->fmt = AFILE_FMT_FLOAT; 653 f->par.bits = 32; 654 break; 655 default: 656 logx(1, "%s: %u: unsupported encoding", f->path, fmt); 657 return 0; 658 } 659 f->par.le = 0; 660 f->par.sig = 1; 661 f->par.bps = f->par.bits / 8; 662 f->par.msb = 0; 663 f->rate = be32_get(&hdr.rate); 664 f->nch = be32_get(&hdr.nch); 665 if (lseek(f->fd, f->startpos, SEEK_SET) == -1) { 666 logx(1, "%s: failed to seek to data chunk", f->path); 667 return 0; 668 } 669 return afile_checkpar(f); 670 } 671 672 /* 673 * Write header and seek to start position 674 */ 675 static int 676 afile_au_writehdr(struct afile *f) 677 { 678 struct au_hdr hdr; 679 unsigned int fmt; 680 681 memset(&hdr, 0, sizeof(struct au_hdr)); 682 memcpy(hdr.id, au_id, 4); 683 be32_set(&hdr.offs, f->startpos); 684 be32_set(&hdr.size, f->endpos - f->startpos); 685 switch (f->par.bits) { 686 case 8: 687 fmt = AU_FMT_PCM8; 688 break; 689 case 16: 690 fmt = AU_FMT_PCM16; 691 break; 692 case 24: 693 fmt = AU_FMT_PCM24; 694 break; 695 case 32: 696 fmt = AU_FMT_PCM32; 697 break; 698 #ifdef DEBUG 699 default: 700 logx(1, "%s: %u: wrong precision", f->path, f->par.bits); 701 panic(); 702 return 0; 703 #endif 704 } 705 be32_set(&hdr.fmt, fmt); 706 be32_set(&hdr.rate, f->rate); 707 be32_set(&hdr.nch, f->nch); 708 return afile_writehdr(f, &hdr, sizeof(struct au_hdr)); 709 } 710 711 size_t 712 afile_read(struct afile *f, void *data, size_t count) 713 { 714 off_t maxread; 715 ssize_t n; 716 717 if (f->endpos >= 0) { 718 maxread = f->endpos - f->curpos; 719 if (maxread == 0) { 720 #ifdef DEBUG 721 logx(3, "%s: end reached", f->path); 722 #endif 723 return 0; 724 } 725 if (count > maxread) 726 count = maxread; 727 } 728 n = read(f->fd, data, count); 729 if (n == -1) { 730 logx(1, "%s: couldn't read", f->path); 731 return 0; 732 } 733 f->curpos += n; 734 return n; 735 } 736 737 size_t 738 afile_write(struct afile *f, void *data, size_t count) 739 { 740 off_t maxwrite; 741 int n; 742 743 if (f->maxpos >= 0) { 744 maxwrite = f->maxpos - f->curpos; 745 if (maxwrite == 0) { 746 #ifdef DEBUG 747 logx(3, "%s: max file size reached", f->path); 748 #endif 749 return 0; 750 } 751 if (count > maxwrite) 752 count = maxwrite; 753 } 754 n = write(f->fd, data, count); 755 if (n == -1) { 756 logx(1, "%s: couldn't write", f->path); 757 return 0; 758 } 759 f->curpos += n; 760 if (f->endpos < f->curpos) 761 f->endpos = f->curpos; 762 return n; 763 } 764 765 int 766 afile_seek(struct afile *f, off_t pos) 767 { 768 pos += f->startpos; 769 if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) { 770 logx(1, "%s: attempt to seek outside file boundaries", f->path); 771 return 0; 772 } 773 774 /* 775 * seek only if needed to avoid errors with pipes & sockets 776 */ 777 if (pos != f->curpos) { 778 if (lseek(f->fd, pos, SEEK_SET) == -1) { 779 logx(1, "%s: couldn't seek", f->path); 780 return 0; 781 } 782 f->curpos = pos; 783 } 784 return 1; 785 } 786 787 void 788 afile_close(struct afile *f) 789 { 790 if (f->flags & AFILE_FWRITE) { 791 if (f->hdr == AFILE_HDR_WAV) 792 afile_wav_writehdr(f); 793 else if (f->hdr == AFILE_HDR_AIFF) 794 afile_aiff_writehdr(f); 795 else if (f->hdr == AFILE_HDR_AU) 796 afile_au_writehdr(f); 797 } 798 close(f->fd); 799 } 800 801 int 802 afile_open(struct afile *f, char *path, int hdr, int flags, 803 struct aparams *par, int rate, int nch) 804 { 805 char *ext; 806 static union { 807 struct wav_hdr wav; 808 struct aiff_hdr aiff; 809 struct au_hdr au; 810 } dummy; 811 812 f->par = *par; 813 f->rate = rate; 814 f->nch = nch; 815 f->flags = flags; 816 f->hdr = hdr; 817 if (hdr == AFILE_HDR_AUTO) { 818 f->hdr = AFILE_HDR_RAW; 819 ext = strrchr(path, '.'); 820 if (ext != NULL) { 821 ext++; 822 if (strcasecmp(ext, "aif") == 0 || 823 strcasecmp(ext, "aiff") == 0 || 824 strcasecmp(ext, "aifc") == 0) 825 f->hdr = AFILE_HDR_AIFF; 826 else if (strcasecmp(ext, "au") == 0 || 827 strcasecmp(ext, "snd") == 0) 828 f->hdr = AFILE_HDR_AU; 829 else if (strcasecmp(ext, "wav") == 0) 830 f->hdr = AFILE_HDR_WAV; 831 } 832 } 833 if (f->flags == AFILE_FREAD) { 834 if (strcmp(path, "-") == 0) { 835 f->path = "stdin"; 836 f->fd = STDIN_FILENO; 837 } else { 838 f->path = path; 839 f->fd = open(f->path, O_RDONLY); 840 if (f->fd == -1) { 841 logx(1, "%s: failed to open for reading", f->path); 842 return 0; 843 } 844 } 845 if (f->hdr == AFILE_HDR_WAV) { 846 if (!afile_wav_readhdr(f)) 847 goto bad_close; 848 } else if (f->hdr == AFILE_HDR_AIFF) { 849 if (!afile_aiff_readhdr(f)) 850 goto bad_close; 851 } else if (f->hdr == AFILE_HDR_AU) { 852 if (!afile_au_readhdr(f)) 853 goto bad_close; 854 } else { 855 f->startpos = 0; 856 f->endpos = -1; /* read until EOF */ 857 f->fmt = AFILE_FMT_PCM; 858 } 859 f->curpos = f->startpos; 860 } else if (flags == AFILE_FWRITE) { 861 if (strcmp(path, "-") == 0) { 862 f->path = "stdout"; 863 f->fd = STDOUT_FILENO; 864 } else { 865 f->path = path; 866 f->fd = open(f->path, 867 O_WRONLY | O_TRUNC | O_CREAT, 0666); 868 if (f->fd == -1) { 869 logx(1, "%s: failed to create file", f->path); 870 return 0; 871 } 872 } 873 if (f->hdr == AFILE_HDR_WAV) { 874 f->par.bps = (f->par.bits + 7) >> 3; 875 if (f->par.bits > 8) { 876 f->par.le = 1; 877 f->par.sig = 1; 878 } else 879 f->par.sig = 0; 880 if (f->par.bits & 7) 881 f->par.msb = 1; 882 f->endpos = f->startpos = sizeof(struct wav_hdr); 883 f->maxpos = 0x7fffffff; 884 if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr))) 885 goto bad_close; 886 } else if (f->hdr == AFILE_HDR_AIFF) { 887 f->par.bps = (f->par.bits + 7) >> 3; 888 if (f->par.bps > 1) 889 f->par.le = 0; 890 f->par.sig = 1; 891 if (f->par.bits & 7) 892 f->par.msb = 1; 893 f->endpos = f->startpos = sizeof(struct aiff_hdr); 894 f->maxpos = 0x7fffffff; 895 if (!afile_writehdr(f, &dummy, 896 sizeof(struct aiff_hdr))) 897 goto bad_close; 898 } else if (f->hdr == AFILE_HDR_AU) { 899 f->par.bits = (f->par.bits + 7) & ~7; 900 f->par.bps = f->par.bits / 8; 901 f->par.le = 0; 902 f->par.sig = 1; 903 f->par.msb = 1; 904 f->endpos = f->startpos = sizeof(struct au_hdr); 905 f->maxpos = 0x7fffffff; 906 if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr))) 907 goto bad_close; 908 } else { 909 f->endpos = f->startpos = 0; 910 f->maxpos = -1; 911 } 912 f->curpos = f->startpos; 913 } else { 914 #ifdef DEBUG 915 logx(1, "afile_open: 0x%x: wrong flags", flags); 916 panic(); 917 #endif 918 } 919 return 1; 920 bad_close: 921 close(f->fd); 922 return 0; 923 } 924