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