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

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.13    ! ratchov    26: #include "midi.h"
1.1       ratchov    27: #include "wav.h"
1.13    ! ratchov    28: #include "opt.h"
1.11      ratchov    29: #ifdef DEBUG
                     30: #include "dbg.h"
                     31: #endif
1.1       ratchov    32:
1.6       ratchov    33: short wav_ulawmap[256] = {
                     34:        -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
                     35:        -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
                     36:        -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
                     37:        -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
                     38:         -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
                     39:         -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
                     40:         -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
                     41:         -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
                     42:         -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
                     43:         -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
                     44:          -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
                     45:          -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
                     46:          -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
                     47:          -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
                     48:          -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
                     49:           -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
                     50:         32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
                     51:         23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
                     52:         15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
                     53:         11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
                     54:          7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
                     55:          5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
                     56:          3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
                     57:          2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
                     58:          1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
                     59:          1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
                     60:           876,    844,    812,    780,    748,    716,    684,    652,
                     61:           620,    588,    556,    524,    492,    460,    428,    396,
                     62:           372,    356,    340,    324,    308,    292,    276,    260,
                     63:           244,    228,    212,    196,    180,    164,    148,    132,
                     64:           120,    112,    104,     96,     88,     80,     72,     64,
                     65:            56,     48,     40,     32,     24,     16,      8,      0
                     66: };
                     67:
                     68: short wav_alawmap[256] = {
                     69:         -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
                     70:         -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
                     71:         -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
                     72:         -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
                     73:        -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
                     74:        -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
                     75:        -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
                     76:        -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
                     77:          -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
                     78:          -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
                     79:           -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
                     80:          -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
                     81:         -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
                     82:         -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
                     83:          -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
                     84:          -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
                     85:          5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
                     86:          7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
                     87:          2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
                     88:          3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
                     89:         22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
                     90:         30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
                     91:         11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
                     92:         15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
                     93:           344,    328,    376,    360,    280,    264,    312,    296,
                     94:           472,    456,    504,    488,    408,    392,    440,    424,
                     95:            88,     72,    120,    104,     24,      8,     56,     40,
                     96:           216,    200,    248,    232,    152,    136,    184,    168,
                     97:          1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
                     98:          1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
                     99:           688,    656,    752,    720,    560,    528,    624,    592,
                    100:           944,    912,   1008,    976,    816,    784,    880,    848
                    101: };
                    102:
1.1       ratchov   103: /*
1.7       ratchov   104:  * Max data of a .wav file. The total file size must be smaller than
1.1       ratchov   105:  * 2^31, and we also have to leave some space for the headers (around 40
1.7       ratchov   106:  * bytes).
1.3       ratchov   107:  */
1.1       ratchov   108: #define WAV_DATAMAX    (0x7fff0000)
                    109:
                    110: struct fileops wav_ops = {
                    111:        "wav",
                    112:        sizeof(struct wav),
                    113:        wav_close,
                    114:        wav_read,
                    115:        wav_write,
                    116:        NULL, /* start */
                    117:        NULL, /* stop */
                    118:        pipe_nfds,
                    119:        pipe_pollfd,
                    120:        pipe_revents
                    121: };
                    122:
1.10      ratchov   123: int rwav_in(struct aproc *, struct abuf *);
                    124: int rwav_out(struct aproc *, struct abuf *);
                    125: void rwav_eof(struct aproc *, struct abuf *);
                    126: void rwav_hup(struct aproc *, struct abuf *);
                    127: void rwav_done(struct aproc *);
1.13    ! ratchov   128: struct aproc *rwav_new(struct file *);
1.10      ratchov   129:
                    130: int wwav_in(struct aproc *, struct abuf *);
                    131: int wwav_out(struct aproc *, struct abuf *);
                    132: void wwav_eof(struct aproc *, struct abuf *);
                    133: void wwav_hup(struct aproc *, struct abuf *);
                    134: void wwav_done(struct aproc *);
1.13    ! ratchov   135: struct aproc *wwav_new(struct file *);
        !           136:
        !           137: void wav_setvol(void *, unsigned);
        !           138: void wav_startreq(void *);
        !           139: void wav_stopreq(void *);
        !           140: void wav_locreq(void *, unsigned);
        !           141:
        !           142: struct ctl_ops ctl_wavops = {
        !           143:        wav_setvol,
        !           144:        wav_startreq,
        !           145:        wav_stopreq,
        !           146:        wav_locreq
        !           147: };
