110ba9548Sratchov /* 210ba9548Sratchov * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org> 310ba9548Sratchov * 410ba9548Sratchov * Permission to use, copy, modify, and distribute this software for any 510ba9548Sratchov * purpose with or without fee is hereby granted, provided that the above 610ba9548Sratchov * copyright notice and this permission notice appear in all copies. 710ba9548Sratchov * 810ba9548Sratchov * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES 910ba9548Sratchov * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF 1010ba9548Sratchov * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR 1110ba9548Sratchov * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES 1210ba9548Sratchov * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN 1310ba9548Sratchov * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF 1410ba9548Sratchov * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. 1510ba9548Sratchov */ 1610ba9548Sratchov 1710ba9548Sratchov #include <fcntl.h> 1810ba9548Sratchov #include <string.h> 1910ba9548Sratchov #include <unistd.h> 2010ba9548Sratchov #include "afile.h" 2110ba9548Sratchov #include "utils.h" 2210ba9548Sratchov 2310ba9548Sratchov typedef struct { 2410ba9548Sratchov unsigned char ld[4]; 2510ba9548Sratchov } le32_t; 2610ba9548Sratchov 2710ba9548Sratchov typedef struct { 2810ba9548Sratchov unsigned char lw[2]; 2910ba9548Sratchov } le16_t; 3010ba9548Sratchov 3110ba9548Sratchov typedef struct { 3210ba9548Sratchov unsigned char bd[4]; 3310ba9548Sratchov } be32_t; 3410ba9548Sratchov 3510ba9548Sratchov typedef struct { 3610ba9548Sratchov unsigned char bw[2]; 3710ba9548Sratchov } be16_t; 3810ba9548Sratchov 3910ba9548Sratchov struct wav_riff { 4010ba9548Sratchov char id[4]; 4110ba9548Sratchov le32_t size; 4210ba9548Sratchov char type[4]; 4310ba9548Sratchov }; 4410ba9548Sratchov 4510ba9548Sratchov struct wav_chunk { 4610ba9548Sratchov char id[4]; 4710ba9548Sratchov le32_t size; 4810ba9548Sratchov }; 4910ba9548Sratchov 5010ba9548Sratchov struct wav_fmt { 5110ba9548Sratchov #define WAV_FMT_PCM 1 5210ba9548Sratchov #define WAV_FMT_FLOAT 3 5310ba9548Sratchov #define WAV_FMT_ALAW 6 5410ba9548Sratchov #define WAV_FMT_ULAW 7 5510ba9548Sratchov #define WAV_FMT_EXT 0xfffe 5610ba9548Sratchov le16_t fmt; 5710ba9548Sratchov le16_t nch; 5810ba9548Sratchov le32_t rate; 5910ba9548Sratchov le32_t byterate; 6010ba9548Sratchov le16_t blkalign; 6110ba9548Sratchov le16_t bits; 6210ba9548Sratchov #define WAV_FMT_SIZE 16 6310ba9548Sratchov #define WAV_FMT_EXT_SIZE (16 + 24) 6410ba9548Sratchov le16_t extsize; 6510ba9548Sratchov le16_t valbits; 6610ba9548Sratchov le32_t chanmask; 6710ba9548Sratchov le16_t extfmt; 6810ba9548Sratchov char guid[14]; 6910ba9548Sratchov }; 7010ba9548Sratchov 7110ba9548Sratchov struct wav_hdr { 7210ba9548Sratchov struct wav_riff riff; /* 00..11 */ 7310ba9548Sratchov struct wav_chunk fmt_hdr; /* 12..20 */ 7410ba9548Sratchov struct wav_fmt fmt; 7510ba9548Sratchov struct wav_chunk data_hdr; 7610ba9548Sratchov }; 7710ba9548Sratchov 7810ba9548Sratchov struct aiff_form { 7910ba9548Sratchov char id[4]; 8010ba9548Sratchov be32_t size; 8110ba9548Sratchov char type[4]; 8210ba9548Sratchov }; 8310ba9548Sratchov 8410ba9548Sratchov struct aiff_chunk { 8510ba9548Sratchov char id[4]; 8610ba9548Sratchov be32_t size; 8710ba9548Sratchov }; 8810ba9548Sratchov 8910ba9548Sratchov struct aiff_comm { 9010ba9548Sratchov struct aiff_commbase { 9110ba9548Sratchov be16_t nch; 9210ba9548Sratchov be32_t nfr; 9310ba9548Sratchov be16_t bits; 9410ba9548Sratchov /* rate in 80-bit floating point */ 9510ba9548Sratchov be16_t rate_ex; 9610ba9548Sratchov be32_t rate_hi; 9710ba9548Sratchov be32_t rate_lo; 9810ba9548Sratchov } base; 9910ba9548Sratchov char comp_id[4]; 10010ba9548Sratchov /* followed by stuff we don't care about */ 10110ba9548Sratchov }; 10210ba9548Sratchov 10310ba9548Sratchov struct aiff_data { 10410ba9548Sratchov be32_t offs; 10510ba9548Sratchov be32_t blksz; 10610ba9548Sratchov }; 10710ba9548Sratchov 10810ba9548Sratchov struct aiff_hdr { 10910ba9548Sratchov struct aiff_form form; 11010ba9548Sratchov struct aiff_chunk comm_hdr; 11110ba9548Sratchov struct aiff_commbase comm; 11210ba9548Sratchov struct aiff_chunk data_hdr; 11310ba9548Sratchov struct aiff_data data; 11410ba9548Sratchov }; 11510ba9548Sratchov 11610ba9548Sratchov struct au_hdr { 11710ba9548Sratchov char id[4]; 11810ba9548Sratchov be32_t offs; 11910ba9548Sratchov be32_t size; 12010ba9548Sratchov #define AU_FMT_PCM8 2 12110ba9548Sratchov #define AU_FMT_PCM16 3 12210ba9548Sratchov #define AU_FMT_PCM24 4 12310ba9548Sratchov #define AU_FMT_PCM32 5 12410ba9548Sratchov #define AU_FMT_FLOAT 6 12510ba9548Sratchov #define AU_FMT_ALAW 0x1b 12610ba9548Sratchov #define AU_FMT_ULAW 1 12710ba9548Sratchov be32_t fmt; 12810ba9548Sratchov be32_t rate; 12910ba9548Sratchov be32_t nch; 13010ba9548Sratchov char desc[8]; 13110ba9548Sratchov /* followed by optional desc[] continuation */ 13210ba9548Sratchov }; 13310ba9548Sratchov 134b020cfe1Snaddy const char wav_id_riff[4] = {'R', 'I', 'F', 'F'}; 135b020cfe1Snaddy const char wav_id_wave[4] = {'W', 'A', 'V', 'E'}; 136b020cfe1Snaddy const char wav_id_data[4] = {'d', 'a', 't', 'a'}; 137b020cfe1Snaddy const char wav_id_fmt[4] = {'f', 'm', 't', ' '}; 138b020cfe1Snaddy const char wav_guid[14] = { 13910ba9548Sratchov 0x00, 0x00, 0x00, 0x00, 14010ba9548Sratchov 0x10, 0x00, 0x80, 0x00, 14110ba9548Sratchov 0x00, 0xAA, 0x00, 0x38, 14210ba9548Sratchov 0x9B, 0x71 14310ba9548Sratchov }; 14410ba9548Sratchov 145b020cfe1Snaddy const char aiff_id_form[4] = {'F', 'O', 'R', 'M'}; 146b020cfe1Snaddy const char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'}; 147b020cfe1Snaddy const char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'}; 148b020cfe1Snaddy const char aiff_id_data[4] = {'S', 'S', 'N', 'D'}; 149b020cfe1Snaddy const char aiff_id_comm[4] = {'C', 'O', 'M', 'M'}; 150b020cfe1Snaddy const char aiff_id_none[4] = {'N', 'O', 'N', 'E'}; 151b020cfe1Snaddy const char aiff_id_fl32[4] = {'f', 'l', '3', '2'}; 152b020cfe1Snaddy const char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'}; 153b020cfe1Snaddy const char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'}; 15410ba9548Sratchov 155b020cfe1Snaddy const char au_id[4] = {'.', 's', 'n', 'd'}; 15610ba9548Sratchov 15710ba9548Sratchov static inline unsigned int 15810ba9548Sratchov le16_get(le16_t *p) 15910ba9548Sratchov { 16010ba9548Sratchov return p->lw[0] | p->lw[1] << 8; 16110ba9548Sratchov } 16210ba9548Sratchov 16310ba9548Sratchov static inline void 16410ba9548Sratchov le16_set(le16_t *p, unsigned int v) 16510ba9548Sratchov { 16610ba9548Sratchov p->lw[0] = v; 16710ba9548Sratchov p->lw[1] = v >> 8; 16810ba9548Sratchov } 16910ba9548Sratchov 17010ba9548Sratchov static inline unsigned int 17110ba9548Sratchov le32_get(le32_t *p) 17210ba9548Sratchov { 17310ba9548Sratchov return p->ld[0] | 17410ba9548Sratchov p->ld[1] << 8 | 17510ba9548Sratchov p->ld[2] << 16 | 17610ba9548Sratchov p->ld[3] << 24; 17710ba9548Sratchov } 17810ba9548Sratchov 17910ba9548Sratchov static inline void 18010ba9548Sratchov le32_set(le32_t *p, unsigned int v) 18110ba9548Sratchov { 18210ba9548Sratchov p->ld[0] = v; 18310ba9548Sratchov p->ld[1] = v >> 8; 18410ba9548Sratchov p->ld[2] = v >> 16; 18510ba9548Sratchov p->ld[3] = v >> 24; 18610ba9548Sratchov } 18710ba9548Sratchov 18810ba9548Sratchov static inline unsigned int 18910ba9548Sratchov be16_get(be16_t *p) 19010ba9548Sratchov { 19110ba9548Sratchov return p->bw[1] | p->bw[0] << 8; 19210ba9548Sratchov } 19310ba9548Sratchov 19410ba9548Sratchov static inline void 19510ba9548Sratchov be16_set(be16_t *p, unsigned int v) 19610ba9548Sratchov { 19710ba9548Sratchov p->bw[1] = v; 19810ba9548Sratchov p->bw[0] = v >> 8; 19910ba9548Sratchov } 20010ba9548Sratchov 20110ba9548Sratchov static inline unsigned int 20210ba9548Sratchov be32_get(be32_t *p) 20310ba9548Sratchov { 20410ba9548Sratchov return p->bd[3] | 20510ba9548Sratchov p->bd[2] << 8 | 20610ba9548Sratchov p->bd[1] << 16 | 20710ba9548Sratchov p->bd[0] << 24; 20810ba9548Sratchov } 20910ba9548Sratchov 21010ba9548Sratchov static inline void 21110ba9548Sratchov be32_set(be32_t *p, unsigned int v) 21210ba9548Sratchov { 21310ba9548Sratchov p->bd[3] = v; 21410ba9548Sratchov p->bd[2] = v >> 8; 21510ba9548Sratchov p->bd[1] = v >> 16; 21610ba9548Sratchov p->bd[0] = v >> 24; 21710ba9548Sratchov } 21810ba9548Sratchov 21910ba9548Sratchov static int 22010ba9548Sratchov afile_readhdr(struct afile *f, void *addr, size_t size) 22110ba9548Sratchov { 2223aaa63ebSderaadt if (lseek(f->fd, 0, SEEK_SET) == -1) { 223*b4d5e3c9Sratchov logx(1, "%s: failed to seek to beginning of file", f->path); 22410ba9548Sratchov return 0; 22510ba9548Sratchov } 22610ba9548Sratchov if (read(f->fd, addr, size) != size) { 227*b4d5e3c9Sratchov logx(1, "%s: failed to read header", f->path); 22810ba9548Sratchov return 0; 22910ba9548Sratchov } 23010ba9548Sratchov return 1; 23110ba9548Sratchov } 23210ba9548Sratchov 23310ba9548Sratchov static int 23410ba9548Sratchov afile_writehdr(struct afile *f, void *addr, size_t size) 23510ba9548Sratchov { 2363aaa63ebSderaadt if (lseek(f->fd, 0, SEEK_SET) == -1) { 237*b4d5e3c9Sratchov logx(1, "%s: failed to seek back to header", f->path); 23810ba9548Sratchov return 0; 23910ba9548Sratchov } 24010ba9548Sratchov if (write(f->fd, addr, size) != size) { 241*b4d5e3c9Sratchov logx(1, "%s: failed to write header", f->path); 24210ba9548Sratchov return 0; 24310ba9548Sratchov } 24410ba9548Sratchov f->curpos = f->startpos; 24510ba9548Sratchov return 1; 24610ba9548Sratchov } 24710ba9548Sratchov 24810ba9548Sratchov static int 24910ba9548Sratchov afile_checkpar(struct afile *f) 25010ba9548Sratchov { 25110ba9548Sratchov if (f->nch == 0 || f->nch > NCHAN_MAX) { 252*b4d5e3c9Sratchov logx(1, "%s: %u: unsupported number of channels", f->path, f->nch); 25310ba9548Sratchov return 0; 25410ba9548Sratchov } 25510ba9548Sratchov if (f->rate < RATE_MIN || f->rate > RATE_MAX) { 256*b4d5e3c9Sratchov logx(1, "%s: %u: unsupported rate", f->path, f->rate); 25710ba9548Sratchov return 0; 25810ba9548Sratchov } 25910ba9548Sratchov if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) { 260*b4d5e3c9Sratchov logx(1, "%s: %u: unsupported bits per sample", f->path, f->par.bits); 26110ba9548Sratchov return 0; 26210ba9548Sratchov } 26310ba9548Sratchov if (f->par.bits > f->par.bps * 8) { 264*b4d5e3c9Sratchov logx(1, "%s: bits larger than bytes-per-sample", f->path); 26510ba9548Sratchov return 0; 26610ba9548Sratchov } 26710ba9548Sratchov if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) { 268*b4d5e3c9Sratchov logx(1, "%s: only 32-bit floating points are supported", f->path); 26910ba9548Sratchov return 0; 27010ba9548Sratchov } 27110ba9548Sratchov return 1; 27210ba9548Sratchov } 27310ba9548Sratchov 27410ba9548Sratchov static int 27510ba9548Sratchov afile_wav_readfmt(struct afile *f, unsigned int csize) 27610ba9548Sratchov { 27710ba9548Sratchov struct wav_fmt fmt; 27810ba9548Sratchov unsigned int wenc; 27910ba9548Sratchov 28010ba9548Sratchov if (csize < WAV_FMT_SIZE) { 281*b4d5e3c9Sratchov logx(1, "%s: %u: bogus format chunk size", f->path, csize); 28210ba9548Sratchov return 0; 28310ba9548Sratchov } 28410ba9548Sratchov if (csize > WAV_FMT_EXT_SIZE) 28510ba9548Sratchov csize = WAV_FMT_EXT_SIZE; 28610ba9548Sratchov if (read(f->fd, &fmt, csize) != csize) { 287*b4d5e3c9Sratchov logx(1, "%s: failed to read format chunk", f->path); 28810ba9548Sratchov return 0; 28910ba9548Sratchov } 29010ba9548Sratchov wenc = le16_get(&fmt.fmt); 29110ba9548Sratchov f->par.bits = le16_get(&fmt.bits); 29210ba9548Sratchov if (wenc == WAV_FMT_EXT) { 29310ba9548Sratchov if (csize != WAV_FMT_EXT_SIZE) { 294*b4d5e3c9Sratchov logx(1, "%s: missing extended format chunk", f->path); 29510ba9548Sratchov return 0; 29610ba9548Sratchov } 29710ba9548Sratchov if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) { 298*b4d5e3c9Sratchov logx(1, "%s: unknown format (GUID)", f->path); 29910ba9548Sratchov return 0; 30010ba9548Sratchov } 30110ba9548Sratchov f->par.bps = (f->par.bits + 7) / 8; 30210ba9548Sratchov f->par.bits = le16_get(&fmt.valbits); 30310ba9548Sratchov wenc = le16_get(&fmt.extfmt); 30410ba9548Sratchov } else 30510ba9548Sratchov f->par.bps = (f->par.bits + 7) / 8; 30610ba9548Sratchov f->nch = le16_get(&fmt.nch); 30710ba9548Sratchov f->rate = le32_get(&fmt.rate); 30810ba9548Sratchov f->par.le = 1; 30910ba9548Sratchov f->par.msb = 1; 31010ba9548Sratchov switch (wenc) { 31110ba9548Sratchov case WAV_FMT_PCM: 31210ba9548Sratchov f->fmt = AFILE_FMT_PCM; 31310ba9548Sratchov f->par.sig = (f->par.bits <= 8) ? 0 : 1; 31410ba9548Sratchov break; 31510ba9548Sratchov case WAV_FMT_ALAW: 31610ba9548Sratchov f->fmt = AFILE_FMT_ALAW; 31710ba9548Sratchov f->par.bits = 8; 31810ba9548Sratchov f->par.bps = 1; 31910ba9548Sratchov break; 32010ba9548Sratchov case WAV_FMT_ULAW: 32110ba9548Sratchov f->fmt = AFILE_FMT_ULAW; 32210ba9548Sratchov f->par.bits = 8; 32310ba9548Sratchov f->par.bps = 1; 32410ba9548Sratchov break; 32510ba9548Sratchov case WAV_FMT_FLOAT: 32610ba9548Sratchov f->fmt = AFILE_FMT_FLOAT; 32710ba9548Sratchov break; 32810ba9548Sratchov default: 329*b4d5e3c9Sratchov logx(1, "%s: %u: unsupported encoding", f->path, wenc); 33010ba9548Sratchov return 0; 33110ba9548Sratchov } 33210ba9548Sratchov return afile_checkpar(f); 33310ba9548Sratchov } 33410ba9548Sratchov 33510ba9548Sratchov static int 33610ba9548Sratchov afile_wav_readhdr(struct afile *f) 33710ba9548Sratchov { 33810ba9548Sratchov struct wav_riff riff; 33910ba9548Sratchov struct wav_chunk chunk; 34010ba9548Sratchov unsigned int csize, rsize, pos = 0; 34110ba9548Sratchov int fmt_done = 0; 34210ba9548Sratchov 34310ba9548Sratchov if (!afile_readhdr(f, &riff, sizeof(struct wav_riff))) 34410ba9548Sratchov return 0; 34510ba9548Sratchov if (memcmp(&riff.id, &wav_id_riff, 4) != 0 || 3464e3fdb5bSop memcmp(&riff.type, &wav_id_wave, 4) != 0) { 347*b4d5e3c9Sratchov logx(1, "%s: not a .wav file", f->path); 34810ba9548Sratchov return 0; 34910ba9548Sratchov } 35010ba9548Sratchov rsize = le32_get(&riff.size); 35110ba9548Sratchov for (;;) { 35210ba9548Sratchov if (pos + sizeof(struct wav_chunk) > rsize) { 353*b4d5e3c9Sratchov logx(1, "%s: missing data chunk", f->path); 35410ba9548Sratchov return 0; 35510ba9548Sratchov } 35610ba9548Sratchov if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) { 357*b4d5e3c9Sratchov logx(1, "%s: failed to read chunk header", f->path); 35810ba9548Sratchov return 0; 35910ba9548Sratchov } 36010ba9548Sratchov csize = le32_get(&chunk.size); 36110ba9548Sratchov if (memcmp(chunk.id, wav_id_fmt, 4) == 0) { 36210ba9548Sratchov if (!afile_wav_readfmt(f, csize)) 36310ba9548Sratchov return 0; 36410ba9548Sratchov fmt_done = 1; 36510ba9548Sratchov } else if (memcmp(chunk.id, wav_id_data, 4) == 0) { 36610ba9548Sratchov f->startpos = pos + sizeof(riff) + sizeof(chunk); 36710ba9548Sratchov f->endpos = f->startpos + csize; 36810ba9548Sratchov break; 36910ba9548Sratchov } else { 37010ba9548Sratchov #ifdef DEBUG 37110ba9548Sratchov if (log_level >= 2) { 372*b4d5e3c9Sratchov logx(1, "%s: skipped unknown chunk", f->path); 37310ba9548Sratchov } 37410ba9548Sratchov #endif 37510ba9548Sratchov } 37610ba9548Sratchov 37710ba9548Sratchov /* 37810ba9548Sratchov * next chunk 37910ba9548Sratchov */ 38010ba9548Sratchov pos += sizeof(struct wav_chunk) + csize; 3813aaa63ebSderaadt if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) == -1) { 382*b4d5e3c9Sratchov logx(1, "%s: failed to seek to chunk", f->path); 38310ba9548Sratchov return 0; 38410ba9548Sratchov } 38510ba9548Sratchov } 38610ba9548Sratchov if (!fmt_done) { 387*b4d5e3c9Sratchov logx(1, "%s: missing format chunk", f->path); 38810ba9548Sratchov return 0; 38910ba9548Sratchov } 39010ba9548Sratchov return 1; 39110ba9548Sratchov } 39210ba9548Sratchov 39310ba9548Sratchov /* 39410ba9548Sratchov * Write header and seek to start position 39510ba9548Sratchov */ 39610ba9548Sratchov static int 39710ba9548Sratchov afile_wav_writehdr(struct afile *f) 39810ba9548Sratchov { 39910ba9548Sratchov struct wav_hdr hdr; 40010ba9548Sratchov 40110ba9548Sratchov memset(&hdr, 0, sizeof(struct wav_hdr)); 40210ba9548Sratchov memcpy(hdr.riff.id, wav_id_riff, 4); 40310ba9548Sratchov memcpy(hdr.riff.type, wav_id_wave, 4); 40410ba9548Sratchov le32_set(&hdr.riff.size, f->endpos - sizeof(hdr.riff)); 40510ba9548Sratchov memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4); 40610ba9548Sratchov le32_set(&hdr.fmt_hdr.size, sizeof(hdr.fmt)); 407293b7b88Sratchov le16_set(&hdr.fmt.fmt, WAV_FMT_EXT); 40810ba9548Sratchov le16_set(&hdr.fmt.nch, f->nch); 40910ba9548Sratchov le32_set(&hdr.fmt.rate, f->rate); 41010ba9548Sratchov le32_set(&hdr.fmt.byterate, f->rate * f->par.bps * f->nch); 41110ba9548Sratchov le16_set(&hdr.fmt.blkalign, f->par.bps * f->nch); 41210ba9548Sratchov le16_set(&hdr.fmt.bits, f->par.bits); 413293b7b88Sratchov le16_set(&hdr.fmt.extsize, 414293b7b88Sratchov WAV_FMT_EXT_SIZE - WAV_FMT_SIZE - sizeof(hdr.fmt.extsize)); 415293b7b88Sratchov le16_set(&hdr.fmt.valbits, f->par.bits); 416293b7b88Sratchov le16_set(&hdr.fmt.extfmt, 1); 417293b7b88Sratchov memcpy(&hdr.fmt.guid, wav_guid, sizeof(hdr.fmt.guid)); 41810ba9548Sratchov memcpy(hdr.data_hdr.id, wav_id_data, 4); 41910ba9548Sratchov le32_set(&hdr.data_hdr.size, f->endpos - f->startpos); 42010ba9548Sratchov return afile_writehdr(f, &hdr, sizeof(struct wav_hdr)); 42110ba9548Sratchov } 42210ba9548Sratchov 42310ba9548Sratchov static int 42410ba9548Sratchov afile_aiff_readcomm(struct afile *f, unsigned int csize, 42510ba9548Sratchov int comp, unsigned int *nfr) 42610ba9548Sratchov { 42710ba9548Sratchov struct aiff_comm comm; 42810ba9548Sratchov unsigned int csize_min; 42910ba9548Sratchov unsigned int e, m; 43010ba9548Sratchov 43110ba9548Sratchov csize_min = comp ? 43210ba9548Sratchov sizeof(struct aiff_comm) : sizeof(struct aiff_commbase); 43310ba9548Sratchov if (csize < csize_min) { 434*b4d5e3c9Sratchov logx(1, "%s: %u: bogus comm chunk size", f->path, csize); 43510ba9548Sratchov return 0; 43610ba9548Sratchov } 43710ba9548Sratchov if (read(f->fd, &comm, csize_min) != csize_min) { 438*b4d5e3c9Sratchov logx(1, "%s: failed to read comm chunk", f->path); 43910ba9548Sratchov return 0; 44010ba9548Sratchov } 44110ba9548Sratchov f->nch = be16_get(&comm.base.nch); 44210ba9548Sratchov e = be16_get(&comm.base.rate_ex); 44310ba9548Sratchov m = be32_get(&comm.base.rate_hi); 44410ba9548Sratchov if (e < 0x3fff || e > 0x3fff + 31) { 445*b4d5e3c9Sratchov logx(1, "%s: malformed sample rate", f->path); 44610ba9548Sratchov return 0; 44710ba9548Sratchov } 44810ba9548Sratchov f->rate = m >> (0x3fff + 31 - e); 44910ba9548Sratchov if (comp) { 45010ba9548Sratchov if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) { 45110ba9548Sratchov f->fmt = AFILE_FMT_PCM; 45210ba9548Sratchov f->par.bits = be16_get(&comm.base.bits); 45310ba9548Sratchov } else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) { 45410ba9548Sratchov f->fmt = AFILE_FMT_FLOAT; 45510ba9548Sratchov f->par.bits = 32; 45610ba9548Sratchov } else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) { 45710ba9548Sratchov f->fmt = AFILE_FMT_ULAW; 45810ba9548Sratchov f->par.bits = 8; 45910ba9548Sratchov } else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) { 46010ba9548Sratchov f->fmt = AFILE_FMT_ALAW; 46110ba9548Sratchov f->par.bits = 8; 46210ba9548Sratchov } else { 463*b4d5e3c9Sratchov logx(1, "%s: unsupported encoding", f->path); 46410ba9548Sratchov return 0; 46510ba9548Sratchov } 46610ba9548Sratchov } else { 46710ba9548Sratchov f->fmt = AFILE_FMT_PCM; 46810ba9548Sratchov f->par.bits = be16_get(&comm.base.bits); 46910ba9548Sratchov } 47010ba9548Sratchov f->par.le = 0; 47110ba9548Sratchov f->par.sig = 1; 47210ba9548Sratchov f->par.msb = 1; 47310ba9548Sratchov f->par.bps = (f->par.bits + 7) / 8; 47410ba9548Sratchov *nfr = be32_get(&comm.base.nfr); 47510ba9548Sratchov return afile_checkpar(f); 47610ba9548Sratchov } 47710ba9548Sratchov 47810ba9548Sratchov static int 47910ba9548Sratchov afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs) 48010ba9548Sratchov { 48110ba9548Sratchov struct aiff_data data; 48210ba9548Sratchov 48310ba9548Sratchov if (csize < sizeof(struct aiff_data)) { 484*b4d5e3c9Sratchov logx(1, "%s: %u: bogus data chunk size", f->path, csize); 48510ba9548Sratchov return 0; 48610ba9548Sratchov } 48710ba9548Sratchov csize = sizeof(struct aiff_data); 48810ba9548Sratchov if (read(f->fd, &data, csize) != csize) { 489*b4d5e3c9Sratchov logx(1, "%s: failed to read data chunk", f->path); 49010ba9548Sratchov return 0; 49110ba9548Sratchov } 49210ba9548Sratchov *roffs = csize + be32_get(&data.offs); 49310ba9548Sratchov return 1; 49410ba9548Sratchov } 49510ba9548Sratchov 49610ba9548Sratchov static int 49710ba9548Sratchov afile_aiff_readhdr(struct afile *f) 49810ba9548Sratchov { 49910ba9548Sratchov struct aiff_form form; 50010ba9548Sratchov struct aiff_chunk chunk; 50110ba9548Sratchov unsigned int csize, rsize, nfr = 0, pos = 0, offs; 50210ba9548Sratchov int comm_done = 0, comp; 50310ba9548Sratchov 504c85a1a12Snicm if (!afile_readhdr(f, &form, sizeof(struct aiff_form))) 50510ba9548Sratchov return 0; 50610ba9548Sratchov if (memcmp(&form.id, &aiff_id_form, 4) != 0) { 507*b4d5e3c9Sratchov logx(1, "%s: not an aiff file", f->path); 50810ba9548Sratchov return 0; 50910ba9548Sratchov } 51010ba9548Sratchov if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) { 51110ba9548Sratchov comp = 0; 51210ba9548Sratchov } else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0) 51310ba9548Sratchov comp = 1; 51410ba9548Sratchov else { 515*b4d5e3c9Sratchov logx(1, "%s: unsupported aiff file sub-type", f->path); 51610ba9548Sratchov return 0; 51710ba9548Sratchov } 51810ba9548Sratchov rsize = be32_get(&form.size); 51910ba9548Sratchov for (;;) { 52010ba9548Sratchov if (pos + sizeof(struct aiff_chunk) > rsize) { 521*b4d5e3c9Sratchov logx(1, "%s: missing data chunk", f->path); 52210ba9548Sratchov return 0; 52310ba9548Sratchov } 52410ba9548Sratchov if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) { 525*b4d5e3c9Sratchov logx(1, "%s: failed to read chunk header", f->path); 52610ba9548Sratchov return 0; 52710ba9548Sratchov } 52810ba9548Sratchov csize = be32_get(&chunk.size); 52910ba9548Sratchov if (memcmp(chunk.id, aiff_id_comm, 4) == 0) { 53010ba9548Sratchov if (!afile_aiff_readcomm(f, csize, comp, &nfr)) 53110ba9548Sratchov return 0; 53210ba9548Sratchov comm_done = 1; 53310ba9548Sratchov } else if (memcmp(chunk.id, aiff_id_data, 4) == 0) { 53410ba9548Sratchov if (!afile_aiff_readdata(f, csize, &offs)) 53510ba9548Sratchov return 0; 5363d938fd4Sratchov f->startpos = sizeof(form) + pos + 5373d938fd4Sratchov sizeof(chunk) + offs; 53810ba9548Sratchov break; 53910ba9548Sratchov } else { 54010ba9548Sratchov #ifdef DEBUG 541*b4d5e3c9Sratchov logx(2, "%s: skipped unknown chunk", f->path); 54210ba9548Sratchov #endif 54310ba9548Sratchov } 54410ba9548Sratchov 54510ba9548Sratchov /* 54610ba9548Sratchov * The aiff spec says "Each Chunk must contain an even 54710ba9548Sratchov * number of bytes. For those Chunks whose total 54810ba9548Sratchov * contents would yield an odd number of bytes, a zero 54910ba9548Sratchov * pad byte must be added at the end of the Chunk. This 55010ba9548Sratchov * pad byte is not included in ckDataSize, which 55110ba9548Sratchov * indicates the size of the data in the Chunk." 55210ba9548Sratchov */ 55310ba9548Sratchov csize = (csize + 1) & ~1; 55410ba9548Sratchov pos += sizeof(struct aiff_chunk) + csize; 55510ba9548Sratchov 5563aaa63ebSderaadt if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) == -1) { 557*b4d5e3c9Sratchov logx(1, "%s: failed to seek to chunk", f->path); 55810ba9548Sratchov return 0; 55910ba9548Sratchov } 56010ba9548Sratchov } 56110ba9548Sratchov if (!comm_done) { 562*b4d5e3c9Sratchov logx(1, "%s: missing comm chunk", f->path); 56310ba9548Sratchov return 0; 56410ba9548Sratchov } 56510ba9548Sratchov f->endpos = f->startpos + f->par.bps * f->nch * nfr; 56610ba9548Sratchov return 1; 56710ba9548Sratchov } 56810ba9548Sratchov 56910ba9548Sratchov /* 57010ba9548Sratchov * Write header and seek to start position 57110ba9548Sratchov */ 57210ba9548Sratchov static int 57310ba9548Sratchov afile_aiff_writehdr(struct afile *f) 57410ba9548Sratchov { 57510ba9548Sratchov struct aiff_hdr hdr; 57610ba9548Sratchov unsigned int bpf; 57710ba9548Sratchov unsigned int e, m; 57810ba9548Sratchov 57910ba9548Sratchov /* convert rate to 80-bit float (exponent and fraction part) */ 58010ba9548Sratchov m = f->rate; 58110ba9548Sratchov e = 0x3fff + 31; 58210ba9548Sratchov while ((m & 0x80000000) == 0) { 58310ba9548Sratchov e--; 58410ba9548Sratchov m <<= 1; 58510ba9548Sratchov } 58610ba9548Sratchov 58710ba9548Sratchov /* bytes per frame */ 58810ba9548Sratchov bpf = f->nch * f->par.bps; 58910ba9548Sratchov 59010ba9548Sratchov memset(&hdr, 0, sizeof(struct aiff_hdr)); 59110ba9548Sratchov memcpy(hdr.form.id, aiff_id_form, 4); 59210ba9548Sratchov memcpy(hdr.form.type, aiff_id_aiff, 4); 59310ba9548Sratchov be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form)); 59410ba9548Sratchov 59510ba9548Sratchov memcpy(hdr.comm_hdr.id, aiff_id_comm, 4); 59610ba9548Sratchov be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm)); 59710ba9548Sratchov be16_set(&hdr.comm.nch, f->nch); 59810ba9548Sratchov be16_set(&hdr.comm.bits, f->par.bits); 59910ba9548Sratchov be16_set(&hdr.comm.rate_ex, e); 60010ba9548Sratchov be32_set(&hdr.comm.rate_hi, m); 60110ba9548Sratchov be32_set(&hdr.comm.rate_lo, 0); 60210ba9548Sratchov be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf); 60310ba9548Sratchov 60410ba9548Sratchov memcpy(hdr.data_hdr.id, aiff_id_data, 4); 60510ba9548Sratchov be32_set(&hdr.data_hdr.size, f->endpos - f->startpos); 60610ba9548Sratchov be32_set(&hdr.data.offs, 0); 60710ba9548Sratchov be32_set(&hdr.data.blksz, 0); 60810ba9548Sratchov return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr)); 60910ba9548Sratchov } 61010ba9548Sratchov 61110ba9548Sratchov static int 61210ba9548Sratchov afile_au_readhdr(struct afile *f) 61310ba9548Sratchov { 61410ba9548Sratchov struct au_hdr hdr; 61510ba9548Sratchov unsigned int fmt; 61610ba9548Sratchov 617c85a1a12Snicm if (!afile_readhdr(f, &hdr, sizeof(struct au_hdr))) 61810ba9548Sratchov return 0; 61910ba9548Sratchov if (memcmp(&hdr.id, &au_id, 4) != 0) { 620*b4d5e3c9Sratchov logx(1, "%s: not a .au file", f->path); 62110ba9548Sratchov return 0; 62210ba9548Sratchov } 62310ba9548Sratchov f->startpos = be32_get(&hdr.offs); 62410ba9548Sratchov f->endpos = f->startpos + be32_get(&hdr.size); 62510ba9548Sratchov fmt = be32_get(&hdr.fmt); 62610ba9548Sratchov switch (fmt) { 62710ba9548Sratchov case AU_FMT_PCM8: 62810ba9548Sratchov f->fmt = AFILE_FMT_PCM; 62910ba9548Sratchov f->par.bits = 8; 63010ba9548Sratchov break; 63110ba9548Sratchov case AU_FMT_PCM16: 63210ba9548Sratchov f->fmt = AFILE_FMT_PCM; 63310ba9548Sratchov f->par.bits = 16; 63410ba9548Sratchov break; 63510ba9548Sratchov case AU_FMT_PCM24: 63610ba9548Sratchov f->fmt = AFILE_FMT_PCM; 63710ba9548Sratchov f->par.bits = 24; 63810ba9548Sratchov break; 63910ba9548Sratchov case AU_FMT_PCM32: 64010ba9548Sratchov f->fmt = AFILE_FMT_PCM; 64110ba9548Sratchov f->par.bits = 32; 64210ba9548Sratchov break; 64310ba9548Sratchov case AU_FMT_ULAW: 64410ba9548Sratchov f->fmt = AFILE_FMT_ULAW; 64510ba9548Sratchov f->par.bits = 8; 64610ba9548Sratchov break; 64710ba9548Sratchov case AU_FMT_ALAW: 64810ba9548Sratchov f->fmt = AFILE_FMT_ALAW; 64910ba9548Sratchov f->par.bits = 8; 65010ba9548Sratchov break; 65110ba9548Sratchov case AU_FMT_FLOAT: 65210ba9548Sratchov f->fmt = AFILE_FMT_FLOAT; 65310ba9548Sratchov f->par.bits = 32; 65410ba9548Sratchov break; 65510ba9548Sratchov default: 656*b4d5e3c9Sratchov logx(1, "%s: %u: unsupported encoding", f->path, fmt); 65710ba9548Sratchov return 0; 65810ba9548Sratchov } 65910ba9548Sratchov f->par.le = 0; 66010ba9548Sratchov f->par.sig = 1; 66110ba9548Sratchov f->par.bps = f->par.bits / 8; 66210ba9548Sratchov f->par.msb = 0; 66310ba9548Sratchov f->rate = be32_get(&hdr.rate); 66410ba9548Sratchov f->nch = be32_get(&hdr.nch); 6653aaa63ebSderaadt if (lseek(f->fd, f->startpos, SEEK_SET) == -1) { 666*b4d5e3c9Sratchov logx(1, "%s: failed to seek to data chunk", f->path); 66710ba9548Sratchov return 0; 66810ba9548Sratchov } 66910ba9548Sratchov return afile_checkpar(f); 67010ba9548Sratchov } 67110ba9548Sratchov 67210ba9548Sratchov /* 67310ba9548Sratchov * Write header and seek to start position 67410ba9548Sratchov */ 67510ba9548Sratchov static int 67610ba9548Sratchov afile_au_writehdr(struct afile *f) 67710ba9548Sratchov { 67810ba9548Sratchov struct au_hdr hdr; 67910ba9548Sratchov unsigned int fmt; 68010ba9548Sratchov 68110ba9548Sratchov memset(&hdr, 0, sizeof(struct au_hdr)); 68210ba9548Sratchov memcpy(hdr.id, au_id, 4); 68310ba9548Sratchov be32_set(&hdr.offs, f->startpos); 68410ba9548Sratchov be32_set(&hdr.size, f->endpos - f->startpos); 68510ba9548Sratchov switch (f->par.bits) { 68610ba9548Sratchov case 8: 68710ba9548Sratchov fmt = AU_FMT_PCM8; 68810ba9548Sratchov break; 68910ba9548Sratchov case 16: 69010ba9548Sratchov fmt = AU_FMT_PCM16; 69110ba9548Sratchov break; 69210ba9548Sratchov case 24: 69310ba9548Sratchov fmt = AU_FMT_PCM24; 69410ba9548Sratchov break; 69510ba9548Sratchov case 32: 69610ba9548Sratchov fmt = AU_FMT_PCM32; 69710ba9548Sratchov break; 69810ba9548Sratchov #ifdef DEBUG 69910ba9548Sratchov default: 700*b4d5e3c9Sratchov logx(1, "%s: %u: wrong precision", f->path, f->par.bits); 70110ba9548Sratchov panic(); 70210ba9548Sratchov return 0; 70310ba9548Sratchov #endif 70410ba9548Sratchov } 70510ba9548Sratchov be32_set(&hdr.fmt, fmt); 70610ba9548Sratchov be32_set(&hdr.rate, f->rate); 70710ba9548Sratchov be32_set(&hdr.nch, f->nch); 70810ba9548Sratchov return afile_writehdr(f, &hdr, sizeof(struct au_hdr)); 70910ba9548Sratchov } 71010ba9548Sratchov 71110ba9548Sratchov size_t 71210ba9548Sratchov afile_read(struct afile *f, void *data, size_t count) 71310ba9548Sratchov { 71410ba9548Sratchov off_t maxread; 71510ba9548Sratchov ssize_t n; 71610ba9548Sratchov 71710ba9548Sratchov if (f->endpos >= 0) { 71810ba9548Sratchov maxread = f->endpos - f->curpos; 71910ba9548Sratchov if (maxread == 0) { 72010ba9548Sratchov #ifdef DEBUG 721*b4d5e3c9Sratchov logx(3, "%s: end reached", f->path); 72210ba9548Sratchov #endif 72310ba9548Sratchov return 0; 72410ba9548Sratchov } 72510ba9548Sratchov if (count > maxread) 72610ba9548Sratchov count = maxread; 72710ba9548Sratchov } 72810ba9548Sratchov n = read(f->fd, data, count); 7293aaa63ebSderaadt if (n == -1) { 730*b4d5e3c9Sratchov logx(1, "%s: couldn't read", f->path); 73110ba9548Sratchov return 0; 73210ba9548Sratchov } 73310ba9548Sratchov f->curpos += n; 73410ba9548Sratchov return n; 73510ba9548Sratchov } 73610ba9548Sratchov 73710ba9548Sratchov size_t 73810ba9548Sratchov afile_write(struct afile *f, void *data, size_t count) 73910ba9548Sratchov { 74010ba9548Sratchov off_t maxwrite; 74110ba9548Sratchov int n; 74210ba9548Sratchov 74310ba9548Sratchov if (f->maxpos >= 0) { 74410ba9548Sratchov maxwrite = f->maxpos - f->curpos; 74510ba9548Sratchov if (maxwrite == 0) { 74610ba9548Sratchov #ifdef DEBUG 747*b4d5e3c9Sratchov logx(3, "%s: max file size reached", f->path); 74810ba9548Sratchov #endif 74910ba9548Sratchov return 0; 75010ba9548Sratchov } 75110ba9548Sratchov if (count > maxwrite) 75210ba9548Sratchov count = maxwrite; 75310ba9548Sratchov } 75410ba9548Sratchov n = write(f->fd, data, count); 7553aaa63ebSderaadt if (n == -1) { 756*b4d5e3c9Sratchov logx(1, "%s: couldn't write", f->path); 75710ba9548Sratchov return 0; 75810ba9548Sratchov } 75910ba9548Sratchov f->curpos += n; 76010ba9548Sratchov if (f->endpos < f->curpos) 76110ba9548Sratchov f->endpos = f->curpos; 76210ba9548Sratchov return n; 76310ba9548Sratchov } 76410ba9548Sratchov 76510ba9548Sratchov int 76610ba9548Sratchov afile_seek(struct afile *f, off_t pos) 76710ba9548Sratchov { 76810ba9548Sratchov pos += f->startpos; 769e5f071b5Sratchov if (f->endpos >= 0 && pos > f->endpos && !f->par.sig) { 770*b4d5e3c9Sratchov logx(1, "%s: attempt to seek outside file boundaries", f->path); 77110ba9548Sratchov return 0; 77210ba9548Sratchov } 77310ba9548Sratchov 77410ba9548Sratchov /* 77510ba9548Sratchov * seek only if needed to avoid errors with pipes & sockets 77610ba9548Sratchov */ 77710ba9548Sratchov if (pos != f->curpos) { 7783aaa63ebSderaadt if (lseek(f->fd, pos, SEEK_SET) == -1) { 779*b4d5e3c9Sratchov logx(1, "%s: couldn't seek", f->path); 78010ba9548Sratchov return 0; 78110ba9548Sratchov } 78210ba9548Sratchov f->curpos = pos; 78310ba9548Sratchov } 78410ba9548Sratchov return 1; 78510ba9548Sratchov } 78610ba9548Sratchov 78710ba9548Sratchov void 78810ba9548Sratchov afile_close(struct afile *f) 78910ba9548Sratchov { 79010ba9548Sratchov if (f->flags & AFILE_FWRITE) { 79110ba9548Sratchov if (f->hdr == AFILE_HDR_WAV) 79210ba9548Sratchov afile_wav_writehdr(f); 79310ba9548Sratchov else if (f->hdr == AFILE_HDR_AIFF) 79410ba9548Sratchov afile_aiff_writehdr(f); 79510ba9548Sratchov else if (f->hdr == AFILE_HDR_AU) 79610ba9548Sratchov afile_au_writehdr(f); 79710ba9548Sratchov } 79810ba9548Sratchov close(f->fd); 79910ba9548Sratchov } 80010ba9548Sratchov 80110ba9548Sratchov int 80210ba9548Sratchov afile_open(struct afile *f, char *path, int hdr, int flags, 80310ba9548Sratchov struct aparams *par, int rate, int nch) 80410ba9548Sratchov { 80510ba9548Sratchov char *ext; 80610ba9548Sratchov static union { 80710ba9548Sratchov struct wav_hdr wav; 80810ba9548Sratchov struct aiff_hdr aiff; 80910ba9548Sratchov struct au_hdr au; 81010ba9548Sratchov } dummy; 81110ba9548Sratchov 81210ba9548Sratchov f->par = *par; 81310ba9548Sratchov f->rate = rate; 81410ba9548Sratchov f->nch = nch; 81510ba9548Sratchov f->flags = flags; 81610ba9548Sratchov f->hdr = hdr; 81710ba9548Sratchov if (hdr == AFILE_HDR_AUTO) { 81810ba9548Sratchov f->hdr = AFILE_HDR_RAW; 81910ba9548Sratchov ext = strrchr(path, '.'); 82010ba9548Sratchov if (ext != NULL) { 82110ba9548Sratchov ext++; 82210ba9548Sratchov if (strcasecmp(ext, "aif") == 0 || 82310ba9548Sratchov strcasecmp(ext, "aiff") == 0 || 82410ba9548Sratchov strcasecmp(ext, "aifc") == 0) 82510ba9548Sratchov f->hdr = AFILE_HDR_AIFF; 82610ba9548Sratchov else if (strcasecmp(ext, "au") == 0 || 82710ba9548Sratchov strcasecmp(ext, "snd") == 0) 82810ba9548Sratchov f->hdr = AFILE_HDR_AU; 82910ba9548Sratchov else if (strcasecmp(ext, "wav") == 0) 83010ba9548Sratchov f->hdr = AFILE_HDR_WAV; 83110ba9548Sratchov } 83210ba9548Sratchov } 83310ba9548Sratchov if (f->flags == AFILE_FREAD) { 83410ba9548Sratchov if (strcmp(path, "-") == 0) { 83510ba9548Sratchov f->path = "stdin"; 83610ba9548Sratchov f->fd = STDIN_FILENO; 83710ba9548Sratchov } else { 83810ba9548Sratchov f->path = path; 839b7041c07Sderaadt f->fd = open(f->path, O_RDONLY); 8403aaa63ebSderaadt if (f->fd == -1) { 841*b4d5e3c9Sratchov logx(1, "%s: failed to open for reading", f->path); 84210ba9548Sratchov return 0; 84310ba9548Sratchov } 84410ba9548Sratchov } 84510ba9548Sratchov if (f->hdr == AFILE_HDR_WAV) { 84610ba9548Sratchov if (!afile_wav_readhdr(f)) 84710ba9548Sratchov goto bad_close; 84810ba9548Sratchov } else if (f->hdr == AFILE_HDR_AIFF) { 84910ba9548Sratchov if (!afile_aiff_readhdr(f)) 85010ba9548Sratchov goto bad_close; 85110ba9548Sratchov } else if (f->hdr == AFILE_HDR_AU) { 85210ba9548Sratchov if (!afile_au_readhdr(f)) 85310ba9548Sratchov goto bad_close; 85410ba9548Sratchov } else { 85510ba9548Sratchov f->startpos = 0; 85610ba9548Sratchov f->endpos = -1; /* read until EOF */ 85710ba9548Sratchov f->fmt = AFILE_FMT_PCM; 85810ba9548Sratchov } 85910ba9548Sratchov f->curpos = f->startpos; 86010ba9548Sratchov } else if (flags == AFILE_FWRITE) { 86110ba9548Sratchov if (strcmp(path, "-") == 0) { 86210ba9548Sratchov f->path = "stdout"; 86310ba9548Sratchov f->fd = STDOUT_FILENO; 86410ba9548Sratchov } else { 86510ba9548Sratchov f->path = path; 8663d938fd4Sratchov f->fd = open(f->path, 8673d938fd4Sratchov O_WRONLY | O_TRUNC | O_CREAT, 0666); 8683aaa63ebSderaadt if (f->fd == -1) { 869*b4d5e3c9Sratchov logx(1, "%s: failed to create file", f->path); 87010ba9548Sratchov return 0; 87110ba9548Sratchov } 87210ba9548Sratchov } 87310ba9548Sratchov if (f->hdr == AFILE_HDR_WAV) { 87410ba9548Sratchov f->par.bps = (f->par.bits + 7) >> 3; 87510ba9548Sratchov if (f->par.bits > 8) { 87610ba9548Sratchov f->par.le = 1; 87710ba9548Sratchov f->par.sig = 1; 87810ba9548Sratchov } else 87910ba9548Sratchov f->par.sig = 0; 88010ba9548Sratchov if (f->par.bits & 7) 88110ba9548Sratchov f->par.msb = 1; 88210ba9548Sratchov f->endpos = f->startpos = sizeof(struct wav_hdr); 88310ba9548Sratchov f->maxpos = 0x7fffffff; 88410ba9548Sratchov if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr))) 88510ba9548Sratchov goto bad_close; 88610ba9548Sratchov } else if (f->hdr == AFILE_HDR_AIFF) { 88710ba9548Sratchov f->par.bps = (f->par.bits + 7) >> 3; 88810ba9548Sratchov if (f->par.bps > 1) 88910ba9548Sratchov f->par.le = 0; 89010ba9548Sratchov f->par.sig = 1; 89110ba9548Sratchov if (f->par.bits & 7) 89210ba9548Sratchov f->par.msb = 1; 89310ba9548Sratchov f->endpos = f->startpos = sizeof(struct aiff_hdr); 89410ba9548Sratchov f->maxpos = 0x7fffffff; 8953d938fd4Sratchov if (!afile_writehdr(f, &dummy, 8963d938fd4Sratchov sizeof(struct aiff_hdr))) 89710ba9548Sratchov goto bad_close; 89810ba9548Sratchov } else if (f->hdr == AFILE_HDR_AU) { 89910ba9548Sratchov f->par.bits = (f->par.bits + 7) & ~7; 90010ba9548Sratchov f->par.bps = f->par.bits / 8; 90110ba9548Sratchov f->par.le = 0; 90210ba9548Sratchov f->par.sig = 1; 90310ba9548Sratchov f->par.msb = 1; 90410ba9548Sratchov f->endpos = f->startpos = sizeof(struct au_hdr); 90510ba9548Sratchov f->maxpos = 0x7fffffff; 90610ba9548Sratchov if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr))) 90710ba9548Sratchov goto bad_close; 90810ba9548Sratchov } else { 90910ba9548Sratchov f->endpos = f->startpos = 0; 91010ba9548Sratchov f->maxpos = -1; 91110ba9548Sratchov } 91210ba9548Sratchov f->curpos = f->startpos; 91310ba9548Sratchov } else { 91410ba9548Sratchov #ifdef DEBUG 915*b4d5e3c9Sratchov logx(1, "afile_open: 0x%x: wrong flags", flags); 91610ba9548Sratchov panic(); 91710ba9548Sratchov #endif 91810ba9548Sratchov } 91910ba9548Sratchov return 1; 92010ba9548Sratchov bad_close: 92110ba9548Sratchov close(f->fd); 92210ba9548Sratchov return 0; 92310ba9548Sratchov } 924