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

Annotation of src/usr.bin/aucat/wav.c, Revision 1.10

1.7       ratchov     1: /*
                      2:  * Copyright (c) 2008 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:
1.1       ratchov    17: #include <stdlib.h>
1.10    ! ratchov    18: #include <stdio.h>
        !            19: #include <fcntl.h>
        !            20: #include <unistd.h>
1.1       ratchov    21:
1.10    ! ratchov    22: #include "abuf.h"
        !            23: #include "aproc.h"
1.1       ratchov    24: #include "conf.h"
1.10    ! ratchov    25: #include "dev.h"
1.1       ratchov    26: #include "wav.h"
                     27:
1.6       ratchov    28: short wav_ulawmap[256] = {
                     29:        -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
                     30:        -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
                     31:        -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
                     32:        -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
                     33:         -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
                     34:         -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
                     35:         -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
                     36:         -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
                     37:         -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
                     38:         -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
                     39:          -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
                     40:          -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
                     41:          -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
                     42:          -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
                     43:          -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
                     44:           -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
                     45:         32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
                     46:         23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
                     47:         15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
                     48:         11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
                     49:          7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
                     50:          5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
                     51:          3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
                     52:          2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
                     53:          1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
                     54:          1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
                     55:           876,    844,    812,    780,    748,    716,    684,    652,
                     56:           620,    588,    556,    524,    492,    460,    428,    396,
                     57:           372,    356,    340,    324,    308,    292,    276,    260,
                     58:           244,    228,    212,    196,    180,    164,    148,    132,
                     59:           120,    112,    104,     96,     88,     80,     72,     64,
                     60:            56,     48,     40,     32,     24,     16,      8,      0
                     61: };
                     62:
                     63: short wav_alawmap[256] = {
                     64:         -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
                     65:         -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
                     66:         -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
                     67:         -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
                     68:        -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
                     69:        -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
                     70:        -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
                     71:        -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
                     72:          -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
                     73:          -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
                     74:           -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
                     75:          -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
                     76:         -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
                     77:         -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
                     78:          -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
                     79:          -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
                     80:          5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
                     81:          7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
                     82:          2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
                     83:          3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
                     84:         22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
                     85:         30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
                     86:         11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
                     87:         15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
                     88:           344,    328,    376,    360,    280,    264,    312,    296,
                     89:           472,    456,    504,    488,    408,    392,    440,    424,
                     90:            88,     72,    120,    104,     24,      8,     56,     40,
                     91:           216,    200,    248,    232,    152,    136,    184,    168,
                     92:          1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
                     93:          1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
                     94:           688,    656,    752,    720,    560,    528,    624,    592,
                     95:           944,    912,   1008,    976,    816,    784,    880,    848
                     96: };
                     97:
1.1       ratchov    98: /*
1.7       ratchov    99:  * Max data of a .wav file. The total file size must be smaller than
1.1       ratchov   100:  * 2^31, and we also have to leave some space for the headers (around 40
1.7       ratchov   101:  * bytes).
1.3       ratchov   102:  */
1.1       ratchov   103: #define WAV_DATAMAX    (0x7fff0000)
                    104:
                    105: struct fileops wav_ops = {
                    106:        "wav",
                    107:        sizeof(struct wav),
                    108:        wav_close,
                    109:        wav_read,
                    110:        wav_write,
                    111:        NULL, /* start */
                    112:        NULL, /* stop */
                    113:        pipe_nfds,
                    114:        pipe_pollfd,
                    115:        pipe_revents
                    116: };
                    117:
