[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.23

1.23    ! ratchov     1: /*     $OpenBSD$       */
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>
1.16      ratchov    22: #include <stdint.h>
1.1       ratchov    23: #include <stdlib.h>
                     24: #include <string.h>
                     25: #include <unistd.h>
                     26:
1.7       ratchov    27: #include "aparams.h"
1.1       ratchov    28: #include "conf.h"
1.6       ratchov    29: #include "wav.h"
                     30:
                     31: /*
1.7       ratchov    32:  * Encoding IDs used in .wav headers.
1.6       ratchov    33:  */
                     34: #define WAV_ENC_PCM    1
                     35: #define WAV_ENC_ALAW   6
                     36: #define WAV_ENC_ULAW   7
1.15      ratchov    37: #define WAV_ENC_EXT    0xfffe
1.1       ratchov    38:
                     39: struct wavriff {
                     40:        char magic[4];
                     41:        uint32_t size;
                     42:        char type[4];
                     43: } __packed;
                     44:
                     45: struct wavchunk {
                     46:        char id[4];
                     47:        uint32_t size;
                     48: } __packed;
                     49:
                     50: struct wavfmt {
                     51:        uint16_t fmt;
                     52:        uint16_t nch;
                     53:        uint32_t rate;
                     54:        uint32_t byterate;
                     55:        uint16_t blkalign;
1.4       ratchov    56:        uint16_t bits;
1.15      ratchov    57: #define WAV_FMT_SIZE            16
                     58: #define WAV_FMT_SIZE2          (16 + 2)
                     59: #define WAV_FMT_EXT_SIZE       (16 + 24)
                     60:        uint16_t extsize;
                     61:        uint16_t valbits;
                     62:        uint32_t chanmask;
                     63:        uint16_t extfmt;
                     64:        char     guid[14];
1.1       ratchov    65: } __packed;
                     66:
                     67: char wav_id_riff[4] = { 'R', 'I', 'F', 'F' };
                     68: char wav_id_wave[4] = { 'W', 'A', 'V', 'E' };
                     69: char wav_id_data[4] = { 'd', 'a', 't', 'a' };
                     70: char wav_id_fmt[4] = { 'f', 'm', 't', ' ' };
1.15      ratchov    71: char wav_guid[14] = {
                     72:        0x00, 0x00, 0x00, 0x00,
                     73:        0x10, 0x00, 0x80, 0x00,
                     74:        0x00, 0xAA, 0x00, 0x38,
                     75:        0x9B, 0x71
                     76: };
1.23    ! ratchov    77:
        !            78: int wav_readfmt(int, unsigned int, struct aparams *, short **);
1.1       ratchov    79:
                     80: int
1.22      ratchov    81: wav_readfmt(int fd, unsigned int csize, struct aparams *par, short **map)
1.1       ratchov    82: {
                     83:        struct wavfmt fmt;
1.22      ratchov    84:        unsigned int nch, cmax, rate, bits, bps, enc;
1.1       ratchov    85:
1.15      ratchov    86:        if (csize < WAV_FMT_SIZE) {
                     87:                warnx("%u: bugus format chunk size", csize);
1.1       ratchov    88:                return 0;
                     89:        }
1.15      ratchov    90:        if (csize > WAV_FMT_EXT_SIZE)
                     91:                csize = WAV_FMT_EXT_SIZE;
                     92:        if (read(fd, &fmt, csize) != csize) {
1.1       ratchov    93:                warn("riff_read: chunk");
                     94:                return 0;
                     95:        }
                     96:        enc = letoh16(fmt.fmt);
1.15      ratchov    97:        bits = letoh16(fmt.bits);
                     98:        if (enc == WAV_ENC_EXT) {
                     99:                if (csize != WAV_FMT_EXT_SIZE) {
                    100:                        warnx("missing extended format chunk in .wav file");
                    101:                        return 0;
                    102:                }
                    103:                if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) {
                    104:                        warnx("unknown format (GUID) in .wav file");
                    105:                        return 0;
                    106:                }
                    107:                bps = (bits + 7) / 8;
                    108:                bits = letoh16(fmt.valbits);
                    109:                enc = letoh16(fmt.extfmt);
                    110:        } else
                    111:                bps = (bits + 7) / 8;
1.6       ratchov   112:        switch (enc) {
                    113:        case WAV_ENC_PCM:
                    114:                *map = NULL;
                    115:                break;
                    116:        case WAV_ENC_ALAW:
                    117:                *map = wav_alawmap;
                    118:                break;
                    119:        case WAV_ENC_ULAW:
                    120:                *map = wav_ulawmap;
                    121:                break;
                    122:        default:
                    123:                errx(1, "%u: unsupported encoding in .wav file", enc);
1.1       ratchov   124:        }
                    125:        nch = letoh16(fmt.nch);
                    126:        if (nch == 0) {
                    127:                warnx("zero number of channels");
                    128:                return 0;
                    129:        }
                    130:        cmax = par->cmin + nch - 1;
1.2       ratchov   131:        if (cmax >= NCHAN_MAX) {
1.1       ratchov   132:                warnx("%u:%u: bad range", par->cmin, cmax);
                    133:                return 0;
                    134:        }
                    135:        rate = letoh32(fmt.rate);
1.9       ratchov   136:        if (rate < RATE_MIN || rate > RATE_MAX) {
1.1       ratchov   137:                warnx("%u: bad sample rate", rate);
                    138:                return 0;
                    139:        }
1.9       ratchov   140:        if (bits == 0 || bits > 32) {
1.1       ratchov   141:                warnx("%u: bad number of bits", bits);
                    142:                return 0;
                    143:        }
1.15      ratchov   144:        if (bits > bps * 8) {
                    145:                warnx("%u: bits larger than bytes-per-sample", bps);
                    146:                return 0;
                    147:        }
1.6       ratchov   148:        if (enc == WAV_ENC_PCM) {
1.15      ratchov   149:                par->bps = bps;
1.6       ratchov   150:                par->bits = bits;
                    151:                par->le = 1;
                    152:                par->sig = (bits <= 8) ? 0 : 1; /* ask microsoft why... */
1.19      ratchov   153:                par->msb = 1;
1.6       ratchov   154:        } else {
                    155:                if (bits != 8) {
                    156:                        warnx("%u: mulaw/alaw encoding not 8-bit", bits);
                    157:                        return 0;
                    158:                }
1.19      ratchov   159:                par->bits = ADATA_BITS;
                    160:                par->bps = sizeof(adata_t);
                    161:                par->le = ADATA_LE;
1.6       ratchov   162:                par->sig = 1;
1.19      ratchov   163:                par->msb = 0;
1.6       ratchov   164:        }
1.1       ratchov   165:        par->cmax = cmax;
                    166:        par->rate = rate;
                    167:        return 1;
                    168: }
                    169:
                    170: int
1.13      ratchov   171: wav_readhdr(int fd, struct aparams *par, off_t *startpos, off_t *datasz, short **map)
1.1       ratchov   172: {
                    173:        struct wavriff riff;
                    174:        struct wavchunk chunk;
1.22      ratchov   175:        unsigned int csize, rsize, pos = 0;
1.1       ratchov   176:        int fmt_done = 0;
                    177:
                    178:        if (lseek(fd, 0, SEEK_SET) < 0) {
                    179:                warn("lseek: 0");
                    180:                return 0;
                    181:        }
                    182:        if (read(fd, &riff, sizeof(riff)) != sizeof(riff)) {
1.8       ratchov   183:                warn("wav_readhdr: header");
1.1       ratchov   184:                return 0;
                    185:        }
                    186:        if (memcmp(&riff.magic, &wav_id_riff, 4) != 0 ||
                    187:            memcmp(&riff.type, &wav_id_wave, 4)) {
                    188:                warnx("not a wave file");
                    189:                return 0;
                    190:        }
                    191:        rsize = letoh32(riff.size);
1.17      ratchov   192:        for (;;) {
                    193:                if (pos + sizeof(struct wavchunk) > rsize) {
                    194:                        warnx("missing data chunk");
                    195:                        return 0;
                    196:                }
1.1       ratchov   197:                if (read(fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
1.8       ratchov   198:                        warn("wav_readhdr: chunk");
1.1       ratchov   199:                        return 0;
                    200:                }
                    201:                csize = letoh32(chunk.size);
                    202:                if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
1.6       ratchov   203:                        if (!wav_readfmt(fd, csize, par, map))
1.1       ratchov   204:                                return 0;
                    205:                        fmt_done = 1;
                    206:                } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
1.18      ratchov   207:                        *startpos = pos + sizeof(riff) + sizeof(chunk);
1.1       ratchov   208:                        *datasz = csize;
                    209:                        break;
                    210:                } else {
1.10      ratchov   211: #ifdef DEBUG
1.14      ratchov   212:                        if (debug_level >= 2)
1.21      ratchov   213:                                warnx("ignoring chunk <%.4s>\n", chunk.id);
1.10      ratchov   214: #endif
1.1       ratchov   215:                }
                    216:
                    217:                /*
                    218:                 * next chunk
                    219:                 */
                    220:                pos += sizeof(struct wavchunk) + csize;
                    221:                if (lseek(fd, sizeof(riff) + pos, SEEK_SET) < 0) {
                    222:                        warn("lseek");
                    223:                        return 0;
                    224:                }
                    225:        }
                    226:        if (!fmt_done) {
                    227:                warnx("missing format chunk");
                    228:                return 0;
                    229:        }
                    230:        return 1;
                    231: }
                    232:
1.13      ratchov   233: /*
                    234:  * Write header and seek to start position
                    235:  */
1.1       ratchov   236: int
1.13      ratchov   237: wav_writehdr(int fd, struct aparams *par, off_t *startpos, off_t datasz)
1.1       ratchov   238: {
1.22      ratchov   239:        unsigned int nch = par->cmax - par->cmin + 1;
1.1       ratchov   240:        struct {
                    241:                struct wavriff riff;
                    242:                struct wavchunk fmt_hdr;
                    243:                struct wavfmt fmt;
                    244:                struct wavchunk data_hdr;
1.20      ratchov   245:        } __packed hdr;
1.1       ratchov   246:
                    247:        /*
1.7       ratchov   248:         * Check that encoding is supported by .wav file format.
1.1       ratchov   249:         */
                    250:        if (par->bits > 8 && !par->le) {
                    251:                warnx("samples must be little endian");
                    252:                return 0;
                    253:        }
                    254:        if (8 * par->bps - par->bits >= 8) {
                    255:                warnx("padding must be less than 8 bits");
                    256:                return 0;
                    257:        }
                    258:        if ((par->bits <= 8 && par->sig) || (par->bits > 8 && !par->sig)) {
1.7       ratchov   259:                warnx("samples with more (less) than 8 bits must be signed "
                    260:                    "(unsigned)");
1.1       ratchov   261:                return 0;
                    262:        }
                    263:        if (8 * par->bps != par->bits && !par->msb) {
                    264:                warnx("samples must be MSB justified");
                    265:                return 0;
                    266:        }
                    267:
                    268:        memcpy(hdr.riff.magic, wav_id_riff, 4);
                    269:        memcpy(hdr.riff.type, wav_id_wave, 4);
                    270:        hdr.riff.size = htole32(datasz + sizeof(hdr) - sizeof(hdr.riff));
                    271:
                    272:        memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
                    273:        hdr.fmt_hdr.size = htole32(sizeof(hdr.fmt));
                    274:        hdr.fmt.fmt = htole16(1);
                    275:        hdr.fmt.nch = htole16(nch);
                    276:        hdr.fmt.rate = htole32(par->rate);
                    277:        hdr.fmt.byterate = htole32(par->rate * par->bps * nch);
1.20      ratchov   278:        hdr.fmt.blkalign = par->bps * nch;
1.1       ratchov   279:        hdr.fmt.bits = htole16(par->bits);
                    280:
                    281:        memcpy(hdr.data_hdr.id, wav_id_data, 4);
                    282:        hdr.data_hdr.size = htole32(datasz);
1.4       ratchov   283:
1.1       ratchov   284:        if (lseek(fd, 0, SEEK_SET) < 0) {
                    285:                warn("wav_writehdr: lseek");
                    286:                return 0;
                    287:        }
                    288:        if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
                    289:                warn("wav_writehdr: write");
                    290:                return 0;
                    291:        }
1.13      ratchov   292:        *startpos = sizeof(hdr);
1.1       ratchov   293:        return 1;
                    294: }