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
le16_get(le16_t * p)15810ba9548Sratchov le16_get(le16_t *p)
15910ba9548Sratchov {
16010ba9548Sratchov return p->lw[0] | p->lw[1] << 8;
16110ba9548Sratchov }
16210ba9548Sratchov
16310ba9548Sratchov static inline void
le16_set(le16_t * p,unsigned int v)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
le32_get(le32_t * p)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
le32_set(le32_t * p,unsigned int v)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
be16_get(be16_t * p)18910ba9548Sratchov be16_get(be16_t *p)
19010ba9548Sratchov {
19110ba9548Sratchov return p->bw[1] | p->bw[0] << 8;
19210ba9548Sratchov }
19310ba9548Sratchov
19410ba9548Sratchov static inline void
be16_set(be16_t * p,unsigned int v)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
be32_get(be32_t * p)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
be32_set(be32_t * p,unsigned int v)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
afile_readhdr(struct afile * f,void * addr,size_t size)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
afile_writehdr(struct afile * f,void * addr,size_t size)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
afile_checkpar(struct afile * f)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
afile_wav_readfmt(struct afile * f,unsigned int csize)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
afile_wav_readhdr(struct afile * f)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
afile_wav_writehdr(struct afile * f)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
afile_aiff_readcomm(struct afile * f,unsigned int csize,int comp,unsigned int * nfr)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
afile_aiff_readdata(struct afile * f,unsigned int csize,unsigned int * roffs)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
afile_aiff_readhdr(struct afile * f)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
afile_aiff_writehdr(struct afile * f)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
afile_au_readhdr(struct afile * f)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
afile_au_writehdr(struct afile * f)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
afile_read(struct afile * f,void * data,size_t count)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
afile_write(struct afile * f,void * data,size_t count)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
afile_seek(struct afile * f,off_t pos)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
afile_close(struct afile * f)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
afile_open(struct afile * f,char * path,int hdr,int flags,struct aparams * par,int rate,int nch)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