1.10    ! ratchov   118: int rwav_in(struct aproc *, struct abuf *);
        !           119: int rwav_out(struct aproc *, struct abuf *);
        !           120: void rwav_eof(struct aproc *, struct abuf *);
        !           121: void rwav_hup(struct aproc *, struct abuf *);
        !           122: void rwav_done(struct aproc *);
        !           123:
        !           124: int wwav_in(struct aproc *, struct abuf *);
        !           125: int wwav_out(struct aproc *, struct abuf *);
        !           126: void wwav_eof(struct aproc *, struct abuf *);
        !           127: void wwav_hup(struct aproc *, struct abuf *);
        !           128: void wwav_done(struct aproc *);
        !           129:
        !           130: struct aproc_ops rwav_ops = {
        !           131:        "rwav",
        !           132:        rwav_in,
        !           133:        rwav_out,
        !           134:        rwav_eof,
        !           135:        rwav_hup,
        !           136:        NULL, /* newin */
        !           137:        NULL, /* newout */
        !           138:        NULL, /* ipos */
        !           139:        NULL, /* opos */
        !           140:        rwav_done
        !           141: };
        !           142:
        !           143: struct aproc_ops wwav_ops = {
        !           144:        "wwav",
        !           145:        wwav_in,
        !           146:        wwav_out,
        !           147:        wwav_eof,
        !           148:        wwav_hup,
        !           149:        NULL, /* newin */
        !           150:        NULL, /* newout */
        !           151:        NULL, /* ipos */
        !           152:        NULL, /* opos */
        !           153:        wwav_done
        !           154: };
        !           155:
        !           156: struct aproc *
        !           157: rwav_new(struct file *f)
        !           158: {
        !           159:        struct aproc *p;
        !           160:
        !           161:        p = aproc_new(&rwav_ops, f->name);
        !           162:        p->u.io.file = f;
        !           163:        f->rproc = p;
        !           164:        return p;
        !           165: }
        !           166:
        !           167: int
        !           168: rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
        !           169: {
        !           170:        struct abuf *obuf = LIST_FIRST(&p->obuflist);
        !           171:        struct file *f = p->u.io.file;
        !           172:        unsigned char *data;
        !           173:        unsigned count;
        !           174:
        !           175:        if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
        !           176:                return 0;
        !           177:        data = abuf_wgetblk(obuf, &count, 0);
        !           178:        count = file_read(f, data, count);
        !           179:        if (count == 0)
        !           180:                return 0;
        !           181:        abuf_wcommit(obuf, count);
        !           182:        if (!abuf_flush(obuf))
        !           183:                return 0;
        !           184:        return 1;
        !           185: }
        !           186:
        !           187: int
        !           188: rwav_out(struct aproc *p, struct abuf *obuf)
        !           189: {
        !           190:        struct file *f = p->u.io.file;
        !           191:        unsigned char *data;
        !           192:        unsigned count;
        !           193:
        !           194:        if (f->state & FILE_RINUSE)
        !           195:                return 0;
        !           196:        if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
        !           197:                return 0;
        !           198:        data = abuf_wgetblk(obuf, &count, 0);
        !           199:        count = file_read(f, data, count);
        !           200:        if (count == 0)
        !           201:                return 0;
        !           202:        abuf_wcommit(obuf, count);
        !           203:        return 1;
        !           204: }
        !           205:
        !           206: void
        !           207: rwav_done(struct aproc *p)
        !           208: {
        !           209:        struct file *f = p->u.io.file;
        !           210:        struct abuf *obuf;
        !           211:
        !           212:        if (f == NULL)
        !           213:                return;
        !           214:        /*
        !           215:         * all buffers must be detached before deleting f->wproc,
        !           216:         * because otherwise it could trigger this code again
        !           217:         */
        !           218:        obuf = LIST_FIRST(&p->obuflist);
        !           219:        if (obuf)
        !           220:                abuf_eof(obuf);
        !           221:        if (f->wproc) {
        !           222:                f->rproc = NULL;
        !           223:                aproc_del(f->wproc);
        !           224:        } else
        !           225:                file_del(f);
        !           226:        p->u.io.file = NULL;
        !           227: }
        !           228:
        !           229: void
        !           230: rwav_eof(struct aproc *p, struct abuf *ibuf_dummy)
        !           231: {
        !           232:        aproc_del(p);
        !           233: }
        !           234:
        !           235: void
        !           236: rwav_hup(struct aproc *p, struct abuf *obuf)
        !           237: {
        !           238:        aproc_del(p);
        !           239: }
        !           240:
        !           241: struct aproc *
        !           242: wwav_new(struct file *f)
        !           243: {
        !           244:        struct aproc *p;
        !           245:
        !           246:        p = aproc_new(&wwav_ops, f->name);
        !           247:        p->u.io.file = f;
        !           248:        f->wproc = p;
        !           249:        return p;
        !           250: }
        !           251:
        !           252: void
        !           253: wwav_done(struct aproc *p)
        !           254: {
        !           255:        struct file *f = p->u.io.file;
        !           256:        struct abuf *ibuf;
        !           257:
        !           258:        if (f == NULL)
        !           259:                return;
        !           260:        /*
        !           261:         * all buffers must be detached before deleting f->rproc,
        !           262:         * because otherwise it could trigger this code again
        !           263:         */
        !           264:        ibuf = LIST_FIRST(&p->ibuflist);
        !           265:        if (ibuf)
        !           266:                abuf_hup(ibuf);
        !           267:        if (f->rproc) {
        !           268:                f->wproc = NULL;
        !           269:                aproc_del(f->rproc);
        !           270:        } else
        !           271:                file_del(f);
        !           272:        p->u.io.file = NULL;
        !           273: }
        !           274:
        !           275: int
        !           276: wwav_in(struct aproc *p, struct abuf *ibuf)
        !           277: {
        !           278:        struct file *f = p->u.io.file;
        !           279:        unsigned char *data;
        !           280:        unsigned count;
        !           281:
        !           282:        if (f->state & FILE_WINUSE)
        !           283:                return 0;
        !           284:        if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
        !           285:                return 0;
        !           286:        data = abuf_rgetblk(ibuf, &count, 0);
        !           287:        count = file_write(f, data, count);
        !           288:        if (count == 0)
        !           289:                return 0;
        !           290:        abuf_rdiscard(ibuf, count);
        !           291:        return 1;
        !           292: }
        !           293:
        !           294: int
        !           295: wwav_out(struct aproc *p, struct abuf *obuf_dummy)
        !           296: {
        !           297:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
        !           298:        struct file *f = p->u.io.file;
        !           299:        unsigned char *data;
        !           300:        unsigned count;
        !           301:
        !           302:        if (!abuf_fill(ibuf))
        !           303:                return 0;
        !           304:        if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
        !           305:                return 0;
        !           306:        data = abuf_rgetblk(ibuf, &count, 0);
        !           307:        if (count == 0) {
        !           308:                /* XXX: this can't happen, right ? */
        !           309:                return 0;
        !           310:        }
        !           311:        count = file_write(f, data, count);
        !           312:        if (count == 0)
        !           313:                return 0;
        !           314:        abuf_rdiscard(ibuf, count);
        !           315:        return 1;
        !           316: }
        !           317:
        !           318: void
        !           319: wwav_eof(struct aproc *p, struct abuf *ibuf)
        !           320: {
        !           321:        aproc_del(p);
        !           322: }
        !           323:
        !           324: void
        !           325: wwav_hup(struct aproc *p, struct abuf *obuf_dummy)
        !           326: {
        !           327:        aproc_del(p);
        !           328: }
        !           329:
