Annotation of src/usr.bin/aucat/headers.c, Revision 1.10
1.10 ! ratchov 1: /* $OpenBSD: headers.c,v 1.9 2009/12/12 15:15:34 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:
1.7 ratchov 26: #include "aparams.h"
1.1 ratchov 27: #include "conf.h"
1.6 ratchov 28: #include "wav.h"
29:
30: /*
1.7 ratchov 31: * Encoding IDs used in .wav headers.
1.6 ratchov 32: */
33: #define WAV_ENC_PCM 1
34: #define WAV_ENC_ALAW 6
35: #define WAV_ENC_ULAW 7
1.1 ratchov 36:
37: struct wavriff {
38: char magic[4];
39: uint32_t size;
40: char type[4];
41: } __packed;
42:
43: struct wavchunk {
44: char id[4];
45: uint32_t size;
46: } __packed;
47:
48: struct wavfmt {
49: uint16_t fmt;
50: uint16_t nch;
51: uint32_t rate;
52: uint32_t byterate;
53: uint16_t blkalign;
1.4 ratchov 54: uint16_t bits;
1.1 ratchov 55: } __packed;
56:
57: char wav_id_riff[4] = { 'R', 'I', 'F', 'F' };
58: char wav_id_wave[4] = { 'W', 'A', 'V', 'E' };
59: char wav_id_data[4] = { 'd', 'a', 't', 'a' };
60: char wav_id_fmt[4] = { 'f', 'm', 't', ' ' };
61:
62: int
1.6 ratchov 63: wav_readfmt(int fd, unsigned csize, struct aparams *par, short **map)
1.1 ratchov 64: {
65: struct wavfmt fmt;
66: unsigned nch, cmax, rate, bits, enc;
67:
68: if (csize < sizeof(fmt)) {
69: warnx("bogus format chunk");
70: return 0;
71: }
72: if (read(fd, &fmt, sizeof(fmt)) != sizeof(fmt)) {
73: warn("riff_read: chunk");
74: return 0;
75: }
76: enc = letoh16(fmt.fmt);
1.6 ratchov 77: switch (enc) {
78: case WAV_ENC_PCM:
79: *map = NULL;
80: break;
81: case WAV_ENC_ALAW:
82: *map = wav_alawmap;
83: break;
84: case WAV_ENC_ULAW:
85: *map = wav_ulawmap;
86: break;
87: default:
88: errx(1, "%u: unsupported encoding in .wav file", enc);
1.1 ratchov 89: }
90: nch = letoh16(fmt.nch);
91: if (nch == 0) {
92: warnx("zero number of channels");
93: return 0;
94: }
95: cmax = par->cmin + nch - 1;
1.2 ratchov 96: if (cmax >= NCHAN_MAX) {
1.1 ratchov 97: warnx("%u:%u: bad range", par->cmin, cmax);
98: return 0;
99: }
100: rate = letoh32(fmt.rate);
1.9 ratchov 101: if (rate < RATE_MIN || rate > RATE_MAX) {
1.1 ratchov 102: warnx("%u: bad sample rate", rate);
103: return 0;
104: }
105: bits = letoh16(fmt.bits);
1.9 ratchov 106: if (bits == 0 || bits > 32) {
1.1 ratchov 107: warnx("%u: bad number of bits", bits);
108: return 0;
109: }
1.6 ratchov 110: if (enc == WAV_ENC_PCM) {
111: par->bps = (bits + 7) / 8;
112: par->bits = bits;
113: par->le = 1;
114: par->sig = (bits <= 8) ? 0 : 1; /* ask microsoft why... */
115: } else {
116: if (bits != 8) {
117: warnx("%u: mulaw/alaw encoding not 8-bit", bits);
118: return 0;
119: }
120: par->bits = 8 * sizeof(short);
121: par->bps = sizeof(short);
122: par->le = NATIVE_LE;
123: par->sig = 1;
124: }
1.1 ratchov 125: par->msb = 1;
126: par->cmax = cmax;
127: par->rate = rate;
128: return 1;
129: }
130:
131: int
1.6 ratchov 132: wav_readhdr(int fd, struct aparams *par, off_t *datasz, short **map)
1.1 ratchov 133: {
134: struct wavriff riff;
135: struct wavchunk chunk;
136: unsigned csize, rsize, pos = 0;
137: int fmt_done = 0;
138:
139: if (lseek(fd, 0, SEEK_SET) < 0) {
140: warn("lseek: 0");
141: return 0;
142: }
143: if (read(fd, &riff, sizeof(riff)) != sizeof(riff)) {
1.8 ratchov 144: warn("wav_readhdr: header");
1.1 ratchov 145: return 0;
146: }
147: if (memcmp(&riff.magic, &wav_id_riff, 4) != 0 ||
148: memcmp(&riff.type, &wav_id_wave, 4)) {
149: warnx("not a wave file");
150: return 0;
151: }
152: rsize = letoh32(riff.size);
153: while (pos + sizeof(struct wavchunk) <= rsize) {
154: if (read(fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
1.8 ratchov 155: warn("wav_readhdr: chunk");
1.1 ratchov 156: return 0;
157: }
158: csize = letoh32(chunk.size);
159: if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
1.6 ratchov 160: if (!wav_readfmt(fd, csize, par, map))
1.1 ratchov 161: return 0;
162: fmt_done = 1;
163: } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
164: *datasz = csize;
165: break;
166: } else {
1.10 ! ratchov 167: #ifdef DEBUG
! 168: if (debug_level >= 1)
! 169: warnx("ignoring chuck <%.4s>\n", chunk.id);
! 170: #endif
1.1 ratchov 171: }
172:
173: /*
174: * next chunk
175: */
176: pos += sizeof(struct wavchunk) + csize;
177: if (lseek(fd, sizeof(riff) + pos, SEEK_SET) < 0) {
178: warn("lseek");
179: return 0;
180: }
181: }
182: if (!fmt_done) {
183: warnx("missing format chunk");
184: return 0;
185: }
186: return 1;
187: }
188:
189: int
190: wav_writehdr(int fd, struct aparams *par)
191: {
192: off_t datasz;
193: unsigned nch = par->cmax - par->cmin + 1;
194: struct {
195: struct wavriff riff;
196: struct wavchunk fmt_hdr;
197: struct wavfmt fmt;
198: struct wavchunk data_hdr;
199: } hdr;
200:
201: datasz = lseek(fd, 0, SEEK_CUR);
202: if (datasz < 0) {
203: warn("wav_writehdr: lseek(end)");
204: return 0;
205: }
206: if (datasz >= sizeof(hdr))
207: datasz -= sizeof(hdr);
208: else
209: datasz = 0;
210:
211: /*
1.7 ratchov 212: * Check that encoding is supported by .wav file format.
1.1 ratchov 213: */
214: if (par->bits > 8 && !par->le) {
215: warnx("samples must be little endian");
216: return 0;
217: }
218: if (8 * par->bps - par->bits >= 8) {
219: warnx("padding must be less than 8 bits");
220: return 0;
221: }
222: if ((par->bits <= 8 && par->sig) || (par->bits > 8 && !par->sig)) {
1.7 ratchov 223: warnx("samples with more (less) than 8 bits must be signed "
224: "(unsigned)");
1.1 ratchov 225: return 0;
226: }
227: if (8 * par->bps != par->bits && !par->msb) {
228: warnx("samples must be MSB justified");
229: return 0;
230: }
231:
232: memcpy(hdr.riff.magic, wav_id_riff, 4);
233: memcpy(hdr.riff.type, wav_id_wave, 4);
234: hdr.riff.size = htole32(datasz + sizeof(hdr) - sizeof(hdr.riff));
235:
236: memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
237: hdr.fmt_hdr.size = htole32(sizeof(hdr.fmt));
238: hdr.fmt.fmt = htole16(1);
239: hdr.fmt.nch = htole16(nch);
240: hdr.fmt.rate = htole32(par->rate);
241: hdr.fmt.byterate = htole32(par->rate * par->bps * nch);
242: hdr.fmt.bits = htole16(par->bits);
243: hdr.fmt.blkalign = 0;
244:
245: memcpy(hdr.data_hdr.id, wav_id_data, 4);
246: hdr.data_hdr.size = htole32(datasz);
1.4 ratchov 247:
1.1 ratchov 248: if (lseek(fd, 0, SEEK_SET) < 0) {
249: warn("wav_writehdr: lseek");
250: return 0;
251: }
252: if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
253: warn("wav_writehdr: write");
254: return 0;
255: }
256: return 1;
257: }