1.10      ratchov   148:
                    149: struct aproc_ops rwav_ops = {
                    150:        "rwav",
                    151:        rwav_in,
                    152:        rwav_out,
1.13    ! ratchov   153:        rfile_eof,
        !           154:        rfile_hup,
1.10      ratchov   155:        NULL, /* newin */
                    156:        NULL, /* newout */
                    157:        NULL, /* ipos */
                    158:        NULL, /* opos */
                    159:        rwav_done
                    160: };
                    161:
                    162: struct aproc_ops wwav_ops = {
                    163:        "wwav",
                    164:        wwav_in,
                    165:        wwav_out,
1.13    ! ratchov   166:        wfile_eof,
        !           167:        wfile_hup,
1.10      ratchov   168:        NULL, /* newin */
                    169:        NULL, /* newout */
                    170:        NULL, /* ipos */
                    171:        NULL, /* opos */
                    172:        wwav_done
                    173: };
                    174:
1.13    ! ratchov   175: #ifdef DEBUG
        !           176: /*
        !           177:  * print the given wav structure
        !           178:  */
        !           179: void
        !           180: wav_dbg(struct wav *f)
        !           181: {
        !           182:        static char *pstates[] = { "ini", "sta", "rdy", "run", "fai" };
        !           183:
        !           184:        dbg_puts("wav(");
        !           185:        if (f->slot >= 0 && APROC_OK(dev_midi)) {
        !           186:                dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
        !           187:                dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
        !           188:        } else
        !           189:                dbg_puts(f->pipe.file.name);
        !           190:        dbg_puts(")/");
        !           191:        dbg_puts(pstates[f->pstate]);
        !           192: }
        !           193: #endif
        !           194:
        !           195: /*
        !           196:  * convert ``count'' samples using the given char->short map
        !           197:  */
        !           198: void
        !           199: wav_conv(unsigned char *data, unsigned count, short *map)
1.10      ratchov   200: {
1.13    ! ratchov   201:        unsigned i;
        !           202:        unsigned char *iptr;
        !           203:        short *optr;
1.10      ratchov   204:
1.13    ! ratchov   205:        iptr = data + count;
        !           206:        optr = (short *)data + count;
        !           207:        for (i = count; i > 0; i--) {
        !           208:                --optr;
        !           209:                --iptr;
        !           210:                *optr = map[*iptr];
        !           211:        }
1.10      ratchov   212: }
                    213:
1.13    ! ratchov   214: /*
        !           215:  * read method of the file structure
        !           216:  */
        !           217: unsigned
        !           218: wav_read(struct file *file, unsigned char *data, unsigned count)
1.10      ratchov   219: {
1.13    ! ratchov   220:        struct wav *f = (struct wav *)file;
        !           221:        unsigned n;
        !           222:
        !           223:        if (f->map)
        !           224:                count /= sizeof(short);
        !           225:        if (f->rbytes >= 0 && count > f->rbytes) {
        !           226:                count = f->rbytes; /* file->rbytes fits in count */
        !           227:                if (count == 0) {
        !           228: #ifdef DEBUG
        !           229:                        if (debug_level >= 3) {
        !           230:                                wav_dbg(f);
        !           231:                                dbg_puts(": read complete\n");
        !           232:                        }
        !           233: #endif
        !           234:                        if (!f->tr)
        !           235:                                file_eof(&f->pipe.file);
        !           236:                        return 0;
        !           237:                }
        !           238:        }
        !           239:        n = pipe_read(file, data, count);
        !           240:        if (n == 0)
1.10      ratchov   241:                return 0;
1.13    ! ratchov   242:        if (f->rbytes >= 0)
        !           243:                f->rbytes -= n;
        !           244:        if (f->map) {
        !           245:                wav_conv(data, n, f->map);
        !           246:                n *= sizeof(short);
        !           247:        }
        !           248:        return n;
        !           249: }
        !           250:
        !           251: /*
        !           252:  * write method of the file structure
        !           253:  */
        !           254: unsigned
        !           255: wav_write(struct file *file, unsigned char *data, unsigned count)
        !           256: {
        !           257:        struct wav *f = (struct wav *)file;
        !           258:        unsigned n;
        !           259:
        !           260:        if (f->wbytes >= 0 && count > f->wbytes) {
        !           261:                count = f->wbytes; /* wbytes fits in count */
        !           262:                if (count == 0) {
        !           263: #ifdef DEBUG
        !           264:                        if (debug_level >= 3) {
        !           265:                                wav_dbg(f);
        !           266:                                dbg_puts(": write complete\n");
        !           267:                        }
        !           268: #endif
        !           269:                        file_hup(&f->pipe.file);
        !           270:                        return 0;
        !           271:                }
        !           272:        }
        !           273:        n = pipe_write(file, data, count);
        !           274:        if (f->wbytes >= 0)
        !           275:                f->wbytes -= n;
        !           276:        f->endpos += n;
        !           277:        return n;
        !           278: }
        !           279:
        !           280: /*
        !           281:  * close method of the file structure
        !           282:  */
        !           283: void
        !           284: wav_close(struct file *file)
        !           285: {
        !           286:        struct wav *f = (struct wav *)file;
        !           287:
        !           288:        if (f->mode & MODE_RECMASK) {
        !           289:                pipe_trunc(&f->pipe.file, f->endpos);
        !           290:                if (f->hdr == HDR_WAV) {
        !           291:                        wav_writehdr(f->pipe.fd,
        !           292:                            &f->hpar,
        !           293:                            &f->startpos,
        !           294:                            f->endpos - f->startpos);
        !           295:                }
        !           296:        }
        !           297:        pipe_close(file);
1.10      ratchov   298: }
                    299:
1.13    ! ratchov   300: /*
        !           301:  * attach play (rec) abuf structure to the device and
        !           302:  * switch to the ``RUN'' state; the play abug must not be empty
        !           303:  */
1.10      ratchov   304: int
1.13    ! ratchov   305: wav_attach(struct wav *f, int force)
1.10      ratchov   306: {
1.13    ! ratchov   307:        struct abuf *rbuf = NULL, *wbuf = NULL;
1.10      ratchov   308:
1.13    ! ratchov   309:        if (f->mode & MODE_PLAY)
        !           310:                rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
        !           311:        if (f->mode & MODE_RECMASK)
        !           312:                wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
        !           313:        f->pstate = WAV_RUN;
        !           314: #ifdef DEBUG
        !           315:        if (debug_level >= 3) {
        !           316:                wav_dbg(f);
        !           317:                dbg_puts(": attaching\n");
        !           318:        }
        !           319: #endif
        !           320:        dev_attach(f->pipe.file.name, f->mode,
        !           321:            rbuf, &f->hpar, wbuf, &f->hpar, f->xrun, f->maxweight);
        !           322:        if (f->mode & MODE_PLAY)
        !           323:                dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
1.10      ratchov   324:        return 1;
                    325: }
                    326:
1.13    ! ratchov   327: /*
        !           328:  * allocate the play (rec) abuf structure; if this is a
        !           329:  * file to record, then attach it to the device
        !           330:  *
        !           331:  * XXX: buffer size should be larger than dev_bufsz, because
        !           332:  *     in non-server mode we don't prime play buffers with
        !           333:  *     silence
        !           334:  */
1.10      ratchov   335: void
1.13    ! ratchov   336: wav_allocbuf(struct wav *f)
1.10      ratchov   337: {
1.13    ! ratchov   338:        struct abuf *buf;
        !           339:        unsigned nfr;
1.10      ratchov   340:
1.13    ! ratchov   341:        f->pstate = WAV_START;
        !           342:        if (f->mode & MODE_PLAY) {
        !           343:                nfr = 2 * dev_bufsz * f->hpar.rate / dev_rate;
        !           344:                buf = abuf_new(nfr, &f->hpar);
        !           345:                aproc_setout(f->pipe.file.rproc, buf);
        !           346:                abuf_fill(buf);
        !           347:                if (!ABUF_WOK(buf) || (f->pipe.file.state & FILE_EOF))
        !           348:                        f->pstate = WAV_READY;
        !           349:        }
        !           350:        if (f->mode & MODE_RECMASK) {
        !           351:                nfr = 2 * dev_bufsz * f->hpar.rate / dev_rate;
        !           352:                buf = abuf_new(nfr, &f->hpar);
        !           353:                aproc_setin(f->pipe.file.wproc, buf);
        !           354:                f->pstate = WAV_READY;
        !           355:        }
        !           356: #ifdef DEBUG
        !           357:        if (debug_level >= 3) {
        !           358:                wav_dbg(f);
        !           359:                dbg_puts(": allocating buffers\n");
        !           360:        }
        !           361: #endif
        !           362:        if (f->pstate == WAV_READY && ctl_slotstart(dev_midi, f->slot))
        !           363:                (void)wav_attach(f, 0);
1.10      ratchov   364: }
                    365:
1.13    ! ratchov   366: /*
        !           367:  * free abuf structure and switch to the ``INIT'' state
        !           368:  */
1.10      ratchov   369: void
1.13    ! ratchov   370: wav_freebuf(struct wav *f)
1.10      ratchov   371: {
1.13    ! ratchov   372:        struct abuf *rbuf = NULL, *wbuf = NULL;
        !           373:
        !           374:        if (f->mode & MODE_PLAY)
        !           375:                rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
        !           376:        if (f->mode & MODE_RECMASK)
        !           377:                wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
        !           378:        f->pstate = WAV_INIT;
        !           379: #ifdef DEBUG
        !           380:        if (debug_level >= 3) {
        !           381:                wav_dbg(f);
        !           382:                dbg_puts(": freeing buffers\n");
        !           383:        }
        !           384: #endif
        !           385:        if (rbuf || wbuf)
        !           386:                ctl_slotstop(dev_midi, f->slot);
        !           387:        if (rbuf)
        !           388:                abuf_eof(rbuf);
        !           389:        if (wbuf)
        !           390:                abuf_hup(wbuf);
1.10      ratchov   391: }
                    392:
1.13    ! ratchov   393: /*
        !           394:  * switch to the ``INIT'' state performing
        !           395:  * necessary actions to reach it
        !           396:  */
1.10      ratchov   397: void
1.13    ! ratchov   398: wav_reset(struct wav *f)
1.10      ratchov   399: {
1.13    ! ratchov   400:        switch (f->pstate) {
        !           401:        case WAV_START:
        !           402:        case WAV_READY:
        !           403:                if (ctl_slotstart(dev_midi, f->slot))
        !           404:                        (void)wav_attach(f, 1);
        !           405:                /* PASSTHROUGH */
        !           406:        case WAV_RUN:
        !           407:                wav_freebuf(f);
        !           408:                f->pstate = WAV_INIT;
        !           409:                /* PASSTHROUGH */
        !           410:        case WAV_INIT:
        !           411:        case WAV_FAILED:
        !           412:                /* nothing yet */
        !           413:                break;
        !           414:        }
1.10      ratchov   415: }
                    416:
1.13    ! ratchov   417: /*
        !           418:  * terminate the wav reader/writer
        !           419:  */
        !           420: void
        !           421: wav_exit(struct wav *f)
1.10      ratchov   422: {
1.13    ! ratchov   423:        if (f->mode & MODE_PLAY) {
        !           424:                aproc_del(f->pipe.file.rproc);
        !           425:        } else if (f->mode & MODE_RECMASK) {
        !           426:                aproc_del(f->pipe.file.wproc);
        !           427:        }
1.10      ratchov   428: }
                    429:
1.13    ! ratchov   430: /*
        !           431:  * seek to f->mmcpos and prepare to start, close
        !           432:  * the file on error.
        !           433:  */
        !           434: int
        !           435: wav_seekmmc(struct wav *f)
1.10      ratchov   436: {
                    437:        /*
1.13    ! ratchov   438:         * don't go beyond the end-of-file, if so
        !           439:         * put it in INIT state so it dosn't start
1.10      ratchov   440:         */
1.13    ! ratchov   441:        if (f->mmcpos > f->endpos) {
        !           442:                wav_reset(f);
        !           443:                f->pstate = WAV_FAILED;
        !           444:                /*
        !           445:                 * don't make other stream wait for us
        !           446:                 */
        !           447:                if (f->slot >= 0)
        !           448:                        ctl_slotstart(dev_midi, f->slot);
        !           449:                return 0;
        !           450:        }
        !           451:        if (!pipe_seek(&f->pipe.file, f->mmcpos)) {
        !           452:                wav_exit(f);
        !           453:                return 0;
        !           454:        }
        !           455:        if (f->hdr == HDR_WAV)
        !           456:                f->wbytes = WAV_DATAMAX - f->mmcpos;
        !           457:        f->rbytes = f->endpos - f->mmcpos;
        !           458:        wav_reset(f);
        !           459:        wav_allocbuf(f);
        !           460:        return 1;
1.10      ratchov   461: }
                    462:
1.13    ! ratchov   463: /*
        !           464:  * read samples from the file and possibly start it
        !           465:  */
1.10      ratchov   466: int
1.13    ! ratchov   467: wav_rdata(struct wav *f)
1.10      ratchov   468: {
1.13    ! ratchov   469:        struct aproc *p;
        !           470:        struct abuf *obuf;
1.10      ratchov   471:
1.13    ! ratchov   472:        p = f->pipe.file.rproc;
        !           473:        obuf = LIST_FIRST(&p->obuflist);
        !           474:        if (obuf == NULL)
1.10      ratchov   475:                return 0;
1.13    ! ratchov   476:        if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
1.10      ratchov   477:                return 0;
1.13    ! ratchov   478:        if (!rfile_do(p, obuf->len, NULL))
1.10      ratchov   479:                return 0;
1.13    ! ratchov   480:        switch (f->pstate) {
        !           481:        case WAV_START:
        !           482:                if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
        !           483:                        f->pstate = WAV_READY;
        !           484:                /* PASSTHROUGH */
        !           485:        case WAV_READY:
        !           486:                if (ctl_slotstart(dev_midi, f->slot))
        !           487:                        (void)wav_attach(f, 0);
        !           488:                break;
        !           489: #ifdef DEBUG
        !           490:        case WAV_RUN:
        !           491:                break;
        !           492:        default:
        !           493:                wav_dbg(f);
        !           494:                dbg_puts(": bad state\n");
        !           495:                dbg_panic();
        !           496: #endif
        !           497:        }
        !           498:        if (f->rbytes == 0 && f->tr) {
        !           499: #ifdef DEBUG
        !           500:                if (debug_level >= 3) {
        !           501:                        wav_dbg(f);
        !           502:                        dbg_puts(": trying to restart\n");
        !           503:                }
        !           504: #endif
        !           505:                if (!wav_seekmmc(f))
        !           506:                        return 0;
        !           507:        }
1.10      ratchov   508:        return 1;
                    509: }
                    510:
                    511: int
1.13    ! ratchov   512: wav_wdata(struct wav *f)
1.10      ratchov   513: {
1.13    ! ratchov   514:        struct aproc *p;
        !           515:        struct abuf *ibuf;
1.10      ratchov   516:
1.13    ! ratchov   517:        if (!(f->pipe.file.state & FILE_WOK))
1.10      ratchov   518:                return 0;
1.13    ! ratchov   519:        p = f->pipe.file.wproc;
        !           520:        ibuf = LIST_FIRST(&p->ibuflist);
        !           521:        if (ibuf == NULL)
1.10      ratchov   522:                return 0;
1.13    ! ratchov   523:        if (!ABUF_ROK(ibuf))
1.10      ratchov   524:                return 0;
1.13    ! ratchov   525:        if (!wfile_do(p, ibuf->len, NULL))
1.10      ratchov   526:                return 0;
                    527:        return 1;
                    528: }
                    529:
1.13    ! ratchov   530: /*
        !           531:  * callback to set the volume, invoked by the MIDI control code
        !           532:  */
        !           533: void
        !           534: wav_setvol(void *arg, unsigned vol)
        !           535: {
        !           536:        struct wav *f = (struct wav *)arg;
        !           537:        struct abuf *rbuf;
        !           538:
        !           539:        f->vol = vol;
        !           540:        if ((f->mode & MODE_PLAY) && f->pstate == WAV_RUN) {
        !           541:                rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
        !           542:                dev_setvol(rbuf, MIDI_TO_ADATA(vol));
        !           543:        }
        !           544: }
        !           545:
        !           546: /*
        !           547:  * callback to start the stream, invoked by the MIDI control code
        !           548:  */
        !           549: void
        !           550: wav_startreq(void *arg)
        !           551: {
        !           552:        struct wav *f = (struct wav *)arg;
        !           553:
        !           554:        switch (f->pstate) {
        !           555:        case WAV_FAILED:
        !           556: #ifdef DEBUG
        !           557:                if (debug_level >= 2) {
        !           558:                        wav_dbg(f);
        !           559:                        dbg_puts(": skipped (failed to seek)\n");
        !           560:                }
        !           561: #endif
        !           562:                return;
        !           563:        case WAV_READY:
        !           564:                if (f->mode & MODE_RECMASK)
        !           565:                        f->endpos = f->startpos;
        !           566:                (void)wav_attach(f, 0);
        !           567:                break;
        !           568: #ifdef DEBUG
        !           569:        default:
        !           570:                wav_dbg(f);
        !           571:                dbg_puts(": not in READY state\n");
        !           572:                dbg_panic();
        !           573:                break;
        !           574: #endif
        !           575:        }
        !           576: }
        !           577:
        !           578: /*
        !           579:  * callback to stop the stream, invoked by the MIDI control code
        !           580:  */