1.1       ratchov   330: struct wav *
1.10    ! ratchov   331: wav_new_in(struct fileops *ops, char *name, unsigned hdr,
        !           332:     struct aparams *par, unsigned xrun, unsigned volctl)
1.1       ratchov   333: {
1.10    ! ratchov   334:        int fd;
1.1       ratchov   335:        struct wav *f;
1.10    ! ratchov   336:        struct aproc *p;
        !           337:        struct abuf *buf;
        !           338:        unsigned nfr;
        !           339:
        !           340:        if (name != NULL) {
        !           341:                fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
        !           342:                if (fd < 0) {
        !           343:                        perror(name);
        !           344:                        return NULL;
        !           345:                }
        !           346:        } else {
        !           347:                name = "stdin";
        !           348:                fd = STDIN_FILENO;
        !           349:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
        !           350:                        perror(name);
        !           351:        }
1.1       ratchov   352:        f = (struct wav *)pipe_new(ops, fd, name);
1.4       ratchov   353:        if (f == NULL)
                    354:                return NULL;
1.1       ratchov   355:        if (hdr == HDR_WAV) {
1.10    ! ratchov   356:                if (!wav_readhdr(f->pipe.fd, par, &f->rbytes, &f->map)) {
        !           357:                        file_del((struct file *)f);
        !           358:                        return NULL;
        !           359:                }
1.1       ratchov   360:                f->hpar = *par;
1.6       ratchov   361:        } else {
1.1       ratchov   362:                f->rbytes = -1;
1.6       ratchov   363:                f->map = NULL;
                    364:        }
1.1       ratchov   365:        f->hdr = 0;
1.10    ! ratchov   366:        nfr = dev_bufsz * par->rate / dev_rate;
        !           367:        buf = abuf_new(nfr, par);
        !           368:        p = rwav_new((struct file *)f);
        !           369:        aproc_setout(p, buf);
        !           370:        abuf_fill(buf); /* XXX: move this in dev_attach() ? */
        !           371:        dev_attach(name, buf, par, xrun, NULL, NULL, 0, ADATA_UNIT);
        !           372:        dev_setvol(buf, MIDI_TO_ADATA(volctl));
1.1       ratchov   373:        return f;
                    374: }
                    375:
                    376: struct wav *
1.10    ! ratchov   377: wav_new_out(struct fileops *ops, char *name, unsigned hdr,
        !           378:     struct aparams *par, unsigned xrun)
