[BACK]Return to headers.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / aucat

Annotation of src/usr.bin/aucat/headers.c, Revision 1.6

1.6     ! ratchov     1: /*     $OpenBSD: headers.c,v 1.5 2009/04/11 10:24:21 jakemsr 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"
1.6     ! ratchov    28: #include "wav.h"
        !            29:
        !            30: /*
        !            31:  * encoding IDs used in .wav headers
        !            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);
                    101:        if (rate < RATE_MIN || rate >= RATE_MAX) {
                    102:                warnx("%u: bad sample rate", rate);
                    103:                return 0;
                    104:        }
                    105:        bits = letoh16(fmt.bits);
                    106:        if (bits == 0 || bits >= 32) {
                    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;
1.3       ratchov   128: #ifdef DEBUG
1.1       ratchov   129:        if (debug_level > 0) {
                    130:                fprintf(stderr, "wav_readfmt: using ");
                    131:                aparams_print(par);
                    132:                fprintf(stderr, "\n");
                    133:        }
1.3       ratchov   134: #endif
1.1       ratchov   135:        return 1;
                    136: }
                    137:
                    138: int
1.6     ! ratchov   139: wav_readhdr(int fd, struct aparams *par, off_t *datasz, short **map)
1.1       ratchov   140: {
                    141:        struct wavriff riff;
                    142:        struct wavchunk chunk;
                    143:        unsigned csize, rsize, pos = 0;
                    144:        int fmt_done = 0;
                    145:
                    146:        if (lseek(fd, 0, SEEK_SET) < 0) {
                    147:                warn("lseek: 0");
                    148:                return 0;
                    149:        }
                    150:        if (read(fd, &riff, sizeof(riff)) != sizeof(riff)) {
                    151:                warn("riff_read: header");
                    152:                return 0;
                    153:        }
                    154:        if (memcmp(&riff.magic, &wav_id_riff, 4) != 0 ||
                    155:            memcmp(&riff.type, &wav_id_wave, 4)) {
                    156:                warnx("not a wave file");
                    157:                return 0;
                    158:        }
                    159:        rsize = letoh32(riff.size);
                    160:        while (pos + sizeof(struct wavchunk) <= rsize) {
                    161:                if (read(fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
                    162:                        warn("riff_read: chunk");
                    163:                        return 0;
                    164:                }
                    165:                csize = letoh32(chunk.size);
                    166:                if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
1.6     ! ratchov   167:                        if (!wav_readfmt(fd, csize, par, map))
1.1       ratchov   168:                                return 0;
                    169:                        fmt_done = 1;
                    170:                } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
                    171:                        *datasz = csize;
                    172:                        break;
                    173:                } else {
                    174:                        DPRINTF("unknown chunk: <%.4s>\n", chunk.id);
                    175:                }
                    176:
                    177:                /*
                    178:                 * next chunk
                    179:                 */
                    180:                pos += sizeof(struct wavchunk) + csize;
                    181:                if (lseek(fd, sizeof(riff) + pos, SEEK_SET) < 0) {
                    182:                        warn("lseek");
                    183:                        return 0;
                    184:                }
                    185:        }
                    186:        if (!fmt_done) {
                    187:                warnx("missing format chunk");
                    188:                return 0;
                    189:        }
                    190:        return 1;
                    191: }
                    192:
                    193: int
                    194: wav_writehdr(int fd, struct aparams *par)
                    195: {
                    196:        off_t datasz;
                    197:        unsigned nch = par->cmax - par->cmin + 1;
                    198:        struct {
                    199:                struct wavriff riff;
                    200:                struct wavchunk fmt_hdr;
                    201:                struct wavfmt fmt;
                    202:                struct wavchunk data_hdr;
                    203:        } hdr;
                    204:
                    205:        datasz = lseek(fd, 0, SEEK_CUR);
                    206:        if (datasz < 0) {
                    207:                warn("wav_writehdr: lseek(end)");
                    208:                return 0;
                    209:        }
                    210:        if (datasz >= sizeof(hdr))
                    211:                datasz -= sizeof(hdr);
                    212:        else
                    213:                datasz = 0;
                    214:
                    215:        /*
                    216:         * check that encoding is supported by .wav file format
                    217:         */
                    218:        if (par->bits > 8 && !par->le) {
                    219:                warnx("samples must be little endian");
                    220:                return 0;
                    221:        }
                    222:        if (8 * par->bps - par->bits >= 8) {
                    223:                warnx("padding must be less than 8 bits");
                    224:                return 0;
                    225:        }
                    226:        if ((par->bits <= 8 && par->sig) || (par->bits > 8 && !par->sig)) {
                    227:                warnx("samples with more (less) than 8 bits must be signed (unsigned)");
                    228:                return 0;
                    229:        }
                    230:        if (8 * par->bps != par->bits && !par->msb) {
                    231:                warnx("samples must be MSB justified");
                    232:                return 0;
                    233:        }
                    234:
                    235:        memcpy(hdr.riff.magic, wav_id_riff, 4);
                    236:        memcpy(hdr.riff.type, wav_id_wave, 4);
                    237:        hdr.riff.size = htole32(datasz + sizeof(hdr) - sizeof(hdr.riff));
                    238:
                    239:        memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
                    240:        hdr.fmt_hdr.size = htole32(sizeof(hdr.fmt));
                    241:        hdr.fmt.fmt = htole16(1);
                    242:        hdr.fmt.nch = htole16(nch);
                    243:        hdr.fmt.rate = htole32(par->rate);
                    244:        hdr.fmt.byterate = htole32(par->rate * par->bps * nch);
                    245:        hdr.fmt.bits = htole16(par->bits);
                    246:        hdr.fmt.blkalign = 0;
                    247:
                    248:        memcpy(hdr.data_hdr.id, wav_id_data, 4);
                    249:        hdr.data_hdr.size = htole32(datasz);
1.4       ratchov   250:
1.1       ratchov   251:        if (lseek(fd, 0, SEEK_SET) < 0) {
                    252:                warn("wav_writehdr: lseek");
                    253:                return 0;
                    254:        }
                    255:        if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
                    256:                warn("wav_writehdr: write");
                    257:                return 0;
                    258:        }
                    259:        return 1;
                    260: }