1.10      ratchov   581: void
1.13    ! ratchov   582: wav_stopreq(void *arg)
1.10      ratchov   583: {
1.13    ! ratchov   584:        struct wav *f = (struct wav *)arg;
        !           585:
        !           586: #ifdef DEBUG
        !           587:        if (debug_level >= 2) {
        !           588:                wav_dbg(f);
        !           589:                dbg_puts(": stopping");
        !           590:                if (f->pstate != WAV_FAILED && (f->mode & MODE_RECMASK)) {
        !           591:                        dbg_puts(", ");
        !           592:                        dbg_putu(f->endpos);
        !           593:                        dbg_puts(" bytes recorded");
        !           594:                }
        !           595:                dbg_puts("\n");
        !           596:        }
        !           597: #endif
        !           598:        if (!f->tr) {
        !           599:                wav_exit(f);
        !           600:                return;
        !           601:        }
        !           602:        (void)wav_seekmmc(f);
1.10      ratchov   603: }
                    604:
1.13    ! ratchov   605: /*
        !           606:  * callback to relocate the stream, invoked by the MIDI control code
        !           607:  * on a stopped stream
        !           608:  */
1.10      ratchov   609: void
1.13    ! ratchov   610: wav_locreq(void *arg, unsigned mmc)
1.10      ratchov   611: {
1.13    ! ratchov   612:        struct wav *f = (struct wav *)arg;
        !           613:
        !           614: #ifdef DEBUG
        !           615:        if (f->pstate == WAV_RUN) {
        !           616:                wav_dbg(f);
        !           617:                dbg_puts(": in RUN state\n");
        !           618:                dbg_panic();
        !           619:        }
        !           620: #endif
        !           621:        f->mmcpos = f->startpos +
        !           622:            ((off_t)mmc * f->hpar.rate / MTC_SEC) * aparams_bpf(&f->hpar);
        !           623:        (void)wav_seekmmc(f);
1.10      ratchov   624: }
                    625:
1.13    ! ratchov   626: /*
        !           627:  * create a file reader in the ``INIT'' state
        !           628:  */
1.1       ratchov   629: struct wav *
1.13    ! ratchov   630: wav_new_in(struct fileops *ops, unsigned mode, char *name, unsigned hdr,
        !           631:     struct aparams *par, unsigned xrun, unsigned volctl, int tr)
1.1       ratchov   632: {
1.10      ratchov   633:        int fd;
1.1       ratchov   634:        struct wav *f;
1.10      ratchov   635:
                    636:        if (name != NULL) {
                    637:                fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
                    638:                if (fd < 0) {
                    639:                        perror(name);
                    640:                        return NULL;
                    641:                }
                    642:        } else {
                    643:                name = "stdin";
                    644:                fd = STDIN_FILENO;
                    645:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    646:                        perror(name);
                    647:        }
1.1       ratchov   648:        f = (struct wav *)pipe_new(ops, fd, name);
1.4       ratchov   649:        if (f == NULL)
                    650:                return NULL;
1.1       ratchov   651:        if (hdr == HDR_WAV) {
1.13    ! ratchov   652:                if (!wav_readhdr(f->pipe.fd, par, &f->startpos, &f->rbytes, &f->map)) {
1.10      ratchov   653:                        file_del((struct file *)f);
                    654:                        return NULL;
                    655:                }
1.13    ! ratchov   656:                f->endpos = f->startpos + f->rbytes;
1.6       ratchov   657:        } else {
1.13    ! ratchov   658:                f->startpos = 0;
        !           659:                f->endpos = pipe_endpos(&f->pipe.file);
        !           660:                if (f->endpos > 0) {
        !           661:                        if (!pipe_seek(&f->pipe.file, 0)) {
        !           662:                                file_del((struct file *)f);
        !           663:                                return NULL;
        !           664:                        }
        !           665:                        f->rbytes = f->endpos;
        !           666:                } else
        !           667:                        f->rbytes = -1;
1.6       ratchov   668:                f->map = NULL;
                    669:        }
1.13    ! ratchov   670:        f->tr = tr;
        !           671:        f->mode = mode;
        !           672:        f->hpar = *par;
1.1       ratchov   673:        f->hdr = 0;
1.13    ! ratchov   674:        f->xrun = xrun;
        !           675:        f->maxweight = MIDI_TO_ADATA(volctl);
        !           676:        f->slot = ctl_slotnew(dev_midi, "play", &ctl_wavops, f, 1);
        !           677:        rwav_new((struct file *)f);
        !           678:        wav_allocbuf(f);
1.12      ratchov   679: #ifdef DEBUG
                    680:        if (debug_level >= 2) {
                    681:                dbg_puts(name);
                    682:                dbg_puts(": playing ");
1.13    ! ratchov   683:                dbg_putu(f->startpos);
        !           684:                dbg_puts("..");
        !           685:                dbg_putu(f->endpos);
        !           686:                dbg_puts(": playing ");
1.12      ratchov   687:                aparams_dbg(par);
1.13    ! ratchov   688:                if (f->tr)
        !           689:                        dbg_puts(", mmc");
1.12      ratchov   690:                dbg_puts("\n");
                    691:        }
                    692: #endif
1.1       ratchov   693:        return f;
                    694: }
                    695:
1.13    ! ratchov   696: /*
        !           697:  * create a file writer in the ``INIT'' state
        !           698:  */
1.1       ratchov   699: struct wav *
1.13    ! ratchov   700: wav_new_out(struct fileops *ops, unsigned mode, char *name, unsigned hdr,
        !           701:     struct aparams *par, unsigned xrun, int tr)
1.1       ratchov   702: {
1.10      ratchov   703:        int fd;
1.1       ratchov   704:        struct wav *f;
1.10      ratchov   705:
                    706:        if (name == NULL) {
                    707:                name = "stdout";
                    708:                fd = STDOUT_FILENO;
                    709:                if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
                    710:                        perror(name);
                    711:        } else {
                    712:                fd = open(name,
                    713:                    O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
                    714:                if (fd < 0) {
                    715:                        perror(name);
                    716:                        return NULL;
                    717:                }
                    718:        }
1.1       ratchov   719:        f = (struct wav *)pipe_new(ops, fd, name);
1.4       ratchov   720:        if (f == NULL)
                    721:                return NULL;
1.1       ratchov   722:        if (hdr == HDR_WAV) {
1.2       ratchov   723:                par->le = 1;
1.3       ratchov   724:                par->sig = (par->bits <= 8) ? 0 : 1;
1.2       ratchov   725:                par->bps = (par->bits + 7) / 8;
1.13    ! ratchov   726:                if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) {
1.10      ratchov   727:                        file_del((struct file *)f);
                    728:                        return NULL;
                    729:                }
1.1       ratchov   730:                f->wbytes = WAV_DATAMAX;
1.13    ! ratchov   731:                f->endpos = f->startpos;
        !           732:        } else {
1.1       ratchov   733:                f->wbytes = -1;
1.13    ! ratchov   734:                f->startpos = f->endpos = 0;
        !           735:        }
        !           736:        f->tr = tr;
        !           737:        f->mode = mode;
        !           738:        f->hpar = *par;
1.1       ratchov   739:        f->hdr = hdr;
1.13    ! ratchov   740:        f->xrun = xrun;
        !           741:        f->slot = ctl_slotnew(dev_midi, "rec", &ctl_wavops, f, 1);
        !           742:        wwav_new((struct file *)f);
        !           743:        wav_allocbuf(f);
1.12      ratchov   744: #ifdef DEBUG
                    745:        if (debug_level >= 2) {
                    746:                dbg_puts(name);
                    747:                dbg_puts(": recording ");
                    748:                aparams_dbg(par);
                    749:                dbg_puts("\n");
                    750:        }
                    751: #endif
1.1       ratchov   752:        return f;
                    753: }
                    754:
1.6       ratchov   755: void
1.13    ! ratchov   756: rwav_done(struct aproc *p)
        !           757: {
        !           758:        struct wav *f = (struct wav *)p->u.io.file;
        !           759:
        !           760:        if (f->slot >= 0)
        !           761:                ctl_slotdel(dev_midi, f->slot);
        !           762:        f->slot = -1;
        !           763:        rfile_done(p);
        !           764: }
        !           765:
        !           766: int
        !           767: rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
1.6       ratchov   768: {
1.13    ! ratchov   769:        struct wav *f = (struct wav *)p->u.io.file;
        !           770:        struct abuf *obuf;
1.6       ratchov   771:
1.13    ! ratchov   772:        if (!wav_rdata(f))
        !           773:                return 0;
        !           774:        obuf = LIST_FIRST(&p->obuflist);
        !           775:        if (obuf && f->pstate >= WAV_RUN) {
        !           776:                if (!abuf_flush(obuf))
        !           777:                        return 0;
1.6       ratchov   778:        }
1.13    ! ratchov   779:        return 1;
1.6       ratchov   780: }
                    781:
1.13    ! ratchov   782: int
        !           783: rwav_out(struct aproc *p, struct abuf *obuf)
1.1       ratchov   784: {
1.13    ! ratchov   785:        struct wav *f = (struct wav *)p->u.io.file;
1.1       ratchov   786:
1.13    ! ratchov   787:        if (f->pipe.file.state & FILE_RINUSE)
        !           788:                return 0;
        !           789:        for (;;) {
        !           790:                if (!wav_rdata(f))
1.1       ratchov   791:                        return 0;
                    792:        }
1.13    ! ratchov   793:        return 1;
        !           794: }
        !           795:
        !           796: struct aproc *
        !           797: rwav_new(struct file *f)
        !           798: {
        !           799:        struct aproc *p;
        !           800:
        !           801:        p = aproc_new(&rwav_ops, f->name);
        !           802:        p->u.io.file = f;
        !           803:        p->u.io.partial = 0;;
        !           804:        f->rproc = p;
        !           805:        return p;
        !           806: }
        !           807:
        !           808: void
        !           809: wwav_done(struct aproc *p)
        !           810: {
        !           811:        struct wav *f = (struct wav *)p->u.io.file;
        !           812:
        !           813:        if (f->slot >= 0)
        !           814:                ctl_slotdel(dev_midi, f->slot);
        !           815:        f->slot = -1;
        !           816:        wfile_done(p);
        !           817: }
        !           818:
        !           819: int
        !           820: wwav_in(struct aproc *p, struct abuf *ibuf)
        !           821: {
        !           822:        struct wav *f = (struct wav *)p->u.io.file;
        !           823:
        !           824:        if (f->pipe.file.state & FILE_WINUSE)
1.8       jakemsr   825:                return 0;
1.13    ! ratchov   826:        for (;;) {
        !           827:                if (!wav_wdata(f))
        !           828:                        return 0;
1.6       ratchov   829:        }
1.13    ! ratchov   830:        return 1;
1.1       ratchov   831: }
                    832:
1.13    ! ratchov   833: int
        !           834: wwav_out(struct aproc *p, struct abuf *obuf_dummy)
1.1       ratchov   835: {
1.13    ! ratchov   836:        struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
        !           837:        struct wav *f = (struct wav *)p->u.io.file;
1.3       ratchov   838:
1.13    ! ratchov   839:        if (ibuf && f->pstate == WAV_RUN) {
        !           840:                if (!abuf_fill(ibuf))
1.1       ratchov   841:                        return 0;
                    842:        }
1.13    ! ratchov   843:        if (!wav_wdata(f))
        !           844:                return 0;
        !           845:        return 1;
1.1       ratchov   846: }
                    847:
1.13    ! ratchov   848: struct aproc *
        !           849: wwav_new(struct file *f)
1.1       ratchov   850: {
1.13    ! ratchov   851:        struct aproc *p;
1.1       ratchov   852:
1.13    ! ratchov   853:        p = aproc_new(&wwav_ops, f->name);
        !           854:        p->u.io.file = f;
        !           855:        p->u.io.partial = 0;;
        !           856:        f->wproc = p;
        !           857:        return p;
1.1       ratchov   858: }
1.10      ratchov   859: