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