Annotation of src/usr.bin/aucat/headers.c, Revision 1.5
1.5 ! jakemsr 1: /* $OpenBSD: headers.c,v 1.4 2009/01/23 17:38:15 ratchov Exp $ */
1.1 ratchov 2: /*
3: * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
4: *
5: * Permission to use, copy, modify, and distribute this software for any
6: * purpose with or without fee is hereby granted, provided that the above
7: * copyright notice and this permission notice appear in all copies.
8: *
9: * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
10: * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
11: * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
12: * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
13: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
14: * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
15: * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
16: */
17:
18: #include <sys/param.h>
19:
20: #include <err.h>
21: #include <stdio.h>
22: #include <stdlib.h>
23: #include <string.h>
24: #include <unistd.h>
25:
26: #include "conf.h"
27: #include "aparams.h"
28:
29: struct wavriff {
30: char magic[4];
31: uint32_t size;
32: char type[4];
33: } __packed;
34:
35: struct wavchunk {
36: char id[4];
37: uint32_t size;
38: } __packed;
39:
40: struct wavfmt {
41: uint16_t fmt;
42: uint16_t nch;
43: uint32_t rate;
44: uint32_t byterate;
45: uint16_t blkalign;
1.4 ratchov 46: uint16_t bits;
1.1 ratchov 47: } __packed;
48:
49: char wav_id_riff[4] = { 'R', 'I', 'F', 'F' };
50: char wav_id_wave[4] = { 'W', 'A', 'V', 'E' };
51: char wav_id_data[4] = { 'd', 'a', 't', 'a' };
52: char wav_id_fmt[4] = { 'f', 'm', 't', ' ' };
53:
54: int
1.5 ! jakemsr 55: wav_readfmt(int fd, unsigned csize, struct aparams *par, int *renc)
1.1 ratchov 56: {
57: struct wavfmt fmt;
58: unsigned nch, cmax, rate, bits, enc;
59:
60: if (csize < sizeof(fmt)) {
61: warnx("bogus format chunk");
62: return 0;
63: }
64: if (read(fd, &fmt, sizeof(fmt)) != sizeof(fmt)) {
65: warn("riff_read: chunk");
66: return 0;
67: }
68: enc = letoh16(fmt.fmt);
1.5 ! jakemsr 69: if (renc == NULL && enc != 1) {
1.1 ratchov 70: warnx("%u: only \"pcm\" encoding supported", enc);
71: return 0;
72: }
73: nch = letoh16(fmt.nch);
74: if (nch == 0) {
75: warnx("zero number of channels");
76: return 0;
77: }
78: cmax = par->cmin + nch - 1;
1.2 ratchov 79: if (cmax >= NCHAN_MAX) {
1.1 ratchov 80: warnx("%u:%u: bad range", par->cmin, cmax);
81: return 0;
82: }
83: rate = letoh32(fmt.rate);
84: if (rate < RATE_MIN || rate >= RATE_MAX) {
85: warnx("%u: bad sample rate", rate);
86: return 0;
87: }
88: bits = letoh16(fmt.bits);
89: if (bits == 0 || bits >= 32) {
90: warnx("%u: bad number of bits", bits);
91: return 0;
92: }
93: par->bps = (bits + 7) / 8;
94: par->bits = bits;
95: par->le = 1;
96: par->sig = (bits <= 8) ? 0 : 1; /* ask microsoft why... */
97: par->msb = 1;
98: par->cmax = cmax;
99: par->rate = rate;
1.5 ! jakemsr 100: if (renc)
! 101: *renc = enc;
1.3 ratchov 102: #ifdef DEBUG
1.1 ratchov 103: if (debug_level > 0) {
104: fprintf(stderr, "wav_readfmt: using ");
105: aparams_print(par);
106: fprintf(stderr, "\n");
107: }
1.3 ratchov 108: #endif
1.1 ratchov 109: return 1;
110: }
111:
112: int
1.5 ! jakemsr 113: wav_readhdr(int fd, struct aparams *par, off_t *datasz, int *renc)
1.1 ratchov 114: {
115: struct wavriff riff;
116: struct wavchunk chunk;
117: unsigned csize, rsize, pos = 0;
118: int fmt_done = 0;
119:
120: if (lseek(fd, 0, SEEK_SET) < 0) {
121: warn("lseek: 0");
122: return 0;
123: }
124: if (read(fd, &riff, sizeof(riff)) != sizeof(riff)) {
125: warn("riff_read: header");
126: return 0;
127: }
128: if (memcmp(&riff.magic, &wav_id_riff, 4) != 0 ||
129: memcmp(&riff.type, &wav_id_wave, 4)) {
130: warnx("not a wave file");
131: return 0;
132: }
133: rsize = letoh32(riff.size);
134: while (pos + sizeof(struct wavchunk) <= rsize) {
135: if (read(fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
136: warn("riff_read: chunk");
137: return 0;
138: }
139: csize = letoh32(chunk.size);
140: if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
1.5 ! jakemsr 141: if (!wav_readfmt(fd, csize, par, renc))
1.1 ratchov 142: return 0;
143: fmt_done = 1;
144: } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
145: *datasz = csize;
146: break;
147: } else {
148: DPRINTF("unknown chunk: <%.4s>\n", chunk.id);
149: }
150:
151: /*
152: * next chunk
153: */
154: pos += sizeof(struct wavchunk) + csize;
155: if (lseek(fd, sizeof(riff) + pos, SEEK_SET) < 0) {
156: warn("lseek");
157: return 0;
158: }
159: }
160: if (!fmt_done) {
161: warnx("missing format chunk");
162: return 0;
163: }
164: return 1;
165: }
166:
167: int
168: wav_writehdr(int fd, struct aparams *par)
169: {
170: off_t datasz;
171: unsigned nch = par->cmax - par->cmin + 1;
172: struct {
173: struct wavriff riff;
174: struct wavchunk fmt_hdr;
175: struct wavfmt fmt;
176: struct wavchunk data_hdr;
177: } hdr;
178:
179: datasz = lseek(fd, 0, SEEK_CUR);
180: if (datasz < 0) {
181: warn("wav_writehdr: lseek(end)");
182: return 0;
183: }
184: if (datasz >= sizeof(hdr))
185: datasz -= sizeof(hdr);
186: else
187: datasz = 0;
188:
189: /*
190: * check that encoding is supported by .wav file format
191: */
192: if (par->bits > 8 && !par->le) {
193: warnx("samples must be little endian");
194: return 0;
195: }
196: if (8 * par->bps - par->bits >= 8) {
197: warnx("padding must be less than 8 bits");
198: return 0;
199: }
200: if ((par->bits <= 8 && par->sig) || (par->bits > 8 && !par->sig)) {
201: warnx("samples with more (less) than 8 bits must be signed (unsigned)");
202: return 0;
203: }
204: if (8 * par->bps != par->bits && !par->msb) {
205: warnx("samples must be MSB justified");
206: return 0;
207: }
208:
209: memcpy(hdr.riff.magic, wav_id_riff, 4);
210: memcpy(hdr.riff.type, wav_id_wave, 4);
211: hdr.riff.size = htole32(datasz + sizeof(hdr) - sizeof(hdr.riff));
212:
213: memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
214: hdr.fmt_hdr.size = htole32(sizeof(hdr.fmt));
215: hdr.fmt.fmt = htole16(1);
216: hdr.fmt.nch = htole16(nch);
217: hdr.fmt.rate = htole32(par->rate);
218: hdr.fmt.byterate = htole32(par->rate * par->bps * nch);
219: hdr.fmt.bits = htole16(par->bits);
220: hdr.fmt.blkalign = 0;
221:
222: memcpy(hdr.data_hdr.id, wav_id_data, 4);
223: hdr.data_hdr.size = htole32(datasz);
1.4 ratchov 224:
1.1 ratchov 225: if (lseek(fd, 0, SEEK_SET) < 0) {
226: warn("wav_writehdr: lseek");
227: return 0;
228: }
229: if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
230: warn("wav_writehdr: write");
231: return 0;
232: }
233: return 1;
234: }