1.1       ratchov   379: {
1.10    ! ratchov   380:        int fd;
1.1       ratchov   381:        struct wav *f;
1.10    ! ratchov   382:        struct aproc *p;
        !           383:        struct abuf *buf;
        !           384:        unsigned nfr;
        !           385:
        !           386:        if (name == NULL) {
        !           387:                name = "stdout";
        !           388:                fd = STDOUT_FILENO;
        !           389:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
        !           390:                        perror(name);
        !           391:        } else {
        !           392:                fd = open(name,
        !           393:                    O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
        !           394:                if (fd < 0) {
        !           395:                        perror(name);
        !           396:                        return NULL;
        !           397:                }
        !           398:        }
1.1       ratchov   399:        f = (struct wav *)pipe_new(ops, fd, name);
1.4       ratchov   400:        if (f == NULL)
                    401:                return NULL;
1.1       ratchov   402:        if (hdr == HDR_WAV) {
1.2       ratchov   403:                par->le = 1;
1.3       ratchov   404:                par->sig = (par->bits <= 8) ? 0 : 1;
1.2       ratchov   405:                par->bps = (par->bits + 7) / 8;
1.10    ! ratchov   406:                if (!wav_writehdr(f->pipe.fd, par)) {
        !           407:                        file_del((struct file *)f);
        !           408:                        return NULL;
        !           409:                }
1.1       ratchov   410:                f->hpar = *par;
                    411:                f->wbytes = WAV_DATAMAX;
                    412:        } else
                    413:                f->wbytes = -1;
                    414:        f->hdr = hdr;
1.10    ! ratchov   415:        nfr = dev_bufsz * par->rate / dev_rate;
        !           416:        p = wwav_new((struct file *)f);
        !           417:        buf = abuf_new(nfr, par);
        !           418:        aproc_setin(p, buf);
        !           419:        dev_attach(name, NULL, NULL, 0, buf, par, xrun, 0);
1.1       ratchov   420:        return f;
                    421: }
                    422:
1.6       ratchov   423: void
                    424: wav_conv(unsigned char *data, unsigned count, short *map)
                    425: {
                    426:        unsigned i;
                    427:        unsigned char *iptr;
                    428:        short *optr;
                    429:
                    430:        iptr = data + count;
                    431:        optr = (short *)data + count;
                    432:        for (i = count; i > 0; i--) {
                    433:                --optr;
                    434:                --iptr;
                    435:                *optr = map[*iptr];
                    436:        }
                    437: }
                    438:
1.1       ratchov   439: unsigned
                    440: wav_read(struct file *file, unsigned char *data, unsigned count)
                    441: {
                    442:        struct wav *f = (struct wav *)file;
                    443:        unsigned n;
                    444:
1.6       ratchov   445:        if (f->map)
                    446:                count /= sizeof(short);
1.1       ratchov   447:        if (f->rbytes >= 0 && count > f->rbytes) {
                    448:                count = f->rbytes; /* file->rbytes fits in count */
                    449:                if (count == 0) {
                    450:                        file_eof(&f->pipe.file);
                    451:                        return 0;
                    452:                }
                    453:        }
                    454:        n = pipe_read(file, data, count);
1.8       jakemsr   455:        if (n == 0)
                    456:                return 0;
1.1       ratchov   457:        if (f->rbytes >= 0)
                    458:                f->rbytes -= n;
1.6       ratchov   459:        if (f->map) {
                    460:                wav_conv(data, n, f->map);
                    461:                n *= sizeof(short);
                    462:        }
1.1       ratchov   463:        return n;
                    464: }
                    465:
                    466: unsigned
                    467: wav_write(struct file *file, unsigned char *data, unsigned count)
                    468: {
                    469:        struct wav *f = (struct wav *)file;
                    470:        unsigned n;
1.3       ratchov   471:
1.1       ratchov   472:        if (f->wbytes >= 0 && count > f->wbytes) {
                    473:                count = f->wbytes; /* wbytes fits in count */
                    474:                if (count == 0) {
                    475:                        file_hup(&f->pipe.file);
                    476:                        return 0;
                    477:                }
                    478:        }
                    479:        n = pipe_write(file, data, count);
                    480:        if (f->wbytes >= 0)
                    481:                f->wbytes -= n;
                    482:        return n;
                    483: }
                    484:
                    485: void
                    486: wav_close(struct file *file)
                    487: {
                    488:        struct wav *f = (struct wav *)file;
                    489:
                    490:        if (f->hdr == HDR_WAV)
                    491:                wav_writehdr(f->pipe.fd, &f->hpar);
                    492:        pipe_close(file);
                    493: }
1.10    ! ratchov   494: