Simplify internals and rewrite file header parsing code:
authorratchov <ratchov@openbsd.org>
Wed, 21 Jan 2015 08:43:55 +0000 (08:43 +0000)
committerratchov <ratchov@openbsd.org>
Wed, 21 Jan 2015 08:43:55 +0000 (08:43 +0000)
- remove -M, -t, -w, -C, -x flags that don't make sense anymore
- make "-j off" the default (sndiod already does the job)
- don't limit the number of played/recorded files.
- add support for floating-point encoded files.
- add support for apple .aiff and sun/next .au files

35 files changed:
usr.bin/aucat/Makefile
usr.bin/aucat/abuf.c
usr.bin/aucat/abuf.h
usr.bin/aucat/afile.c [new file with mode: 0644]
usr.bin/aucat/afile.h [new file with mode: 0644]
usr.bin/aucat/aparams.c [deleted file]
usr.bin/aucat/aparams.h [deleted file]
usr.bin/aucat/aproc.c [deleted file]
usr.bin/aucat/aproc.h [deleted file]
usr.bin/aucat/aucat.1
usr.bin/aucat/aucat.c
usr.bin/aucat/conf.h [deleted file]
usr.bin/aucat/dbg.c [deleted file]
usr.bin/aucat/dbg.h [deleted file]
usr.bin/aucat/defs.h [new file with mode: 0644]
usr.bin/aucat/dev.c [deleted file]
usr.bin/aucat/dev.h [deleted file]
usr.bin/aucat/dsp.c [new file with mode: 0644]
usr.bin/aucat/dsp.h [new file with mode: 0644]
usr.bin/aucat/file.c [deleted file]
usr.bin/aucat/file.h [deleted file]
usr.bin/aucat/headers.c [deleted file]
usr.bin/aucat/midi.c [deleted file]
usr.bin/aucat/midi.h [deleted file]
usr.bin/aucat/miofile.c [deleted file]
usr.bin/aucat/miofile.h [deleted file]
usr.bin/aucat/pipe.c [deleted file]
usr.bin/aucat/pipe.h [deleted file]
usr.bin/aucat/siofile.c [deleted file]
usr.bin/aucat/siofile.h [deleted file]
usr.bin/aucat/sysex.h
usr.bin/aucat/utils.c [new file with mode: 0644]
usr.bin/aucat/utils.h [new file with mode: 0644]
usr.bin/aucat/wav.c [deleted file]
usr.bin/aucat/wav.h [deleted file]

index 2d35539..7f4e336 100644 (file)
@@ -1,8 +1,7 @@
-#      $OpenBSD: Makefile,v 1.21 2013/11/21 08:15:46 ratchov Exp $
+#      $OpenBSD: Makefile,v 1.22 2015/01/21 08:43:55 ratchov Exp $
 
 PROG=  aucat
-SRCS=  aucat.c abuf.c aparams.c aproc.c dev.c midi.c file.c headers.c \
-       siofile.c miofile.c pipe.c wav.c dbg.c
+SRCS=  abuf.c afile.c aucat.c dsp.c utils.c
 MAN=   aucat.1
 CFLAGS+=-DDEBUG -I${.CURDIR}/../../lib/libsndio
 COPTS+=        -Wall -Wstrict-prototypes -Wmissing-prototypes -Wpointer-arith -Wundef
index 63f7f4b..dd35076 100644 (file)
@@ -1,6 +1,6 @@
-/*     $OpenBSD: abuf.c,v 1.25 2013/11/18 17:37:45 ratchov Exp $       */
+/*     $OpenBSD: abuf.c,v 1.26 2015/01/21 08:43:55 ratchov Exp $       */
 /*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
+ * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 /*
- * Simple byte fifo. It has one reader and one writer. The abuf
- * structure is used to interconnect audio processing units (aproc
- * structures).
+ * Simple byte fifo.
  *
  * The abuf data is split in two parts: (1) valid data available to the reader
  * (2) space available to the writer, which is not necessarily unused. It works
  * as follows: the write starts filling at offset (start + used), once the data
  * is ready, the writer adds to used the count of bytes available.
  */
-/*
- * TODO
- *
- *     use blocks instead of frames for WOK and ROK macros. If necessary
- *     (unlikely) define reader block size and writer blocks size to
- *     ease pipe/socket implementation
- */
-#include <err.h>
-#include <stdarg.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 
 #include "abuf.h"
-#include "aparams.h"
-#include "aproc.h"
-#include "conf.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-void abuf_dump(struct abuf *);
-int abuf_flush_do(struct abuf *);
-int abuf_fill_do(struct abuf *);
-void abuf_eof_do(struct abuf *);
-void abuf_hup_do(struct abuf *);
+#include "utils.h"
 
 #ifdef DEBUG
 void
-abuf_dbg(struct abuf *buf)
-{
-       if (buf->wproc) {
-               aproc_dbg(buf->wproc);
-       } else {
-               dbg_puts("none");
-       }
-       dbg_puts(buf->inuse ? "=>" : "->");
-       if (buf->rproc) {
-               aproc_dbg(buf->rproc);
-       } else {
-               dbg_puts("none");
-       }
-}
-
-void
-abuf_dump(struct abuf *buf)
+abuf_log(struct abuf *buf)
 {
-       abuf_dbg(buf);
-       dbg_puts(": used = ");
-       dbg_putu(buf->used);
-       dbg_puts("/");
-       dbg_putu(buf->len);
-       dbg_puts(" start = ");
-       dbg_putu(buf->start);
-       dbg_puts("\n");
+       log_putu(buf->start);
+       log_puts("+");
+       log_putu(buf->used);
+       log_puts("/");
+       log_putu(buf->len);
 }
 #endif
 
-struct abuf *
-abuf_new(unsigned int nfr, struct aparams *par)
+void
+abuf_init(struct abuf *buf, unsigned int len)
 {
-       struct abuf *buf;
-       unsigned int len, bpf;
-
-       bpf = aparams_bpf(par);
-       len = nfr * bpf;
-       buf = malloc(sizeof(struct abuf) + len);
-       if (buf == NULL) {
-#ifdef DEBUG
-               dbg_puts("couldn't allocate abuf of ");
-               dbg_putu(nfr);
-               dbg_puts("fr * ");
-               dbg_putu(bpf);
-               dbg_puts("bpf\n");
-               dbg_panic();
-#else
-               err(1, "malloc");
-#endif
-       }
-       buf->bpf = bpf;
-       buf->cmin = par->cmin;
-       buf->cmax = par->cmax;
-       buf->inuse = 0;
-
-       /*
-        * fill fifo pointers
-        */
-       buf->len = nfr;
+       buf->data = xmalloc(len);
+       buf->len = len;
        buf->used = 0;
        buf->start = 0;
-       buf->rproc = NULL;
-       buf->wproc = NULL;
-       buf->duplex = NULL;
-       return buf;
 }
 
 void
-abuf_del(struct abuf *buf)
+abuf_done(struct abuf *buf)
 {
-       if (buf->duplex)
-               buf->duplex->duplex = NULL;
-#ifdef DEBUG
-       if (buf->rproc || buf->wproc) {
-               abuf_dbg(buf);
-               dbg_puts(": can't delete referenced buffer\n");
-               dbg_panic();
-       }
-       if (ABUF_ROK(buf)) {
-               /*
-                * XXX: we should call abort(), here.
-                * However, poll() doesn't seem to return POLLHUP,
-                * so the reader is never destroyed; instead it appears 
-                * as blocked. Fix file_poll(), if fixable, and add
-                * a call to abord() here.
-                */
-               if (debug_level >= 3) {
-                       abuf_dbg(buf);
-                       dbg_puts(": deleting non-empty buffer, used = ");
-                       dbg_putu(buf->used);
-                       dbg_puts("\n");
+#ifdef DEBUG   
+       if (buf->used > 0) {
+               if (log_level >= 3) {
+                       log_puts("deleting non-empty buffer, used = ");
+                       log_putu(buf->used);
+                       log_puts("\n");
                }
        }
 #endif
-       free(buf);
-}
-
-/*
- * Clear buffer contents.
- */
-void
-abuf_clear(struct abuf *buf)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(buf);
-               dbg_puts(": cleared\n");
-       }
-#endif
-       buf->used = 0;
-       buf->start = 0;
+       xfree(buf->data);
+       buf->data = (void *)0xdeadbeef;
 }
 
 /*
- * Get a pointer to the readable block at the given offset.
+ * return the reader pointer and the number of bytes available
  */
 unsigned char *
-abuf_rgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs)
+abuf_rgetblk(struct abuf *buf, int *rsize)
 {
-       unsigned int count, start, used;
+       int count;
 
-       start = buf->start + ofs;
-       used = buf->used - ofs;
-       if (start >= buf->len)
-               start -= buf->len;
-#ifdef DEBUG
-       if (start >= buf->len || used > buf->used) {
-               abuf_dump(buf);
-               dbg_puts(": rgetblk: bad ofs = ");
-               dbg_putu(ofs);
-               dbg_puts("\n");
-               dbg_panic();
-       }
-#endif
-       count = buf->len - start;
-       if (count > used)
-               count = used;
+       count = buf->len - buf->start;
+       if (count > buf->used)
+               count = buf->used;
        *rsize = count;
-       return (unsigned char *)buf + sizeof(struct abuf) + start * buf->bpf;
+       return buf->data + buf->start;
 }
 
 /*
- * Discard the block at the start postion.
+ * discard "count" bytes at the start postion.
  */
 void
-abuf_rdiscard(struct abuf *buf, unsigned int count)
+abuf_rdiscard(struct abuf *buf, int count)
 {
 #ifdef DEBUG
-       if (count > buf->used) {
-               abuf_dump(buf);
-               dbg_puts(": rdiscard: bad count = ");
-               dbg_putu(count);
-               dbg_puts("\n");
-               dbg_panic();
-       }
-       if (debug_level >= 4) {
-               abuf_dbg(buf);
-               dbg_puts(": discard(");
-               dbg_putu(count);
-               dbg_puts(")\n");
+       if (count < 0 || count > buf->used) {
+               log_puts("abuf_rdiscard: bad count = ");
+               log_putu(count);
+               log_puts("\n");
+               panic();
        }
 #endif
        buf->used -= count;
@@ -222,404 +102,37 @@ abuf_rdiscard(struct abuf *buf, unsigned int count)
 }
 
 /*
- * Commit the data written at the end postion.
+ * advance the writer pointer by "count" bytes
  */
 void
-abuf_wcommit(struct abuf *buf, unsigned int count)
+abuf_wcommit(struct abuf *buf, int count)
 {
 #ifdef DEBUG
-       if (count > (buf->len - buf->used)) {
-               abuf_dump(buf);
-               dbg_puts(": rdiscard: bad count = ");
-               dbg_putu(count);
-               dbg_puts("\n");
-               dbg_panic();
-       }
-       if (debug_level >= 4) {
-               abuf_dbg(buf);
-               dbg_puts(": commit(");
-               dbg_putu(count);
-               dbg_puts(")\n");
+       if (count < 0 || count > (buf->len - buf->used)) {
+               log_puts("abuf_wcommit: bad count = ");
+               log_putu(count);
+               log_puts("\n");
+               panic();
        }
 #endif
        buf->used += count;
 }
 
 /*
- * Get a pointer to the writable block at offset ofs.
+ * get writer pointer and the number of bytes writable
  */
 unsigned char *
-abuf_wgetblk(struct abuf *buf, unsigned int *rsize, unsigned int ofs)
+abuf_wgetblk(struct abuf *buf, int *rsize)
 {
-       unsigned int end, avail, count;
+       int end, avail, count;
 
-
-       end = buf->start + buf->used + ofs;
+       end = buf->start + buf->used;
        if (end >= buf->len)
                end -= buf->len;
-#ifdef DEBUG
-       if (end >= buf->len) {
-               abuf_dump(buf);
-               dbg_puts(": wgetblk: bad ofs = ");
-               dbg_putu(ofs);
-               dbg_puts("\n");
-               dbg_panic();
-       }
-#endif
-       avail = buf->len - (buf->used + ofs);
+       avail = buf->len - buf->used;
        count = buf->len - end;
        if (count > avail)
-                       count = avail;
+               count = avail;
        *rsize = count;
-       return (unsigned char *)buf + sizeof(struct abuf) + end * buf->bpf;
-}
-
-/*
- * Flush buffer either by dropping samples or by calling the aproc
- * call-back to consume data. Return 0 if blocked, 1 otherwise.
- */
-int
-abuf_flush_do(struct abuf *buf)
-{
-       struct aproc *p;
-
-       p = buf->rproc;
-       if (!p)
-               return 0;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": in\n");
-       }
-#endif
-       return p->ops->in(p, buf);
-}
-
-/*
- * Fill the buffer either by generating silence or by calling the aproc
- * call-back to provide data. Return 0 if blocked, 1 otherwise.
- */
-int
-abuf_fill_do(struct abuf *buf)
-{
-       struct aproc *p;
-
-       p = buf->wproc;
-       if (!p)
-               return 0;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": out\n");
-       }
-#endif
-       return p->ops->out(p, buf);
-}
-
-/*
- * Notify the reader that there will be no more input (producer
- * disappeared) and destroy the buffer.
- */
-void
-abuf_eof_do(struct abuf *buf)
-{
-       struct aproc *p;
-
-       p = buf->rproc;
-       if (p) {
-               buf->rproc = NULL;
-               LIST_REMOVE(buf, ient);
-               buf->inuse++;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       aproc_dbg(p);
-                       dbg_puts(": eof\n");
-               }
-#endif
-               p->ops->eof(p, buf);
-               buf->inuse--;
-       }
-       abuf_del(buf);
-}
-
-/*
- * Notify the writer that the buffer has no more consumer,
- * and destroy the buffer.
- */
-void
-abuf_hup_do(struct abuf *buf)
-{
-       struct aproc *p;
-
-       if (ABUF_ROK(buf)) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       abuf_dbg(buf);
-                       dbg_puts(": hup: lost ");
-                       dbg_putu(buf->used);
-                       dbg_puts(" bytes\n");
-               }
-#endif
-               buf->used = 0;
-       }
-       p = buf->wproc;
-       if (p != NULL) {
-               buf->wproc = NULL;
-               LIST_REMOVE(buf, oent);
-               buf->inuse++;
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       aproc_dbg(p);
-                       dbg_puts(": hup\n");
-               }
-#endif
-               p->ops->hup(p, buf);
-               buf->inuse--;
-       }
-       abuf_del(buf);
-}
-
-/*
- * Notify the read end of the buffer that there is input available
- * and that data can be processed again.
- */
-int
-abuf_flush(struct abuf *buf)
-{
-       if (buf->inuse) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(buf);
-                       dbg_puts(": flush blocked (inuse)\n");
-               }
-#endif
-       } else {
-               buf->inuse++;
-               for (;;) {
-                       if (!abuf_flush_do(buf))
-                               break;
-               }
-               buf->inuse--;
-               if (ABUF_HUP(buf)) {
-                       abuf_hup_do(buf);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-/*
- * Notify the write end of the buffer that there is room and data can be
- * written again. This routine can only be called from the out()
- * call-back of the reader.
- *
- * Return 1 if the buffer was filled, and 0 if eof condition occured. The
- * reader must detach the buffer on EOF condition, since its aproc->eof()
- * call-back will never be called.
- */
-int
-abuf_fill(struct abuf *buf)
-{
-       if (buf->inuse) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(buf);
-                       dbg_puts(": fill blocked (inuse)\n");
-               }
-#endif
-       } else {
-               buf->inuse++;
-               for (;;) {
-                       if (!abuf_fill_do(buf))
-                               break;
-               }
-               buf->inuse--;
-               if (ABUF_EOF(buf)) {
-                       abuf_eof_do(buf);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-/*
- * Run a read/write loop on the buffer until either the reader or the
- * writer blocks, or until the buffer reaches eofs. We can not get hup here,
- * since hup() is only called from terminal nodes, from the main loop.
- *
- * NOTE: The buffer may disappear (ie. be free()ed) if eof is reached, so
- * do not keep references to the buffer or to its writer or reader.
- */
-void
-abuf_run(struct abuf *buf)
-{
-       int canfill = 1, canflush = 1;
-
-       if (buf->inuse) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(buf);
-                       dbg_puts(": run blocked (inuse)\n");
-               }
-#endif
-               return;
-       }
-       buf->inuse++;
-       for (;;) {
-               if (canfill) {
-                       if (!abuf_fill_do(buf))
-                               canfill = 0;
-                       else
-                               canflush = 1;
-               } else if (canflush) {
-                       if (!abuf_flush_do(buf))
-                               canflush = 0;
-                       else
-                               canfill = 1;
-               } else
-                       break;
-       }
-       buf->inuse--;
-       if (ABUF_EOF(buf)) {
-               abuf_eof_do(buf);
-               return;
-       }
-       if (ABUF_HUP(buf)) {
-               abuf_hup_do(buf);
-               return;
-       }
-}
-
-/*
- * Notify the reader that there will be no more input (producer
- * disappeared). The buffer is flushed and eof() is called only if all
- * data is flushed.
- */
-void
-abuf_eof(struct abuf *buf)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(buf);
-               dbg_puts(": eof requested\n");
-       }
-       if (buf->wproc == NULL) {
-               abuf_dbg(buf);
-               dbg_puts(": eof, no writer\n");
-               dbg_panic();
-       }
-#endif
-       LIST_REMOVE(buf, oent);
-       buf->wproc = NULL;
-       if (buf->rproc != NULL) {
-               if (!abuf_flush(buf))
-                       return;
-               if (ABUF_ROK(buf)) {
-                       /*
-                        * Could not flush everything, the reader will
-                        * have a chance to delete the abuf later.
-                        */
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(buf);
-                               dbg_puts(": eof, blocked (drain)\n");
-                       }
-#endif
-                       return;
-               }
-       }
-       if (buf->inuse) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       abuf_dbg(buf);
-                       dbg_puts(": eof, blocked (inuse)\n");
-               }
-#endif
-               return;
-       }
-       abuf_eof_do(buf);
-}
-
-/*
- * Notify the writer that the buffer has no more consumer,
- * and that no more data will accepted.
- */
-void
-abuf_hup(struct abuf *buf)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(buf);
-               dbg_puts(": hup requested\n");
-       }
-       if (buf->rproc == NULL) {
-               abuf_dbg(buf);
-               dbg_puts(": hup, no reader\n");
-               dbg_panic();
-       }
-#endif
-       buf->rproc = NULL;
-       LIST_REMOVE(buf, ient);
-       if (buf->wproc != NULL) {
-               if (buf->inuse) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(buf);
-                               dbg_puts(": eof, blocked (inuse)\n");
-                       }
-#endif
-                       return;
-               }
-       }
-       abuf_hup_do(buf);
-}
-
-/*
- * Notify the reader of the change of its real-time position
- */
-void
-abuf_ipos(struct abuf *buf, int delta)
-{
-       struct aproc *p = buf->rproc;
-
-       if (p && p->ops->ipos) {
-               buf->inuse++;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       aproc_dbg(p);
-                       dbg_puts(": ipos delta = ");
-                       dbg_puti(delta);
-                       dbg_puts("\n");
-               }
-#endif
-               p->ops->ipos(p, buf, delta);
-               buf->inuse--;
-       }
-       if (ABUF_HUP(buf))
-               abuf_hup_do(buf);
-}
-
-/*
- * Notify the writer of the change of its real-time position
- */
-void
-abuf_opos(struct abuf *buf, int delta)
-{
-       struct aproc *p = buf->wproc;
-
-       if (p && p->ops->opos) {
-               buf->inuse++;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       aproc_dbg(p);
-                       dbg_puts(": opos delta = ");
-                       dbg_puti(delta);
-                       dbg_puts("\n");
-               }
-#endif
-               p->ops->opos(p, buf, delta);
-               buf->inuse--;
-       }
-       if (ABUF_HUP(buf))
-               abuf_hup_do(buf);
+       return buf->data + end;
 }
index 2440393..0c38b9f 100644 (file)
@@ -1,6 +1,6 @@
-/*     $OpenBSD: abuf.h,v 1.25 2012/04/11 06:05:43 ratchov Exp $       */
+/*     $OpenBSD: abuf.h,v 1.26 2015/01/21 08:43:55 ratchov Exp $       */
 /*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
+ * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
 #ifndef ABUF_H
 #define ABUF_H
 
-#include <sys/queue.h>
-
-struct aproc;
-struct aparams;
-
 struct abuf {
-       LIST_ENTRY(abuf) ient;  /* reader's list of inputs entry */
-       LIST_ENTRY(abuf) oent;  /* writer's list of outputs entry */
-
-       /*
-        * fifo parameters
-        */
-       unsigned int bpf;               /* bytes per frame */
-       unsigned int cmin, cmax;        /* channel range of this buf */
-       unsigned int start;             /* offset where data starts */
-       unsigned int used;              /* valid data */
-       unsigned int len;               /* size of the ring */
-       struct aproc *rproc;            /* reader */
-       struct aproc *wproc;            /* writer */
-       struct abuf *duplex;            /* link to buffer of the other dir */
-       unsigned int inuse;             /* in abuf_{flush,fill,run}() */
-       unsigned int tickets;           /* max data to (if throttling) */
-
-       /*
-        * Misc reader aproc-specific per-buffer parameters.
-        */
-       union {
-               struct {
-                       int weight;             /* dynamic range */     
-                       int maxweight;          /* max dynamic range allowed */
-                       unsigned int vol;       /* volume within the vol */
-                       unsigned int done;      /* frames ready */
-                       unsigned int xrun;      /* underrun policy */
-                       int drop;               /* to drop on next read */
-               } mix;
-               struct {
-                       unsigned int st;        /* MIDI running status */
-                       unsigned int used;      /* bytes used from ``msg'' */
-                       unsigned int idx;       /* actual MIDI message size */
-                       unsigned int len;       /* MIDI message length */
-#define MIDI_MSGMAX    16                      /* max size of MIDI msg */
-                       unsigned char msg[MIDI_MSGMAX];
-               } midi;
-       } r;
-
-       /*
-        * Misc reader aproc-specific per-buffer parameters.
-        */
-       union {
-               struct {
-                       unsigned int todo;      /* frames to process */
-               } mix;
-               struct {
-                       unsigned int done;      /* frames copied */
-                       unsigned int xrun;      /* one of XRUN_XXX */
-                       int silence;            /* to add on next write */
-               } sub;
-               struct {
-                       struct abuf *owner;     /* current input stream */
-               } midi;
-       } w;
+       int start;      /* offset (frames) where stored data starts */
+       int used;       /* frames stored in the buffer */
+       int len;        /* total size of the buffer (frames) */
+       unsigned char *data;
 };
 
-/*
- * the buffer contains at least one frame. This macro should
- * be used to check if the buffer can be flushed
- */
-#define ABUF_ROK(b) ((b)->used > 0)
-
-/*
- * there's room for at least one frame
- */
-#define ABUF_WOK(b) ((b)->len - (b)->used > 0)
-
-/*
- * the buffer is empty and has no writer anymore
- */
-#define ABUF_EOF(b) (!ABUF_ROK(b) && (b)->wproc == NULL)
-
-/*
- * the buffer has no reader anymore, note that it's not
- * enough the buffer to be disconnected, because it can
- * be not yet connected buffer (eg. socket play buffer)
- */
-#define ABUF_HUP(b) (!ABUF_WOK(b) && (b)->rproc == NULL)
-
-struct abuf *abuf_new(unsigned int, struct aparams *);
-void abuf_del(struct abuf *);
-void abuf_dbg(struct abuf *);
-void abuf_clear(struct abuf *);
-unsigned char *abuf_rgetblk(struct abuf *, unsigned int *, unsigned int);
-unsigned char *abuf_wgetblk(struct abuf *, unsigned int *, unsigned int);
-void abuf_rdiscard(struct abuf *, unsigned int);
-void abuf_wcommit(struct abuf *, unsigned int);
-int abuf_fill(struct abuf *);
-int abuf_flush(struct abuf *);
-void abuf_eof(struct abuf *);
-void abuf_hup(struct abuf *);
-void abuf_run(struct abuf *);
-void abuf_ipos(struct abuf *, int);
-void abuf_opos(struct abuf *, int);
+void abuf_init(struct abuf *, unsigned int);
+void abuf_done(struct abuf *);
+void abuf_log(struct abuf *);
+unsigned char *abuf_rgetblk(struct abuf *, int *);
+unsigned char *abuf_wgetblk(struct abuf *, int *);
+void abuf_rdiscard(struct abuf *, int);
+void abuf_wcommit(struct abuf *, int);
 
 #endif /* !defined(ABUF_H) */
diff --git a/usr.bin/aucat/afile.c b/usr.bin/aucat/afile.c
new file mode 100644 (file)
index 0000000..69680e7
--- /dev/null
@@ -0,0 +1,986 @@
+/*
+ * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include <fcntl.h>
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include "afile.h"
+#include "utils.h"
+
+typedef struct {
+       unsigned char ld[4];
+} le32_t;
+
+typedef struct {
+       unsigned char lw[2];
+} le16_t;
+
+typedef struct {
+       unsigned char bd[4];
+} be32_t;
+
+typedef struct {
+       unsigned char bw[2];
+} be16_t;
+
+struct wav_riff {
+       char id[4];
+       le32_t size;
+       char type[4];
+};
+
+struct wav_chunk {
+       char id[4];
+       le32_t size;
+};
+
+struct wav_fmt {
+#define WAV_FMT_PCM    1
+#define WAV_FMT_FLOAT  3
+#define WAV_FMT_ALAW   6
+#define WAV_FMT_ULAW   7
+#define WAV_FMT_EXT    0xfffe
+       le16_t fmt;
+       le16_t nch;
+       le32_t rate;
+       le32_t byterate;
+       le16_t blkalign;
+       le16_t bits;
+#define WAV_FMT_SIZE            16
+#define WAV_FMT_EXT_SIZE       (16 + 24)
+       le16_t extsize;
+       le16_t valbits;
+       le32_t chanmask;
+       le16_t extfmt;
+       char guid[14];
+};
+
+struct wav_hdr {
+       struct wav_riff riff;           /* 00..11 */
+       struct wav_chunk fmt_hdr;       /* 12..20 */
+       struct wav_fmt fmt;
+       struct wav_chunk data_hdr;
+};
+
+struct aiff_form {
+       char id[4];
+       be32_t size;
+       char type[4];
+};
+
+struct aiff_chunk {
+       char id[4];
+       be32_t size;
+};
+
+struct aiff_comm {
+       struct aiff_commbase {
+               be16_t nch;
+               be32_t nfr;
+               be16_t bits;
+               /* rate in 80-bit floating point */
+               be16_t rate_ex;
+               be32_t rate_hi;
+               be32_t rate_lo;
+       } base;
+       char comp_id[4];
+       /* followed by stuff we don't care about */
+};
+
+struct aiff_data {
+       be32_t offs;
+       be32_t blksz;
+};
+
+struct aiff_hdr {
+       struct aiff_form form;
+       struct aiff_chunk comm_hdr;
+       struct aiff_commbase comm;
+       struct aiff_chunk data_hdr;
+       struct aiff_data data;
+};
+
+struct au_hdr {
+       char id[4];
+       be32_t offs;
+       be32_t size;
+#define AU_FMT_PCM8    2
+#define AU_FMT_PCM16   3
+#define AU_FMT_PCM24   4
+#define AU_FMT_PCM32   5
+#define AU_FMT_FLOAT   6
+#define AU_FMT_ALAW    0x1b
+#define AU_FMT_ULAW    1
+       be32_t fmt;
+       be32_t rate;
+       be32_t nch;
+       char desc[8];
+       /* followed by optional desc[] continuation */
+};
+
+char wav_id_riff[4] = {'R', 'I', 'F', 'F'};
+char wav_id_wave[4] = {'W', 'A', 'V', 'E'};
+char wav_id_data[4] = {'d', 'a', 't', 'a'};
+char wav_id_fmt[4] = {'f', 'm', 't', ' '};
+char wav_guid[14] = {
+       0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x80, 0x00,
+       0x00, 0xAA, 0x00, 0x38,
+       0x9B, 0x71
+};
+
+char aiff_id_form[4] = {'F', 'O', 'R', 'M'};
+char aiff_id_aiff[4] = {'A', 'I', 'F', 'F'};
+char aiff_id_aifc[4] = {'A', 'I', 'F', 'C'};
+char aiff_id_data[4] = {'S', 'S', 'N', 'D'};
+char aiff_id_comm[4] = {'C', 'O', 'M', 'M'};
+char aiff_id_none[4] = {'N', 'O', 'N', 'E'};
+char aiff_id_fl32[4] = {'f', 'l', '3', '2'};
+char aiff_id_ulaw[4] = {'u', 'l', 'a', 'w'};
+char aiff_id_alaw[4] = {'a', 'l', 'a', 'w'};
+
+char au_id[4] = {'.', 's', 'n', 'd'};
+
+static inline unsigned int
+le16_get(le16_t *p)
+{
+       return p->lw[0] | p->lw[1] << 8;
+}
+
+static inline void
+le16_set(le16_t *p, unsigned int v)
+{
+       p->lw[0] = v;
+       p->lw[1] = v >> 8;
+}
+
+static inline unsigned int
+le32_get(le32_t *p)
+{
+       return p->ld[0] |
+              p->ld[1] << 8 |
+              p->ld[2] << 16 |
+              p->ld[3] << 24;
+}
+
+static inline void
+le32_set(le32_t *p, unsigned int v)
+{
+       p->ld[0] = v;
+       p->ld[1] = v >> 8;
+       p->ld[2] = v >> 16;
+       p->ld[3] = v >> 24;
+}
+
+static inline unsigned int
+be16_get(be16_t *p)
+{
+       return p->bw[1] | p->bw[0] << 8;
+}
+
+static inline void
+be16_set(be16_t *p, unsigned int v)
+{
+       p->bw[1] = v;
+       p->bw[0] = v >> 8;
+}
+
+static inline unsigned int
+be32_get(be32_t *p)
+{
+       return p->bd[3] |
+              p->bd[2] << 8 |
+              p->bd[1] << 16 |
+              p->bd[0] << 24;
+}
+
+static inline void
+be32_set(be32_t *p, unsigned int v)
+{
+       p->bd[3] = v;
+       p->bd[2] = v >> 8;
+       p->bd[1] = v >> 16;
+       p->bd[0] = v >> 24;
+}
+
+static int
+afile_readhdr(struct afile *f, void *addr, size_t size)
+{
+       if (lseek(f->fd, 0, SEEK_SET) < 0) {
+               log_puts(f->path);
+               log_puts(": failed to seek to beginning of file\n");
+               return 0;
+       }
+       if (read(f->fd, addr, size) != size) {
+               log_puts(f->path);
+               log_puts(": failed to read header\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int
+afile_writehdr(struct afile *f, void *addr, size_t size)
+{
+       if (lseek(f->fd, 0, SEEK_SET) < 0) {
+               log_puts(f->path);
+               log_puts(": failed to seek back to header\n");
+               return 0;
+       }
+       if (write(f->fd, addr, size) != size) {
+               log_puts(f->path);
+               log_puts(": failed to write header\n");
+               return 0;
+       }
+       f->curpos = f->startpos;
+       return 1;
+}
+
+static int
+afile_checkpar(struct afile *f)
+{
+       if (f->nch == 0 || f->nch > NCHAN_MAX) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(f->nch);
+               log_puts(": unsupported number of channels\n");
+               return 0;
+       }
+       if (f->rate < RATE_MIN || f->rate > RATE_MAX) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(f->rate);
+               log_puts(": unsupported rate\n");
+               return 0;
+       }
+       if (f->par.bits < BITS_MIN || f->par.bits > BITS_MAX) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(f->par.bits);
+               log_puts(": unsupported bits per sample\n");
+               return 0;
+       }
+       if (f->par.bits > f->par.bps * 8) {
+               log_puts(f->path);
+               log_puts(": bits larger than bytes-per-sample\n");
+               return 0;
+       }
+       if (f->fmt == AFILE_FMT_FLOAT && f->par.bits != 32) {
+               log_puts(f->path);
+               log_puts(": only 32-bit floating points are supported\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int
+afile_wav_readfmt(struct afile *f, unsigned int csize)
+{
+       struct wav_fmt fmt;
+       unsigned int wenc;
+
+       if (csize < WAV_FMT_SIZE) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(csize);
+               log_puts(": bogus format chunk size\n");
+               return 0;
+       }
+       if (csize > WAV_FMT_EXT_SIZE)
+               csize = WAV_FMT_EXT_SIZE;
+       if (read(f->fd, &fmt, csize) != csize) {
+               log_puts(f->path);
+               log_puts(": failed to read format chunk\n");
+               return 0;
+       }
+       wenc = le16_get(&fmt.fmt);
+       f->par.bits = le16_get(&fmt.bits);
+       if (wenc == WAV_FMT_EXT) {
+               if (csize != WAV_FMT_EXT_SIZE) {
+                       log_puts(f->path);
+                       log_puts(": missing extended format chunk\n");
+                       return 0;
+               }
+               if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) {
+                       log_puts(f->path);
+                       log_puts(": unknown format (GUID)\n");
+                       return 0;
+               }
+               f->par.bps = (f->par.bits + 7) / 8;
+               f->par.bits = le16_get(&fmt.valbits);
+               wenc = le16_get(&fmt.extfmt);
+       } else
+               f->par.bps = (f->par.bits + 7) / 8;
+       f->nch = le16_get(&fmt.nch);
+       f->rate = le32_get(&fmt.rate);
+       f->par.le = 1;
+       f->par.msb = 1;
+       switch (wenc) {
+       case WAV_FMT_PCM:
+               f->fmt = AFILE_FMT_PCM;
+               f->par.sig = (f->par.bits <= 8) ? 0 : 1;
+               break;
+       case WAV_FMT_ALAW:
+               f->fmt = AFILE_FMT_ALAW;
+               f->par.bits = 8;
+               f->par.bps = 1;
+               break;
+       case WAV_FMT_ULAW:
+               f->fmt = AFILE_FMT_ULAW;
+               f->par.bits = 8;
+               f->par.bps = 1;
+               break;
+       case WAV_FMT_FLOAT:
+               f->fmt = AFILE_FMT_FLOAT;
+               break;
+       default:
+               log_putu(wenc);
+               log_puts(": unsupported encoding\n");
+               return 0;
+       }
+       return afile_checkpar(f);
+}
+
+static int
+afile_wav_readhdr(struct afile *f)
+{
+       struct wav_riff riff;
+       struct wav_chunk chunk;
+       unsigned int csize, rsize, pos = 0;
+       int fmt_done = 0;
+
+       if (!afile_readhdr(f, &riff, sizeof(struct wav_riff)))
+               return 0;
+       if (memcmp(&riff.id, &wav_id_riff, 4) != 0 ||
+           memcmp(&riff.type, &wav_id_wave, 4)) {
+               log_puts(f->path);
+               log_puts(": not a .wav file\n");
+               return 0;
+       }
+       rsize = le32_get(&riff.size);
+       for (;;) {
+               if (pos + sizeof(struct wav_chunk) > rsize) {
+                       log_puts(f->path);
+                       log_puts(": missing data chunk\n");
+                       return 0;
+               }
+               if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
+                       log_puts(f->path);
+                       log_puts(": failed to read chunk header\n");
+                       return 0;
+               }
+               csize = le32_get(&chunk.size);
+               if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
+                       if (!afile_wav_readfmt(f, csize))
+                               return 0;
+                       fmt_done = 1;
+               } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
+                       f->startpos = pos + sizeof(riff) + sizeof(chunk);
+                       f->endpos = f->startpos + csize;
+                       break;
+               } else {
+#ifdef DEBUG
+                       if (log_level >= 2) {
+                               log_puts(f->path);
+                               log_puts(": skipped unknown chunk\n");
+                       }
+#endif
+               }
+
+               /*
+                * next chunk
+                */
+               pos += sizeof(struct wav_chunk) + csize;
+               if (lseek(f->fd, sizeof(riff) + pos, SEEK_SET) < 0) {
+                       log_puts(f->path);
+                       log_puts(": filed to seek to chunk\n");
+                       return 0;
+               }
+       }
+       if (!fmt_done) {
+               log_puts(f->path);
+               log_puts(": missing format chunk\n");
+               return 0;
+       }
+       return 1;
+}
+
+/*
+ * Write header and seek to start position
+ */
+static int
+afile_wav_writehdr(struct afile *f)
+{
+       struct wav_hdr hdr;
+
+       memset(&hdr, 0, sizeof(struct wav_hdr));
+       memcpy(hdr.riff.id, wav_id_riff, 4);
+       memcpy(hdr.riff.type, wav_id_wave, 4);
+       le32_set(&hdr.riff.size, f->endpos - sizeof(hdr.riff));
+       memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
+       le32_set(&hdr.fmt_hdr.size, sizeof(hdr.fmt));
+       le16_set(&hdr.fmt.fmt, 1);
+       le16_set(&hdr.fmt.nch, f->nch);
+       le32_set(&hdr.fmt.rate, f->rate);
+       le32_set(&hdr.fmt.byterate, f->rate * f->par.bps * f->nch);
+       le16_set(&hdr.fmt.blkalign, f->par.bps * f->nch);
+       le16_set(&hdr.fmt.bits, f->par.bits);
+       memcpy(hdr.data_hdr.id, wav_id_data, 4);
+       le32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
+       return afile_writehdr(f, &hdr, sizeof(struct wav_hdr));
+}
+
+static int
+afile_aiff_readcomm(struct afile *f, unsigned int csize,
+    int comp, unsigned int *nfr)
+{
+       struct aiff_comm comm;
+       unsigned int csize_min;
+       unsigned int e, m;
+
+       csize_min = comp ?
+           sizeof(struct aiff_comm) : sizeof(struct aiff_commbase);
+       if (csize < csize_min) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(csize);
+               log_puts(": bogus comm chunk size\n");
+               return 0;
+       }
+       if (read(f->fd, &comm, csize_min) != csize_min) {
+               log_puts(f->path);
+               log_puts(": failed to read comm chunk\n");
+               return 0;
+       }
+       f->nch = be16_get(&comm.base.nch);
+       e = be16_get(&comm.base.rate_ex);
+       m = be32_get(&comm.base.rate_hi);
+       if (e < 0x3fff || e > 0x3fff + 31) {
+               log_puts(f->path);
+               log_puts(": malformed sample rate\n");
+               return 0;
+       }
+       f->rate = m >> (0x3fff + 31 - e);
+       if (comp) {
+               if (memcmp(comm.comp_id, aiff_id_none, 4) == 0) {
+                       f->fmt = AFILE_FMT_PCM;
+                       f->par.bits = be16_get(&comm.base.bits);
+               } else if (memcmp(comm.comp_id, aiff_id_fl32, 4) == 0) {
+                       f->fmt = AFILE_FMT_FLOAT;
+                       f->par.bits = 32;
+               } else if (memcmp(comm.comp_id, aiff_id_ulaw, 4) == 0) {
+                       f->fmt = AFILE_FMT_ULAW;
+                       f->par.bits = 8;
+               } else if (memcmp(comm.comp_id, aiff_id_alaw, 4) == 0) {
+                       f->fmt = AFILE_FMT_ALAW;
+                       f->par.bits = 8;
+               } else {
+                       log_puts(f->path);
+                       log_puts(": unsupported encoding\n");
+                       return 0;
+               }
+       } else {
+               f->fmt = AFILE_FMT_PCM;
+               f->par.bits = be16_get(&comm.base.bits);
+       }
+       f->par.le = 0;
+       f->par.sig = 1;
+       f->par.msb = 1;
+       f->par.bps = (f->par.bits + 7) / 8;
+       *nfr = be32_get(&comm.base.nfr);
+       return afile_checkpar(f);
+}
+
+static int
+afile_aiff_readdata(struct afile *f, unsigned int csize, unsigned int *roffs)
+{
+       struct aiff_data data;
+
+       if (csize < sizeof(struct aiff_data)) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(csize);
+               log_puts(": bogus data chunk size\n");
+               return 0;
+       }
+       csize = sizeof(struct aiff_data);
+       if (read(f->fd, &data, csize) != csize) {
+               log_puts(f->path);
+               log_puts(": failed to read data chunk\n");
+               return 0;
+       }
+       *roffs = csize + be32_get(&data.offs);
+       return 1;
+}
+
+static int
+afile_aiff_readhdr(struct afile *f)
+{
+       struct aiff_form form;
+       struct aiff_chunk chunk;
+       unsigned int csize, rsize, nfr = 0, pos = 0, offs;
+       int comm_done = 0, comp;
+
+       if (!afile_readhdr(f, &form, sizeof(struct wav_riff)))
+               return 0;
+       if (memcmp(&form.id, &aiff_id_form, 4) != 0) {
+               log_puts(f->path);
+               log_puts(": not an aiff file\n");
+               return 0;
+       }
+       if (memcmp(&form.type, &aiff_id_aiff, 4) == 0) {
+               comp = 0;
+       } else if (memcmp(&form.type, &aiff_id_aifc, 4) == 0)
+               comp = 1;
+       else {
+               log_puts(f->path);
+               log_puts(": unsupported aiff file sub-type\n");
+               return 0;
+       }
+       rsize = be32_get(&form.size);
+       for (;;) {
+               if (pos + sizeof(struct aiff_chunk) > rsize) {
+                       log_puts(f->path);
+                       log_puts(": missing data chunk\n");
+                       return 0;
+               }
+               if (read(f->fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
+                       log_puts(f->path);
+                       log_puts(": failed to read chunk header\n");
+                       return 0;
+               }               
+               csize = be32_get(&chunk.size);
+               if (memcmp(chunk.id, aiff_id_comm, 4) == 0) {
+                       if (!afile_aiff_readcomm(f, csize, comp, &nfr))
+                               return 0;
+                       comm_done = 1;
+               } else if (memcmp(chunk.id, aiff_id_data, 4) == 0) {
+                       if (!afile_aiff_readdata(f, csize, &offs))
+                               return 0;
+                       f->startpos = sizeof(form) + pos + sizeof(chunk) + offs;
+                       break;
+               } else {
+#ifdef DEBUG
+                       if (log_level >= 2) {
+                               log_puts(f->path);
+                               log_puts(": skipped unknown chunk\n");
+                       }
+#endif
+               }
+
+               /*
+                * The aiff spec says "Each Chunk must contain an even
+                * number of bytes. For those Chunks whose total
+                * contents would yield an odd number of bytes, a zero
+                * pad byte must be added at the end of the Chunk. This
+                * pad byte is not included in ckDataSize, which
+                * indicates the size of the data in the Chunk."
+                */
+               csize = (csize + 1) & ~1;
+               pos += sizeof(struct aiff_chunk) + csize;
+
+               if (lseek(f->fd, sizeof(form) + pos, SEEK_SET) < 0) {
+                       log_puts(f->path);
+                       log_puts(": filed to seek to chunk\n");
+                       return 0;
+               }
+       }
+       if (!comm_done) {
+               log_puts(f->path);
+               log_puts(": missing comm chunk\n");
+               return 0;
+       }
+       f->endpos = f->startpos + f->par.bps * f->nch * nfr;
+       return 1;
+}
+
+/*
+ * Write header and seek to start position
+ */
+static int
+afile_aiff_writehdr(struct afile *f)
+{
+       struct aiff_hdr hdr;
+       unsigned int bpf;
+       unsigned int e, m;
+
+       /* convert rate to 80-bit float (exponent and fraction part) */
+       m = f->rate;
+       e = 0x3fff + 31;
+       while ((m & 0x80000000) == 0) {
+               e--;
+               m <<= 1;
+       }
+
+       /* bytes per frame */
+       bpf = f->nch * f->par.bps;
+
+       memset(&hdr, 0, sizeof(struct aiff_hdr));
+       memcpy(hdr.form.id, aiff_id_form, 4);
+       memcpy(hdr.form.type, aiff_id_aiff, 4);
+       be32_set(&hdr.form.size, f->endpos - sizeof(hdr.form));
+
+       memcpy(hdr.comm_hdr.id, aiff_id_comm, 4);
+       be32_set(&hdr.comm_hdr.size, sizeof(hdr.comm));
+       be16_set(&hdr.comm.nch, f->nch);
+       be16_set(&hdr.comm.bits, f->par.bits);
+       be16_set(&hdr.comm.rate_ex, e);
+       be32_set(&hdr.comm.rate_hi, m);
+       be32_set(&hdr.comm.rate_lo, 0);
+       be32_set(&hdr.comm.nfr, (f->endpos - f->startpos) / bpf);
+
+       memcpy(hdr.data_hdr.id, aiff_id_data, 4);
+       be32_set(&hdr.data_hdr.size, f->endpos - f->startpos);
+       be32_set(&hdr.data.offs, 0);
+       be32_set(&hdr.data.blksz, 0);
+       return afile_writehdr(f, &hdr, sizeof(struct aiff_hdr));
+}
+
+static int
+afile_au_readhdr(struct afile *f)
+{
+       struct au_hdr hdr;
+       unsigned int fmt;
+
+       if (!afile_readhdr(f, &hdr, sizeof(struct wav_riff)))
+               return 0;
+       if (memcmp(&hdr.id, &au_id, 4) != 0) {
+               log_puts(f->path);
+               log_puts(": not a .au file\n");
+               return 0;
+       }
+       f->startpos = be32_get(&hdr.offs);
+       f->endpos = f->startpos + be32_get(&hdr.size);
+       fmt = be32_get(&hdr.fmt);
+       switch (fmt) {
+       case AU_FMT_PCM8:
+               f->fmt = AFILE_FMT_PCM;
+               f->par.bits = 8;
+               break;
+       case AU_FMT_PCM16:
+               f->fmt = AFILE_FMT_PCM;
+               f->par.bits = 16;
+               break;
+       case AU_FMT_PCM24:
+               f->fmt = AFILE_FMT_PCM;
+               f->par.bits = 24;
+               break;
+       case AU_FMT_PCM32:
+               f->fmt = AFILE_FMT_PCM;
+               f->par.bits = 32;
+               break;
+       case AU_FMT_ULAW:
+               f->fmt = AFILE_FMT_ULAW;
+               f->par.bits = 8;
+               f->par.bps = 1;
+               break;
+       case AU_FMT_ALAW:
+               f->fmt = AFILE_FMT_ALAW;
+               f->par.bits = 8;
+               f->par.bps = 1;
+               break;
+       case AU_FMT_FLOAT:
+               f->fmt = AFILE_FMT_FLOAT;
+               f->par.bits = 32;
+               f->par.bps = 4;
+               break;
+       default:
+               log_puts(f->path);
+               log_puts(": ");
+               log_putu(fmt);
+               log_puts(": unsupported encoding\n");
+               return 0;
+       }
+       f->par.le = 0;
+       f->par.sig = 1;
+       f->par.bps = f->par.bits / 8;
+       f->par.msb = 0;
+       f->rate = be32_get(&hdr.rate);
+       f->nch = be32_get(&hdr.nch);
+       if (lseek(f->fd, f->startpos, SEEK_SET) < 0) {
+               log_puts(f->path);
+               log_puts(": ");
+               log_puts("failed to seek to data chunk\n");
+               return 0;
+       }
+       return afile_checkpar(f);
+}
+
+/*
+ * Write header and seek to start position
+ */
+static int
+afile_au_writehdr(struct afile *f)
+{
+       struct au_hdr hdr;
+       unsigned int fmt;
+
+       memset(&hdr, 0, sizeof(struct au_hdr));
+       memcpy(hdr.id, au_id, 4);
+       be32_set(&hdr.offs, f->startpos);
+       be32_set(&hdr.size, f->endpos - f->startpos);
+       switch (f->par.bits) {
+       case 8:
+               fmt = AU_FMT_PCM8;
+               break;
+       case 16:
+               fmt = AU_FMT_PCM16;
+               break;
+       case 24:
+               fmt = AU_FMT_PCM24;
+               break;
+       case 32:
+               fmt = AU_FMT_PCM32;
+               break;
+#ifdef DEBUG
+       default:
+               log_puts(f->path);
+               log_puts(": wrong precision\n");
+               panic();
+               return 0;
+#endif
+       }
+       be32_set(&hdr.fmt, fmt);
+       be32_set(&hdr.rate, f->rate);
+       be32_set(&hdr.nch, f->nch);
+       return afile_writehdr(f, &hdr, sizeof(struct au_hdr));
+}
+
+size_t
+afile_read(struct afile *f, void *data, size_t count)
+{
+       off_t maxread;
+       ssize_t n;
+
+       if (f->endpos >= 0) {
+               maxread = f->endpos - f->curpos;
+               if (maxread == 0) {
+#ifdef DEBUG
+                       if (log_level >= 3) {
+                               log_puts(f->path);
+                               log_puts(": end reached\n");
+                       }
+#endif
+                       return 0;
+               }
+               if (count > maxread)
+                       count = maxread;
+       }
+       n = read(f->fd, data, count);
+       if (n < 0) {
+               log_puts(f->path);
+               log_puts(": couldn't read\n");
+               return 0;
+       }
+       f->curpos += n;
+       return n;
+}
+
+size_t
+afile_write(struct afile *f, void *data, size_t count)
+{
+       off_t maxwrite;
+       int n;
+
+       if (f->maxpos >= 0) {
+               maxwrite = f->maxpos - f->curpos;
+               if (maxwrite == 0) {
+#ifdef DEBUG
+                       if (log_level >= 3) {
+                               log_puts(f->path);
+                               log_puts(": max file size reached\n");
+                       }
+#endif
+                       return 0;
+               }
+               if (count > maxwrite)
+                       count = maxwrite;
+       }
+       n = write(f->fd, data, count);
+       if (n < 0) {
+               log_puts(f->path);
+               log_puts(": couldn't write\n");
+               return 0;
+       }
+       f->curpos += n;
+       if (f->endpos < f->curpos)
+               f->endpos = f->curpos;
+       return n;
+}
+
+int
+afile_seek(struct afile *f, off_t pos)
+{
+       pos += f->startpos;
+       if (f->endpos >= 0 && pos > f->endpos) {
+               log_puts(f->path);
+               log_puts(": attempt to seek outside file boundaries\n");
+               return 0;
+       }
+
+       /*
+        * seek only if needed to avoid errors with pipes & sockets
+        */
+       if (pos != f->curpos) {
+               if (lseek(f->fd, pos, SEEK_SET) < 0) {
+                       log_puts(f->path);
+                       log_puts(": couldn't seek\n");
+                       return 0;
+               }
+               f->curpos = pos;
+       }
+       return 1;
+}
+
+void
+afile_close(struct afile *f)
+{
+       if (f->flags & AFILE_FWRITE) {
+               if (f->hdr == AFILE_HDR_WAV)
+                       afile_wav_writehdr(f);
+               else if (f->hdr == AFILE_HDR_AIFF)
+                       afile_aiff_writehdr(f);
+               else if (f->hdr == AFILE_HDR_AU)
+                       afile_au_writehdr(f);
+       }
+       close(f->fd);
+}
+
+int
+afile_open(struct afile *f, char *path, int hdr, int flags,
+    struct aparams *par, int rate, int nch)
+{
+       char *ext;
+       static union {
+               struct wav_hdr wav;
+               struct aiff_hdr aiff;
+               struct au_hdr au;
+       } dummy;
+
+       f->par = *par;
+       f->rate = rate;
+       f->nch = nch;
+       f->flags = flags;
+       f->hdr = hdr;
+       if (hdr == AFILE_HDR_AUTO) {
+               f->hdr = AFILE_HDR_RAW;
+               ext = strrchr(path, '.');
+               if (ext != NULL) {
+                       ext++;
+                       if (strcasecmp(ext, "aif") == 0 ||
+                           strcasecmp(ext, "aiff") == 0 ||
+                           strcasecmp(ext, "aifc") == 0)
+                               f->hdr = AFILE_HDR_AIFF;
+                       else if (strcasecmp(ext, "au") == 0 ||
+                           strcasecmp(ext, "snd") == 0)
+                               f->hdr = AFILE_HDR_AU;
+                       else if (strcasecmp(ext, "wav") == 0)
+                               f->hdr = AFILE_HDR_WAV;
+               }
+       }
+       if (f->flags == AFILE_FREAD) {
+               if (strcmp(path, "-") == 0) {
+                       f->path = "stdin";
+                       f->fd = STDIN_FILENO;
+               } else {
+                       f->path = path;
+                       f->fd = open(f->path, O_RDONLY, 0);
+                       if (f->fd < 0) {
+                               log_puts(f->path);
+                               log_puts(": failed to open for reading\n");
+                               return 0;
+                       }
+               }
+               if (f->hdr == AFILE_HDR_WAV) {
+                       if (!afile_wav_readhdr(f))
+                               goto bad_close;
+               } else if (f->hdr == AFILE_HDR_AIFF) {
+                       if (!afile_aiff_readhdr(f))
+                               goto bad_close;
+               } else if (f->hdr == AFILE_HDR_AU) {
+                       if (!afile_au_readhdr(f))
+                               goto bad_close;
+               } else {
+                       f->startpos = 0;
+                       f->endpos = -1; /* read until EOF */
+                       f->fmt = AFILE_FMT_PCM;
+               }
+               f->curpos = f->startpos;
+       } else if (flags == AFILE_FWRITE) {
+               if (strcmp(path, "-") == 0) {
+                       f->path = "stdout";
+                       f->fd = STDOUT_FILENO;
+               } else {
+                       f->path = path;
+                       f->fd = open(f->path, O_WRONLY | O_TRUNC | O_CREAT, 0666);
+                       if (f->fd < 0) {
+                               log_puts(f->path);
+                               log_puts(": failed to create file\n");
+                               return 0;
+                       }
+               }
+               if (f->hdr == AFILE_HDR_WAV) {
+                       f->par.bps = (f->par.bits + 7) >> 3;
+                       if (f->par.bits > 8) {
+                               f->par.le = 1;
+                               f->par.sig = 1;
+                       } else
+                               f->par.sig = 0;
+                       if (f->par.bits & 7)
+                               f->par.msb = 1;
+                       f->endpos = f->startpos = sizeof(struct wav_hdr);
+                       f->maxpos = 0x7fffffff;
+                       if (!afile_writehdr(f, &dummy, sizeof(struct wav_hdr)))
+                               goto bad_close;
+               } else if (f->hdr == AFILE_HDR_AIFF) {
+                       f->par.bps = (f->par.bits + 7) >> 3;
+                       if (f->par.bps > 1)
+                               f->par.le = 0;
+                       f->par.sig = 1;
+                       if (f->par.bits & 7)
+                               f->par.msb = 1;
+                       f->endpos = f->startpos = sizeof(struct aiff_hdr);
+                       f->maxpos = 0x7fffffff;
+                       if (!afile_writehdr(f, &dummy, sizeof(struct aiff_hdr)))
+                               goto bad_close;
+               } else if (f->hdr == AFILE_HDR_AU) {
+                       f->par.bits = (f->par.bits + 7) & ~7;
+                       f->par.bps = f->par.bits / 8;
+                       f->par.le = 0;
+                       f->par.sig = 1;
+                       f->par.msb = 1;
+                       f->endpos = f->startpos = sizeof(struct au_hdr);
+                       f->maxpos = 0x7fffffff;
+                       if (!afile_writehdr(f, &dummy, sizeof(struct au_hdr)))
+                               goto bad_close;
+               } else {
+                       f->endpos = f->startpos = 0;
+                       f->maxpos = -1;
+               }
+               f->curpos = f->startpos;
+       } else {
+#ifdef DEBUG
+               log_puts("afile_open: wrong flags\n");
+               panic();
+#endif
+       }
+       return 1;
+bad_close:
+       close(f->fd);
+       return 0;
+}
diff --git a/usr.bin/aucat/afile.h b/usr.bin/aucat/afile.h
new file mode 100644 (file)
index 0000000..4966ed3
--- /dev/null
@@ -0,0 +1,55 @@
+/*     $OpenBSD: afile.h,v 1.1 2015/01/21 08:43:55 ratchov Exp $       */
+/*
+ * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef WAV_H
+#define WAV_H
+
+#include <sys/types.h>
+#include "dsp.h"
+
+struct afile {
+       struct aparams par;             /* file params */
+#define AFILE_FMT_PCM  0               /* integers (fixed point) */
+#define AFILE_FMT_ULAW 1               /* 8-bit mu-law */
+#define AFILE_FMT_ALAW 2               /* 8-bit a-law */
+#define AFILE_FMT_FLOAT        3               /* IEEE 754 32-bit floats */
+       int fmt;                        /* one of above */
+       int rate;                       /* file sample rate */
+       int nch;                        /* file channel count */
+#define AFILE_HDR_AUTO 0               /* guess from file name */
+#define AFILE_HDR_RAW  1               /* headerless aka "raw" file */
+#define AFILE_HDR_WAV  2               /* microsoft .wav */
+#define AFILE_HDR_AIFF 3               /* apple .aiff */
+#define AFILE_HDR_AU   4               /* sun/next .au */
+       int hdr;                        /* header type */
+       int fd;                         /* file descriptor */
+#define AFILE_FREAD    1               /* open for reading */
+#define AFILE_FWRITE   2               /* open for writing */
+       int flags;                      /* bitmap of above */
+       off_t curpos;                   /* read/write position (bytes) */
+       off_t startpos;                 /* where payload starts */
+       off_t endpos;                   /* where payload ends */
+       off_t maxpos;                   /* max allowed pos (.wav limitation) */
+       char *path;                     /* file name (debug only) */
+};
+
+int afile_open(struct afile *, char *, int, int, struct aparams *, int, int);
+size_t afile_read(struct afile *, void *, size_t);
+size_t afile_write(struct afile *, void *, size_t);
+int afile_seek(struct afile *, off_t);
+void afile_close(struct afile *);
+
+#endif /* !defined(WAV_H) */
diff --git a/usr.bin/aucat/aparams.c b/usr.bin/aucat/aparams.c
deleted file mode 100644 (file)
index 7fe727e..0000000
+++ /dev/null
@@ -1,272 +0,0 @@
-/*     $OpenBSD: aparams.c,v 1.15 2015/01/16 06:40:05 deraadt Exp $    */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <endian.h>
-
-#include "aparams.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-int aparams_ctltovol[128] = {
-           0,
-         256,    266,    276,    287,    299,    310,    323,    335,
-         348,    362,    376,    391,    406,    422,    439,    456,
-         474,    493,    512,    532,    553,    575,    597,    621,
-         645,    670,    697,    724,    753,    782,    813,    845,
-         878,    912,    948,    985,   1024,   1064,   1106,   1149,
-        1195,   1241,   1290,   1341,   1393,   1448,   1505,   1564,
-        1625,   1689,   1756,   1825,   1896,   1971,   2048,   2128,
-        2212,   2299,   2389,   2483,   2580,   2682,   2787,   2896,
-        3010,   3128,   3251,   3379,   3511,   3649,   3792,   3941,
-        4096,   4257,   4424,   4598,   4778,   4966,   5161,   5363,
-        5574,   5793,   6020,   6256,   6502,   6757,   7023,   7298,
-        7585,   7883,   8192,   8514,   8848,   9195,   9556,   9931,
-       10321,  10726,  11148,  11585,  12040,  12513,  13004,  13515,
-       14045,  14596,  15170,  15765,  16384,  17027,  17696,  18390,
-       19112,  19863,  20643,  21453,  22295,  23170,  24080,  25025,
-       26008,  27029,  28090,  29193,  30339,  31530,  32768
-};
-
-/*
- * Fake parameters for byte-streams
- */
-struct aparams aparams_none = { 1, 0, 0, 0, 0, 0, 0, 0 };
-
-#ifdef DEBUG
-/*
- * Generate a string corresponding to the encoding in par,
- * return the length of the resulting string.
- */
-int
-aparams_enctostr(struct aparams *par, char *ostr)
-{
-       char *p = ostr;
-
-       *p++ = par->sig ? 's' : 'u';
-       if (par->bits > 9)
-               *p++ = '0' + par->bits / 10;
-       *p++ = '0' + par->bits % 10;
-       if (par->bps > 1) {
-               *p++ = par->le ? 'l' : 'b';
-               *p++ = 'e';
-               if (par->bps != APARAMS_BPS(par->bits) ||
-                   par->bits < par->bps * 8) {
-                       *p++ = par->bps + '0';
-                       if (par->bits < par->bps * 8) {
-                               *p++ = par->msb ? 'm' : 'l';
-                               *p++ = 's';
-                               *p++ = 'b';
-                       }
-               }
-       }
-       *p++ = '\0';
-       return p - ostr - 1;
-}
-#endif /* DEBUG */
-
-/*
- * Parse an encoding string, examples: s8, u8, s16, s16le, s24be ...
- * set *istr to the char following the encoding. Return the number
- * of bytes consumed.
- */
-int
-aparams_strtoenc(struct aparams *par, char *istr)
-{
-       char *p = istr;
-       int i, sig, bits, le, bps, msb;
-
-#define IS_SEP(c)                      \
-       (((c) < 'a' || (c) > 'z') &&    \
-        ((c) < 'A' || (c) > 'Z') &&    \
-        ((c) < '0' || (c) > '9'))
-
-       /*
-        * get signedness
-        */
-       if (*p == 's') {
-               sig = 1;
-       } else if (*p == 'u') {
-               sig = 0;
-       } else
-               return 0;
-       p++;
-
-       /*
-        * get number of bits per sample
-        */
-       bits = 0;
-       for (i = 0; i < 2; i++) {
-               if (*p < '0' || *p > '9')
-                       break;
-               bits = (bits * 10) + *p - '0';
-               p++;
-       }
-       if (bits < BITS_MIN || bits > BITS_MAX)
-               return 0;
-       bps = APARAMS_BPS(bits);
-       msb = 1;
-       le = ADATA_LE;
-
-       /*
-        * get (optional) endianness
-        */
-       if (p[0] == 'l' && p[1] == 'e') {
-               le = 1;
-               p += 2;
-       } else if (p[0] == 'b' && p[1] == 'e') {
-               le = 0;
-               p += 2;
-       } else if (IS_SEP(*p)) {
-               goto done;
-       } else
-               return 0;
-
-       /*
-        * get (optional) number of bytes
-        */
-       if (*p >= '0' && *p <= '9') {
-               bps = *p - '0';
-               if (bps < (bits + 7) / 8 ||
-                   bps > (BITS_MAX + 7) / 8)
-                       return 0;
-               p++;
-
-               /*
-                * get (optional) alignement
-                */
-               if (p[0] == 'm' && p[1] == 's' && p[2] == 'b') {
-                       msb = 1;
-                       p += 3;
-               } else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b') {
-                       msb = 0;
-                       p += 3;
-               } else if (IS_SEP(*p)) {
-                       goto done;
-               } else
-                       return 0;
-       } else if (!IS_SEP(*p))
-               return 0;
-
-done:
-               par->msb = msb;
-       par->sig = sig;
-       par->bits = bits;
-       par->bps = bps;
-       par->le = le;
-       return p - istr;
-}
-
-/*
- * Initialise parameters structure with the defaults natively supported
- * by the machine.
- */
-void
-aparams_init(struct aparams *par, unsigned int cmin, unsigned int cmax,
-    unsigned int rate)
-{
-       par->bps = sizeof(adata_t);
-       par->bits = ADATA_BITS;
-       par->le = ADATA_LE;
-       par->sig = 1;
-       par->msb = 0;
-       par->cmin = cmin;
-       par->cmax = cmax;
-       par->rate = rate;
-}
-
-#ifdef DEBUG
-/*
- * Print the format/channels/encoding on stderr.
- */
-void
-aparams_dbg(struct aparams *par)
-{
-       char enc[ENCMAX];
-
-       aparams_enctostr(par, enc);
-       dbg_puts(enc);
-       dbg_puts(",");
-       dbg_putu(par->cmin);
-       dbg_puts(":");
-       dbg_putu(par->cmax);
-       dbg_puts(",");
-       dbg_putu(par->rate);
-}
-#endif
-
-/*
- * Return true if both encodings are the same.
- */
-int
-aparams_eqenc(struct aparams *par1, struct aparams *par2)
-{
-       if (par1->bps != par2->bps ||
-           par1->bits != par2->bits ||
-           par1->sig != par2->sig)
-               return 0;
-       if ((par1->bits != 8 * par1->bps) && par1->msb != par2->msb)
-               return 0;
-       if (par1->bps > 1 && par1->le != par2->le)
-               return 0;
-       return 1;
-}
-
-/*
- * Grow channels range and sample rate of ``set'' in order ``subset'' to
- * become an actual subset of it.
- */
-void
-aparams_grow(struct aparams *set, struct aparams *subset)
-{
-       if (set->cmin > subset->cmin)
-               set->cmin = subset->cmin;
-       if (set->cmax < subset->cmax)
-               set->cmax = subset->cmax;
-       if (set->rate < subset->rate)
-               set->rate = subset->rate;
-}
-
-/*
- * Return true if rates are the same.
- */
-int
-aparams_eqrate(struct aparams *p1, struct aparams *p2)
-{
-       /* XXX: allow 1/9 halftone of difference */
-       return p1->rate == p2->rate;
-}
-
-
-/*
- * Return the number of bytes per frame with the given parameters.
- */
-unsigned int
-aparams_bpf(struct aparams *par)
-{
-       return (par->cmax - par->cmin + 1) * par->bps;
-}
-
-void
-aparams_copyenc(struct aparams *dst, struct aparams *src)
-{
-       dst->sig = src->sig;
-       dst->le = src->le;
-       dst->msb = src->msb;
-       dst->bits = src->bits;
-       dst->bps = src->bps;
-}
diff --git a/usr.bin/aucat/aparams.h b/usr.bin/aucat/aparams.h
deleted file mode 100644 (file)
index c9c59b8..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-/*     $OpenBSD: aparams.h,v 1.13 2015/01/16 06:40:05 deraadt Exp $    */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef APARAMS_H
-#define APARAMS_H
-
-#define NCHAN_MAX      16              /* max channel in a stream */
-#define RATE_MIN       4000            /* min sample rate */
-#define RATE_MAX       192000          /* max sample rate */
-#define BITS_MIN       1               /* min bits per sample */
-#define BITS_MAX       32              /* max bits per sample */
-
-/*
- * Maximum size of the encording string (the longest possible
- * encoding is ``s24le3msb'').
- */
-#define ENCMAX 10
-
-/*
- * Default bytes per sample for the given bits per sample.
- */
-#define APARAMS_BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))
-
-/*
- * Encoding specification.
- */
-struct aparams {
-       unsigned int bps;               /* bytes per sample */
-       unsigned int bits;              /* actually used bits */
-       unsigned int le;                /* 1 if little endian, 0 if big endian */
-       unsigned int sig;               /* 1 if signed, 0 if unsigned */
-       unsigned int msb;               /* 1 if msb justified, 0 if lsb justified */
-       unsigned int cmin, cmax;        /* provided/consumed channels */
-       unsigned int rate;              /* frames per second */
-};
-
-/*
- * Samples are numbers in the interval [-1, 1[, note that 1, the upper
- * boundary is excluded. We represent them as signed fixed point numbers
- * of ADATA_BITS. We also assume that 2^(ADATA_BITS - 1) fits in a int.
- */
-#ifndef ADATA_BITS
-#define ADATA_BITS                     16
-#endif
-#define ADATA_LE                       (BYTE_ORDER == LITTLE_ENDIAN)
-#define ADATA_UNIT                     (1 << (ADATA_BITS - 1))
-
-#if ADATA_BITS == 16
-
-typedef short adata_t;
-
-#define ADATA_MUL(x,y)         (((int)(x) * (int)(y)) >> (ADATA_BITS - 1))
-#define ADATA_MULDIV(x,y,z)    ((int)(x) * (int)(y) / (int)(z))
-
-#elif ADATA_BITS == 24
-
-typedef int adata_t;
-
-#if defined(__i386__) && defined(__GNUC__)
-
-static inline int
-fp24_mul(int x, int a)
-{
-       int res;
-
-       asm volatile (
-               "imull  %2\n\t"
-               "shrdl $23, %%edx, %%eax\n\t"
-               : "=a" (res)
-               : "a" (x), "r" (a)
-               : "%edx"
-               );
-       return res;
-}
-
-static inline int
-fp24_muldiv(int x, int a, int b)
-{
-       int res;
-
-       asm volatile (
-               "imull %2\n\t"
-               "idivl %3\n\t"
-               : "=a" (res)
-               : "a" (x), "d" (a), "r" (b)
-               );
-       return res;
-}
-
-#define ADATA_MUL(x,y)         fp24_mul(x, y)
-#define ADATA_MULDIV(x,y,z)    fp24_muldiv(x, y, z);
-
-#elif defined(__amd64__) || defined(__sparc64__)
-
-#define ADATA_MUL(x,y)         \
-       ((int)(((long long)(x) * (long long)(y)) >> (ADATA_BITS - 1)))
-#define ADATA_MULDIV(x,y,z)    \
-       ((int)((long long)(x) * (long long)(y) / (long long)(z)))
-
-#else
-#error "no 24-bit code for this architecture"
-#endif
-
-#else
-#error "only 16-bit and 24-bit precisions are supported"
-#endif
-
-#define MIDI_MAXCTL            127
-#define MIDI_TO_ADATA(m)       (aparams_ctltovol[m] << (ADATA_BITS - 16))
-
-extern int aparams_ctltovol[128];
-extern struct aparams aparams_none;
-
-void aparams_init(struct aparams *, unsigned int, unsigned int, unsigned int);
-void aparams_dbg(struct aparams *);
-int aparams_eqrate(struct aparams *, struct aparams *);
-int aparams_eqenc(struct aparams *, struct aparams *);
-int aparams_eq(struct aparams *, struct aparams *);
-int aparams_subset(struct aparams *, struct aparams *);
-void aparams_grow(struct aparams *, struct aparams *);
-unsigned int aparams_bpf(struct aparams *);
-int aparams_strtoenc(struct aparams *, char *);
-int aparams_enctostr(struct aparams *, char *);
-void aparams_copyenc(struct aparams *, struct aparams *);
-
-#endif /* !defined(APARAMS_H) */
diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c
deleted file mode 100644 (file)
index f65ac2d..0000000
+++ /dev/null
@@ -1,2394 +0,0 @@
-/*     $OpenBSD: aproc.c,v 1.74 2013/11/18 17:37:45 ratchov Exp $      */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * aproc structures are simple audio processing units. They are
- * interconnected by abuf structures and form a kind of circuit. aproc
- * structure have call-backs that do the actual processing.
- *
- * This module implements the following processing units:
- *
- *  - rpipe: read end of an unix file (pipe, socket, device...)
- *
- *  - wpipe: write end of an unix file (pipe, socket, device...)
- *
- *  - mix: mix N inputs -> 1 output
- *
- *  - sub: from 1 input -> extract/copy N outputs
- *
- *  - conv: converts/resamples/remaps a single stream
- *
- *  - resamp: resample streams in native format
- *
- */
-#include <err.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "abuf.h"
-#include "aparams.h"
-#include "aproc.h"
-#include "conf.h"
-#include "file.h"
-#include "midi.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-/*
- * Same as ABUF_ROK(), but consider that a buffer is 
- * readable if there's silence pending to be inserted
- */
-#define MIX_ROK(buf) (ABUF_ROK(buf) || (buf)->r.mix.drop < 0)
-
-/*
- * Same as ABUF_WOK(), but consider that a buffer is 
- * writeable if there are samples to drop
- */
-#define SUB_WOK(buf) (ABUF_WOK(buf) || (buf)->w.sub.silence < 0)
-
-int zomb_in(struct aproc *, struct abuf *);
-int zomb_out(struct aproc *, struct abuf *);
-void zomb_eof(struct aproc *, struct abuf *);
-void zomb_hup(struct aproc *, struct abuf *);
-void zomb_newin(struct aproc *, struct abuf *);
-void zomb_newout(struct aproc *, struct abuf *);
-void zomb_ipos(struct aproc *, struct abuf *, int);
-void zomb_opos(struct aproc *, struct abuf *, int);
-
-int rfile_do(struct aproc *, unsigned int, unsigned int *);
-int rfile_in(struct aproc *, struct abuf *);
-int rfile_out(struct aproc *, struct abuf *);
-void rfile_done(struct aproc *);
-void rfile_eof(struct aproc *, struct abuf *);
-void rfile_hup(struct aproc *, struct abuf *);
-
-void wfile_done(struct aproc *);
-int wfile_do(struct aproc *, unsigned int, unsigned int *);
-int wfile_in(struct aproc *, struct abuf *);
-int wfile_out(struct aproc *, struct abuf *);
-void wfile_eof(struct aproc *, struct abuf *);
-void wfile_hup(struct aproc *, struct abuf *);
-
-void mix_drop(struct abuf *, int);
-void mix_bzero(struct abuf *, unsigned int);
-unsigned int mix_badd(struct abuf *, struct abuf *);
-int mix_xrun(struct aproc *, struct abuf *);
-int mix_in(struct aproc *, struct abuf *);
-int mix_out(struct aproc *, struct abuf *);
-void mix_eof(struct aproc *, struct abuf *);
-void mix_hup(struct aproc *, struct abuf *);
-void mix_newin(struct aproc *, struct abuf *);
-void mix_newout(struct aproc *, struct abuf *);
-void mix_opos(struct aproc *, struct abuf *, int);
-void mix_setmaster(struct aproc *);
-void mix_clear(struct aproc *);
-void mix_quit(struct aproc *);
-
-void sub_silence(struct abuf *, int);
-void sub_bcopy(struct abuf *, struct abuf *);
-int sub_xrun(struct aproc *, struct abuf *);
-int sub_in(struct aproc *, struct abuf *);
-int sub_out(struct aproc *, struct abuf *);
-void sub_eof(struct aproc *, struct abuf *);
-void sub_hup(struct aproc *, struct abuf *);
-void sub_newout(struct aproc *, struct abuf *);
-void sub_ipos(struct aproc *, struct abuf *, int);
-void sub_clear(struct aproc *);
-
-void resamp_bcopy(struct aproc *, struct abuf *, struct abuf *);
-int resamp_in(struct aproc *, struct abuf *);
-int resamp_out(struct aproc *, struct abuf *);
-void resamp_eof(struct aproc *, struct abuf *);
-void resamp_hup(struct aproc *, struct abuf *);
-void resamp_ipos(struct aproc *, struct abuf *, int);
-void resamp_opos(struct aproc *, struct abuf *, int);
-
-void enc_bcopy(struct aproc *, struct abuf *, struct abuf *);
-int enc_in(struct aproc *, struct abuf *);
-int enc_out(struct aproc *, struct abuf *);
-void enc_eof(struct aproc *, struct abuf *);
-void enc_hup(struct aproc *, struct abuf *);
-
-void dec_bcopy(struct aproc *, struct abuf *, struct abuf *);
-int dec_in(struct aproc *, struct abuf *);
-int dec_out(struct aproc *, struct abuf *);
-void dec_eof(struct aproc *, struct abuf *);
-void dec_hup(struct aproc *, struct abuf *);
-
-void join_bcopy(struct aproc *, struct abuf *, struct abuf *);
-int join_in(struct aproc *, struct abuf *);
-int join_out(struct aproc *, struct abuf *);
-void join_eof(struct aproc *, struct abuf *);
-void join_hup(struct aproc *, struct abuf *);
-
-void mon_flush(struct aproc *);
-void mon_snoop(struct aproc *, struct abuf *, unsigned int, unsigned int);
-int mon_in(struct aproc *, struct abuf *);
-void mon_clear(struct aproc *);
-int mon_out(struct aproc *, struct abuf *);
-void mon_eof(struct aproc *, struct abuf *);
-void mon_hup(struct aproc *, struct abuf *);
-void mon_ipos(struct aproc *, struct abuf *, int);
-
-#ifdef DEBUG
-void
-aproc_dbg(struct aproc *p)
-{
-       dbg_puts(p->ops->name);
-       dbg_puts("(");
-       dbg_puts(p->name);
-       dbg_puts(")");
-}
-
-int
-zomb_in(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": in: terminated\n");
-       dbg_panic();
-       return 0;
-}
-
-
-int
-zomb_out(struct aproc *p, struct abuf *obuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": out: terminated\n");
-       dbg_panic();
-       return 0;
-}
-
-void
-zomb_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": eof: terminated\n");
-       dbg_panic();
-}
-
-void
-zomb_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": hup: terminated\n");
-       dbg_panic();
-}
-
-void
-zomb_newin(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": newin: terminated\n");
-       dbg_panic();
-}
-
-void
-zomb_newout(struct aproc *p, struct abuf *obuf)
-{
-       aproc_dbg(p);
-       dbg_puts(": newout: terminated\n");
-       dbg_panic();
-}
-
-void
-zomb_ipos(struct aproc *p, struct abuf *ibuf, int delta)
-{
-       aproc_dbg(p);
-       dbg_puts(": ipos: terminated\n");
-       dbg_panic();
-}
-
-void
-zomb_opos(struct aproc *p, struct abuf *obuf, int delta)
-{
-       aproc_dbg(p);
-       dbg_puts(": opos: terminated\n");
-       dbg_panic();
-}
-
-struct aproc_ops zomb_ops = {
-       "zomb",
-       zomb_in,
-       zomb_out,
-       zomb_eof,
-       zomb_hup,
-       zomb_newin,
-       zomb_newout,
-       zomb_ipos,
-       zomb_opos,
-       NULL
-};
-#endif
-
-struct aproc *
-aproc_new(struct aproc_ops *ops, char *name)
-{
-       struct aproc *p;
-
-       p = malloc(sizeof(struct aproc));
-       if (p == NULL)
-               err(1, "%s", name);
-       LIST_INIT(&p->ins);
-       LIST_INIT(&p->outs);
-       p->name = name;
-       p->ops = ops;
-       p->refs = 0;
-       p->flags = 0;
-       return p;
-}
-
-void
-aproc_del(struct aproc *p)
-{
-       struct abuf *i;
-
-#ifdef DEBUG
-       if (!p) {
-               dbg_puts("aproc_del: called with NULL argument\n");
-               dbg_panic();
-       }
-#endif
-       if (!(p->flags & APROC_ZOMB)) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       aproc_dbg(p);
-                       dbg_puts(": terminating...\n");
-               }
-#endif
-               if (p->ops->done) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               aproc_dbg(p);
-                               dbg_puts(": done\n");
-                       }
-#endif
-                       p->ops->done(p);
-               }
-               while (!LIST_EMPTY(&p->ins)) {
-                       i = LIST_FIRST(&p->ins);
-                       abuf_hup(i);
-               }
-               while (!LIST_EMPTY(&p->outs)) {
-                       i = LIST_FIRST(&p->outs);
-                       abuf_eof(i);
-               }
-               p->flags |= APROC_ZOMB;
-       }
-       if (p->refs > 0) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       aproc_dbg(p);
-                       dbg_puts(": free delayed\n");
-                       p->ops = &zomb_ops;
-               }
-#endif
-               return;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": freed\n");
-       }
-#endif
-       free(p);
-}
-
-void
-aproc_setin(struct aproc *p, struct abuf *ibuf)
-{
-       LIST_INSERT_HEAD(&p->ins, ibuf, ient);
-       ibuf->rproc = p;
-       if (p->ops->newin)
-               p->ops->newin(p, ibuf);
-}
-
-void
-aproc_setout(struct aproc *p, struct abuf *obuf)
-{
-       LIST_INSERT_HEAD(&p->outs, obuf, oent);
-       obuf->wproc = p;
-       if (p->ops->newout)
-               p->ops->newout(p, obuf);
-}
-
-void
-aproc_ipos(struct aproc *p, struct abuf *ibuf, int delta)
-{
-       struct abuf *obuf;
-
-       LIST_FOREACH(obuf, &p->outs, oent) {
-               abuf_ipos(obuf, delta);
-       }
-}
-
-void
-aproc_opos(struct aproc *p, struct abuf *obuf, int delta)
-{
-       struct abuf *ibuf;
-
-       LIST_FOREACH(ibuf, &p->ins, ient) {
-               abuf_opos(ibuf, delta);
-       }
-}
-
-int
-aproc_inuse(struct aproc *p)
-{
-       struct abuf *i;
-
-       LIST_FOREACH(i, &p->ins, ient) {
-               if (i->inuse)
-                       return 1;
-       }
-       LIST_FOREACH(i, &p->outs, oent) {
-               if (i->inuse)
-                       return 1;
-       }
-       return 0;
-}
-
-int
-aproc_depend(struct aproc *p, struct aproc *dep)
-{
-       struct abuf *i;
-
-       if (p == dep)
-               return 1;
-       if (p == NULL)
-               return 0;
-       LIST_FOREACH(i, &p->ins, ient) {
-               if (i->wproc && aproc_depend(i->wproc, dep))
-                       return 1;
-       }
-       return 0;
-}
-
-int
-rfile_do(struct aproc *p, unsigned int todo, unsigned int *done)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       struct file *f = p->u.io.file;
-       unsigned char *data;
-       unsigned int n, count, off;
-
-       off = p->u.io.partial;
-       data = abuf_wgetblk(obuf, &count, 0);
-       if (count > todo)
-               count = todo;
-       n = file_read(f, data + off, count * obuf->bpf - off);
-       if (n == 0)
-               return 0;
-       n += off;
-       p->u.io.partial = n % obuf->bpf;
-       count = n / obuf->bpf;
-       if (count > 0)
-               abuf_wcommit(obuf, count);
-       if (done)
-               *done = count;
-       return 1;
-}
-
-int
-rfile_in(struct aproc *p, struct abuf *ibuf_dummy)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       struct file *f = p->u.io.file;
-
-       if (!ABUF_WOK(obuf) || !(f->state & FILE_ROK))
-               return 0;
-       if (!rfile_do(p, obuf->len, NULL))
-               return 0;
-       if (!abuf_flush(obuf))
-               return 0;
-       return 1;
-}
-
-int
-rfile_out(struct aproc *p, struct abuf *obuf)
-{
-       struct file *f = p->u.io.file;
-
-       if (f->state & FILE_RINUSE)
-               return 0;
-       if (!ABUF_WOK(obuf) || !(f->state & FILE_ROK))
-               return 0;
-       if (!rfile_do(p, obuf->len, NULL))
-               return 0;
-       return 1;
-}
-
-void
-rfile_done(struct aproc *p)
-{
-       struct file *f = p->u.io.file;
-       struct abuf *obuf;
-
-       if (f == NULL)
-               return;
-       /*
-        * disconnect from file structure
-        */
-       f->rproc = NULL;
-       p->u.io.file = NULL;
-
-       /*
-        * all buffers must be detached before deleting f->wproc,
-        * because otherwise it could trigger this code again
-        */
-       obuf = LIST_FIRST(&p->outs);
-       if (obuf)
-               abuf_eof(obuf);
-       if (f->wproc) {
-               aproc_del(f->wproc);
-       } else
-               file_del(f);
-
-#ifdef DEBUG
-       if (debug_level >= 2 && p->u.io.partial > 0) {
-               aproc_dbg(p);
-               dbg_puts(": ");
-               dbg_putu(p->u.io.partial);
-               dbg_puts(" bytes lost in partial read\n");
-       }
-#endif
-}
-
-void
-rfile_eof(struct aproc *p, struct abuf *ibuf_dummy)
-{
-       aproc_del(p);
-}
-
-void
-rfile_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-struct aproc_ops rfile_ops = {
-       "rfile",
-       rfile_in,
-       rfile_out,
-       rfile_eof,
-       rfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       aproc_ipos,
-       aproc_opos,
-       rfile_done
-};
-
-struct aproc *
-rfile_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&rfile_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->rproc = p;
-       return p;
-}
-
-void
-wfile_done(struct aproc *p)
-{
-       struct file *f = p->u.io.file;
-       struct abuf *ibuf;
-
-       if (f == NULL)
-               return;
-       /*
-        * disconnect from file structure
-        */
-       f->wproc = NULL;
-       p->u.io.file = NULL;
-
-       /*
-        * all buffers must be detached before deleting f->rproc,
-        * because otherwise it could trigger this code again
-        */
-       ibuf = LIST_FIRST(&p->ins);
-       if (ibuf)
-               abuf_hup(ibuf);
-       if (f->rproc) {
-               aproc_del(f->rproc);
-       } else
-               file_del(f);
-#ifdef DEBUG
-       if (debug_level >= 2 && p->u.io.partial > 0) {
-               aproc_dbg(p);
-               dbg_puts(": ");
-               dbg_putu(p->u.io.partial);
-               dbg_puts(" bytes lost in partial write\n");
-       }
-#endif
-}
-
-int
-wfile_do(struct aproc *p, unsigned int todo, unsigned int *done)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       struct file *f = p->u.io.file;
-       unsigned char *data;
-       unsigned int n, count, off;
-
-       off = p->u.io.partial;
-       data = abuf_rgetblk(ibuf, &count, 0);
-       if (count > todo)
-               count = todo;
-       n = file_write(f, data + off, count * ibuf->bpf - off);
-       if (n == 0)
-               return 0;
-       n += off;
-       p->u.io.partial = n % ibuf->bpf;
-       count = n / ibuf->bpf;
-       if (count > 0)
-               abuf_rdiscard(ibuf, count);
-       if (done)
-               *done = count;
-       return 1;
-}
-int
-wfile_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct file *f = p->u.io.file;
-
-       if (f->state & FILE_WINUSE)
-               return 0;
-       if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK))
-               return 0;
-       if (!wfile_do(p, ibuf->len, NULL))
-               return 0;
-       return 1;
-}
-
-int
-wfile_out(struct aproc *p, struct abuf *obuf_dummy)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       struct file *f = p->u.io.file;
-
-       if (!abuf_fill(ibuf))
-               return 0;
-       if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK))
-               return 0;
-       if (!wfile_do(p, ibuf->len, NULL))
-               return 0;
-       return 1;
-}
-
-void
-wfile_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-wfile_hup(struct aproc *p, struct abuf *obuf_dummy)
-{
-       aproc_del(p);
-}
-
-struct aproc_ops wfile_ops = {
-       "wfile",
-       wfile_in,
-       wfile_out,
-       wfile_eof,
-       wfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       aproc_ipos,
-       aproc_opos,
-       wfile_done
-};
-
-struct aproc *
-wfile_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&wfile_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->wproc = p;
-       return p;
-}
-
-/*
- * Drop as much as possible samples from the reader end,
- * negative values mean ``insert silence''.
- */
-void
-mix_drop(struct abuf *buf, int extra)
-{
-       unsigned int count;
-
-       buf->r.mix.drop += extra;
-       while (buf->r.mix.drop > 0) {
-               count = buf->r.mix.drop;
-               if (count > buf->used)
-                       count = buf->used;
-               if (count == 0) {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               abuf_dbg(buf);
-                               dbg_puts(": drop: no data\n");
-                       }
-#endif
-                       return;
-               }
-               abuf_rdiscard(buf, count);
-               buf->r.mix.drop -= count;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(buf);
-                       dbg_puts(": dropped ");
-                       dbg_putu(count);
-                       dbg_puts(", to drop = ");
-                       dbg_putu(buf->r.mix.drop);
-                       dbg_puts("\n");
-               }
-#endif
-       }
-}
-
-/*
- * Append the necessary amount of silence, in a way
- * obuf->w.mix.todo doesn't exceed the given value
- */
-void
-mix_bzero(struct abuf *obuf, unsigned int maxtodo)
-{
-       adata_t *odata;
-       unsigned int ocount, todo;
-
-       if (obuf->w.mix.todo >= maxtodo)
-               return;
-       todo = maxtodo - obuf->w.mix.todo;
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.todo);
-       if (ocount > todo)
-               ocount = todo;
-       if (ocount == 0)
-               return;
-       memset(odata, 0, ocount * obuf->bpf);
-       obuf->w.mix.todo += ocount;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               abuf_dbg(obuf);
-               dbg_puts(": bzero(");
-               dbg_putu(obuf->w.mix.todo);
-               dbg_puts(")\n");
-       }
-#endif
-}
-
-/*
- * Mix an input block over an output block.
- */
-unsigned int
-mix_badd(struct abuf *ibuf, struct abuf *obuf)
-{
-       adata_t *idata, *odata;
-       unsigned int i, scount, icount, ocount;
-       int j, cc, cmin, cmax, istart, inext, onext, ostart, onch;
-       int vol, s;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               abuf_dbg(ibuf);
-               dbg_puts(": badd: done = ");
-               dbg_putu(ibuf->r.mix.done);
-               dbg_puts("/");
-               dbg_putu(obuf->w.mix.todo);
-               dbg_puts(", drop = ");
-               dbg_puti(ibuf->r.mix.drop);
-               dbg_puts("\n");
-       }
-#endif
-       /*
-        * Insert silence for xrun correction
-        */
-       while (ibuf->r.mix.drop < 0) {
-               icount = -ibuf->r.mix.drop;
-               mix_bzero(obuf, ibuf->r.mix.done + icount);
-               ocount = obuf->w.mix.todo - ibuf->r.mix.done;
-               if (ocount == 0)
-                       return 0;
-               scount = (icount < ocount) ? icount : ocount;
-               ibuf->r.mix.done += scount;
-               ibuf->r.mix.drop += scount;
-       }
-
-       /*
-        * Calculate the maximum we can read.
-        */
-       idata = (adata_t *)abuf_rgetblk(ibuf, &icount, 0);
-       if (icount == 0)
-               return 0;
-
-       /*
-        * Calculate the maximum we can write.
-        */
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, ibuf->r.mix.done);
-       if (ocount == 0)
-               return 0;
-
-       scount = (icount < ocount) ? icount : ocount;
-       mix_bzero(obuf, scount + ibuf->r.mix.done);
-
-       vol = ADATA_MUL(ibuf->r.mix.weight, ibuf->r.mix.vol);
-       cmin = obuf->cmin > ibuf->cmin ? obuf->cmin : ibuf->cmin;
-       cmax = obuf->cmax < ibuf->cmax ? obuf->cmax : ibuf->cmax;
-       onch = obuf->cmax - obuf->cmin + 1;
-       ostart = cmin - obuf->cmin;
-       if (ostart > onch)
-               ostart = onch;
-       onext = obuf->cmax - cmax;      
-       if (onext > onch)
-               onext = onch;
-       istart = cmin - ibuf->cmin;
-       inext = ibuf->cmax - cmax;
-       cc = cmax - cmin + 1;
-       for (i = scount; i > 0; i--) {
-               odata += ostart;
-               idata += istart;
-               for (j = cc; j > 0; j--) {
-                       s = *odata + ADATA_MUL(*idata, vol);
-                       if (s >= ADATA_UNIT)
-                               s = ADATA_UNIT - 1;
-                       else if (s < -ADATA_UNIT)
-                               s = -ADATA_UNIT;
-                       *odata = s;
-                       idata++;
-                       odata++;
-               }
-               odata += onext;
-               idata += inext;
-       }
-       abuf_rdiscard(ibuf, scount);
-       ibuf->r.mix.done += scount;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               abuf_dbg(ibuf);
-               dbg_puts(": badd: done = ");
-               dbg_putu(ibuf->r.mix.done);
-               dbg_puts("/");
-               dbg_putu(obuf->w.mix.todo);
-               dbg_puts("\n");
-       }
-#endif
-       return scount;
-}
-
-/*
- * Handle buffer underrun, return 0 if stream died.
- */
-int
-mix_xrun(struct aproc *p, struct abuf *i)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       unsigned int fdrop, remain;
-
-       if (i->r.mix.done > 0)
-               return 1;
-       if (i->r.mix.xrun == XRUN_ERROR) {
-               abuf_hup(i);
-               return 0;
-       }
-       fdrop = obuf->w.mix.todo;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(i);
-               dbg_puts(": underrun, dropping ");
-               dbg_putu(fdrop);
-               dbg_puts(" + ");
-               dbg_putu(i->r.mix.drop);
-               dbg_puts("\n");
-       }
-#endif
-       i->r.mix.done += fdrop;
-       if (i->r.mix.xrun == XRUN_SYNC)
-               mix_drop(i, fdrop);
-       else {
-               remain = fdrop % p->u.mix.round;
-               if (remain)
-                       remain = p->u.mix.round - remain;
-               mix_drop(i, -(int)remain);
-               fdrop += remain;
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       abuf_dbg(i);
-                       dbg_puts(": underrun, adding ");
-                       dbg_putu(remain);
-                       dbg_puts("\n");
-               }
-#endif
-               abuf_opos(i, -(int)fdrop);
-               if (i->duplex) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(i->duplex);
-                               dbg_puts(": full-duplex resync\n");
-                       }
-#endif
-                       sub_silence(i->duplex, -(int)fdrop);
-                       abuf_ipos(i->duplex, -(int)fdrop);
-               }
-       }
-       return 1;
-}
-
-int
-mix_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *i, *inext, *obuf = LIST_FIRST(&p->outs);
-       unsigned int odone;
-       unsigned int maxwrite;
-       unsigned int scount;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": used = ");
-               dbg_putu(ibuf->used);
-               dbg_puts("/");
-               dbg_putu(ibuf->len);
-               dbg_puts(", done = ");
-               dbg_putu(ibuf->r.mix.done);
-               dbg_puts("/");
-               dbg_putu(obuf->w.mix.todo);
-               dbg_puts("\n");
-       }
-#endif
-       if (!MIX_ROK(ibuf))
-               return 0;
-       scount = 0;
-       odone = obuf->len;
-       for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, ient);
-               if (i->r.mix.drop >= 0 && !abuf_fill(i))
-                       continue; /* eof */
-               mix_drop(i, 0);
-               scount += mix_badd(i, obuf);
-               if (odone > i->r.mix.done)
-                       odone = i->r.mix.done;
-       }
-       if (LIST_EMPTY(&p->ins) || scount == 0)
-               return 0;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": maxwrite = ");
-               dbg_putu(p->u.mix.maxlat);
-               dbg_puts(" - ");
-               dbg_putu(p->u.mix.lat);
-               dbg_puts(" = ");
-               dbg_putu(p->u.mix.maxlat - p->u.mix.lat);
-               dbg_puts("\n");
-       }
-#endif
-       maxwrite = p->u.mix.maxlat - p->u.mix.lat;
-       if (maxwrite > 0) {
-               if (odone > maxwrite)
-                       odone = maxwrite;
-               p->u.mix.lat += odone;
-               LIST_FOREACH(i, &p->ins, ient) {
-                       i->r.mix.done -= odone;
-               }
-               abuf_wcommit(obuf, odone);
-               obuf->w.mix.todo -= odone;
-               if (APROC_OK(p->u.mix.mon))
-                       mon_snoop(p->u.mix.mon, obuf, obuf->used - odone, odone);
-               if (!abuf_flush(obuf))
-                       return 0; /* hup */
-       }
-       return 1;
-}
-
-int
-mix_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *i, *inext;
-       unsigned int odone;
-       unsigned int maxwrite;
-       unsigned int scount;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": used = ");
-               dbg_putu(obuf->used);
-               dbg_puts("/");
-               dbg_putu(obuf->len);
-               dbg_puts(", todo = ");
-               dbg_putu(obuf->w.mix.todo);
-               dbg_puts("/");
-               dbg_putu(obuf->len);
-               dbg_puts("\n");
-       }
-#endif
-       if (!ABUF_WOK(obuf))
-               return 0;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": maxwrite = ");
-               dbg_putu(p->u.mix.maxlat);
-               dbg_puts(" - ");
-               dbg_putu(p->u.mix.lat);
-               dbg_puts(" = ");
-               dbg_putu(p->u.mix.maxlat - p->u.mix.lat);
-               dbg_puts("\n");
-       }
-#endif
-       maxwrite = p->u.mix.maxlat - p->u.mix.lat;
-       if (maxwrite > obuf->w.mix.todo) {
-               if ((p->flags & (APROC_QUIT | APROC_DROP)) == APROC_DROP)
-                       mix_bzero(obuf, maxwrite);
-       }
-       scount = 0;
-       odone = obuf->len;
-       for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, ient);
-               if (i->r.mix.drop >= 0 && !abuf_fill(i))
-                       continue; /* eof */
-               mix_drop(i, 0);
-               if (maxwrite > 0 && !MIX_ROK(i)) {
-                       if (p->flags & APROC_DROP) {
-                               if (!mix_xrun(p, i))
-                                       continue;
-                       }
-               } else
-                       scount += mix_badd(i, obuf);
-               if (odone > i->r.mix.done)
-                       odone = i->r.mix.done;
-       }
-       if (LIST_EMPTY(&p->ins) && obuf->w.mix.todo == 0) {
-               if (p->flags & APROC_QUIT) {
-                       aproc_del(p);
-                       return 0;
-               }
-               if (!(p->flags & APROC_DROP))
-                       return 0;
-       }
-       if (odone > obuf->w.mix.todo)
-               odone = obuf->w.mix.todo;
-       if (odone > maxwrite)
-               odone = maxwrite;
-       if (odone > 0) {
-               p->u.mix.lat += odone;
-               LIST_FOREACH(i, &p->ins, ient) {
-                       i->r.mix.done -= odone;
-               }
-               abuf_wcommit(obuf, odone);
-               obuf->w.mix.todo -= odone;
-               if (APROC_OK(p->u.mix.mon))
-                       mon_snoop(p->u.mix.mon, obuf, obuf->used - odone, odone);
-       }
-       if (LIST_EMPTY(&p->ins))
-               p->u.mix.idle += odone;
-       if (scount == 0)
-               return 0;
-       return 1;
-}
-
-void
-mix_eof(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *i, *obuf = LIST_FIRST(&p->outs);
-       unsigned int odone;
-
-       mix_setmaster(p);
-
-       if (!aproc_inuse(p)) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       aproc_dbg(p);
-                       dbg_puts(": running other streams\n");
-               }
-#endif
-               /*
-                * Find a blocked input.
-                */
-               odone = obuf->len;
-               LIST_FOREACH(i, &p->ins, ient) {
-                       /*
-                        * abuf_fill() may trigger mix_eof(), do the job
-                        * and possibly reorder the list
-                        */
-                       if (!abuf_fill(i))
-                               return;
-                       if (MIX_ROK(i) && i->r.mix.done < obuf->w.mix.todo) {
-                               abuf_run(i);
-                               return;
-                       }
-                       if (odone > i->r.mix.done)
-                               odone = i->r.mix.done;
-               }
-               /*
-                * No blocked inputs. Check if output is blocked.
-                */
-               if (LIST_EMPTY(&p->ins) || odone == obuf->w.mix.todo)
-                       abuf_run(obuf);
-       }
-}
-
-void
-mix_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-void
-mix_newin(struct aproc *p, struct abuf *ibuf)
-{
-       p->u.mix.idle = 0;
-       ibuf->r.mix.done = 0;
-       ibuf->r.mix.vol = ADATA_UNIT;
-       ibuf->r.mix.weight = ADATA_UNIT;
-       ibuf->r.mix.maxweight = ADATA_UNIT;
-       ibuf->r.mix.xrun = XRUN_IGNORE;
-       ibuf->r.mix.drop = 0;
-}
-
-void
-mix_newout(struct aproc *p, struct abuf *obuf)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": newout, will use ");
-               dbg_putu(obuf->len);
-               dbg_puts(" fr\n");
-       }
-#endif
-       obuf->w.mix.todo = 0;
-}
-
-void
-mix_opos(struct aproc *p, struct abuf *obuf, int delta)
-{
-       p->u.mix.lat -= delta;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": opos: lat = ");
-               dbg_puti(p->u.mix.lat);
-               dbg_puts("/");
-               dbg_puti(p->u.mix.maxlat);
-               dbg_puts("\n");
-       }
-#endif
-       aproc_opos(p, obuf, delta);
-       if (APROC_OK(p->u.mix.mon))
-               p->u.mix.mon->ops->ipos(p->u.mix.mon, NULL, delta);
-}
-
-struct aproc_ops mix_ops = {
-       "mix",
-       mix_in,
-       mix_out,
-       mix_eof,
-       mix_hup,
-       mix_newin,
-       mix_newout,
-       aproc_ipos,
-       mix_opos,
-       NULL
-};
-
-struct aproc *
-mix_new(char *name, int maxlat, unsigned int round,
-    unsigned int autovol, unsigned int master)
-{
-       struct aproc *p;
-
-       p = aproc_new(&mix_ops, name);
-       p->u.mix.idle = 0;
-       p->u.mix.lat = 0;
-       p->u.mix.round = round;
-       p->u.mix.maxlat = maxlat;
-       p->u.mix.mon = NULL;
-       p->u.mix.autovol = autovol;
-       p->u.mix.master = master;
-       return p;
-}
-
-/*
- * Normalize input levels.
- */
-void
-mix_setmaster(struct aproc *p)
-{
-       unsigned int n;
-       struct abuf *i, *j;
-       int weight;
-
-       LIST_FOREACH(i, &p->ins, ient) {
-               weight = ADATA_UNIT;
-               if (p->u.mix.autovol) {
-                       /*
-                        * count the number of inputs that have
-                        * overlapping channel sets
-                        */
-                       n = 0;
-                       LIST_FOREACH(j, &p->ins, ient) {
-                               if (i->cmin <= j->cmax && i->cmax >= j->cmin)
-                                       n++;
-                       }
-                       weight /= n;
-               }
-               if (weight > i->r.mix.maxweight)
-                       weight = i->r.mix.maxweight;
-               i->r.mix.weight = ADATA_MUL(weight, p->u.mix.master);
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       abuf_dbg(i);
-                       dbg_puts(": setmaster: ");
-                       dbg_puti(i->r.mix.weight);
-                       dbg_puts("/");
-                       dbg_puti(i->r.mix.maxweight);
-                       dbg_puts("\n");
-               }
-#endif
-       }
-}
-
-void
-mix_clear(struct aproc *p)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       p->u.mix.lat = 0;
-       obuf->w.mix.todo = 0;
-}
-
-/*
- * Gracefully terminate the mixer: raise the APROC_QUIT flag
- * and let the rest of the code do the job. If there are neither
- * inputs nor uncommited data, then terminate right away
- */
-void
-mix_quit(struct aproc *p)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       p->flags |= APROC_QUIT;
-
-       /*
-        * eof the last input will trigger aproc_del()
-        */
-       if (!LIST_EMPTY(&p->ins) || obuf->w.mix.todo > 0)
-               return;
-       aproc_del(p);   
-}
-
-/*
- * Append as much as possible silence on the writer end
- */
-void
-sub_silence(struct abuf *buf, int extra)
-{
-       unsigned char *data;
-       unsigned int count;
-
-       buf->w.sub.silence += extra;
-       if (buf->w.sub.silence > 0) {
-               data = abuf_wgetblk(buf, &count, 0);
-               if (count >= buf->w.sub.silence)
-                       count = buf->w.sub.silence;
-               if (count == 0) {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               abuf_dbg(buf);
-                               dbg_puts(": no space for silence\n");
-                       }
-#endif
-                       return;
-               }
-               memset(data, 0, count * buf->bpf);
-               abuf_wcommit(buf, count);
-               buf->w.sub.silence -= count;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(buf);
-                       dbg_puts(": appended ");
-                       dbg_putu(count);
-                       dbg_puts(", remaining silence = ");
-                       dbg_putu(buf->w.sub.silence);
-                       dbg_puts("\n");
-               }
-#endif
-       }
-}
-
-/*
- * Copy data from ibuf to obuf.
- */
-void
-sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
-{
-       adata_t *idata, *odata;
-       unsigned int i, icount, ocount, scount;
-       int j, cc, cmin, cmax, istart, inext, onext, ostart, onch;
-
-       /*
-        * Drop samples for xrun correction
-        */
-       if (obuf->w.sub.silence < 0) {
-               scount = -obuf->w.sub.silence;
-               if (scount > ibuf->used)
-                       scount = ibuf->used;
-               obuf->w.sub.done += scount;
-               obuf->w.sub.silence += scount;
-       }
-
-       idata = (adata_t *)abuf_rgetblk(ibuf, &icount, obuf->w.sub.done);
-       if (icount == 0)
-               return;
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, 0);
-       if (ocount == 0)
-               return;
-       cmin = obuf->cmin > ibuf->cmin ? obuf->cmin : ibuf->cmin;
-       cmax = obuf->cmax < ibuf->cmax ? obuf->cmax : ibuf->cmax;
-       onch = obuf->cmax - obuf->cmin + 1;
-       ostart = cmin - obuf->cmin;
-       if (ostart > onch)
-               ostart = onch;
-       onext = obuf->cmax - cmax;
-       if (onext > onch)
-               onext = onch;
-       istart = cmin - ibuf->cmin;
-       inext = ibuf->cmax - cmax;
-       cc = cmax - cmin + 1;
-       scount = (icount < ocount) ? icount : ocount;
-       for (i = scount; i > 0; i--) {
-               idata += istart;
-               for (j = ostart; j > 0; j--)
-                       *odata++ = 0x1111;
-               for (j = cc; j > 0; j--) {
-                       *odata = *idata;
-                       odata++;
-                       idata++;
-               }
-               for (j = onext; j > 0; j--)
-                       *odata++ = 0x2222;
-               idata += inext;
-       }
-       abuf_wcommit(obuf, scount);
-       obuf->w.sub.done += scount;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               abuf_dbg(obuf);
-               dbg_puts(": bcopy ");
-               dbg_putu(scount);
-               dbg_puts("\n");
-       }
-#endif
-}
-
-/*
- * Handle buffer overruns. Return 0 if the stream died.
- */
-int
-sub_xrun(struct aproc *p, struct abuf *i)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       unsigned int fdrop, remain;
-
-       if (i->w.sub.done > 0)
-               return 1;
-       if (i->w.sub.xrun == XRUN_ERROR) {
-               abuf_eof(i);
-               return 0;
-       }
-       fdrop = ibuf->used;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(i);
-               dbg_puts(": overrun, silence ");
-               dbg_putu(fdrop);
-               dbg_puts(" + ");
-               dbg_putu(i->w.sub.silence);
-               dbg_puts("\n");
-       }
-#endif
-       i->w.sub.done += fdrop;
-       if (i->w.sub.xrun == XRUN_SYNC)
-               sub_silence(i, fdrop);
-       else {
-               remain = fdrop % p->u.sub.round;
-               if (remain)
-                       remain = p->u.sub.round - remain;
-               sub_silence(i, -(int)remain);
-               fdrop += remain;
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       abuf_dbg(i);
-                       dbg_puts(": overrun, adding ");
-                       dbg_putu(remain);
-                       dbg_puts("\n");
-               }
-#endif
-
-               abuf_ipos(i, -(int)fdrop);
-               if (i->duplex) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(i->duplex);
-                               dbg_puts(": full-duplex resync\n");
-                       }
-#endif
-                       mix_drop(i->duplex, -(int)fdrop);
-                       abuf_opos(i->duplex, -(int)fdrop);
-               }
-       }
-       return 1;
-}
-
-int
-sub_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *i, *inext;
-       unsigned int idone;
-
-       if (!ABUF_ROK(ibuf))
-               return 0;
-       idone = ibuf->len;
-       for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, oent);
-               sub_silence(i, 0);
-               if (!SUB_WOK(i)) {
-                       if (p->flags & APROC_DROP) {
-                               if (!sub_xrun(p, i))
-                                       continue;
-                       }
-               } else
-                       sub_bcopy(ibuf, i);
-               if (idone > i->w.sub.done)
-                       idone = i->w.sub.done;
-               if (!abuf_flush(i))
-                       continue;
-       }
-       if (LIST_EMPTY(&p->outs)) {
-               if (p->flags & APROC_QUIT) {
-                       aproc_del(p);
-                       return 0;
-               }
-               if (!(p->flags & APROC_DROP))
-                       return 0;
-               idone = ibuf->used;
-               p->u.sub.idle += idone;
-       }
-       if (idone == 0)
-               return 0;
-       LIST_FOREACH(i, &p->outs, oent) {
-               i->w.sub.done -= idone;
-       }
-       abuf_rdiscard(ibuf, idone);
-       abuf_opos(ibuf, idone);
-       p->u.sub.lat -= idone;
-       return 1;
-}
-
-int
-sub_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       struct abuf *i, *inext;
-       unsigned int idone;
-
-       if (!SUB_WOK(obuf))
-               return 0;
-       if (!abuf_fill(ibuf))
-               return 0; /* eof */
-       idone = ibuf->len;
-       for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, oent);
-               sub_silence(i, 0);
-               sub_bcopy(ibuf, i);
-               if (idone > i->w.sub.done)
-                       idone = i->w.sub.done;
-               if (!abuf_flush(i))
-                       continue;
-       }
-       if (LIST_EMPTY(&p->outs) || idone == 0)
-               return 0;
-       LIST_FOREACH(i, &p->outs, oent) {
-               i->w.sub.done -= idone;
-       }
-       abuf_rdiscard(ibuf, idone);
-       abuf_opos(ibuf, idone);
-       p->u.sub.lat -= idone;
-       return 1;
-}
-
-void
-sub_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-sub_hup(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *i, *ibuf = LIST_FIRST(&p->ins);
-       unsigned int idone;
-
-       if (!aproc_inuse(p)) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       aproc_dbg(p);
-                       dbg_puts(": running other streams\n");
-               }
-#endif
-               /*
-                * Find a blocked output.
-                */
-               idone = ibuf->len;
-               LIST_FOREACH(i, &p->outs, oent) {
-                       /*
-                        * abuf_flush() may trigger sub_hup(), do the job
-                        * and possibly reorder the list
-                        */
-                       if (!abuf_flush(i))
-                               return;
-                       if (SUB_WOK(i) && i->w.sub.done < ibuf->used) {
-                               abuf_run(i);
-                               return;
-                       }
-                       if (idone > i->w.sub.done)
-                               idone = i->w.sub.done;
-               }
-               /*
-                * No blocked outputs. Check if input is blocked.
-                */
-               if (LIST_EMPTY(&p->outs) || idone == ibuf->used)
-                       abuf_run(ibuf);
-       }
-}
-
-void
-sub_newout(struct aproc *p, struct abuf *obuf)
-{
-       p->u.sub.idle = 0;
-       obuf->w.sub.done = 0;
-       obuf->w.sub.xrun = XRUN_IGNORE;
-       obuf->w.sub.silence = 0;
-}
-
-void
-sub_ipos(struct aproc *p, struct abuf *ibuf, int delta)
-{
-       p->u.sub.lat += delta;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": ipos: lat = ");
-               dbg_puti(p->u.sub.lat);
-               dbg_puts("/");
-               dbg_puti(p->u.sub.maxlat);
-               dbg_puts("\n");
-       }
-#endif
-       aproc_ipos(p, ibuf, delta);
-}
-
-struct aproc_ops sub_ops = {
-       "sub",
-       sub_in,
-       sub_out,
-       sub_eof,
-       sub_hup,
-       NULL,
-       sub_newout,
-       sub_ipos,
-       aproc_opos,
-       NULL
-};
-
-struct aproc *
-sub_new(char *name, int maxlat, unsigned int round)
-{
-       struct aproc *p;
-
-       p = aproc_new(&sub_ops, name);
-       p->u.sub.idle = 0;
-       p->u.sub.lat = 0;
-       p->u.sub.round = round;
-       p->u.sub.maxlat = maxlat;
-       return p;
-}
-
-void
-sub_clear(struct aproc *p)
-{
-       p->u.sub.lat = 0;
-}
-
-/*
- * Convert one block.
- */
-void
-resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
-{
-       unsigned int inch;
-       adata_t *idata;
-       unsigned int oblksz;
-       unsigned int ifr;
-       unsigned int onch;
-       int s, ds, diff;
-       adata_t *odata;
-       unsigned int iblksz;
-       unsigned int ofr;
-       unsigned int c;
-       adata_t *ctxbuf, *ctx;
-       unsigned int ctx_start;
-       unsigned int icount, ocount;
-
-       /*
-        * Calculate max frames readable at once from the input buffer.
-        */
-       idata = (adata_t *)abuf_rgetblk(ibuf, &icount, 0);
-       ifr = icount;
-
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, 0);
-       ofr = ocount;
-
-       /*
-        * Partially copy structures into local variables, to avoid
-        * unnecessary indirections; this also allows the compiler to
-        * order local variables more "cache-friendly".
-        */
-       diff = p->u.resamp.diff;
-       inch = ibuf->cmax - ibuf->cmin + 1;
-       iblksz = p->u.resamp.iblksz;
-       onch = obuf->cmax - obuf->cmin + 1;
-       oblksz = p->u.resamp.oblksz;
-       ctxbuf = p->u.resamp.ctx;
-       ctx_start = p->u.resamp.ctx_start;
-
-       /*
-        * Start conversion.
-        */
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": starting diff = ");
-               dbg_puti(diff);
-               dbg_puts(", ifr = ");
-               dbg_putu(ifr);
-               dbg_puts(", ofr = ");
-               dbg_putu(ofr);
-               dbg_puts(" fr\n");
-       }
-#endif
-       for (;;) {
-               if (diff < 0) {
-                       if (ifr == 0)
-                               break;
-                       ctx_start ^= 1;
-                       ctx = ctxbuf + ctx_start;
-                       for (c = inch; c > 0; c--) {
-                               *ctx = *idata++;
-                               ctx += RESAMP_NCTX;
-                       }
-                       diff += oblksz;
-                       ifr--;
-               } else if (diff > 0) {
-                       if (ofr == 0)
-                               break;
-                       ctx = ctxbuf;
-                       for (c = onch; c > 0; c--) {
-                               s = ctx[ctx_start];
-                               ds = ctx[ctx_start ^ 1] - s;
-                               ctx += RESAMP_NCTX;
-                               *odata++ = s + ADATA_MULDIV(ds, diff, oblksz);
-                       }
-                       diff -= iblksz;
-                       ofr--;
-               } else {
-                       if (ifr == 0 || ofr == 0)
-                               break;
-                       ctx = ctxbuf + ctx_start;
-                       for (c = onch; c > 0; c--) {
-                               *odata++ = *ctx;
-                               ctx += RESAMP_NCTX;
-                       }
-                       ctx_start ^= 1;
-                       ctx = ctxbuf + ctx_start;
-                       for (c = inch; c > 0; c--) {
-                               *ctx = *idata++;
-                               ctx += RESAMP_NCTX;
-                       }
-                       diff -= iblksz;
-                       diff += oblksz;
-                       ifr--;
-                       ofr--;
-               }
-       }
-       p->u.resamp.diff = diff;
-       p->u.resamp.ctx_start = ctx_start;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": done delta = ");
-               dbg_puti(diff);
-               dbg_puts(", ifr = ");
-               dbg_putu(ifr);
-               dbg_puts(", ofr = ");
-               dbg_putu(ofr);
-               dbg_puts(" fr\n");
-       }
-#endif
-       /*
-        * Update FIFO pointers.
-        */
-       icount -= ifr;
-       ocount -= ofr;
-       abuf_rdiscard(ibuf, icount);
-       abuf_wcommit(obuf, ocount);
-}
-
-int
-resamp_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       resamp_bcopy(p, ibuf, obuf);
-       if (!abuf_flush(obuf))
-               return 0;
-       return 1;
-}
-
-int
-resamp_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-
-       if (!abuf_fill(ibuf))
-               return 0;
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       resamp_bcopy(p, ibuf, obuf);
-       return 1;
-}
-
-void
-resamp_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-resamp_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-void
-resamp_ipos(struct aproc *p, struct abuf *ibuf, int delta)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       long long ipos;
-       
-       ipos = (long long)delta * p->u.resamp.oblksz + p->u.resamp.idelta;
-       p->u.resamp.idelta = ipos % p->u.resamp.iblksz;
-       abuf_ipos(obuf, ipos / (int)p->u.resamp.iblksz);
-}
-
-void
-resamp_opos(struct aproc *p, struct abuf *obuf, int delta)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       long long opos;
-
-       opos = (long long)delta * p->u.resamp.iblksz + p->u.resamp.odelta;
-       p->u.resamp.odelta = opos % p->u.resamp.oblksz;
-       abuf_opos(ibuf, opos / p->u.resamp.oblksz);
-}
-
-struct aproc_ops resamp_ops = {
-       "resamp",
-       resamp_in,
-       resamp_out,
-       resamp_eof,
-       resamp_hup,
-       NULL,
-       NULL,
-       resamp_ipos,
-       resamp_opos,
-       NULL
-};
-
-struct aproc *
-resamp_new(char *name, unsigned int iblksz, unsigned int oblksz)
-{
-       struct aproc *p;
-       unsigned int i;
-
-       p = aproc_new(&resamp_ops, name);
-       p->u.resamp.iblksz = iblksz;
-       p->u.resamp.oblksz = oblksz;
-       p->u.resamp.diff = 0;
-       p->u.resamp.idelta = 0;
-       p->u.resamp.odelta = 0;
-       p->u.resamp.ctx_start = 0;
-       for (i = 0; i < NCHAN_MAX * RESAMP_NCTX; i++)
-               p->u.resamp.ctx[i] = 0;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": new ");
-               dbg_putu(iblksz);
-               dbg_puts("/");
-               dbg_putu(oblksz);
-               dbg_puts("\n");
-       }
-#endif
-       return p;
-}
-
-/*
- * Convert one block.
- */
-void
-enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
-{
-       unsigned int nch, scount, icount, ocount;
-       unsigned int f;
-       adata_t *idata;
-       int s;
-       unsigned int oshift;
-       int osigbit;
-       unsigned int obps;
-       unsigned int i;
-       unsigned char *odata;
-       int obnext;
-       int osnext;
-
-       /*
-        * Calculate max frames readable at once from the input buffer.
-        */
-       idata = (adata_t *)abuf_rgetblk(ibuf, &icount, 0);
-       if (icount == 0)
-               return;
-       odata = abuf_wgetblk(obuf, &ocount, 0);
-       if (ocount == 0)
-               return;
-       scount = (icount < ocount) ? icount : ocount;
-       nch = ibuf->cmax - ibuf->cmin + 1;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": bcopy ");
-               dbg_putu(scount);
-               dbg_puts(" fr / ");
-               dbg_putu(nch);
-               dbg_puts(" ch\n");
-       }
-#endif
-       /*
-        * Partially copy structures into local variables, to avoid
-        * unnecessary indirections; this also allows the compiler to
-        * order local variables more "cache-friendly".
-        */
-       oshift = p->u.conv.shift;
-       osigbit = p->u.conv.sigbit;
-       obps = p->u.conv.bps;
-       obnext = p->u.conv.bnext;
-       osnext = p->u.conv.snext;
-
-       /*
-        * Start conversion.
-        */
-       odata += p->u.conv.bfirst;
-       for (f = scount * nch; f > 0; f--) {
-               s = *idata++;
-               s <<= 32 - ADATA_BITS;
-               s >>= oshift;
-               s ^= osigbit;
-               for (i = obps; i > 0; i--) {
-                       *odata = (unsigned char)s;
-                       s >>= 8;
-                       odata += obnext;
-               }
-               odata += osnext;
-       }
-
-       /*
-        * Update FIFO pointers.
-        */
-       abuf_rdiscard(ibuf, scount);
-       abuf_wcommit(obuf, scount);
-}
-
-int
-enc_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       enc_bcopy(p, ibuf, obuf);
-       if (!abuf_flush(obuf))
-               return 0;
-       return 1;
-}
-
-int
-enc_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-
-       if (!abuf_fill(ibuf))
-               return 0;
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       enc_bcopy(p, ibuf, obuf);
-       return 1;
-}
-
-void
-enc_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-enc_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-struct aproc_ops enc_ops = {
-       "enc",
-       enc_in,
-       enc_out,
-       enc_eof,
-       enc_hup,
-       NULL,
-       NULL,
-       aproc_ipos,
-       aproc_opos,
-       NULL
-};
-
-struct aproc *
-enc_new(char *name, struct aparams *par)
-{
-       struct aproc *p;
-
-       p = aproc_new(&enc_ops, name);
-       p->u.conv.bps = par->bps;
-       p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
-       if (par->msb) {
-               p->u.conv.shift = 32 - par->bps * 8;
-       } else {
-               p->u.conv.shift = 32 - par->bits;
-       }
-       if (!par->le) {
-               p->u.conv.bfirst = par->bps - 1;
-               p->u.conv.bnext = -1;
-               p->u.conv.snext = 2 * par->bps;
-       } else {
-               p->u.conv.bfirst = 0;
-               p->u.conv.bnext = 1;
-               p->u.conv.snext = 0;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": new ");
-               aparams_dbg(par);
-               dbg_puts("\n");
-       }
-#endif
-       return p;
-}
-
-/*
- * Convert one block.
- */
-void
-dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
-{
-       unsigned int nch, scount, icount, ocount;
-       unsigned int f;
-       unsigned int ibps;
-       unsigned int i;
-       int s = 0xdeadbeef;
-       unsigned char *idata;
-       int ibnext;
-       int isnext;
-       int isigbit;
-       unsigned int ishift;
-       adata_t *odata;
-
-       /*
-        * Calculate max frames readable at once from the input buffer.
-        */
-       idata = abuf_rgetblk(ibuf, &icount, 0);
-       if (icount == 0)
-               return;
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, 0);
-       if (ocount == 0)
-               return;
-       scount = (icount < ocount) ? icount : ocount;
-       nch = obuf->cmax - obuf->cmin + 1;
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": bcopy ");
-               dbg_putu(scount);
-               dbg_puts(" fr / ");
-               dbg_putu(nch);
-               dbg_puts(" ch\n");
-       }
-#endif
-       /*
-        * Partially copy structures into local variables, to avoid
-        * unnecessary indirections; this also allows the compiler to
-        * order local variables more "cache-friendly".
-        */
-       ibps = p->u.conv.bps;
-       ibnext = p->u.conv.bnext;
-       isigbit = p->u.conv.sigbit;
-       ishift = p->u.conv.shift;
-       isnext = p->u.conv.snext;
-
-       /*
-        * Start conversion.
-        */
-       idata += p->u.conv.bfirst;
-       for (f = scount * nch; f > 0; f--) {
-               for (i = ibps; i > 0; i--) {
-                       s <<= 8;
-                       s |= *idata;
-                       idata += ibnext;
-               }
-               idata += isnext;
-               s ^= isigbit;
-               s <<= ishift;
-               s >>= 32 - ADATA_BITS;
-               *odata++ = s;
-       }
-
-       /*
-        * Update FIFO pointers.
-        */
-       abuf_rdiscard(ibuf, scount);
-       abuf_wcommit(obuf, scount);
-}
-
-int
-dec_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       dec_bcopy(p, ibuf, obuf);
-       if (!abuf_flush(obuf))
-               return 0;
-       return 1;
-}
-
-int
-dec_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-
-       if (!abuf_fill(ibuf))
-               return 0;
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       dec_bcopy(p, ibuf, obuf);
-       return 1;
-}
-
-void
-dec_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-dec_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-struct aproc_ops dec_ops = {
-       "dec",
-       dec_in,
-       dec_out,
-       dec_eof,
-       dec_hup,
-       NULL,
-       NULL,
-       aproc_ipos,
-       aproc_opos,
-       NULL
-};
-
-struct aproc *
-dec_new(char *name, struct aparams *par)
-{
-       struct aproc *p;
-
-       p = aproc_new(&dec_ops, name);
-       p->u.conv.bps = par->bps;
-       p->u.conv.sigbit = par->sig ? 0 : 1 << (par->bits - 1);
-       if (par->msb) {
-               p->u.conv.shift = 32 - par->bps * 8;
-       } else {
-               p->u.conv.shift = 32 - par->bits;
-       }
-       if (par->le) {
-               p->u.conv.bfirst = par->bps - 1;
-               p->u.conv.bnext = -1;
-               p->u.conv.snext = 2 * par->bps;
-       } else {
-               p->u.conv.bfirst = 0;
-               p->u.conv.bnext = 1;
-               p->u.conv.snext = 0;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": new ");
-               aparams_dbg(par);
-               dbg_puts("\n");
-       }
-#endif
-       return p;
-}
-
-/*
- * Convert one block.
- */
-void
-join_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
-{
-       unsigned int h, hops;
-       unsigned int inch, inext;
-       adata_t *idata;
-       unsigned int onch, onext;
-       adata_t *odata;
-       int scale;
-       unsigned int c, f, scount, icount, ocount;
-
-       /*
-        * Calculate max frames readable at once from the input buffer.
-        */
-       idata = (adata_t *)abuf_rgetblk(ibuf, &icount, 0);
-       if (icount == 0)
-               return;
-       odata = (adata_t *)abuf_wgetblk(obuf, &ocount, 0);
-       if (ocount == 0)
-               return;
-       scount = icount < ocount ? icount : ocount;
-       inch = ibuf->cmax - ibuf->cmin + 1;
-       onch = obuf->cmax - obuf->cmin + 1;
-       if (2 * inch <= onch) {
-               hops = onch / inch;
-               inext = inch * hops;
-               onext = onch - inext;
-               for (f = scount; f > 0; f--) {
-                       h = hops;
-                       for (;;) {
-                               for (c = inch; c > 0; c--)
-                                       *odata++ = *idata++;
-                               if (--h == 0)
-                                       break;
-                               idata -= inch;
-                       }
-                       for (c = onext; c > 0; c--)
-                               *odata++ = 0;
-               }
-       } else if (inch >= 2 * onch) {
-               hops = inch / onch;
-               inext = inch - onch * hops;
-               scale = ADATA_UNIT / hops;
-               inch -= onch + inext;
-               hops--;
-               for (f = scount; f > 0; f--) {
-                       for (c = onch; c > 0; c--)
-                               *odata++ = ADATA_MUL(*idata++, scale);
-                       for (h = hops; h > 0; h--) {
-                               odata -= onch;
-                               for (c = onch; c > 0; c--)
-                                       *odata++ += ADATA_MUL(*idata++, scale);
-                       }
-                       idata += inext;
-               }
-       } else {
-#ifdef DEBUG
-               aproc_dbg(p);
-               dbg_puts(": nothing to do\n");
-               dbg_panic();
-#endif
-       }
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": bcopy ");
-               dbg_putu(scount);
-               dbg_puts(" fr\n");
-       }
-#endif
-       abuf_rdiscard(ibuf, scount);
-       abuf_wcommit(obuf, scount);
-}
-
-int
-join_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       join_bcopy(p, ibuf, obuf);
-       if (!abuf_flush(obuf))
-               return 0;
-       return 1;
-}
-
-int
-join_out(struct aproc *p, struct abuf *obuf)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-
-       if (!abuf_fill(ibuf))
-               return 0;
-       if (!ABUF_WOK(obuf) || !ABUF_ROK(ibuf))
-               return 0;
-       join_bcopy(p, ibuf, obuf);
-       return 1;
-}
-
-void
-join_eof(struct aproc *p, struct abuf *ibuf)
-{
-       aproc_del(p);
-}
-
-void
-join_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-struct aproc_ops join_ops = {
-       "join",
-       join_in,
-       join_out,
-       join_eof,
-       join_hup,
-       NULL,
-       NULL,
-       aproc_ipos,
-       aproc_opos,
-       NULL
-};
-
-struct aproc *
-join_new(char *name)
-{
-       struct aproc *p;
-
-       p = aproc_new(&join_ops, name);
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": new\n");
-       }
-#endif
-       return p;
-}
-
-/*
- * Commit and flush part of the output buffer
- */
-void
-mon_flush(struct aproc *p)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       unsigned int count;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": delta = ");
-               dbg_puti(p->u.mon.delta);
-               dbg_puts("/");
-               dbg_putu(p->u.mon.bufsz);
-               dbg_puts(" pending = ");
-               dbg_puti(p->u.mon.pending);
-               dbg_puts("\n");
-       }
-#endif
-       if (p->u.mon.delta <= 0 || p->u.mon.pending == 0)
-               return;
-       count = p->u.mon.delta;
-       if (count > p->u.mon.pending)
-               count = p->u.mon.pending;
-       abuf_wcommit(obuf, count);
-       p->u.mon.pending -= count;
-       p->u.mon.delta -= count;
-       abuf_flush(obuf);
-}
-
-/*
- * Copy one block.
- */
-void
-mon_snoop(struct aproc *p, struct abuf *ibuf,
-    unsigned int pos, unsigned int todo)
-{
-       struct abuf *obuf = LIST_FIRST(&p->outs);
-       unsigned int scount, icount, ocount;
-       adata_t *idata, *odata;
-
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               aproc_dbg(p);
-               dbg_puts(": snooping ");
-               dbg_putu(pos);
-               dbg_puts("..");
-               dbg_putu(todo);
-               dbg_puts("\n");
-       }
-#endif
-       if (!abuf_flush(obuf))
-               return;
-
-       while (todo > 0) {
-               /*
-                * Calculate max frames readable at once from the input buffer.
-                */
-               idata = (adata_t *)abuf_rgetblk(ibuf, &icount, pos);
-               odata = (adata_t *)abuf_wgetblk(obuf, &ocount, p->u.mon.pending);
-               scount = (icount < ocount) ? icount : ocount;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       aproc_dbg(p);
-                       dbg_puts(": snooping ");
-                       dbg_putu(scount);
-                       dbg_puts(" fr\n");
-               }
-               if (scount == 0) {
-                       dbg_puts("monitor xrun, not allowed\n");
-                       dbg_panic();
-               }
-#endif
-               memcpy(odata, idata, scount * obuf->bpf);
-               p->u.mon.pending += scount;
-               todo -= scount;
-               pos += scount;
-       }
-       mon_flush(p);
-}
-
-int
-mon_in(struct aproc *p, struct abuf *ibuf)
-{
-#ifdef DEBUG
-       dbg_puts("monitor can't have inputs to read\n");
-       dbg_panic();
-#endif
-       return 0;
-}
-
-/*
- * put the monitor into ``empty'' state
- */
-void
-mon_clear(struct aproc *p)
-{
-       p->u.mon.pending = 0;
-       p->u.mon.delta = 0;
-}
-
-int
-mon_out(struct aproc *p, struct abuf *obuf)
-{
-       /*
-        * can't trigger monitored stream to produce data
-        */
-       return 0;
-}
-
-void
-mon_eof(struct aproc *p, struct abuf *ibuf)
-{
-#ifdef DEBUG
-       dbg_puts("monitor can't have inputs to eof\n");
-       dbg_panic();
-#endif
-}
-
-void
-mon_hup(struct aproc *p, struct abuf *obuf)
-{
-       aproc_del(p);
-}
-
-void
-mon_ipos(struct aproc *p, struct abuf *ibuf, int delta)
-{
-       aproc_ipos(p, ibuf, delta);
-       p->u.mon.delta += delta;
-       mon_flush(p);
-}
-
-struct aproc_ops mon_ops = {
-       "mon",
-       mon_in,
-       mon_out,
-       mon_eof,
-       mon_hup,
-       NULL,
-       NULL,
-       mon_ipos,
-       aproc_opos,
-       NULL
-};
-
-struct aproc *
-mon_new(char *name, unsigned int bufsz)
-{
-       struct aproc *p;
-
-       p = aproc_new(&mon_ops, name);
-       p->u.mon.pending = 0;
-       p->u.mon.delta = 0;
-       p->u.mon.bufsz = bufsz;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": new\n");
-       }
-#endif
-       return p;
-}
diff --git a/usr.bin/aucat/aproc.h b/usr.bin/aucat/aproc.h
deleted file mode 100644 (file)
index 659d756..0000000
+++ /dev/null
@@ -1,248 +0,0 @@
-/*     $OpenBSD: aproc.h,v 1.45 2013/11/18 17:37:45 ratchov Exp $      */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef APROC_H
-#define APROC_H
-
-#include <sys/queue.h>
-
-#include "aparams.h"
-#include "file.h"
-
-struct abuf;
-struct aproc;
-struct file;
-
-struct aproc_ops {
-       /*
-        * Name of the ops structure, ie type of the unit.
-        */
-       char *name;
-
-       /*
-        * The state of the given input abuf changed (eg. an input block
-        * is ready for processing). This function must get the block
-        * from the input, process it and remove it from the buffer.
-        *
-        * Processing the block will result in a change of the state of
-        * OTHER buffers that are attached to the aproc (eg. the output
-        * buffer was filled), thus this routine MUST notify ALL aproc
-        * structures that are waiting on it; most of the time this
-        * means just calling abuf_flush() on the output buffer.
-        */
-       int (*in)(struct aproc *, struct abuf *);
-
-       /*
-        * The state of the given output abuf changed (eg. space for a
-        * new output block was made available) so processing can
-        * continue.  This function must process more input in order to
-        * fill the output block.
-        *
-        * Producing a block will result in the change of the state of
-        * OTHER buffers that are attached to the aproc, thus this
-        * routine MUST notify ALL aproc structures that are waiting on
-        * it; most of the time this means calling abuf_fill() on the
-        * source buffers.
-        *
-        * Before filling input buffers (using abuf_fill()), this
-        * routine must ALWAYS check for eof condition, and if needed,
-        * handle it appropriately and call abuf_hup() to free the input
-        * buffer.
-        */
-       int (*out)(struct aproc *, struct abuf *);
-
-       /*
-        * The input buffer is empty and we can no more receive data
-        * from it. The buffer will be destroyed as soon as this call
-        * returns so the abuf pointer will stop being valid after this
-        * call returns. There's no need to drain the buffer because the
-        * in() call-back was just called before.
-        *
-        * If this call reads and/or writes data on other buffers,
-        * abuf_flush() and abuf_fill() must be called appropriately.
-        */
-       void (*eof)(struct aproc *, struct abuf *);
-
-       /*
-        * The output buffer can no more accept data (it should be
-        * considered as full). After this function returns, it will be
-        * destroyed and the "abuf" pointer will be no more valid.
-        */
-       void (*hup)(struct aproc *, struct abuf *);
-
-       /*
-        * A new input was connected.
-        */
-       void (*newin)(struct aproc *, struct abuf *);
-
-       /*
-        * A new output was connected
-        */
-       void (*newout)(struct aproc *, struct abuf *);
-
-       /*
-        * Real-time record position changed (for input buffer),
-        * by the given amount of _frames_.
-        */
-       void (*ipos)(struct aproc *, struct abuf *, int);
-
-       /*
-        * Real-time play position changed (for output buffer),
-        * by the given amount of _frames_.
-        */
-       void (*opos)(struct aproc *, struct abuf *, int);
-
-       /*
-        * Destroy the aproc, called just before to free the
-        * aproc structure.
-        */
-       void (*done)(struct aproc *);
-};
-
-/*
- * The aproc structure represents a simple audio processing unit; they are
- * interconnected by abuf structures and form a kind of "circuit". The circuit
- * cannot have loops.
- */
-struct aproc {
-       char *name;                             /* for debug purposes */
-       struct aproc_ops *ops;                  /* call-backs */
-       LIST_HEAD(, abuf) ins;                  /* list of inputs */
-       LIST_HEAD(, abuf) outs;                 /* list of outputs */
-       unsigned int refs;                      /* extern references */
-#define APROC_ZOMB     1                       /* destroyed but not freed */
-#define APROC_QUIT     2                       /* try to terminate if unused */
-#define APROC_DROP     4                       /* xrun if capable */
-       unsigned int flags;                                     
-       union {                                 /* follow type-specific data */
-               struct {                        /* file/device io */
-                       struct file *file;      /* file to read/write */
-                       unsigned int partial;   /* bytes of partial frame */
-               } io;
-               struct {
-                       unsigned int idle;      /* frames since idleing */
-                       unsigned int round;     /* block size, for xruns */
-                       int lat;                /* current latency */
-                       int maxlat;             /* max latency allowed */
-                       unsigned int abspos;    /* frames produced */
-                       struct aproc *mon;      /* snoop output */
-                       unsigned int autovol;   /* adjust volume dynamically */
-                       int master;             /* master attenuation */
-               } mix;
-               struct {
-                       unsigned int idle;      /* frames since idleing */
-                       unsigned int round;     /* block size, for xruns */
-                       int lat;                /* current latency */
-                       int maxlat;             /* max latency allowed */
-                       unsigned int abspos;    /* frames consumed */
-               } sub;
-               struct {
-                       int delta;              /* time position */
-                       unsigned int bufsz;     /* buffer size (latency) */
-                       unsigned int pending;   /* uncommited samples */
-               } mon;
-               struct {
-#define RESAMP_NCTX    2
-                       unsigned int ctx_start;
-                       adata_t ctx[NCHAN_MAX * RESAMP_NCTX];
-                       unsigned int iblksz, oblksz;
-                       int diff;
-                       int idelta, odelta;     /* remainder of resamp_xpos */
-               } resamp;
-               struct {
-                       int bfirst;             /* bytes to skip at startup */
-                       unsigned int bps;       /* bytes per sample */
-                       unsigned int shift;     /* shift to get 32bit MSB */
-                       int sigbit;             /* sign bits to XOR */
-                       int bnext;              /* to reach the next byte */
-                       int snext;              /* to reach the next sample */
-               } conv;
-               struct {
-                       struct dev *dev;        /* controlled device */
-                       struct timo timo;       /* timout for throtteling */
-                       unsigned int fps;       /* MTC frames per second */
-#define MTC_FPS_24     0
-#define MTC_FPS_25     1
-#define MTC_FPS_30     3
-                       unsigned int fps_id;    /* one of above */
-                       unsigned int hr;        /* MTC hours */
-                       unsigned int min;       /* MTC minutes */
-                       unsigned int sec;       /* MTC seconds */
-                       unsigned int fr;        /* MTC frames */
-                       unsigned int qfr;       /* MTC quarter frames */
-                       int delta;              /* rel. to the last MTC tick */
-               } midi;
-       } u;
-};
-
-/*
- * Check if the given pointer is a valid aproc structure.
- *
- * aproc structures are not free()'d immediately, because
- * there may be pointers to them, instead the APROC_ZOMB flag
- * is set which means that they should not be used. When
- * aprocs reference counter reaches zero, they are actually
- * freed
- */
-#define APROC_OK(p) ((p) && !((p)->flags & APROC_ZOMB))
-
-
-struct aproc *aproc_new(struct aproc_ops *, char *);
-void aproc_del(struct aproc *);
-void aproc_dbg(struct aproc *);
-void aproc_setin(struct aproc *, struct abuf *);
-void aproc_setout(struct aproc *, struct abuf *);
-int aproc_inuse(struct aproc *);
-int aproc_depend(struct aproc *, struct aproc *);
-
-void aproc_ipos(struct aproc *, struct abuf *, int);
-void aproc_opos(struct aproc *, struct abuf *, int);
-
-struct aproc *rfile_new(struct file *);
-struct aproc *wfile_new(struct file *);
-struct aproc *mix_new(char *, int, unsigned int, unsigned int, unsigned int);
-struct aproc *sub_new(char *, int, unsigned int);
-struct aproc *resamp_new(char *, unsigned int, unsigned int);
-struct aproc *enc_new(char *, struct aparams *);
-struct aproc *dec_new(char *, struct aparams *);
-struct aproc *join_new(char *);
-struct aproc *mon_new(char *, unsigned int);
-
-int rfile_in(struct aproc *, struct abuf *);
-int rfile_out(struct aproc *, struct abuf *);
-void rfile_eof(struct aproc *, struct abuf *);
-void rfile_hup(struct aproc *, struct abuf *);
-void rfile_done(struct aproc *);
-int rfile_do(struct aproc *, unsigned int, unsigned int *);
-
-int wfile_in(struct aproc *, struct abuf *);
-int wfile_out(struct aproc *, struct abuf *);
-void wfile_eof(struct aproc *, struct abuf *);
-void wfile_hup(struct aproc *, struct abuf *);
-void wfile_done(struct aproc *);
-int wfile_do(struct aproc *, unsigned int, unsigned int *);
-
-void mix_setmaster(struct aproc *);
-void mix_clear(struct aproc *);
-void mix_prime(struct aproc *);
-void mix_quit(struct aproc *);
-void mix_drop(struct abuf *, int);
-void sub_silence(struct abuf *, int);
-void sub_clear(struct aproc *);
-void mon_snoop(struct aproc *, struct abuf *, unsigned int, unsigned int);
-void mon_clear(struct aproc *);
-
-#endif /* !defined(APROC_H) */
index 7fb89a6..010018b 100644 (file)
@@ -1,4 +1,4 @@
-.\"    $OpenBSD: aucat.1,v 1.106 2014/02/08 15:18:54 ratchov Exp $
+.\"    $OpenBSD: aucat.1,v 1.107 2015/01/21 08:43:55 ratchov Exp $
 .\"
 .\" Copyright (c) 2006 Alexandre Ratchov <alex@caoua.org>
 .\"
 .\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
 .\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
 .\"
-.Dd $Mdocdate: February 8 2014 $
+.Dd $Mdocdate: January 21 2015 $
 .Dt AUCAT 1
 .Os
 .Sh NAME
 .Nm aucat
-.Nd audio/MIDI stream manipulation tool
+.Nd audio files manipulation tool
 .Sh SYNOPSIS
 .Nm aucat
 .Bk -words
-.Op Fl dMn
-.Op Fl C Ar min : Ns Ar max
+.Op Fl dn
+.Op Dl b Ar size
 .Op Fl c Ar min : Ns Ar max
 .Op Fl e Ar enc
 .Op Fl f Ar device
 .Op Fl o Ar file
 .Op Fl q Ar port
 .Op Fl r Ar rate
-.Op Fl t Ar mode
 .Op Fl v Ar volume
-.Op Fl w Ar flag
-.Op Fl x Ar policy
 .Ek
 .Sh DESCRIPTION
 The
 .Nm
-utility can play, record, mix, and convert audio files.
+utility can play, record, mix, and process audio files
+on the fly.
 During playback,
 .Nm
-reads audio data concurrently from all played files, mixes it and sends
-the result to the device.
-Similarly, during recording it duplicates audio data recorded
-from the device and stores it into corresponding files.
-It can process audio data on the fly:
+reads audio data concurrently from all played files,
+mixes it and plays the result on the device.
+Similarly, it stores audio data recorded
+from the device into corresponding files.
+An
+.Em off-line
+mode could be used to process audio files without
+involving audio hardware.
+Processing includes:
 .Pp
 .Bl -bullet -offset indent -compact
 .It
 Change the sound encoding.
 .It
-Route the sound from one channel to another,
-join stereo or split mono.
+Route the sound from one channel to another.
 .It
 Control the per-file playback volume.
-.It
-Monitor the sound being played, allowing the playback mix
-to be recorded.
 .El
 .Pp
 Finally,
@@ -77,262 +75,132 @@ Start, stop and relocate playback and recording.
 .Pp
 The options are as follows:
 .Bl -tag -width Ds
+.It Fl Ar b size
+The buffer size of the audio device in frames.
+Default is 7680.
 .It Xo
-.Fl C Ar min : Ns Ar max ,
 .Fl c Ar min : Ns Ar max
 .Xc
-The range of stream channel numbers for recording and playback directions,
-respectively.
+The range of audio file channel numbers.
 The default is
 .Cm 0:1 ,
 i.e. stereo.
 .It Fl d
 Increase log verbosity.
 .It Fl e Ar enc
-Encoding of the playback or recording stream (see below).
-The default is signed, 16-bit, native byte order.
+Encoding of the audio file.
+The default is
+.Va s16 .
+Encoding names use the follwing scheme: signedness
+.Po
+.Va s
+or
+.Va u
+.Pc
+followed
+by the precision in bits, the byte-order
+.Po
+.Va le
+or
+.Va be
+.Pc ,
+the number of
+bytes per sample, and the alignment
+.Po
+.Va msb
+or
+.Va lsb
+.Pc .
+Only the signedness and the precision are mandatory.
+Examples:
+.Va u8 , s16le , s24le3 , s24le4lsb .
 .It Fl f Ar device
 Use this
 .Xr sndio 7
 audio device.
-Preceding per-device options apply to this device.
-Streams
-.Pq Fl io
-and control MIDI ports
-.Pq Fl q
-that are applied after will be attached to this device.
-Device mode and parameters are determined from streams
-attached to it.
+Device mode and parameters are determined from audio files.
+Default is
+.Pa default .
 .It Fl h Ar fmt
-File format of the playback or record stream (see below).
-The default is
-.Cm auto .
+Audio file type.
+The following file types are supported:
+.Bl -tag -width auto
+.It Ar raw
+Headerless file.
+.It Ar wav
+Microsoft WAV file format.
+.It Ar aiff
+Apple's audio interchange file format.
+.It Ar au
+Sun/NeXT audio file format.
+.It Ar auto
+Try to guess, depending on the file name.
+This is the default.
+.El
 .It Fl i Ar file
-Add this file to the list of streams to play.
+Play this audio file.
 If the option argument is
 .Sq -
 then standard input will be used.
 .It Fl j Ar flag
-Control whether stream channels are joined or expanded if
-the stream number of channels is not equal to the device number of channels.
+Control whether source channels are joined or expanded if
+they don't match the destination number of channels.
 If the flag is
-.Cm off
-then stream channels are routed to the corresponding
-device channel, possibly discarding channels not present in the device.
+.Cm off ,
+then each source channel is routed to a single destination channel,
+possibly discarding channels.
 If the flag is
 .Cm on ,
-then a single stream channel may be sent on multiple device channels,
-or multiple stream channels may be sent to a single device channel.
-For instance, this feature could be used to request mono streams to
-be sent on multiple outputs or to record a stereo input into a mono stream.
+then a single source may be sent to multiple destinations
+and multiple sources may be mixed into a single destination.
+For instance, this feature could be used to convert
+a stereo file into a mono file mixing left and right channels together.
 The default is
-.Cm on .
-.It Fl M
-Create a MIDI thru box
-.Pq i.e. MIDI-only pseudo device .
-It merges any number of MIDI inputs and broadcasts the result
-to any number of MIDI outputs, similarly to a hardware MIDI thru box.
-Only MIDI ports
-.Pq Fl q
-and MIDI files
-can be attached to it.
+.Cm off .
 .It Fl n
-Create a loopback pseudo audio device.
-Send input streams
-to the output, processing them on the fly.
-This pseudo-device is useful to mix, demultiplex, resample or re-encode
-audio files offline.
+Off-line mode.
+Read input files and store the result in the output files,
+processing them on the fly.
+This mode is useful to mix, demultiplex, resample or re-encode
+audio files off-line.
 It requires at least one input
 .Pq Fl i
 and one output
 .Pq Fl o .
 .It Fl o Ar file
-Add this file to the list of recording streams.
+Record into this audio file.
 If the option argument is
 .Sq -
 then standard output will be used.
 .It Fl q Ar port
-Allow audio device properties to be controlled
-through this MIDI port.
+Control audio device properties through this MIDI port.
 This includes per-stream volumes and the ability to
-synchronously start, stop and relocate streams created in
-MIDI Machine
-Control (MMC) slave mode
-.Pq Fl t .
+synchronously start, stop and relocate audio files.
 .It Fl r Ar rate
-Sample rate in Hertz of the stream.
+Sample rate in Hertz of the audio file.
 The default is
 .Cm 48000 .
-.It Fl t Ar mode
-Select the way streams are controlled by MIDI Machine Control (MMC)
-messages.
-If the mode is
-.Cm off
-(the default), then streams are not affected by MMC messages.
-If the mode is
-.Cm slave ,
-then streams are started synchronously by MMC start messages.
 .It Fl v Ar volume
-Software volume attenuation of the playback stream.
+Software volume attenuation of the file to play.
 The value must be between 1 and 127,
 corresponding to \-42dB and \-0dB attenuation in 1/3dB steps.
 The default is 127, i.e. no attenuation.
-.It Fl w Ar flag
-Control
-.Nm
-behaviour when the maximum volume of the hardware is reached
-and a new stream is connected.
-This happens only when stream volumes
-are not properly set using the
-.Fl v
-option.
-If the flag is
-.Cm on ,
-then the master volume (corresponding to the mix of all playback streams)
-is automatically adjusted to avoid clipping.
-Using
-.Cm off
-makes sense when all streams are recorded or produced with properly lowered
-volumes.
-The default is
-.Cm on .
-.It Fl x Ar policy
-Action when the output stream cannot accept
-recorded data fast enough or the input stream
-cannot provide data to play fast enough.
-If the policy is
-.Cm ignore
-(the default) then samples that cannot be written are discarded
-and samples that cannot be read are replaced by silence.
-If the policy is
-.Cm sync
-then recorded samples are discarded,
-but the same amount of silence will be written
-once the stream is unblocked, in order to reach the right position in time.
-Similarly silence is played, but the same amount of samples will be discarded
-once the stream is unblocked.
-If the policy is
-.Cm error
-then the stream is closed permanently.
-.Pp
-If a stream is created with the
-.Fl t
-option,
-the
-.Cm ignore
-action is disabled for any stream connected to it
-to ensure proper synchronization.
 .El
 .Pp
 On the command line,
-per-device parameters must precede the device definition
-.Pq Fl fMn ,
-and per-stream parameters
-.Pq Fl Ccehjmrtvx
-must precede the stream definition
+per-file parameters
+.Pq Fl cehjrv
+must precede the file definition
 .Pq Fl io .
-MIDI ports
-.Pq Fl q
-and stream definitions
-.Pq Fl io
-must follow the definition of the device
-.Pq Fl fMn
-to which they are attached.
-.Pp
-If no audio devices
-.Pq Fl fMn
-are specified,
-settings are applied as if
-the default device is specified.
 .Pp
 If
-.Nm aucat
+.Nm
 is sent
 .Dv SIGHUP ,
 .Dv SIGINT
 or
 .Dv SIGTERM ,
 it terminates recording to files.
-.Pp
-File formats are specified using the
-.Fl h
-option.
-The following file formats are supported:
-.Bl -tag -width s32lexxx -offset indent
-.It raw
-Headerless file.
-This format is recommended since it has no limitations.
-.It wav
-Microsoft WAVE file format.
-There are limitations inherent to the file format itself:
-not all encodings are supported,
-file sizes are limited to 2GB,
-and the file must support the
-.Xr lseek 2
-operation (e.g. pipes do not support it).
-.It auto
-Try to guess, depending on the file name.
-.El
-.Pp
-Encodings are specified using the
-.Fl e
-option.
-The following encodings are supported:
-.Pp
-.Bl -tag -width s32lexxx -offset indent -compact
-.It s8
-signed 8-bit
-.It u8
-unsigned 8-bit
-.It s16le
-signed 16-bit, little endian
-.It u16le
-unsigned 16-bit, little endian
-.It s16be
-signed 16-bit, big endian
-.It u16be
-unsigned 16-bit, big endian
-.It s24le
-signed 24-bit, stored in 4 bytes, little endian
-.It u24le
-unsigned 24-bit, stored in 4 bytes, little endian
-.It s24be
-signed 24-bit, stored in 4 bytes, big endian
-.It u24be
-unsigned 24-bit, stored in 4 bytes, big endian
-.It s32le
-signed 32-bit, little endian
-.It u32le
-unsigned 32-bit, little endian
-.It s32be
-signed 32-bit, big endian
-.It u32be
-unsigned 32-bit, big endian
-.It s24le3
-signed 24-bit, packed in 3 bytes, little endian
-.It u24le3
-unsigned 24-bit, packed in 3 bytes, big endian
-.It s24be3
-signed 24-bit, packed in 3 bytes, little endian
-.It u24be3
-unsigned 24-bit, packed in 3 bytes, big endian
-.It s20le3
-signed 20-bit, packed in 3 bytes, little endian
-.It u20le3
-unsigned 20-bit, packed in 3 bytes, big endian
-.It s20be3
-signed 20-bit, packed in 3 bytes, little endian
-.It u20be3
-unsigned 20-bit, packed in 3 bytes, big endian
-.It s18le3
-signed 18-bit, packed in 3 bytes, little endian
-.It u18le3
-unsigned 18-bit, packed in 3 bytes, big endian
-.It s18be3
-signed 18-bit, packed in 3 bytes, little endian
-.It u18be3
-unsigned 18-bit, packed in 3 bytes, big endian
-.El
 .Sh MIDI CONTROL
 .Nm
 can be controlled through MIDI
@@ -340,27 +208,21 @@ can be controlled through MIDI
 as follows:
 a MIDI channel is assigned to each stream, and the volume
 is changed using the standard volume controller (number 7).
-Similarly, when the audio client changes its volume,
-the same MIDI controller message is sent out; it can be used
-for instance for monitoring or as feedback for motorized
-faders.
 .Pp
 The master volume can be changed using the standard master volume
 system exclusive message.
 .Pp
-Streams created with the
-.Fl t
-option are controlled by the following MMC messages:
-.Bl -tag -width relocateXXX -offset indent
+All audio files are controlled by the following MMC messages:
+.Bl -tag -width relocate -offset indent
 .It relocate
-Files are relocated to the requested time position.
-If the requested position is beyond the end of file,
-playback of the file is temporarly disabled until a valid
-position is requested.
+All files are relocated to the requested time position.
+If it is beyond the end of a file, the file is temporarly
+disabled until a valid position is requested.
 .It start
-Files are started.
+Playback and/or recording is started.
 .It stop
-Files are stopped and rewound back to the starting position.
+Playback and/or recording is stopped and all files are rewound
+back to the starting position.
 .El
 .Pp
 MIDI control is intended to be used together with
@@ -371,7 +233,7 @@ the default
 and a MMC-controlled one
 .Va snd/0.mmc :
 .Bd -literal -offset indent
-$ sndiod -r 48000 -z 400 -s default -t slave -s mmc
+$ sndiod -r 48000 -z 480 -s default -t slave -s mmc
 .Ed
 .Pp
 Programs using
@@ -386,7 +248,7 @@ connected to the
 .Va midithru/0
 MIDI port:
 .Bd -literal -offset indent
-$ aucat -f snd/0.mmc -t slave -q midithru/0 -i file.wav
+$ aucat -f snd/0.mmc -q midithru/0 -i file.wav
 .Ed
 .Pp
 At this stage,
@@ -400,23 +262,22 @@ Furthermore, the MIDI sequencer could be configured to use the
 port as MTC clock source, assured to be synchronous to playback of
 .Pa file.wav .
 .Sh EXAMPLES
-Mix and play two stereo streams,
-the first at 48kHz and the second at 44.1kHz:
+Mix and play two files while recording a third file:
 .Bd -literal -offset indent
-$ aucat -r 48000 -i file1.raw -r 44100 -i file2.raw
+$ aucat -i file1.wav -i file2.wav -o file3.wav
 .Ed
 .Pp
 Record channels 2 and 3 into one stereo file and
-channels 6 and 7 into another stereo file using a 96kHz sampling rate for
-both:
+channels 6 and 7 into another stereo file using a 44.1kHz sampling
+rate for both:
 .Bd -literal -offset indent
-$ aucat -j off -r 96000 -C 2:3 -o file1.raw -C 6:7 -o file2.raw
+$ aucat -r 44100 -c 2:3 -o file1.wav -c 6:7 -o file2.wav
 .Ed
 .Pp
 Split a stereo file into two mono files:
 .Bd -literal -offset indent
-$ aucat -n -j off -i stereo.wav -C 0:0 -o left.wav -C 1:1 \e
-       -o right.wav
+$ aucat -n -i stereo.wav -c 0:0 -o left.wav \e
+       -c 1:1 -o right.wav
 .Ed
 .Sh SEE ALSO
 .Xr audioctl 1 ,
@@ -426,9 +287,14 @@ $ aucat -n -j off -i stereo.wav -C 0:0 -o left.wav -C 1:1 \e
 .Xr audio 4 ,
 .Xr sndio 7
 .Sh BUGS
-Resampling is low quality; down-sampling especially should be avoided
-when recording.
+Resampling is low quality.
 .Pp
-Processing is done using 16-bit arithmetic,
-thus samples with more than 16 bits are rounded.
-16 bits (i.e. 97dB dynamic) are largely enough for most applications though.
+There are limitations inherent to the
+.Ar wav ,
+.Ar aiff ,
+and
+.Ar au
+file formats: not all encodings are supported,
+file sizes are limited to 2GB, and the files must support the
+.Xr lseek 2
+operation (e.g. pipes do not support it).
index ea3a788..70fbe80 100644 (file)
@@ -1,6 +1,5 @@
-/*     $OpenBSD: aucat.c,v 1.145 2015/01/16 06:40:05 deraadt Exp $     */
 /*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
+ * Copyright (c) 2008-2014 Alexandre Ratchov <alex@caoua.org>
  *
  * Permission to use, copy, modify, and distribute this software for any
  * purpose with or without fee is hereby granted, provided that the above
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <sys/queue.h>
-#include <sys/stat.h>
-#include <sys/types.h>
-#include <sys/resource.h>
-
-#include <err.h>
-#include <errno.h>
 #include <fcntl.h>
-#include <grp.h>
-#include <limits.h>
-#include <pwd.h>
+#include <errno.h>
+#include <poll.h>
 #include <signal.h>
 #include <sndio.h>
 #include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <unistd.h>
-
 #include "abuf.h"
-#include "amsg.h"
-#include "aparams.h"
-#include "aproc.h"
-#include "conf.h"
-#include "dev.h"
-#include "midi.h"
-#include "wav.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
+#include "afile.h"
+#include "dsp.h"
+#include "sysex.h"
+#include "utils.h"
+
+/*
+ * masks to extract command and channel of status byte
+ */
+#define MIDI_CMDMASK   0xf0
+#define MIDI_CHANMASK  0x0f
+
+/*
+ * MIDI status bytes of voice messages
+ */
+#define MIDI_NOFF      0x80            /* note off */
+#define MIDI_NON       0x90            /* note on */
+#define MIDI_KAT       0xa0            /* key after touch */
+#define MIDI_CTL       0xb0            /* controller */
+#define MIDI_PC                0xc0            /* program change */
+#define MIDI_CAT       0xd0            /* channel after touch */
+#define MIDI_BEND      0xe0            /* pitch bend */
+#define MIDI_ACK       0xfe            /* active sensing message */
+
+/*
+ * MIDI controller numbers
+ */
+#define MIDI_CTL_VOL   7
+
+/*
+ * Max coarse value
+ */
+#define MIDI_MAXCTL    127
+
+/*
+ * MIDI status bytes for sysex
+ */
+#define MIDI_SX_START  0xf0
+#define MIDI_SX_STOP   0xf7
+
+/*
+ * audio device defaults
+ */
+#define DEFAULT_RATE           48000
+#define DEFAULT_BUFSZ_MS       200
 
-#define PROG_AUCAT     "aucat"
+struct slot {
+       struct slot *next;              /* next on the play list */
+       int vol;                        /* dynamic range */
+       int volctl;                     /* volume in the 0..127 range */
+       struct abuf buf;                /* file i/o buffer */
+       int bpf;                        /* bytes per frame */
+       int cmin, cmax;                 /* file channel range */
+       struct cmap cmap;               /* channel mapper state */
+       struct resamp resamp;           /* resampler state */
+       struct conv conv;               /* format encoder state */
+       int join;                       /* channel join factor */
+       int expand;                     /* channel expand factor */
+       void *resampbuf, *convbuf;      /* conversion tmp buffers */
+       int dup;                        /* mono-to-stereo and alike */
+       int round;                      /* slot-side block size */
+       int mode;                       /* MODE_{PLAY,REC} */
+#define SLOT_CFG       0               /* buffers not allocated yet */
+#define SLOT_INIT      1               /* not trying to do anything */
+#define SLOT_RUN       2               /* playing/recording */
+#define SLOT_STOP      3               /* draining (play only) */
+       int pstate;                     /* one of above */
+       struct afile afile;                     /* file desc & friends */
+};
 
 /*
- * sample rate if no ``-r'' is used
+ * device properties
  */
-#ifndef DEFAULT_RATE
-#define DEFAULT_RATE   48000
+unsigned int dev_mode;                 /* bitmap of SIO_{PLAY,REC} */
+unsigned int dev_bufsz;                        /* device buffer size */
+unsigned int dev_round;                        /* device block size */
+int dev_rate;                          /* device sample rate (Hz) */
+unsigned int dev_pchan, dev_rchan;     /* play & rec channels count */
+adata_t *dev_pbuf, *dev_rbuf;          /* play & rec buffers */
+unsigned int dev_mmcpos;               /* last MMC position */
+#define DEV_STOP       0               /* stopped */
+#define DEV_START      1               /* started */
+unsigned int dev_pstate;               /* one of above */
+char *dev_name;                                /* device sndio(7) name */
+char *dev_port;                                /* control port sndio(7) name */
+struct sio_hdl *dev_sh;                        /* device handle */
+struct mio_hdl *dev_mh;                        /* MIDI control port handle */
+unsigned int dev_volctl = MIDI_MAXCTL; /* master volume */
+
+/*
+ * MIDI parser state
+ */
+#define MIDI_MSGMAX    32              /* max size of MIDI msg */
+unsigned char dev_msg[MIDI_MSGMAX];    /* parsed input message */
+unsigned int dev_mst;                  /* input MIDI running status */
+unsigned int dev_mused;                        /* bytes used in ``msg'' */
+unsigned int dev_midx;                 /* current ``msg'' size */
+unsigned int dev_mlen;                 /* expected ``msg'' length */
+unsigned int dev_prime;                        /* blocks to write to start */
+
+unsigned int log_level = 1;
+volatile sig_atomic_t quit_flag = 0;
+struct slot *slot_list = NULL;
+
+/*
+ * length of voice and common MIDI messages (status byte included)
+ */
+unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
+unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
+
+char usagestr[] = "usage: aucat [-d] [-b nframes] "
+    "[-c min:max] [-e enc] [-f device]\n\t"
+    "[-j flag] [-q port] [-r rate] [-v volume]\n";
+
+static void
+slot_log(struct slot *s)
+{
+#ifdef DEBUG
+       static char *pstates[] = {
+               "cfg", "ini", "run", "stp"
+       };
+#endif
+       log_puts(s->afile.path);
+#ifdef DEBUG
+       if (log_level >= 3) {
+               log_puts(",pst=");
+               log_puts(pstates[s->pstate]);
+       }
+#endif
+}
+
+static void
+slot_flush(struct slot *s)
+{
+       int todo, count, n;
+       unsigned char *data;
+
+       todo = s->buf.used;
+       while (todo > 0) {
+               data = abuf_rgetblk(&s->buf, &count);
+               if (count > todo)
+                       count = todo;
+               n = afile_write(&s->afile, data, count);
+               if (n == 0) {
+                       slot_log(s);
+                       log_puts(": can't write, disabled\n");
+                       s->pstate = SLOT_INIT;
+                       return;
+               }
+               abuf_rdiscard(&s->buf, n);
+               todo -= n;
+       }
+}
+
+static void
+slot_fill(struct slot *s)
+{
+       int todo, count, n;
+       unsigned char *data;
+
+       todo = s->buf.len;
+       while (todo > 0) {
+               data = abuf_wgetblk(&s->buf, &count);
+               if (count > todo)
+                       count = todo;
+               n = afile_read(&s->afile, data, count);
+               if (n == 0) {
+#ifdef DEBUG
+                       if (log_level >= 3) {
+                               slot_log(s);
+                               log_puts(": eof reached, stopping\n");
+                       }
+#endif
+                       s->pstate = SLOT_STOP;
+                       break;
+               }
+               abuf_wcommit(&s->buf, n);
+               todo -= n;
+       }
+}
+
+static int
+slot_new(char *path, int mode, struct aparams *par, int hdr,
+    int cmin, int cmax, int rate, int dup, int vol)
+{
+       struct slot *s;
+
+       s = xmalloc(sizeof(struct slot));
+       if (!afile_open(&s->afile, path, hdr,
+               mode == SIO_PLAY ? AFILE_FREAD : AFILE_FWRITE,
+               par, rate, cmax - cmin + 1)) {
+               xfree(s);
+               return 0;
+       }
+       s->cmin = cmin;
+       s->cmax = cmin + s->afile.nch - 1;
+       s->dup = dup;
+       s->vol = MIDI_TO_ADATA(vol);
+       s->mode = mode;
+       s->pstate = SLOT_CFG;
+       if (log_level >= 2) {
+               slot_log(s);
+               log_puts(": ");
+               log_puts(s->mode == SIO_PLAY ? "play" : "rec");
+               log_puts(", chan ");
+               log_putu(s->cmin);
+               log_puts(":");
+               log_putu(s->cmax);
+               log_puts(", ");
+               log_putu(s->afile.rate);
+               log_puts("Hz, ");
+               switch (s->afile.fmt) {
+               case AFILE_FMT_PCM:
+                       aparams_log(&s->afile.par);
+                       break;
+               case AFILE_FMT_ULAW:
+                       log_puts("ulaw");
+                       break;
+               case AFILE_FMT_ALAW:
+                       log_puts("alaw");
+                       break;
+               case AFILE_FMT_FLOAT:
+                       log_puts("f32le");
+                       break;
+               }
+               if (s->mode == SIO_PLAY && s->afile.endpos >= 0) {
+                       log_puts(", bytes ");
+                       log_puti(s->afile.startpos);
+                       log_puts("..");
+                       log_puti(s->afile.endpos);
+               }
+               log_puts("\n");
+       }
+       s->next = slot_list;
+       slot_list = s;
+       return 1;
+}
+
+static void
+slot_init(struct slot *s)
+{
+       unsigned int slot_nch, bufsz;
+
+#ifdef DEBUG
+       if (s->pstate != SLOT_CFG) {
+               slot_log(s);
+               log_puts(": slot_init: wrong state\n");
+               panic();
+       }
+#endif
+       s->bpf = s->afile.par.bps * (s->cmax - s->cmin + 1);
+       s->round = (dev_round * s->afile.rate + dev_rate / 2) / dev_rate;
+
+       bufsz = s->round * (dev_bufsz / dev_round);
+       bufsz -= bufsz % s->round;
+       if (bufsz == 0)
+               bufsz = s->round;
+       abuf_init(&s->buf, bufsz * s->bpf);
+#ifdef DEBUG
+       if (log_level >= 3) {
+               slot_log(s);
+               log_puts(": allocated ");
+               log_putu(bufsz);
+               log_puts(" frame buffer\n");
+       }
+#endif
+
+       slot_nch = s->cmax - s->cmin + 1;
+       s->convbuf = NULL;
+       s->resampbuf = NULL;
+       s->join = 1;
+       s->expand = 1;
+       if (s->mode & SIO_PLAY) {
+               if (s->dup) {
+                       if (dev_pchan > slot_nch)
+                               s->expand = dev_pchan / slot_nch;
+                       else if (dev_pchan < slot_nch)
+                               s->join = slot_nch / dev_pchan;
+               }
+               cmap_init(&s->cmap,
+                   s->cmin, s->cmax,
+                   s->cmin, s->cmax,
+                   0, dev_pchan - 1,
+                   0, dev_pchan - 1);
+               if (s->afile.fmt != AFILE_FMT_PCM || !aparams_native(&s->afile.par)) {
+                       dec_init(&s->conv, &s->afile.par, slot_nch);
+                       s->convbuf =
+                           xmalloc(s->round * slot_nch * sizeof(adata_t));
+               }
+               if (s->afile.rate != dev_rate) {
+                       resamp_init(&s->resamp, s->round, dev_round,
+                           slot_nch);
+                       s->resampbuf =
+                           xmalloc(dev_round * slot_nch * sizeof(adata_t));
+               }
+       }
+       if (s->mode & SIO_REC) {
+               if (s->dup) {
+                       if (dev_rchan > slot_nch)
+                               s->join = dev_rchan / slot_nch;
+                       else if (dev_rchan < slot_nch)
+                               s->expand = slot_nch / dev_rchan;
+               }
+               cmap_init(&s->cmap,
+                   0, dev_rchan - 1,
+                   0, dev_rchan - 1,
+                   s->cmin, s->cmax,
+                   s->cmin, s->cmax);
+               if (s->afile.rate != dev_rate) {
+                       resamp_init(&s->resamp, dev_round, s->round,
+                           slot_nch);
+                       s->resampbuf =
+                           xmalloc(dev_round * slot_nch * sizeof(adata_t));
+               }
+               if (!aparams_native(&s->afile.par)) {
+                       enc_init(&s->conv, &s->afile.par, slot_nch);
+                       s->convbuf =
+                           xmalloc(s->round * slot_nch * sizeof(adata_t));
+               }
+       }
+       s->pstate = SLOT_INIT;
+#ifdef DEBUG
+       if (log_level >= 3) {
+               slot_log(s);
+               log_puts(": chain initialized\n");
+       }
+#endif
+}
+
+static void
+slot_start(struct slot *s, unsigned int mmc)
+{
+       off_t mmcpos;
+
+#ifdef DEBUG
+       if (s->pstate != SLOT_INIT) {
+               slot_log(s);
+               log_puts(": slot_start: wrong state\n");
+               panic();
+       }
+#endif
+       mmcpos = ((off_t)mmc * s->afile.rate / MTC_SEC) * s->bpf;
+       if (!afile_seek(&s->afile, mmcpos)) {
+               s->pstate = SLOT_INIT;
+               return;
+       }
+       s->pstate = SLOT_RUN;
+       if (s->mode & SIO_PLAY)
+               slot_fill(s);
+#ifdef DEBUG
+       if (log_level >= 2) {
+               slot_log(s);
+               log_puts(": started\n");
+       }
+#endif
+}
+
+static void
+slot_stop(struct slot *s)
+{
+       if (s->pstate == SLOT_INIT)
+               return;
+       if (s->mode & SIO_REC)
+               slot_flush(s);
+       if (s->mode & SIO_PLAY)
+               s->buf.used = s->buf.start = 0;
+       s->pstate = SLOT_INIT;
+#ifdef DEBUG
+       if (log_level >= 2) {
+               slot_log(s);
+               log_puts(": stopped\n");
+       }
+#endif
+}
+
+static void
+slot_del(struct slot *s)
+{
+       struct slot **ps;
+
+       if (s->pstate != SLOT_CFG) {
+               slot_stop(s);
+               afile_close(&s->afile);
+#ifdef DEBUG
+               if (log_level >= 3) {
+                       slot_log(s);
+                       log_puts(": closed\n");
+               }
 #endif
+               abuf_done(&s->buf);
+               if (s->resampbuf)
+                       xfree(s->resampbuf);
+               if (s->convbuf)
+                       xfree(s->convbuf);
+       }
+       for (ps = &slot_list; *ps != s; ps = &(*ps)->next)
+               ; /* nothing */
+       *ps = s->next;
+       xfree(s);
+}
+
+static int 
+play_filt_resamp(struct slot *s, void *res_in, void *out, int todo)
+{
+       int i, offs, vol, nch;
+       void *in;
+
+       if (s->resampbuf) {
+               todo = resamp_do(&s->resamp,
+                   res_in, s->resampbuf, todo);
+               in = s->resampbuf;
+       } else
+               in = res_in;
+
+       nch = s->cmap.nch;
+       vol = s->vol / s->join; /* XXX */
+       cmap_add(&s->cmap, in, out, vol, todo);
+
+       offs = 0;
+       for (i = s->join - 1; i > 0; i--) {
+               offs += nch;
+               cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, todo);
+       }
+       offs = 0;
+       for (i = s->expand - 1; i > 0; i--) {
+               offs += nch;
+               cmap_add(&s->cmap, in, (adata_t *)out + offs, vol, todo);
+       }
+       return todo;
+}
+
+static int 
+play_filt_dec(struct slot *s, void *in, void *out, int todo)
+{
+       void *tmp;
+
+       tmp = s->convbuf;
+       if (tmp) {
+               switch (s->afile.fmt) {
+               case AFILE_FMT_PCM:
+                       dec_do(&s->conv, in, tmp, todo);
+                       break;
+               case AFILE_FMT_ULAW:
+                       dec_do_ulaw(&s->conv, in, tmp, todo, 0);
+                       break;
+               case AFILE_FMT_ALAW:
+                       dec_do_ulaw(&s->conv, in, tmp, todo, 1);
+                       break;
+               case AFILE_FMT_FLOAT:
+                       dec_do_float(&s->conv, in, tmp, todo);
+                       break;
+               }
+       }
+       return play_filt_resamp(s, tmp ? tmp : in, out, todo);
+}
 
 /*
- * block size if neither ``-z'' nor ``-b'' is used
+ * Mix as many as possible frames (but not more than a block) from the
+ * slot buffer to the given location. Return the number of frames mixed
+ * in the output buffer
  */
-#ifndef DEFAULT_ROUND
-#define DEFAULT_ROUND  960
+static int
+slot_mix_badd(struct slot *s, adata_t *odata)
+{
+       adata_t *idata;
+       int icount, todo, done;
+
+       idata = (adata_t *)abuf_rgetblk(&s->buf, &icount);
+       todo = icount / s->bpf;
+       if (todo > s->round)
+               todo = s->round;
+#ifdef DEBUG
+       if (todo == 0) {
+               log_puts("slot_mix_badd: not enough data\n");
+               panic();
+       }
 #endif
+       done = play_filt_dec(s, idata, odata, todo);
+       abuf_rdiscard(&s->buf, todo * s->bpf);
+       return done;
+}
+
+static int 
+rec_filt_resamp(struct slot *s, void *in, void *res_out, int todo)
+{
+       int i, vol, offs, nch;
+       void *out = res_out;
+
+       out = (s->resampbuf) ? s->resampbuf : res_out;
+
+       nch = s->cmap.nch;
+       vol = ADATA_UNIT / s->join;
+       cmap_copy(&s->cmap, in, out, vol, todo);
+
+       offs = 0;
+       for (i = s->join - 1; i > 0; i--) {
+               offs += nch;
+               cmap_add(&s->cmap, (adata_t *)in + offs, out, vol, todo);
+       }
+       offs = 0;
+       for (i = s->expand - 1; i > 0; i--) {
+               offs += nch;
+               cmap_copy(&s->cmap, in, (adata_t *)out + offs, vol, todo);
+       }
+       if (s->resampbuf) {
+               todo = resamp_do(&s->resamp,
+                   s->resampbuf, res_out, todo);
+       }
+       return todo;
+}
+
+static int 
+rec_filt_enc(struct slot *s, void *in, void *out, int todo)
+{
+       void *tmp;
+
+       tmp = s->convbuf;
+       todo = rec_filt_resamp(s, in, tmp ? tmp : out, todo);
+       if (tmp)
+               enc_do(&s->conv, tmp, out, todo);
+       return todo;
+}
 
 /*
- * buffer size if neither ``-z'' nor ``-b'' is used
+ * Copy "todo" frames from the given buffer to the slot buffer,
+ * but not more than a block.
  */
-#ifndef DEFAULT_BUFSZ
-#define DEFAULT_BUFSZ  7860
+static void
+slot_sub_bcopy(struct slot *s, adata_t *idata, int todo)
+{
+       adata_t *odata;
+       int ocount;
+
+       odata = (adata_t *)abuf_wgetblk(&s->buf, &ocount);
+#ifdef DEBUG
+       if (ocount < s->round * s->bpf) {
+               log_puts("slot_sub_bcopy: not enough space\n");
+               panic();
+       }
 #endif
+       ocount = rec_filt_enc(s, idata, odata, todo);
+       abuf_wcommit(&s->buf, ocount * s->bpf);
+}
+
+static int
+dev_open(char *dev, int mode, int bufsz, char *port)
+{
+       int rate, pmax, rmax;
+       struct sio_par par;
+       struct slot *s;
+
+       if (port) {
+               dev_port = port;
+               dev_mh = mio_open(dev_port, MIO_IN, 0);
+               if (dev_mh == NULL) {
+                       log_puts(port);
+                       log_puts(": couldn't open midi port\n");
+                       return 0;
+               }
+       } else
+               dev_mh = NULL;
+
+       dev_name = dev;
+       dev_sh = sio_open(dev, mode, 0);
+       if (dev_sh == NULL) {
+               log_puts(dev_name);
+               log_puts(": couldn't open audio device\n");
+               return 0;
+       }
+
+       rate = pmax = rmax = 0;
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (s->afile.rate > rate)
+                       rate = s->afile.rate;
+               if (s->mode == SIO_PLAY) {
+                       if (s->cmax > pmax)
+                               pmax = s->cmax;
+               }
+               if (s->mode == SIO_REC) {
+                       if (s->cmax > rmax)
+                               rmax = s->cmax;
+               }
+       }
+       sio_initpar(&par);
+       par.bits = ADATA_BITS;
+       par.bps = sizeof(adata_t);
+       par.msb = 0;
+       par.le = SIO_LE_NATIVE;
+       if (mode & SIO_PLAY)
+               par.pchan = pmax + 1;
+       if (mode & SIO_REC)
+               par.rchan = rmax + 1;
+       par.appbufsz = bufsz > 0 ? bufsz : rate * DEFAULT_BUFSZ_MS / 1000;
+       if (!sio_setpar(dev_sh, &par) || !sio_getpar(dev_sh, &par)) {
+               log_puts(dev_name);
+               log_puts(": couldn't set audio params\n");
+               return 0;
+       }
+       if (par.bits != ADATA_BITS ||
+           par.bps != sizeof(adata_t) ||
+           par.le != SIO_LE_NATIVE ||
+           (par.bps != SIO_BPS(par.bits) && par.msb)) {
+               log_puts(dev_name);
+               log_puts(": unsupported audio params\n");
+               return 0;
+       }
+       dev_mode = mode;
+       dev_rate = par.rate;
+       dev_bufsz = par.bufsz;
+       dev_round = par.round;
+       if (mode & SIO_PLAY) {
+               dev_pchan = par.pchan;
+               dev_pbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
+       }
+       if (mode & SIO_REC) {
+               dev_rchan = par.rchan;
+               dev_rbuf = xmalloc(sizeof(adata_t) * dev_rchan * dev_round);
+       }
+       dev_mmcpos = 0;
+       dev_pstate = DEV_STOP;
+       if (log_level >= 2) {
+               log_puts(dev_name);
+               log_puts(": ");
+               log_putu(dev_rate);
+               log_puts("Hz");
+               if (dev_mode & SIO_PLAY) {
+                       log_puts(", play 0:");
+                       log_puti(dev_pchan - 1);
+               }
+               if (dev_mode & SIO_REC) {
+                       log_puts(", rec 0:");
+                       log_puti(dev_rchan - 1);
+               }
+               log_puts(", ");
+               log_putu(dev_bufsz / dev_round);
+               log_puts(" blocks of ");
+               log_putu(dev_round);
+               log_puts(" frames\n");
+       }
+       return 1;
+}
+
+static void
+dev_close(void)
+{
+       sio_close(dev_sh);
+       if (dev_mh)
+               mio_close(dev_mh);
+       if (dev_mode & SIO_PLAY)
+               xfree(dev_pbuf);
+       if (dev_mode & SIO_REC)
+               xfree(dev_rbuf);
+}
 
-void sigint(int);
-void sigusr1(int);
-void sigusr2(int);
-void opt_ch(struct aparams *);
-void opt_enc(struct aparams *);
-int opt_hdr(void);
-int opt_mmc(void);
-int opt_onoff(void);
-int opt_xrun(void);
-void setsig(void);
-void unsetsig(void);
-struct dev *mkdev(char *, int, int, int, int, int);
+static void
+dev_master(int val)
+{
+       struct slot *s;
+       int mastervol, slotvol;
 
+       mastervol = MIDI_TO_ADATA(dev_volctl);
+       for (s = slot_list; s != NULL; s = s->next) {
+               slotvol = MIDI_TO_ADATA(val);
+               s->vol = ADATA_MUL(mastervol, slotvol);
+       }
 #ifdef DEBUG
-volatile sig_atomic_t debug_level = 1;
+       if (log_level >= 3) {
+               log_puts("master volume set to ");
+               log_putu(val);
+               log_puts("\n");
+       }
 #endif
-volatile sig_atomic_t quit_flag = 0;
+}
 
-char aucat_usage[] = "usage: " PROG_AUCAT " [-dMn]\n\t"
-    "[-C min:max] [-c min:max] [-e enc] [-f device]\n\t"
-    "[-h fmt] [-i file] [-j flag] [-o file] [-q port]\n\t"
-    "[-r rate] [-t mode] [-v volume] [-w flag] [-x policy]\n";
+static void
+dev_slotvol(int midich, int val)
+{
+       struct slot *s;
+       int mastervol, slotvol;
+
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (midich == 0) {
+                       mastervol = MIDI_TO_ADATA(dev_volctl);
+                       slotvol = MIDI_TO_ADATA(val);
+                       s->vol = ADATA_MUL(mastervol, slotvol);
+#ifdef DEBUG
+                       if (log_level >= 3) {
+                               slot_log(s);
+                               log_puts(": volume set to ");
+                               log_putu(val);
+                               log_puts("\n");
+                       }
+#endif
+                       break;
+               }
+       }
+}
 
 /*
- * SIGINT handler, it raises the quit flag. If the flag is already set,
- * that means that the last SIGINT was not handled, because the process
- * is blocked somewhere, so exit.
+ * start all slots simultaneously
  */
-void
-sigint(int s)
+static void
+dev_mmcstart(void)
 {
-       if (quit_flag)
-               _exit(1);
-       quit_flag = 1;
-}
+       struct slot *s;
 
+       if (dev_pstate == DEV_STOP) {
+               dev_pstate = DEV_START;
+               for (s = slot_list; s != NULL; s = s->next)
+                       slot_start(s, dev_mmcpos);
+               dev_prime = (dev_mode & SIO_PLAY) ? dev_bufsz / dev_round : 0;
+               sio_start(dev_sh);
+               if (log_level >= 2)
+                       log_puts("started\n");
+       } else {
 #ifdef DEBUG
+               if (log_level >= 3)
+                       log_puts("ignoring mmc start\n");
+#endif
+       }
+}
+
 /*
- * Increase debug level on SIGUSR1.
+ * stop all slots simultaneously
  */
-void
-sigusr1(int s)
+static void
+dev_mmcstop(void)
 {
-       if (debug_level < 4)
-               debug_level++;
+       struct slot *s;
+
+       if (dev_pstate == DEV_START) {
+               dev_pstate = DEV_STOP;
+               for (s = slot_list; s != NULL; s = s->next)
+                       slot_stop(s);
+               sio_stop(dev_sh);
+               if (log_level >= 2)
+                       log_puts("stopped\n");
+       } else {
+#ifdef DEBUG
+               if (log_level >= 3)
+                       log_puts("ignored mmc stop\n");
+#endif
+       }
 }
 
 /*
- * Decrease debug level on SIGUSR2.
+ * relocate all slots simultaneously
  */
-void
-sigusr2(int s)
+static void
+dev_mmcloc(unsigned int mmc)
 {
-       if (debug_level > 0)
-               debug_level--;
+       if (dev_mmcpos == mmc)
+               return;
+       dev_mmcpos = mmc;
+       if (log_level >= 2) {
+               log_puts("relocated to ");
+               log_putu((dev_mmcpos / (MTC_SEC * 3600)) % 24);
+               log_puts(":");
+               log_putu((dev_mmcpos / (MTC_SEC * 60)) % 60);
+               log_puts(":");
+               log_putu((dev_mmcpos / (MTC_SEC)) % 60);
+               log_puts(".");
+               log_putu((dev_mmcpos / (MTC_SEC / 100)) % 100);
+               log_puts("\n");
+       }
+       if (dev_pstate == DEV_START) {
+               dev_mmcstop();
+               dev_mmcstart();
+       }
 }
-#endif
 
-void
-opt_ch(struct aparams *par)
+static void
+dev_imsg(unsigned char *msg, unsigned int len)
 {
-       char *next, *end;
-       long cmin, cmax;
+       struct sysex *x;
+       unsigned int fps, chan;
 
-       errno = 0;
-       cmin = strtol(optarg, &next, 10);
-       if (next == optarg || *next != ':')
-               goto failed;
-       cmax = strtol(++next, &end, 10);
-       if (end == next || *end != '\0')
-               goto failed;
-       if (cmin < 0 || cmax < cmin || cmax > NCHAN_MAX)
-               goto failed;
-       par->cmin = cmin;
-       par->cmax = cmax;
-       return;
-failed:
-       errx(1, "%s: bad channel range", optarg);
+       if ((msg[0] & MIDI_CMDMASK) == MIDI_CTL && msg[1] == MIDI_CTL_VOL) {
+               chan = msg[0] & MIDI_CHANMASK;
+               dev_slotvol(chan, msg[2]);
+               return;
+       }
+       x = (struct sysex *)msg;
+       if (x->start != SYSEX_START)
+               return;
+       if (len < SYSEX_SIZE(empty))
+               return;
+       if (x->type != SYSEX_TYPE_RT)
+               return;
+       if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
+               if (len == SYSEX_SIZE(master))
+                       dev_master(x->u.master.coarse);
+               return;
+       }
+       if (x->id0 != SYSEX_MMC)
+               return;
+       switch (x->id1) {
+       case SYSEX_MMC_STOP:
+               if (len != SYSEX_SIZE(stop))
+                       return;
+               dev_mmcstop();
+               break;
+       case SYSEX_MMC_START:
+               if (len != SYSEX_SIZE(start))
+                       return;
+               dev_mmcstart();
+               break;
+       case SYSEX_MMC_LOC:
+               if (len != SYSEX_SIZE(loc) ||
+                   x->u.loc.len != SYSEX_MMC_LOC_LEN ||
+                   x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
+                       return;
+               switch (x->u.loc.hr >> 5) {
+               case MTC_FPS_24:
+                       fps = 24;
+                       break;
+               case MTC_FPS_25:
+                       fps = 25;
+                       break;
+               case MTC_FPS_30:
+                       fps = 30;
+                       break;
+               default:
+                       dev_mmcstop();
+                       return;
+               }
+               dev_mmcloc((x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
+                   x->u.loc.min * 60 * MTC_SEC +
+                   x->u.loc.sec * MTC_SEC +
+                   x->u.loc.fr * (MTC_SEC / fps) +
+                   x->u.loc.cent * (MTC_SEC / 100 / fps));
+               break;
+       }
 }
 
-void
-opt_enc(struct aparams *par)
+/*
+ * parse then given data chunk, and calling imsg() for each message
+ */
+static void
+midi_in(unsigned char *idata, int icount)
 {
-       int len;
+       int i;
+       unsigned char c;
 
-       len = aparams_strtoenc(par, optarg);
-       if (len == 0 || optarg[len] != '\0')
-               errx(1, "%s: bad encoding", optarg);
+       for (i = 0; i < icount; i++) {
+               c = *idata++;
+               if (c >= 0xf8) {
+                       /* we don't use reat-time events */
+               } else if (c == SYSEX_END) {
+                       if (dev_mst == SYSEX_START) {
+                               dev_msg[dev_midx++] = c;
+                               dev_imsg(dev_msg, dev_midx);
+                       }
+                       dev_mst = 0;
+                       dev_midx = 0;
+               } else if (c >= 0xf0) {
+                       dev_msg[0] = c;
+                       dev_mlen = common_len[c & 7];
+                       dev_mst = c;
+                       dev_midx = 1;
+               } else if (c >= 0x80) {
+                       dev_msg[0] = c;
+                       dev_mlen = voice_len[(c >> 4) & 7];
+                       dev_mst = c;
+                       dev_midx = 1;
+               } else if (dev_mst) {
+                       if (dev_midx == 0 && dev_mst != SYSEX_START)
+                               dev_msg[dev_midx++] = dev_mst;
+                       dev_msg[dev_midx++] = c;
+                       if (dev_midx == dev_mlen) {
+                               dev_imsg(dev_msg, dev_midx);
+                               if (dev_mst >= 0xf0)
+                                       dev_mst = 0;
+                               dev_midx = 0;
+                       } else if (dev_midx == MIDI_MSGMAX) {
+                               /* sysex too long */
+                               dev_mst = 0;
+                       }
+               }
+       }
 }
 
-int
-opt_hdr(void)
+static int
+slot_list_mix(unsigned int round, unsigned int pchan, adata_t *pbuf)
 {
-       if (strcmp("auto", optarg) == 0)
-               return HDR_AUTO;
-       if (strcmp("raw", optarg) == 0)
-               return HDR_RAW;
-       if (strcmp("wav", optarg) == 0)
-               return HDR_WAV;
-       errx(1, "%s: bad header specification", optarg);
+       unsigned int done, n;
+       struct slot *s;
+
+       memset(pbuf, 0, pchan * round * sizeof(adata_t));
+       done = 0;
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (s->pstate == SLOT_INIT || !(s->mode & SIO_PLAY))
+                       continue;
+               if (s->pstate == SLOT_STOP && s->buf.used < s->bpf) {
+                       s->pstate = SLOT_INIT;
+#ifdef DEBUG
+                       if (log_level >= 3) {
+                               slot_log(s);
+                               log_puts(": drained, done\n");
+                       }
+#endif
+                       continue;
+               }
+               n = slot_mix_badd(s, dev_pbuf);
+               if (n > done)
+                       done = n;
+       }
+       return done;
 }
 
-int
-opt_mmc(void)
+static int
+slot_list_copy(unsigned int count, unsigned int rchan, adata_t *rbuf)
 {
-       if (strcmp("off", optarg) == 0)
-               return 0;
-       if (strcmp("slave", optarg) == 0)
-               return 1;
-       errx(1, "%s: bad MMC mode", optarg);
+       unsigned int done;
+       struct slot *s;
+
+       done = 0;
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (s->pstate == SLOT_INIT || !(s->mode & SIO_REC))
+                       continue;
+               slot_sub_bcopy(s, rbuf, count);
+               done = count;
+       }
+       return done;
 }
 
-int
-opt_onoff(void)
+static void
+slot_list_iodo(void)
 {
-       if (strcmp("off", optarg) == 0)
-               return 0;
-       if (strcmp("on", optarg) == 0)
-               return 1;
-       errx(1, "%s: bad join/expand setting", optarg);
+       struct slot *s;
+
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (s->pstate != SLOT_RUN)
+                       continue;
+               if ((s->mode & SIO_PLAY) && (s->buf.used == 0))
+                       slot_fill(s);
+               if ((s->mode & SIO_REC) && (s->buf.used == s->buf.len))
+                       slot_flush(s);
+       }
 }
 
-int
-opt_xrun(void)
+static int
+offline(void)
 {
-       if (strcmp("ignore", optarg) == 0)
-               return XRUN_IGNORE;
-       if (strcmp("sync", optarg) == 0)
-               return XRUN_SYNC;
-       if (strcmp("error", optarg) == 0)
-               return XRUN_ERROR;
-       errx(1, "%s: bad underrun/overrun policy", optarg);
+       unsigned int todo;
+       int rate, cmax;
+       struct slot *s;
+
+       rate = cmax = 0;
+       for (s = slot_list; s != NULL; s = s->next) {
+               if (s->afile.rate > rate)
+                       rate = s->afile.rate;
+               if (s->cmax > cmax)
+                       cmax = s->cmax;
+       }
+       dev_sh = NULL;
+       dev_name = "offline";
+       dev_mode = SIO_PLAY | SIO_REC;
+       dev_rate = rate;
+       dev_bufsz = rate;
+       dev_round = rate;
+       dev_pchan = dev_rchan = cmax + 1;
+       dev_pbuf = dev_rbuf = xmalloc(sizeof(adata_t) * dev_pchan * dev_round);
+       dev_pstate = DEV_STOP;
+       dev_mmcpos = 0;
+       for (s = slot_list; s != NULL; s = s->next)
+               slot_init(s);
+       for (s = slot_list; s != NULL; s = s->next)
+               slot_start(s, 0);
+       for (;;) {
+               todo = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
+               if (todo == 0)
+                       break;
+               slot_list_copy(todo, dev_pchan, dev_pbuf);
+               slot_list_iodo();
+       }
+       xfree(dev_pbuf);
+       while (slot_list)
+               slot_del(slot_list);
+       return 1;
 }
 
-void
-setsig(void)
+static int
+playrec_cycle(void)
 {
-       struct sigaction sa;
+       unsigned int n, todo;
+       unsigned char *p;
+       int pcnt, rcnt;
 
-       quit_flag = 0;
-       sigfillset(&sa.sa_mask);
-       sa.sa_flags = SA_RESTART;
-       sa.sa_handler = sigint;
-       if (sigaction(SIGINT, &sa, NULL) < 0)
-               err(1, "sigaction(int) failed");
-       if (sigaction(SIGTERM, &sa, NULL) < 0)
-               err(1, "sigaction(term) failed");
-       if (sigaction(SIGHUP, &sa, NULL) < 0)
-               err(1, "sigaction(hup) failed");
 #ifdef DEBUG
-       sa.sa_handler = sigusr1;
-       if (sigaction(SIGUSR1, &sa, NULL) < 0)
-               err(1, "sigaction(usr1) failed");
-       sa.sa_handler = sigusr2;
-       if (sigaction(SIGUSR2, &sa, NULL) < 0)
-               err(1, "sigaction(usr2) failed1n");
+       if (log_level >= 4) {
+               log_puts(dev_name);
+               log_puts(": cycle, prime = ");
+               log_putu(dev_prime);
+               log_puts("\n");
+       }
 #endif
+       pcnt = rcnt = 0;
+       if (dev_mode & SIO_REC) {
+               if (dev_prime > 0)
+                       dev_prime--;
+               else {
+                       todo = dev_round * dev_rchan * sizeof(adata_t);
+                       p = (unsigned char *)dev_rbuf;
+                       while (todo > 0) {
+                               n = sio_read(dev_sh, p, todo);
+                               if (n == 0) {
+                                       log_puts(dev_name);
+                                       log_puts(": failed to read from device\n");
+                                       return 0;
+                               }
+                               p += n;
+                               todo -= n;
+                       }
+                       rcnt = slot_list_copy(dev_round, dev_rchan, dev_rbuf);
+               }
+       }
+       if (dev_mode & SIO_PLAY) {
+               pcnt = slot_list_mix(dev_round, dev_pchan, dev_pbuf);
+               todo = sizeof(adata_t) * dev_pchan * dev_round;
+               n = sio_write(dev_sh, dev_pbuf, todo);
+               if (n == 0) {
+                       log_puts(dev_name);
+                       log_puts(": failed to write to device\n");
+                       return 0;
+               }
+       }
+       slot_list_iodo();
+       return pcnt > 0 || rcnt > 0;
+}
+
+static void
+sigint(int s)
+{
+       if (quit_flag)
+               _exit(1);
+       quit_flag = 1;
 }
 
-void
-unsetsig(void)
+static int
+playrec(char *dev, int mode, int bufsz, char *port)
 {
+#define MIDIBUFSZ 0x100
+       unsigned char mbuf[MIDIBUFSZ];
        struct sigaction sa;
+       struct pollfd *pfds;
+       struct slot *s;
+       int n, ns, nm, ev;
+
+       if (!dev_open(dev, mode, bufsz, port))
+               return 0;
+       n = sio_nfds(dev_sh);
+       if (dev_mh)
+               n += mio_nfds(dev_mh);
+       pfds = xmalloc(n * sizeof(struct pollfd));
+       for (s = slot_list; s != NULL; s = s->next)
+               slot_init(s);
+       if (dev_mh == NULL)
+               dev_mmcstart();
+       else {
+               if (log_level >= 2)
+                       log_puts("ready, waiting for mmc messages\n");
+       }
 
+       quit_flag = 0;
+       sigfillset(&sa.sa_mask);
+       sa.sa_flags = SA_RESTART;
+       sa.sa_handler = sigint;
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGHUP, &sa, NULL);
+       while (!quit_flag) {
+               if (dev_pstate == DEV_START) {
+                       ev = 0;
+                       if (mode & SIO_PLAY)
+                               ev |= POLLOUT;
+                       if (mode & SIO_REC)
+                               ev |= POLLIN;
+                       ns = sio_pollfd(dev_sh, pfds, ev);
+               } else
+                       ns = 0;
+               if (dev_mh)
+                       nm = mio_pollfd(dev_mh, pfds + ns, POLLIN);
+               else
+                       nm = 0;
+               if (poll(pfds, ns + nm, -1) < 0) {
+                       if (errno == EINTR)
+                               continue;
+                       log_puts("poll failed\n");
+                       panic();
+               }               
+               if (dev_pstate == DEV_START) {
+                       ev = sio_revents(dev_sh, pfds);
+                       if (ev & POLLHUP) {
+                               log_puts(dev);
+                               log_puts(": audio device gone, stopping\n");
+                               break;
+                       }
+                       if (ev & (POLLIN | POLLOUT)) {
+                               if (!playrec_cycle() && dev_mh == NULL)
+                                       break;
+                       }
+               }
+               if (dev_mh) {
+                       ev = mio_revents(dev_mh, pfds + ns);
+                       if (ev & POLLHUP) {
+                               log_puts(dev_port);
+                               log_puts(": midi port gone, stopping\n");
+                               break;
+                       }
+                       if (ev & POLLIN) {
+                               n = mio_read(dev_mh, mbuf, MIDIBUFSZ);
+                               midi_in(mbuf, n);
+                       }
+               }
+       }
        sigfillset(&sa.sa_mask);
        sa.sa_flags = SA_RESTART;
        sa.sa_handler = SIG_DFL;
-#ifdef DEBUG
-       if (sigaction(SIGUSR2, &sa, NULL) < 0)
-               err(1, "unsetsig(usr2): sigaction failed");
-       if (sigaction(SIGUSR1, &sa, NULL) < 0)
-               err(1, "unsetsig(usr1): sigaction failed");
-#endif
-       if (sigaction(SIGHUP, &sa, NULL) < 0)
-               err(1, "unsetsig(hup): sigaction failed\n");
-       if (sigaction(SIGTERM, &sa, NULL) < 0)
-               err(1, "unsetsig(term): sigaction failed\n");
-       if (sigaction(SIGINT, &sa, NULL) < 0)
-               err(1, "unsetsig(int): sigaction failed\n");
+       sigaction(SIGINT, &sa, NULL);
+       sigaction(SIGTERM, &sa, NULL);
+       sigaction(SIGHUP, &sa, NULL);
+
+       if (dev_pstate == DEV_START)
+               dev_mmcstop();
+       xfree(pfds);
+       dev_close();
+       while (slot_list)
+               slot_del(slot_list);
+       return 1;
 }
 
-struct dev *
-mkdev(char *path, int mode, int bufsz, int round, int hold, int autovol)
+static int
+opt_onoff(char *s, int *flag)
 {
-       struct dev *d;
+       if (strcmp("off", s) == 0) {
+               *flag = 0;
+               return 1;
+       }
+       if (strcmp("on", s) == 0) {
+               *flag = 1;
+               return 1;
+       }
+       log_puts(s);
+       log_puts(": on/off expected\n");
+       return 0;
+}
 
-       if (path) {
-               for (d = dev_list; d != NULL; d = d->next) {
-                       if (d->reqmode & (MODE_LOOP | MODE_THRU))
-                               continue;
-                       if (strcmp(d->path, path) == 0)
-                               return d;
-               }
-       } else {
-               if (dev_list)
-                       return dev_list;
-               path = SIO_DEVANY;
-       }
-       if (!bufsz && !round) {
-               round = DEFAULT_ROUND;
-               bufsz = DEFAULT_BUFSZ;
-       } else if (!bufsz) {
-               bufsz = round * 2;
-       } else if (!round)
-               round = bufsz / 2;
-       d = dev_new(path, mode, bufsz, round, hold, autovol);
-       if (d == NULL)
-               exit(1);
-       return d;
+static int
+opt_enc(char *s, struct aparams *par)
+{
+       int len;
+
+       len = aparams_strtoenc(par, s);
+       if (len == 0 || s[len] != '\0') {
+               log_puts(s);
+               log_puts(": bad encoding\n");
+               return 0;
+       }
+       return 1;
+}
+
+static int
+opt_hdr(char *s, int *hdr)
+{
+       if (strcmp("auto", s) == 0) {
+               *hdr = AFILE_HDR_AUTO;
+               return 1;
+       }
+       if (strcmp("raw", s) == 0) {
+               *hdr = AFILE_HDR_RAW;
+               return 1;
+       }
+       if (strcmp("wav", s) == 0) {
+               *hdr = AFILE_HDR_WAV;
+               return 1;
+       }
+       if (strcmp("aiff", s) == 0) {
+               *hdr = AFILE_HDR_AIFF;
+               return 1;
+       }
+       if (strcmp("au", s) == 0) {
+               *hdr = AFILE_HDR_AU;
+               return 1;
+       }
+       log_puts(s);
+       log_puts(": bad header type\n");
+       return 0;
+}
+
+static int
+opt_ch(char *s, int *rcmin, int *rcmax)
+{
+       char *next, *end;
+       long cmin, cmax;
+
+       errno = 0;
+       cmin = strtol(s, &next, 10);
+       if (next == s || *next != ':')
+               goto failed;
+       cmax = strtol(++next, &end, 10);
+       if (end == next || *end != '\0')
+               goto failed;
+       if (cmin < 0 || cmax < cmin || cmax >= NCHAN_MAX)
+               goto failed;
+       *rcmin = cmin;
+       *rcmax = cmax;
+       return 1;
+failed:
+       log_puts(s);
+       log_puts(": channel range expected\n");
+       return 0;
+}
+
+static int
+opt_num(char *s, int min, int max, int *num)
+{
+       const char *errstr;
+
+       *num = strtonum(s, min, max, &errstr);
+       if (errstr) {
+               log_puts(s);
+               log_puts(": expected integer between ");
+               log_puti(min);
+               log_puts(" and ");
+               log_puti(max);
+               log_puts("\n");
+               return 0;
+       }
+       return 1;
 }
 
 int
 main(int argc, char **argv)
 {
-       int c, active;
-       unsigned int mode, hdr, xrun, rate, join, mmc, vol;
-       unsigned int hold, autovol, bufsz, round;
-       const char *str;
-       struct aparams ppar, rpar;
-       struct dev *d, *dnext;
-       struct wav *w;
-
-       /*
-        * global options defaults
-        */
-       hdr = HDR_AUTO;
-       xrun = XRUN_IGNORE;
-       vol = MIDI_MAXCTL;
-       join = 1;
-       mmc = 0;
-       hold = 0;
-       autovol = 1;
-       bufsz = 0;
-       round = 0;
-       aparams_init(&ppar, 0, 1, DEFAULT_RATE);
-       aparams_init(&rpar, 0, 1, DEFAULT_RATE);
-       mode = MODE_MIDIMASK | MODE_PLAY | MODE_REC;
-
-#ifdef DEBUG
-       atexit(dbg_flush);
-#endif
-       setsig();
-       filelist_init();
+       int dup, cmin, cmax, rate, vol, bufsz, hdr, mode;
+       char *port, *dev;
+       struct aparams par;
+       int n_flag, c;
 
-       while ((c = getopt(argc, argv,
-                   "a:b:c:C:de:f:h:i:j:Mno:q:r:t:v:w:x:z:")) != -1) {
+       vol = 127;
+       dup = 0;
+       bufsz = 0;
+       rate = DEFAULT_RATE;
+       cmin = 0;
+       cmax = 1;
+       aparams_init(&par);
+       hdr = AFILE_HDR_AUTO;
+       n_flag = 0;
+       port = NULL;
+       dev = NULL;
+       mode = 0;
+       
+       while ((c = getopt(argc, argv, "b:c:de:f:h:i:j:no:q:r:t:v:")) != -1) {
                switch (c) {
-               case 'd':
-#ifdef DEBUG
-                       if (debug_level < 4)
-                               debug_level++;
-#endif
-                       break;
-               case 'h':
-                       hdr = opt_hdr();
-                       break;
-               case 'x':
-                       xrun = opt_xrun();
-                       break;
-               case 'j':
-                       join = opt_onoff();
-                       break;
-               case 't':
-                       mmc = opt_mmc();
+               case 'b':
+                       if (!opt_num(optarg, 1, RATE_MAX, &bufsz))
+                               return 1;
                        break;
                case 'c':
-                       opt_ch(&ppar);
+                       if (!opt_ch(optarg, &cmin, &cmax))
+                               return 1;
                        break;
-               case 'C':
-                       opt_ch(&rpar);
+               case 'd':
+                       log_level++;
                        break;
                case 'e':
-                       opt_enc(&ppar);
-                       aparams_copyenc(&rpar, &ppar);
+                       if (!opt_enc(optarg, &par))
+                               return 1;
                        break;
-               case 'r':
-                       rate = strtonum(optarg, RATE_MIN, RATE_MAX, &str);
-                       if (str)
-                               errx(1, "%s: rate is %s", optarg, str);
-                       ppar.rate = rpar.rate = rate;
+               case 'f':
+                       dev = optarg;
                        break;
-               case 'v':
-                       vol = strtonum(optarg, 0, MIDI_MAXCTL, &str);
-                       if (str)
-                               errx(1, "%s: volume is %s", optarg, str);
+               case 'h':
+                       if (!opt_hdr(optarg, &hdr))
+                               return 1;
                        break;
                case 'i':
-                       d = mkdev(NULL, 0, bufsz, round, 1, autovol);
-                       w = wav_new_in(&wav_ops, d,
-                           mode & (MODE_PLAY | MODE_MIDIOUT), optarg,
-                           hdr, &ppar, xrun, vol, mmc, join);
-                       if (w == NULL)
-                               errx(1, "%s: couldn't create stream", optarg);
-                       dev_adjpar(d, w->mode, NULL, &w->hpar);
-                       break;
-               case 'o':       
-                       d = mkdev(NULL, 0, bufsz, round, 1, autovol);
-                       w = wav_new_out(&wav_ops, d,
-                           mode & (MODE_RECMASK | MODE_MIDIIN), optarg,
-                           hdr, &rpar, xrun, mmc, join);
-                       if (w == NULL)
-                               errx(1, "%s: couldn't create stream", optarg);
-                       dev_adjpar(d, w->mode, &w->hpar, NULL);
+                       if (!slot_new(optarg, SIO_PLAY,
+                               &par, hdr, cmin, cmax, rate, dup, vol))
+                               return 1;
+                       mode |= SIO_PLAY;
                        break;
-               case 'q':
-                       d = mkdev(NULL, mode, bufsz, round, 1, autovol);
-                       if (!devctl_add(d, optarg, MODE_MIDIMASK))
-                               errx(1, "%s: can't open port", optarg);
-                       d->reqmode |= MODE_MIDIMASK;
-                       break;
-               case 'w':
-                       autovol = opt_onoff();
+               case 'j':
+                       if (!opt_onoff(optarg, &dup))
+                               return 1;
                        break;
-               case 'b':
-                       bufsz = strtonum(optarg, 1, RATE_MAX * 5, &str);
-                       if (str)
-                               errx(1, "%s: buffer size is %s", optarg, str);
+               case 'n':
+                       n_flag = 1;
                        break;
-               case 'z':
-                       round = strtonum(optarg, 1, SHRT_MAX, &str);
-                       if (str)
-                               errx(1, "%s: block size is %s", optarg, str);
+               case 'o':
+                       if (!slot_new(optarg, SIO_REC,
+                               &par, hdr, cmin, cmax, rate, dup, 0))
+                               return 1;
+                       mode |= SIO_REC;
                        break;
-               case 'f':
-                       mkdev(optarg, 0, bufsz, round, hold, autovol);
+               case 'q':
+                       port = optarg;
                        break;
-               case 'n':
-                       mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
+               case 'r':
+                       if (!opt_num(optarg, RATE_MIN, RATE_MAX, &rate))
+                               return 1;
                        break;
-               case 'M':
-                       mkdev("midithru", MODE_THRU, 0, 0, hold, 0);
+               case 'v':
+                       if (!opt_num(optarg, 0, MIDI_MAXCTL, &vol))
+                               return 1;
                        break;
                default:
-                       fputs(aucat_usage, stderr);
-                       exit(1);
+                       goto bad_usage;
                }
        }
        argc -= optind;
        argv += optind;
-       if (argc > 0) {
-               fputs(aucat_usage, stderr);
-               exit(1);
-       }
-       if (wav_list) {
-               if ((d = dev_list) && d->next)
-                       errx(1, "only one device allowed");
-               if ((d->reqmode & MODE_THRU) && d->ctl_list == NULL) {
-                       if (!devctl_add(d, "default", MODE_MIDIMASK))
-                               errx(1, "%s: can't open port", optarg);
-                       d->reqmode |= MODE_MIDIMASK;
-               }
-       } else {
-               fputs(aucat_usage, stderr);
-               exit(1);
-       }
-       for (w = wav_list; w != NULL; w = w->next) {
-               if (!wav_init(w))
-                       exit(1);
-       }
-       for (d = dev_list; d != NULL; d = d->next) {
-               if (!dev_init(d))
-                       exit(1);
-               if (d->autostart && (d->mode & MODE_AUDIOMASK))
-                       dev_mmcstart(d);
+       if (argc != 0) {
+       bad_usage:
+               log_puts(usagestr);
+               return 1;
        }
-
-       /*
-        * Loop, start audio.
-        */
-       for (;;) {
-               if (quit_flag)
-                       break;
-               active = 0;
-               for (d = dev_list; d != NULL; d = dnext) {
-                       dnext = d->next;
-                       if (!dev_run(d))
-                               goto fatal;
-                       if (d->refcnt > 0)
-                               active = 1;
+       if (n_flag) {
+               if (dev != NULL || port != NULL) {
+                       log_puts("-f and -q make no sense in off-line mode\n");
+                       return 1;
                }
-               if (dev_list == NULL)
-                       break;
-               if (!active)
-                       break;
-               if (!file_poll())
-                       break;
+               if (mode != (SIO_PLAY | SIO_REC)) {
+                       log_puts("both -i and -o required\n");
+                       return 0;
+               }
+               if (!offline())
+                       return 1;
+       } else {
+               if (dev == NULL)
+                       dev = SIO_DEVANY;
+               if (mode == 0) {
+                       log_puts("at least of -i and -o required\n");
+                       return 1;
+               } 
+               if (!playrec(dev, mode, bufsz, port))
+                       return 1;
        }
-  fatal:
-
-       /*
-        * give a chance to drain
-        */
-       for (d = dev_list; d != NULL; d = d->next)
-               dev_drain(d);
-       while (file_poll())
-               ; /* nothing */
-
-       while (dev_list)
-               dev_del(dev_list);
-       filelist_done();
-       unsetsig();
        return 0;
 }
diff --git a/usr.bin/aucat/conf.h b/usr.bin/aucat/conf.h
deleted file mode 100644 (file)
index ce32140..0000000
+++ /dev/null
@@ -1,68 +0,0 @@
-/*     $OpenBSD: conf.h,v 1.23 2011/10/12 07:20:04 ratchov Exp $       */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef CONF_H
-#define CONF_H
-
-#ifdef DEBUG
-#include <signal.h>
-
-/*
- * Debug trace levels:
- *
- * 0 - fatal errors: bugs, asserts, internal errors.
- * 1 - warnings: bugs in clients, failed allocations, non-fatal errors.
- * 2 - misc information (hardware parameters, incoming clients)
- * 3 - structural changes (new aproc structures and files stream params changes)
- * 4 - data blocks and messages
- */
-extern volatile sig_atomic_t debug_level;
-#endif
-
-/*
- * MIDI buffer size
- */
-#define MIDI_BUFSZ             3125    /* 1 second at 31.25kbit/s */
-
-/*
- * units used for MTC clock.
- */
-#define MTC_SEC                        2400    /* 1 second is 2400 ticks */
-
-/*
- * device or sub-device mode, must be a superset of corresponding SIO_XXX
- * and MIO_XXX constants
- */
-#define MODE_PLAY      0x01    /* allowed to play */
-#define MODE_REC       0x02    /* allowed to rec */
-#define MODE_MIDIOUT   0x04    /* allowed to read midi */
-#define MODE_MIDIIN    0x08    /* allowed to write midi */
-#define MODE_MON       0x10    /* allowed to monitor */
-#define MODE_LOOP      0x20    /* deviceless mode */
-#define MODE_THRU      0x40    /* pass thru insted of device control */
-#define MODE_PLAYREC   (MODE_PLAY | MODE_REC)
-#define MODE_RECMASK   (MODE_REC | MODE_MON)
-#define MODE_AUDIOMASK (MODE_PLAY | MODE_REC | MODE_MON)
-#define MODE_MIDIMASK  (MODE_MIDIIN | MODE_MIDIOUT)
-
-/*
- * underrun/overrun policies, must be the same as SIO_XXX
- */
-#define XRUN_IGNORE    0       /* on xrun silently insert/discard samples */
-#define XRUN_SYNC      1       /* catchup to sync to the mix/sub */
-#define XRUN_ERROR     2       /* xruns are errors, eof/hup buffer */
-
-#endif /* !defined(CONF_H) */
diff --git a/usr.bin/aucat/dbg.c b/usr.bin/aucat/dbg.c
deleted file mode 100644 (file)
index eb5202b..0000000
+++ /dev/null
@@ -1,139 +0,0 @@
-#ifdef DEBUG
-/*
- * Copyright (c) 2003-2007 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * dbg_xxx() routines are used to quickly store traces into a trace buffer.
- * This allows trances to be collected during time sensitive operations without
- * disturbing them. The buffer can be flushed on standard error later, when
- * slow syscalls are no longer disruptive, e.g. at the end of the poll() loop.
- */
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include "dbg.h"
-
-/*
- * size of the buffer where traces are stored
- */
-#define DBG_BUFSZ      8192
-
-/*
- * store a character in the trace buffer
- */
-#define DBG_PUTC(c) do {                       \
-       if (dbg_used < DBG_BUFSZ)               \
-               dbg_buf[dbg_used++] = (c);      \
-} while (0)
-
-char dbg_buf[DBG_BUFSZ];       /* buffer where traces are stored */
-unsigned int dbg_used = 0;             /* bytes used in the buffer */
-unsigned int dbg_sync = 1;             /* if true, flush after each '\n' */
-
-/*
- * write debug info buffer on stderr
- */
-void
-dbg_flush(void)
-{
-       if (dbg_used ==  0)
-               return;
-       write(STDERR_FILENO, dbg_buf, dbg_used);
-       dbg_used = 0;
-}
-
-/*
- * store a string in the debug buffer
- */
-void
-dbg_puts(char *msg)
-{
-       char *p = msg;
-       int c;
-
-       while ((c = *p++) != '\0') {
-               DBG_PUTC(c);
-               if (dbg_sync && c == '\n')
-                       dbg_flush();
-       }
-}
-
-/*
- * store a hex in the debug buffer
- */
-void
-dbg_putx(unsigned long num)
-{
-       char dig[sizeof(num) * 2], *p = dig, c;
-       unsigned int ndig;
-
-       if (num != 0) {
-               for (ndig = 0; num != 0; ndig++) {
-                       *p++ = num & 0xf;
-                       num >>= 4;
-               }
-               for (; ndig != 0; ndig--) {
-                       c = *(--p);
-                       c += (c < 10) ? '0' : 'a' - 10;
-                       DBG_PUTC(c);
-               }
-       } else 
-               DBG_PUTC('0');
-}
-
-/*
- * store a decimal in the debug buffer
- */
-void
-dbg_putu(unsigned long num)
-{
-       char dig[sizeof(num) * 3], *p = dig;
-       unsigned int ndig;
-
-       if (num != 0) {
-               for (ndig = 0; num != 0; ndig++) {
-                       *p++ = num % 10;
-                       num /= 10;
-               }
-               for (; ndig != 0; ndig--)
-                       DBG_PUTC(*(--p) + '0');
-       } else
-               DBG_PUTC('0');
-}
-
-/*
- * store a signed integer in the trace buffer
- */
-void
-dbg_puti(long num)
-{
-       if (num < 0) {
-               DBG_PUTC('-');
-               num = -num;
-       }
-       dbg_putu(num);
-}
-
-/*
- * abort program execution after a fatal error, we should
- * put code here to backup user data
- */
-void
-dbg_panic(void)
-{
-       dbg_flush();
-       abort();
-}
-#endif
diff --git a/usr.bin/aucat/dbg.h b/usr.bin/aucat/dbg.h
deleted file mode 100644 (file)
index 49038ab..0000000
+++ /dev/null
@@ -1,31 +0,0 @@
-#ifdef DEBUG
-/*
- * Copyright (c) 2003-2007 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#ifndef MIDISH_DBG_H
-#define MIDISH_DBG_H
-
-void    dbg_puts(char *);
-void    dbg_putx(unsigned long);
-void    dbg_putu(unsigned long);
-void    dbg_puti(long);
-void    dbg_panic(void);
-void    dbg_flush(void);
-
-extern unsigned int dbg_sync;
-
-#endif /* MIDISH_DBG_H */
-#endif /* DEBUG */
diff --git a/usr.bin/aucat/defs.h b/usr.bin/aucat/defs.h
new file mode 100644 (file)
index 0000000..019e654
--- /dev/null
@@ -0,0 +1,34 @@
+/*     $OpenBSD: defs.h,v 1.1 2015/01/21 08:43:55 ratchov Exp $        */
+/*
+ * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef DEFS_H
+#define DEFS_H
+
+/*
+ * units used for MTC clock.
+ */
+#define MTC_SEC                        2400    /* 1 second is 2400 ticks */
+
+/*
+ * limits
+ */
+#define NCHAN_MAX      16              /* max channel in a stream */
+#define RATE_MIN       4000            /* min sample rate */
+#define RATE_MAX       192000          /* max sample rate */
+#define BITS_MIN       1               /* min bits per sample */
+#define BITS_MAX       32              /* max bits per sample */
+
+#endif /* !defined(DEFS_H) */
diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c
deleted file mode 100644 (file)
index d87d6d1..0000000
+++ /dev/null
@@ -1,1735 +0,0 @@
-/*     $OpenBSD: dev.c,v 1.85 2014/08/10 10:25:35 ratchov Exp $        */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * Device abstraction module
- *
- * This module exposes a ``enhanced device'' that uses aproc
- * structures framework; it does conversions on the fly and can
- * handle multiple streams.  The enhanced device starts and stops
- * automatically, when streams are attached, and provides
- * primitives for MIDI control
- *
- * From the main loop, the device is used as follows:
- *
- *   1. create the device using dev_new_xxx()
- *   2. call dev_run() in the event loop
- *   3. destroy the device using dev_del()
- *   4. continue running the event loop to drain
- *
- * The device is used as follows from aproc context:
- *
- *   1. open the device with dev_ref()
- *   2. negociate parameters (mode, rate, ...)
- *   3. create your stream (ie allocate and fill abufs)
- *   4. attach your stream atomically:
- *       - first call dev_wakeup() to ensure device is not suspended
- *       - possibly fetch dynamic parameters (eg. dev_getpos())
- *       - attach your buffers with dev_attach()
- *   5. close your stream, ie abuf_eof() or abuf_hup()
- *   6. close the device with dev_unref()
- *
- * The device has the following states:
- *
- * CLOSED      sio_open() is not called, it's not ready and
- *             no streams can be attached; dev_ref() must
- *             be called to open the device
- *
- * INIT                device is opened, processing chain is ready, but
- *             DMA is not started yet. Streams can attach,
- *             in which case device will automatically switch
- *             to the START state
- *
- * START       at least one stream is attached, play buffers
- *             are primed (if necessary) DMA is ready and
- *             will start immeadiately (next cycle)
- *
- * RUN         DMA is started. New streams can attach. If the
- *             device is idle (all streams are closed and
- *             finished draining), then the device
- *             automatically switches to INIT or CLOSED
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "abuf.h"
-#include "aproc.h"
-#include "conf.h"
-#include "dev.h"
-#include "pipe.h"
-#include "miofile.h"
-#include "siofile.h"
-#include "midi.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-int  dev_open(struct dev *);
-void dev_close(struct dev *);
-void dev_start(struct dev *);
-void dev_stop(struct dev *);
-void dev_clear(struct dev *);
-void dev_onmove(void *, int);
-int  devctl_open(struct dev *, struct devctl *);
-int  dev_getep(struct dev *, unsigned int, struct abuf **, struct abuf **);
-void dev_sync(struct dev *, unsigned int, struct abuf *, struct abuf *);
-int  dev_mkslot(struct dev *, char *);
-int  dev_try(struct dev *, int);
-
-
-struct dev *dev_list = NULL;
-unsigned int dev_sndnum = 0, dev_thrnum = 0;
-
-#ifdef DEBUG
-void
-dev_dbg(struct dev *d)
-{
-       if (d->num >= DEV_NMAX) {
-               dbg_puts("thr");
-               dbg_putu(d->num - DEV_NMAX);
-       } else {
-               dbg_puts("snd");
-               dbg_putu(d->num);
-       }
-}
-#endif
-
-/*
- * Create a sndio device
- */
-struct dev *
-dev_new(char *path, unsigned int mode, unsigned int bufsz, unsigned int round,
-    unsigned int hold, unsigned int autovol)
-{
-       struct dev *d;
-       unsigned int *pnum, i;
-
-       pnum = (mode & MODE_THRU) ? &dev_thrnum : &dev_sndnum;
-       if (*pnum == DEV_NMAX) {
-#ifdef DEBUG
-               if (debug_level >= 1)
-                       dbg_puts("too many devices\n");
-#endif
-               return NULL;
-       }
-       d = malloc(sizeof(struct dev));
-       if (d == NULL) {
-               perror("malloc");
-               exit(1);
-       }
-       d->num = (*pnum)++;
-       if (mode & MODE_THRU)
-               d->num += DEV_NMAX;
-       d->ctl_list = NULL;
-       d->path = path;
-       d->reqmode = mode;
-       aparams_init(&d->reqopar, NCHAN_MAX, 0, 0);
-       aparams_init(&d->reqipar, NCHAN_MAX, 0, 0);
-       d->reqbufsz = bufsz;
-       d->reqround = round;
-       d->hold = hold;
-       d->autovol = autovol;
-       d->autostart = 0;
-       d->refcnt = 0;
-       d->pstate = DEV_CLOSED;
-       d->serial = 0;
-       for (i = 0; i < CTL_NSLOT; i++) {
-               d->slot[i].unit = i;
-               d->slot[i].ops = NULL;
-               d->slot[i].vol = MIDI_MAXCTL;
-               d->slot[i].tstate = CTL_OFF;
-               d->slot[i].serial = d->serial++;
-               d->slot[i].name[0] = '\0';
-       }
-       d->master = MIDI_MAXCTL;
-       d->origin = 0;
-       d->tstate = CTL_STOP;
-       d->next = dev_list;
-       dev_list = d;      
-       return d;
-}
-
-/*
- * adjust device parameters and mode
- */
-void
-dev_adjpar(struct dev *d, unsigned int mode,
-    struct aparams *ipar, struct aparams *opar)
-{
-       d->reqmode |= (mode | MODE_MIDIMASK);
-       if (mode & MODE_REC)
-               aparams_grow(&d->reqipar, ipar);
-       if (mode & MODE_PLAY)
-               aparams_grow(&d->reqopar, opar);
-}
-
-/*
- * Initialize the device with the current parameters
- */
-int
-dev_init(struct dev *d)
-{
-       if ((d->reqmode & (MODE_AUDIOMASK | MODE_MIDIMASK)) == 0) {
-#ifdef DEBUG
-                   dev_dbg(d);
-                   dbg_puts(": has no streams, skipped\n");
-#endif                             
-                   return 1;
-       }
-       if (d->hold && d->pstate == DEV_CLOSED && !dev_open(d)) {
-               dev_del(d);
-               return 0;
-       }
-       return 1;
-}
-
-/*
- * Add a MIDI port to the device
- */
-int
-devctl_add(struct dev *d, char *path, unsigned int mode)
-{
-       struct devctl *c;
-
-       c = malloc(sizeof(struct devctl));
-       if (c == NULL) {
-               perror("malloc");
-               exit(1);
-       }
-       c->path = path;
-       c->mode = mode;
-       c->next = d->ctl_list;
-       d->ctl_list = c;
-       if (d->pstate != DEV_CLOSED && !devctl_open(d, c))
-               return 0;
-       return 1;
-}
-
-/*
- * Open a MIDI device and connect it to the thru box
- */
-int
-devctl_open(struct dev *d, struct devctl *c)
-{
-       struct file *f;
-       struct abuf *rbuf = NULL, *wbuf = NULL;
-       struct aproc *rproc, *wproc;
-
-       f = (struct file *)miofile_new(&miofile_ops, c->path, c->mode);
-       if (f == NULL)
-               return 0;
-       if (c->mode & MODE_MIDIIN) {
-               rproc = rfile_new(f);
-               rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
-               aproc_setout(rproc, rbuf);
-       }
-       if (c->mode & MODE_MIDIOUT) {
-               wproc = wfile_new(f);
-               wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
-               aproc_setin(wproc, wbuf);
-       }
-       dev_midiattach(d, rbuf, wbuf);
-       return 1;
-}
-
-/*
- * Open the device with the dev_reqxxx capabilities. Setup a mixer, demuxer,
- * monitor, midi control, and any necessary conversions.
- */
-int
-dev_open(struct dev *d)
-{
-       struct file *f;
-       struct devctl *c;
-       struct aparams par;
-       struct aproc *conv;
-       struct abuf *buf;
-       unsigned int siomode, cmin, cmax, rate;
-       
-       d->mode = d->reqmode;
-       d->round = d->reqround;
-       d->bufsz = d->reqbufsz;
-       d->ipar = d->reqipar;
-       d->opar = d->reqopar;
-       d->rec = NULL;
-       d->play = NULL;
-       d->mon = NULL;
-       d->mix = NULL;
-       d->sub = NULL;
-       d->submon = NULL;
-       d->midi = NULL;
-       d->rate = 0;
-
-       if (d->opar.cmin > d->opar.cmax) {
-               d->opar.cmin = 0;
-               d->opar.cmax = 1;
-       }
-       if (d->ipar.cmin > d->ipar.cmax) {
-               d->ipar.cmin = 0;
-               d->ipar.cmax = 1;
-       }
-       if (d->opar.rate > d->ipar.rate)
-               d->ipar.rate = d->opar.rate;
-       else
-               d->opar.rate = d->ipar.rate;
-       if (d->opar.rate == 0)
-               d->opar.rate = d->ipar.rate = 48000; /* XXX */
-
-       if (d->mode & MODE_THRU)
-               d->mode &= ~MODE_AUDIOMASK;
-
-       /*
-        * If needed, open the device (ie create dev_rec and dev_play)
-        */
-       if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) {
-               siomode = d->mode & (MODE_PLAY | MODE_REC);
-               f = (struct file *)siofile_new(&siofile_ops,
-                   d->path,
-                   &siomode,
-                   &d->ipar,
-                   &d->opar,
-                   &d->bufsz,
-                   &d->round);
-               if (f == NULL) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dev_dbg(d);
-                               dbg_puts(": ");
-                               dbg_puts(d->path);
-                               dbg_puts(": failed to open audio device\n");
-                       }
-#endif
-                       return 0;
-               }
-               if (!(siomode & MODE_PLAY))
-                       d->mode &= ~(MODE_PLAY | MODE_MON);
-               if (!(siomode & MODE_REC))
-                       d->mode &= ~MODE_REC;
-               if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dev_dbg(d);
-                               dbg_puts(": mode not supported by device\n");
-                       }
-#endif
-                       return 0;
-               }
-               d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate;
-               if (d->mode & MODE_REC) {
-                       d->rec = rsio_new(f);
-                       d->rec->refs++;
-               }
-               if (d->mode & MODE_PLAY) {
-                       d->play = wsio_new(f);
-                       d->play->refs++;
-               }
-       }
-       if (d->mode & MODE_LOOP) {
-               if (d->mode & MODE_MON) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dbg_puts("monitoring not allowed "
-                                   "in loopback mode\n");
-                       }
-#endif
-                       return 0;
-               }
-               if ((d->mode & MODE_PLAYREC) != MODE_PLAYREC) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dbg_puts("both play and record streams "
-                                   "required in loopback mode\n");
-                       }
-#endif
-                       return 0;
-               }
-               if (d->ctl_list) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dbg_puts("MIDI control not allowed "
-                                   "in loopback mode\n");
-                       }
-#endif
-                       return 0;
-               }
-               cmin = (d->ipar.cmin < d->opar.cmin) ?
-                   d->ipar.cmin : d->opar.cmin;
-               cmax = (d->ipar.cmax > d->opar.cmax) ?
-                   d->ipar.cmax : d->opar.cmax;
-               rate = (d->ipar.rate > d->opar.rate) ?
-                   d->ipar.rate : d->opar.rate;
-               aparams_init(&par, cmin, cmax, rate);
-               d->ipar = par;
-               d->opar = par;
-               d->rate = rate;
-               /* 
-                * block sizes in the resampling code are limited to
-                * 2^15, so use 1/15 of the rate, since all standard
-                * sample rates are multiple of 15
-                */
-               d->round = rate / 15;
-               d->bufsz = 2 * d->round;
-       }
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               if (d->mode & MODE_REC) {
-                       dev_dbg(d);
-                       dbg_puts(": recording ");
-                       aparams_dbg(&d->ipar);
-                       dbg_puts("\n");
-               }
-               if (d->mode & MODE_PLAY) {
-                       dev_dbg(d);
-                       dbg_puts(": playing ");
-                       aparams_dbg(&d->opar);
-                       dbg_puts("\n");
-               }
-       }
-#endif
-       /*
-        * Create the midi control end, or a simple thru box
-        * if there's no device
-        */
-       if (d->mode & MODE_MIDIMASK) {
-               d->midi = midi_new("midi", (d->mode & MODE_THRU) ? NULL : d);
-               d->midi->refs++;
-       }
-
-       /*
-        * Create mixer, demuxer and monitor
-        */
-       if (d->mode & MODE_PLAY) {
-               d->mix = mix_new("play", d->bufsz, d->round,
-                   d->autovol, MIDI_TO_ADATA(d->master));
-               d->mix->refs++;
-       }
-       if (d->mode & MODE_REC) {
-               d->sub = sub_new("rec", d->bufsz, d->round);
-               d->sub->refs++;
-       }
-       if (d->mode & MODE_LOOP) {
-               /*
-                * connect mixer out to demuxer in
-                */
-               buf = abuf_new(d->bufsz, &d->opar);
-               aproc_setout(d->mix, buf);
-               aproc_setin(d->sub, buf);
-
-               d->mix->flags |= APROC_QUIT;
-               d->sub->flags |= APROC_QUIT;
-       }
-       if (d->rec) {
-               aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate);
-
-               /*
-                * Create device <-> demuxer buffer
-                */
-               buf = abuf_new(d->bufsz, &d->ipar);
-               aproc_setout(d->rec, buf);
-
-               /*
-                * Insert a converter, if needed.
-                */
-               if (!aparams_eqenc(&d->ipar, &par)) {
-                       conv = dec_new("rec", &d->ipar);
-                       aproc_setin(conv, buf);
-                       buf = abuf_new(d->round, &par);
-                       aproc_setout(conv, buf);
-               }
-               d->ipar = par;
-               aproc_setin(d->sub, buf);
-       }
-       if (d->play) {
-               aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate);
-
-               /*
-                * Create device <-> mixer buffer
-                */
-               buf = abuf_new(d->bufsz, &d->opar);
-               aproc_setin(d->play, buf);
-
-               /*
-                * Append a converter, if needed.
-                */
-               if (!aparams_eqenc(&par, &d->opar)) {
-                       conv = enc_new("play", &d->opar);
-                       aproc_setout(conv, buf);
-                       buf = abuf_new(d->round, &par);
-                       aproc_setin(conv, buf);
-               }
-               d->opar = par;
-               aproc_setout(d->mix, buf);
-       }
-       if (d->mode & MODE_MON) {
-               d->mon = mon_new("mon", d->bufsz);
-               d->mon->refs++;
-               buf = abuf_new(d->bufsz, &d->opar);
-               aproc_setout(d->mon, buf);
-
-               /*
-                * Append a "sub" to which clients will connect.
-                */
-               d->submon = sub_new("mon", d->bufsz, d->round);
-               d->submon->refs++;
-               aproc_setin(d->submon, buf);
-
-               /*
-                * Attach to the mixer
-                */
-               d->mix->u.mix.mon = d->mon;
-               d->mon->refs++;
-       }
-#ifdef DEBUG
-       if (debug_level >= 2) { 
-               if (d->mode & (MODE_PLAY | MODE_RECMASK)) {
-                       dev_dbg(d);
-                       dbg_puts(": block size is ");
-                       dbg_putu(d->round);
-                       dbg_puts(" frames, using ");
-                       dbg_putu(d->bufsz / d->round);
-                       dbg_puts(" blocks\n");
-               }
-       }
-#endif
-       d->pstate = DEV_INIT;
-       for (c = d->ctl_list; c != NULL; c = c->next) {
-               if (!devctl_open(d, c)) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dbg_puts(c->path);
-                               dbg_puts(": couldn't open MIDI port\n");
-                       }
-#endif
-                       dev_close(d);
-                       return 0;
-               }
-       }
-       return 1;
-}
-
-/*
- * Cleanly stop and drain everything and close the device
- * once both play chain and record chain are gone.
- */
-void
-dev_close(struct dev *d)
-{
-       struct file *f;
-
-       /*
-        * if the device is starting, ensure it actually starts
-        * so buffers are drained, else clear any buffers
-        */
-       switch (d->pstate) {
-       case DEV_START:
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       dev_dbg(d);
-                       dbg_puts(": draining device\n");
-               }
-#endif
-               dev_start(d);
-               break;
-       case DEV_INIT:
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       dev_dbg(d);
-                       dbg_puts(": flushing device\n");
-               }
-#endif
-               dev_clear(d);
-               break;
-       }
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               dev_dbg(d);
-               dbg_puts(": closing device\n");
-       }
-#endif
-       d->pstate = DEV_CLOSED;
-       if (d->mix) {
-               /*
-                * Put the mixer in ``autoquit'' state and generate
-                * EOF on all inputs connected it. Once buffers are
-                * drained the mixer will terminate and shutdown the
-                * device.
-                *
-                * NOTE: since file_eof() can destroy the file and
-                * reorder the file_list, we have to restart the loop
-                * after each call to file_eof().
-                */
-               if (APROC_OK(d->mix))
-                       mix_quit(d->mix);
-
-               /*
-                * XXX: handle this in mix_done()
-                */
-               if (APROC_OK(d->mix->u.mix.mon)) {
-                       d->mix->u.mix.mon->refs--;
-                       aproc_del(d->mix->u.mix.mon);
-                       d->mix->u.mix.mon = NULL;
-               }
-       restart_mix:
-               LIST_FOREACH(f, &file_list, entry) {
-                       if (f->rproc != NULL &&
-                           aproc_depend(d->mix, f->rproc)) {
-                               file_eof(f);
-                               goto restart_mix;
-                       }
-               }
-       } else if (d->sub) {
-               /*
-                * Same as above, but since there's no mixer, 
-                * we generate EOF on the record-end of the
-                * device.
-                */     
-       restart_sub:
-               LIST_FOREACH(f, &file_list, entry) {
-                       if (f->rproc != NULL &&
-                           aproc_depend(d->sub, f->rproc)) {
-                               file_eof(f);
-                               goto restart_sub;
-                       }
-               }
-       } else if (d->submon) {
-               /*
-                * Same as above
-                */     
-       restart_submon:
-               LIST_FOREACH(f, &file_list, entry) {
-                       if (f->rproc != NULL &&
-                           aproc_depend(d->submon, f->rproc)) {
-                               file_eof(f);
-                               goto restart_submon;
-                       }
-               }
-       }
-       if (d->midi) {
-               d->midi->flags |= APROC_QUIT;
-               if (LIST_EMPTY(&d->midi->ins))
-                       aproc_del(d->midi);
-       restart_midi:
-               LIST_FOREACH(f, &file_list, entry) {
-                       if (f->rproc &&
-                           aproc_depend(d->midi, f->rproc)) {
-                               file_eof(f);
-                               goto restart_midi;
-                       }
-               }
-       }
-       if (d->mix) {
-               if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB))
-                       aproc_del(d->mix);
-               d->mix = NULL;
-       }
-       if (d->play) {
-               if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB))
-                       aproc_del(d->play);
-               d->play = NULL;
-       }
-       if (d->sub) {
-               if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB))
-                       aproc_del(d->sub);
-               d->sub = NULL;
-       }
-       if (d->rec) {
-               if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB))
-                       aproc_del(d->rec);
-               d->rec = NULL;
-       }
-       if (d->submon) {
-               if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB))
-                       aproc_del(d->submon);
-               d->submon = NULL;
-       }
-       if (d->mon) {
-               if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB))
-                       aproc_del(d->mon);
-               d->mon = NULL;
-       }
-       if (d->midi) {
-               if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB))
-                       aproc_del(d->midi);
-               d->midi = NULL;
-       }
-}
-
-/*
- * Unless the device is already in process of closing, request it to close
- */
-void
-dev_drain(struct dev *d)
-{
-       unsigned int i;
-       struct ctl_slot *s;
-
-       for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
-               if (s->ops)
-                       s->ops->quit(s->arg);
-       }
-       if (d->pstate != DEV_CLOSED)
-               dev_close(d);
-}
-
-/*
- * Free the device
- */
-void
-dev_del(struct dev *d)
-{
-       struct dev **p;
-
-       dev_drain(d);
-       for (p = &dev_list; *p != d; p = &(*p)->next) {
-#ifdef DEBUG
-               if (*p == NULL) {
-                       dbg_puts("device to delete not on the list\n");
-                       dbg_panic();
-               }
-#endif
-       }
-       *p = d->next;
-       free(d);
-}
-
-/*
- * Attach a bi-directional MIDI stream to the MIDI device
- */
-void
-dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf)
-{
-       if (ibuf)
-               aproc_setin(d->midi, ibuf);
-       if (obuf) {
-               aproc_setout(d->midi, obuf);
-               if (ibuf) {
-                       ibuf->duplex = obuf;
-                       obuf->duplex = ibuf;
-               }
-       }
-}
-
-unsigned int
-dev_roundof(struct dev *d, unsigned int newrate)
-{
-       return (d->round * newrate + d->rate / 2) / d->rate;
-}
-
-/*
- * Start the (paused) device. By default it's paused.
- */
-void
-dev_start(struct dev *d)
-{
-       struct file *f;
-
-#ifdef DEBUG
-       if (debug_level >= 2)
-               dbg_puts("starting device\n");
-#endif
-       d->pstate = DEV_RUN;
-       if (d->mode & MODE_LOOP)
-               return;
-       if (APROC_OK(d->mix))
-               d->mix->flags |= APROC_DROP;
-       if (APROC_OK(d->sub))
-               d->sub->flags |= APROC_DROP;
-       if (APROC_OK(d->submon))
-               d->submon->flags |= APROC_DROP;
-       if (APROC_OK(d->play) && d->play->u.io.file) {
-               f = d->play->u.io.file;
-               f->ops->start(f, dev_onmove, d);
-       } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
-               f = d->rec->u.io.file;
-               f->ops->start(f, dev_onmove, d);
-       }
-}
-
-/*
- * Pause the device. This may trigger context switches,
- * so it shouldn't be called from aproc methods
- */
-void
-dev_stop(struct dev *d)
-{
-       struct file *f;
-
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               dev_dbg(d);
-               dbg_puts(": device stopped\n");
-       }
-#endif
-       d->pstate = DEV_INIT;
-       if (d->mode & MODE_LOOP)
-               return;
-       if (APROC_OK(d->play) && d->play->u.io.file) {
-               f = d->play->u.io.file;
-               f->ops->stop(f);
-       } else if (APROC_OK(d->rec) && d->rec->u.io.file) {
-               f = d->rec->u.io.file;
-               f->ops->stop(f);
-       }
-       if (APROC_OK(d->mix))
-               d->mix->flags &= ~APROC_DROP;
-       if (APROC_OK(d->sub))
-               d->sub->flags &= ~APROC_DROP;
-       if (APROC_OK(d->submon))
-               d->submon->flags &= ~APROC_DROP;
-}
-
-int
-dev_ref(struct dev *d)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dev_dbg(d);
-               dbg_puts(": device requested\n");
-       }
-#endif
-       if (d->pstate == DEV_CLOSED && !dev_open(d)) {
-               if (d->hold)
-                       dev_del(d);
-               return 0;
-       }
-       d->refcnt++;
-       return 1;
-}
-
-void
-dev_unref(struct dev *d)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dev_dbg(d);
-               dbg_puts(": device released\n");
-       }
-#endif
-       d->refcnt--;
-       if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold)
-               dev_close(d);
-}
-
-/*
- * There are actions (like start/stop/close ... ) that may trigger aproc
- * operations, a thus cannot be started from aproc context.
- * To avoid problems, aprocs only change the s!tate of the device,
- * and actual operations are triggered from the main loop,
- * outside the aproc code path.
- *
- * The following routine invokes pending actions, returns 0
- * on fatal error
- */
-int
-dev_run(struct dev *d)
-{
-       if (d->pstate == DEV_CLOSED)
-               return 1;
-       /*
-        * check if device isn't gone
-        */
-       if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) ||
-           ((d->mode & MODE_REC)  && !APROC_OK(d->sub)) ||
-           ((d->mode & MODE_MON)  && !APROC_OK(d->submon))) {
-#ifdef DEBUG
-               if (debug_level >= 2) {
-                       dev_dbg(d);
-                       dbg_puts(": device disappeared\n");
-               }
-#endif
-               if (d->hold) {
-                       dev_del(d);
-                       return 0;
-               }
-               dev_close(d);
-               return 1;
-       }
-       switch (d->pstate) {
-       case DEV_INIT:
-               /* nothing */
-               break;
-       case DEV_START:
-               dev_start(d);
-               /* PASSTHROUGH */
-       case DEV_RUN:
-               /*
-                * if the device is not used, then stop it
-                */
-               if ((!APROC_OK(d->mix) ||
-                       d->mix->u.mix.idle > 2 * d->bufsz) &&
-                   (!APROC_OK(d->sub) ||
-                       d->sub->u.sub.idle > 2 * d->bufsz) &&
-                   (!APROC_OK(d->submon) ||
-                       d->submon->u.sub.idle > 2 * d->bufsz) &&
-                   (!APROC_OK(d->midi) ||
-                       d->tstate != CTL_RUN)) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               dev_dbg(d);
-                               dbg_puts(": device idle, suspending\n");
-                       }
-#endif
-                       dev_stop(d);
-                       if (d->refcnt == 0 && !d->hold)
-                               dev_close(d);
-                       else
-                               dev_clear(d);
-               }
-               break;
-       }
-       return 1;
-}
-
-/*
- * If the device is paused, then resume it.
- * This routine can be called from aproc context.
- */
-void
-dev_wakeup(struct dev *d)
-{
-       if (d->pstate == DEV_INIT)
-               d->pstate = DEV_START;
-}
-
-/*
- * Find the end points connected to the mix/sub.
- */
-int
-dev_getep(struct dev *d,
-    unsigned int mode, struct abuf **sibuf, struct abuf **sobuf)
-{
-       struct abuf *ibuf, *obuf;
-
-       if (mode & MODE_PLAY) {
-               if (!APROC_OK(d->mix))
-                       return 0;
-               ibuf = *sibuf;
-               for (;;) {
-                       if (!ibuf || !ibuf->rproc) {
-#ifdef DEBUG
-                               if (debug_level >= 3) {
-                                       abuf_dbg(*sibuf);
-                                       dbg_puts(": not connected to device\n");
-                               }
-#endif
-                               return 0;
-                       }
-                       if (ibuf->rproc == d->mix)
-                               break;
-                       ibuf = LIST_FIRST(&ibuf->rproc->outs);
-               }
-               *sibuf = ibuf;
-       }
-       if (mode & MODE_REC) {
-               if (!APROC_OK(d->sub))
-                       return 0;
-               obuf = *sobuf;
-               for (;;) {
-                       if (!obuf || !obuf->wproc) {
-#ifdef DEBUG
-                               if (debug_level >= 3) {
-                                       abuf_dbg(*sobuf);
-                                       dbg_puts(": not connected to device\n");
-                               }
-#endif
-                               return 0;
-                       }
-                       if (obuf->wproc == d->sub)
-                               break;
-                       obuf = LIST_FIRST(&obuf->wproc->ins);
-               }
-               *sobuf = obuf;
-       }
-       if (mode & MODE_MON) {
-               if (!APROC_OK(d->submon))
-                       return 0;
-               obuf = *sobuf;
-               for (;;) {
-                       if (!obuf || !obuf->wproc) {
-#ifdef DEBUG
-                               if (debug_level >= 3) {
-                                       abuf_dbg(*sobuf);
-                                       dbg_puts(": not connected to device\n");
-                               }
-#endif
-                               return 0;
-                       }
-                       if (obuf->wproc == d->submon)
-                               break;
-                       obuf = LIST_FIRST(&obuf->wproc->ins);
-               }
-               *sobuf = obuf;
-       }
-       return 1;
-}
-
-/*
- * Sync play buffer to rec buffer (for instance when one of
- * them underruns/overruns).
- */
-void
-dev_sync(struct dev *d, unsigned int mode,
-    struct abuf *ibuf, struct abuf *obuf)
-{
-       int delta, offs;
-       struct abuf *mbuf = NULL;
-
-       if (!dev_getep(d, mode, &ibuf, &obuf))
-               return;
-       /*
-        * Calculate delta, the number of frames the play chain is ahead
-        * of the record chain. It's necessary to schedule silences (or
-        * drops) in order to start playback and record in sync.
-        */
-       offs = 0;
-       delta = 0;
-       if (APROC_OK(d->mix)) {
-               mbuf = LIST_FIRST(&d->mix->outs);
-               offs += mbuf->w.mix.todo;
-               delta += d->mix->u.mix.lat;
-       }
-       if (APROC_OK(d->sub))
-               delta += d->sub->u.sub.lat;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dev_dbg(d);
-               dbg_puts(": syncing device");
-               if (APROC_OK(d->mix)) {
-                       dbg_puts(", ");
-                       aproc_dbg(d->mix);
-                       dbg_puts(": todo = ");
-                       dbg_putu(mbuf->w.mix.todo);
-                       dbg_puts(": lat = ");
-                       dbg_putu(d->mix->u.mix.lat);
-               }
-               if (APROC_OK(d->sub)) {
-                       dbg_puts(", ");
-                       aproc_dbg(d->sub);
-                       dbg_puts(": lat = ");
-                       dbg_putu(d->sub->u.sub.lat);
-               }
-               dbg_puts("\n");
-       }
-#endif
-       if (mode & MODE_PLAY)
-               mix_drop(ibuf, -offs);
-       if (mode & MODE_RECMASK)
-               sub_silence(obuf, -(offs + delta));
-}
-
-/*
- * return the current latency (in frames), ie the latency that
- * a stream would have if dev_attach() is called on it.
- *
- * XXX: return a "unsigned int", since result is always positive, isn't it?
- */
-int
-dev_getpos(struct dev *d)
-{
-       struct abuf *mbuf = NULL;
-
-       if (APROC_OK(d->mix)) {
-               mbuf = LIST_FIRST(&d->mix->outs);
-               return -(mbuf->w.mix.todo + d->mix->u.mix.lat);
-       } else
-               return 0;
-}
-
-/*
- * Attach the given input and output buffers to the mixer and the
- * multiplexer respectively. The operation is done synchronously, so
- * both buffers enter in sync. If buffers do not match play
- * and rec.
- */
-void
-dev_attach(struct dev *d, char *name, unsigned int mode,
-    struct abuf *ibuf, struct aparams *sipar, unsigned int inch,
-    struct abuf *obuf, struct aparams *sopar, unsigned int onch,
-    unsigned int xrun, int vol)
-{
-       struct aparams ipar, opar;
-       struct aproc *conv;
-       unsigned int round, nblk, nch;
-
-#ifdef DEBUG
-       if ((!APROC_OK(d->mix)    && (mode & MODE_PLAY)) ||
-           (!APROC_OK(d->sub)    && (mode & MODE_REC)) ||
-           (!APROC_OK(d->submon) && (mode & MODE_MON))) {
-               dev_dbg(d);
-               dbg_puts(": mode beyond device mode, not attaching\n");
-               return;
-       }
-#endif
-       if (mode & MODE_PLAY) {
-               ipar = *sipar;
-               nblk = (d->bufsz / d->round + 3) / 4;
-               round = dev_roundof(d, ipar.rate);
-               nch = ipar.cmax - ipar.cmin + 1;
-               if (!aparams_eqenc(&ipar, &d->opar)) {
-                       conv = dec_new(name, &ipar);
-                       ipar.bps = d->opar.bps;
-                       ipar.bits = d->opar.bits;
-                       ipar.sig = d->opar.sig;
-                       ipar.le = d->opar.le;
-                       ipar.msb = d->opar.msb;
-                       aproc_setin(conv, ibuf);
-                       ibuf = abuf_new(nblk * round, &ipar);
-                       aproc_setout(conv, ibuf);
-               }
-               if (inch > 0 && nch >= inch * 2) {
-                       conv = join_new(name);
-                       aproc_setin(conv, ibuf);
-                       ipar.cmax = ipar.cmin + inch - 1;
-                       ibuf = abuf_new(nblk * round, &ipar);
-                       aproc_setout(conv, ibuf);
-               }
-               if (!aparams_eqrate(&ipar, &d->opar)) {
-                       conv = resamp_new(name, round, d->round);
-                       ipar.rate = d->opar.rate;
-                       round = d->round;
-                       aproc_setin(conv, ibuf);
-                       ibuf = abuf_new(nblk * round, &ipar);
-                       aproc_setout(conv, ibuf);
-               }
-               if (inch > 0 && nch * 2 <= inch) {
-                       conv = join_new(name);
-                       aproc_setin(conv, ibuf);
-                       ipar.cmax = ipar.cmin + inch - 1;
-                       ibuf = abuf_new(nblk * round, &ipar);
-                       aproc_setout(conv, ibuf);
-               }
-               aproc_setin(d->mix, ibuf);
-               ibuf->r.mix.xrun = xrun;
-               ibuf->r.mix.maxweight = vol;
-               mix_setmaster(d->mix);
-       }
-       if (mode & MODE_REC) {
-               opar = *sopar;
-               round = dev_roundof(d, opar.rate);
-               nblk = (d->bufsz / d->round + 3) / 4;
-               nch = opar.cmax - opar.cmin + 1;
-               if (!aparams_eqenc(&opar, &d->ipar)) {
-                       conv = enc_new(name, &opar);
-                       opar.bps = d->ipar.bps;
-                       opar.bits = d->ipar.bits;
-                       opar.sig = d->ipar.sig;
-                       opar.le = d->ipar.le;
-                       opar.msb = d->ipar.msb;
-                       aproc_setout(conv, obuf);
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (onch > 0 && nch >= onch * 2) {
-                       conv = join_new(name);
-                       aproc_setout(conv, obuf);
-                       opar.cmax = opar.cmin + onch - 1;
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (!aparams_eqrate(&opar, &d->ipar)) {
-                       conv = resamp_new(name, d->round, round);
-                       opar.rate = d->ipar.rate;
-                       round = d->round;
-                       aproc_setout(conv, obuf);
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (onch > 0 && nch * 2 <= onch) {
-                       conv = join_new(name);
-                       aproc_setout(conv, obuf);
-                       opar.cmax = opar.cmin + onch - 1;
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               aproc_setout(d->sub, obuf);
-               obuf->w.sub.xrun = xrun;
-       }
-       if (mode & MODE_MON) {
-               opar = *sopar;
-               round = dev_roundof(d, opar.rate);
-               nblk = (d->bufsz / d->round + 3) / 4;
-               nch = opar.cmax - opar.cmin + 1;
-               if (!aparams_eqenc(&opar, &d->opar)) {
-                       conv = enc_new(name, &opar);
-                       opar.bps = d->opar.bps;
-                       opar.bits = d->opar.bits;
-                       opar.sig = d->opar.sig;
-                       opar.le = d->opar.le;
-                       opar.msb = d->opar.msb;
-                       aproc_setout(conv, obuf);
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (onch > 0 && nch >= onch * 2) {
-                       conv = join_new(name);
-                       aproc_setout(conv, obuf);
-                       opar.cmax = opar.cmin + onch - 1;
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (!aparams_eqrate(&opar, &d->opar)) {
-                       conv = resamp_new(name, d->round, round);
-                       opar.rate = d->opar.rate;
-                       round = d->round;
-                       aproc_setout(conv, obuf);
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               if (onch > 0 && nch * 2 <= onch) {
-                       conv = join_new(name);
-                       aproc_setout(conv, obuf);
-                       opar.cmax = opar.cmin + onch - 1;
-                       obuf = abuf_new(nblk * round, &opar);
-                       aproc_setin(conv, obuf);
-               }
-               aproc_setout(d->submon, obuf);
-               obuf->w.sub.xrun = xrun;
-       }
-
-       /*
-        * Sync play to record.
-        */
-       if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
-               ibuf->duplex = obuf;
-               obuf->duplex = ibuf;
-       }
-       dev_sync(d, mode, ibuf, obuf);
-}
-
-/*
- * Change the playback volume of the given stream.
- */
-void
-dev_setvol(struct dev *d, struct abuf *ibuf, int vol)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               abuf_dbg(ibuf);
-               dbg_puts(": setting volume to ");
-               dbg_putu(vol);
-               dbg_puts("\n");
-       }
-#endif
-       if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) {
-               return;
-       }
-       ibuf->r.mix.vol = vol;
-}
-
-/*
- * Clear buffers of the play and record chains so that when the device
- * is started, playback and record start in sync.
- */
-void
-dev_clear(struct dev *d)
-{
-       struct abuf *buf;
-
-       if (APROC_OK(d->mix)) {
-#ifdef DEBUG
-               if (!LIST_EMPTY(&d->mix->ins)) {
-                       dev_dbg(d);
-                       dbg_puts(": play end not idle, can't clear device\n");
-                       dbg_panic();    
-               }
-#endif
-               buf = LIST_FIRST(&d->mix->outs);
-               while (buf) {
-                       abuf_clear(buf);
-                       buf = LIST_FIRST(&buf->rproc->outs);
-               }
-               mix_clear(d->mix);
-       }
-       if (APROC_OK(d->sub)) {
-#ifdef DEBUG
-               if (!LIST_EMPTY(&d->sub->outs)) {
-                       dev_dbg(d);
-                       dbg_puts(": record end not idle, can't clear device\n");
-                       dbg_panic();    
-               }
-#endif
-               buf = LIST_FIRST(&d->sub->ins);
-               while (buf) {
-                       abuf_clear(buf);
-                       buf = LIST_FIRST(&buf->wproc->ins);
-               }
-               sub_clear(d->sub);
-       }
-       if (APROC_OK(d->submon)) {
-#ifdef DEBUG
-               if (!LIST_EMPTY(&d->submon->outs)) {
-                       dev_dbg(d);
-                       dbg_puts(": monitoring end not idle, can't clear device\n");
-                       dbg_panic();
-               }
-#endif
-               buf = LIST_FIRST(&d->submon->ins);
-               while (buf) {
-                       abuf_clear(buf);
-                       buf = LIST_FIRST(&buf->wproc->ins);
-               }
-               sub_clear(d->submon);
-               mon_clear(d->mon);
-       }
-}
-
-#ifdef DEBUG
-void
-dev_slotdbg(struct dev *d, int slot)
-{
-       struct ctl_slot *s;
-
-       if (slot < 0) {
-               dbg_puts("none");
-       } else {
-               s = d->slot + slot;
-               dbg_puts(s->name);
-               dbg_putu(s->unit);
-               dbg_puts("(");
-               dbg_putu(s->vol);
-               dbg_puts(")/");
-               switch (s->tstate) {
-               case CTL_OFF:
-                       dbg_puts("off");
-                       break;
-               case CTL_RUN:
-                       dbg_puts("run");
-                       break;
-               case CTL_START:
-                       dbg_puts("sta");
-                       break;
-               case CTL_STOP:
-                       dbg_puts("stp");
-                       break;
-               default:
-                       dbg_puts("unk");
-                       break;
-               }
-       }
-}
-#endif
-
-/*
- * find the best matching free slot index (ie midi channel).
- * return -1, if there are no free slots anymore
- */
-int
-dev_mkslot(struct dev *d, char *who)
-{
-       char *s;
-       struct ctl_slot *slot;
-       char name[CTL_NAMEMAX];
-       unsigned int i, unit, umap = 0;
-       unsigned int ser, bestser, bestidx;
-
-       /*
-        * create a ``valid'' control name (lowcase, remove [^a-z], trucate)
-        */
-       for (i = 0, s = who; ; s++) {
-               if (i == CTL_NAMEMAX - 1 || *s == '\0') {
-                       name[i] = '\0';
-                       break;
-               } else if (*s >= 'A' && *s <= 'Z') {
-                       name[i++] = *s + 'a' - 'A';
-               } else if (*s >= 'a' && *s <= 'z')
-                       name[i++] = *s;
-       }
-       if (i == 0)
-               strlcpy(name, "noname", CTL_NAMEMAX);
-
-       /*
-        * find the instance number of the control name
-        */
-       for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
-               if (slot->ops == NULL)
-                       continue;
-               if (strcmp(slot->name, name) == 0)
-                       umap |= (1 << slot->unit);
-       } 
-       for (unit = 0; ; unit++) {
-               if (unit == CTL_NSLOT) {
-#ifdef DEBUG
-                       if (debug_level >= 1) {
-                               dbg_puts(name);
-                               dbg_puts(": too many instances\n");
-                       }
-#endif
-                       return -1;
-               }
-               if ((umap & (1 << unit)) == 0)
-                       break;
-       }
-
-       /*
-        * find a free controller slot with the same name/unit
-        */
-       for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
-               if (slot->ops == NULL &&
-                   strcmp(slot->name, name) == 0 &&
-                   slot->unit == unit) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               dbg_puts(name);
-                               dbg_putu(unit);
-                               dbg_puts(": found slot ");
-                               dbg_putu(i);
-                               dbg_puts("\n");
-                       }
-#endif
-                       return i;
-               }
-       }
-
-       /*
-        * couldn't find a matching slot, pick oldest free slot
-        * and set its name/unit
-        */
-       bestser = 0;
-       bestidx = CTL_NSLOT;
-       for (i = 0, slot = d->slot; i < CTL_NSLOT; i++, slot++) {
-               if (slot->ops != NULL)
-                       continue;
-               ser = d->serial - slot->serial;
-               if (ser > bestser) {
-                       bestser = ser;
-                       bestidx = i;
-               }
-       }
-       if (bestidx == CTL_NSLOT) {
-#ifdef DEBUG
-               if (debug_level >= 1) {
-                       dbg_puts(name);
-                       dbg_putu(unit);
-                       dbg_puts(": out of mixer slots\n");
-               }
-#endif
-               return -1;
-       }
-       slot = d->slot + bestidx;
-       if (slot->name[0] != '\0')
-               slot->vol = MIDI_MAXCTL;
-       strlcpy(slot->name, name, CTL_NAMEMAX);
-       slot->serial = d->serial++;
-       slot->unit = unit;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dbg_puts(name);
-               dbg_putu(unit);
-               dbg_puts(": overwritten slot ");
-               dbg_putu(bestidx);
-               dbg_puts("\n");
-       }
-#endif
-       return bestidx;
-}
-
-/*
- * allocate a new slot and register the given call-backs
- */
-int
-dev_slotnew(struct dev *d, char *who, struct ctl_ops *ops, void *arg, int mmc)
-{
-       int slot;
-       struct ctl_slot *s;
-
-       slot = dev_mkslot(d, who);
-       if (slot < 0)
-               return -1;
-
-       s = d->slot + slot;
-       s->ops = ops;
-       s->arg = arg;
-       s->tstate = mmc ? CTL_STOP : CTL_OFF;
-       s->ops->vol(s->arg, s->vol);
-
-       if (APROC_OK(d->midi)) {
-               midi_send_slot(d->midi, slot);
-               midi_send_vol(d->midi, slot, s->vol);
-               midi_flush(d->midi);
-       } else {
-#ifdef DEBUG
-               if (debug_level >= 2) {
-                       dev_slotdbg(d, slot);
-                       dbg_puts(": MIDI control not available\n");
-               }
-#endif
-       }
-       return slot;
-}
-
-/*
- * release the given slot
- */
-void
-dev_slotdel(struct dev *d, int slot)
-{
-       struct ctl_slot *s;
-
-       s = d->slot + slot;
-       s->ops = NULL;
-}
-
-/*
- * notifty the mixer that volume changed, called by whom allocad the slot using
- * ctl_slotnew(). Note: it doesn't make sens to call this from within the
- * call-back.
- *
- * XXX: set actual volume here and use only this interface. Now, this
- *     can work because all streams have a slot
- */
-void
-dev_slotvol(struct dev *d, int slot, unsigned int vol)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dev_slotdbg(d, slot);
-               dbg_puts(": changing volume to ");
-               dbg_putu(vol);
-               dbg_puts("\n");
-       }
-#endif
-       d->slot[slot].vol = vol;
-       if (APROC_OK(d->midi)) {
-               midi_send_vol(d->midi, slot, vol);
-               midi_flush(d->midi);
-       }
-}
-
-/*
- * check that all clients controlled by MMC are ready to start,
- * if so, start them all but the caller
- */
-int
-dev_try(struct dev *d, int slot)
-{
-       unsigned int i;
-       struct ctl_slot *s;
-
-       if (d->tstate != CTL_START) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       dev_slotdbg(d, slot);
-                       dbg_puts(": server not started, delayed\n");
-               }
-#endif
-               return 0;
-       }
-       for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
-               if (!s->ops || i == slot)
-                       continue;
-               if (s->tstate != CTL_OFF && s->tstate != CTL_START) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               dev_slotdbg(d, i);
-                               dbg_puts(": not ready, server delayed\n");
-                       }
-#endif
-                       return 0;
-               }
-       }
-       for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
-               if (!s->ops || i == slot)
-                       continue;
-               if (s->tstate == CTL_START) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               dev_slotdbg(d, i);
-                               dbg_puts(": started\n");
-                       }
-#endif
-                       s->tstate = CTL_RUN;
-                       s->ops->start(s->arg);
-               }
-       }
-       if (slot >= 0)
-               d->slot[slot].tstate = CTL_RUN;
-       d->tstate = CTL_RUN;
-       if (APROC_OK(d->midi)) {
-               midi_send_full(d->midi,
-                   d->origin, d->rate, d->round, dev_getpos(d));
-               midi_flush(d->midi);
-       }
-       dev_wakeup(d);
-       return 1;
-}
-
-/*
- * notify the MMC layer that the stream is attempting
- * to start. If other streams are not ready, 0 is returned meaning 
- * that the stream should wait. If other streams are ready, they
- * are started, and the caller should start immediately.
- */
-int
-dev_slotstart(struct dev *d, int slot)
-{
-       struct ctl_slot *s = d->slot + slot;
-
-       if (s->tstate == CTL_OFF || d->tstate == CTL_OFF)
-               return 1;
-
-       /*
-        * if the server already started (the client missed the
-        * start rendez-vous) or the server is stopped, then
-        * tag the client as ``wanting to start''
-        */
-       s->tstate = CTL_START;
-       return dev_try(d, slot);
-}
-
-/*
- * notify the MMC layer that the stream no longer is trying to
- * start (or that it just stopped), meaning that its ``start'' call-back
- * shouldn't be called anymore
- */
-void
-dev_slotstop(struct dev *d, int slot)
-{
-       struct ctl_slot *s = d->slot + slot;
-
-       /*
-        * tag the stream as not trying to start,
-        * unless MMC is turned off
-        */
-       if (s->tstate != CTL_OFF)
-               s->tstate = CTL_STOP;
-}
-
-/*
- * start all slots simultaneously
- */
-void
-dev_mmcstart(struct dev *d)
-{
-       if (d->tstate == CTL_STOP) {
-               d->tstate = CTL_START;
-               (void)dev_try(d, -1);
-#ifdef DEBUG
-       } else {
-               if (debug_level >= 3) {
-                       dev_dbg(d);
-                       dbg_puts(": ignoring mmc start\n");
-               }
-#endif
-       }
-}
-
-/*
- * stop all slots simultaneously
- */
-void
-dev_mmcstop(struct dev *d)
-{
-       unsigned int i;
-       struct ctl_slot *s;
-
-       switch (d->tstate) {
-       case CTL_START:
-               d->tstate = CTL_STOP;
-               return;
-       case CTL_RUN:
-               d->tstate = CTL_STOP;
-               break;
-       default:
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       dev_dbg(d);
-                       dbg_puts(": ignored mmc stop\n");
-               }
-#endif
-               return;
-       }
-       for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
-               if (!s->ops)
-                       continue;
-               if (s->tstate == CTL_RUN) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               dev_slotdbg(d, i);
-                               dbg_puts(": requested to stop\n");
-                       }
-#endif
-                       s->ops->stop(s->arg);
-               }
-       }
-}
-
-/*
- * relocate all slots simultaneously
- */
-void
-dev_loc(struct dev *d, unsigned int origin)
-{
-       unsigned int i;
-       struct ctl_slot *s;
-
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               dbg_puts("server relocated to ");
-               dbg_putu(origin);
-               dbg_puts("\n");
-       }
-#endif
-       if (d->tstate == CTL_RUN)
-               dev_mmcstop(d);
-       d->origin = origin;
-       for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
-               if (!s->ops)
-                       continue;
-               s->ops->loc(s->arg, d->origin);
-       }
-       if (d->tstate == CTL_RUN)
-               dev_mmcstart(d);
-}
-
-/*
- * called at every clock tick by the mixer, delta is positive, unless
- * there's an overrun/underrun
- */
-void
-dev_onmove(void *arg, int delta)
-{
-       struct dev *d = (struct dev *)arg;
-
-       /*
-        * don't send ticks before the start signal
-        */
-       if (d->tstate != CTL_RUN)
-               return;
-       if (APROC_OK(d->midi)) {
-               midi_send_qfr(d->midi, d->rate, delta);
-               midi_flush(d->midi);
-       }
-}
-
-void
-dev_master(struct dev *d, unsigned int master)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               dev_dbg(d);
-               dbg_puts(": changing master volume to ");
-               dbg_putu(master);
-               dbg_puts("\n");
-       }
-#endif
-       d->master = master;
-       if (APROC_OK(d->mix)) {
-               d->mix->u.mix.master = MIDI_TO_ADATA(master);
-               mix_setmaster(d->mix);
-       }
-}
diff --git a/usr.bin/aucat/dev.h b/usr.bin/aucat/dev.h
deleted file mode 100644 (file)
index cecedf1..0000000
+++ /dev/null
@@ -1,127 +0,0 @@
-/*     $OpenBSD: dev.h,v 1.36 2012/04/11 06:05:43 ratchov Exp $        */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef DEV_H
-#define DEV_H
-
-#include "aparams.h"
-
-struct aproc;
-struct abuf;
-
-struct dev {
-       struct dev *next;
-
-       /*
-        * desired parameters
-        */
-       unsigned int reqmode;                   /* mode */
-       struct aparams reqipar, reqopar;        /* parameters */
-       unsigned int reqbufsz;                  /* buffer size */
-       unsigned int reqround;                  /* block size */
-       unsigned int hold;                              /* hold the device open ? */
-       unsigned int autovol;                   /* auto adjust playvol ? */
-       unsigned int autostart;                 /* don't wait for MMC start */
-       unsigned int refcnt;                    /* number of openers */
-#define DEV_NMAX       16                      /* max number of devices */
-       unsigned int num;                               /* serial number */
-#define DEV_CLOSED     0                       /* closed */
-#define DEV_INIT       1                       /* stopped */
-#define DEV_START      2                       /* ready to start */
-#define DEV_RUN                3                       /* started */
-       unsigned int pstate;                    /* on of DEV_xxx */
-       char *path;                             /* sio path */
-
-       /*
-        * actual parameters and runtime state (i.e. once opened)
-        */
-       unsigned int mode;                              /* bitmap of MODE_xxx */
-       unsigned int bufsz, round, rate;
-       struct aparams ipar, opar;
-       struct aproc *mix, *sub, *submon;
-       struct aproc *rec, *play, *mon;
-       struct aproc *midi;
-       struct devctl {
-               struct devctl *next;
-               unsigned int mode;
-               char *path;
-       } *ctl_list;
-
-       /* volume control and MMC/MTC */
-#define CTL_NSLOT      8
-#define CTL_NAMEMAX    8
-       unsigned int serial;
-       struct ctl_slot {
-               struct ctl_ops {
-                       void (*vol)(void *, unsigned int);
-                       void (*start)(void *);
-                       void (*stop)(void *);
-                       void (*loc)(void *, unsigned int);
-                       void (*quit)(void *);
-               } *ops;
-               void *arg;
-               unsigned int unit;
-               char name[CTL_NAMEMAX];
-               unsigned int serial;
-               unsigned int vol;
-               unsigned int tstate;
-       } slot[CTL_NSLOT];
-#define CTL_OFF                0                       /* ignore MMC messages */
-#define CTL_STOP       1                       /* stopped, can't start */
-#define CTL_START      2                       /* attempting to start */
-#define CTL_RUN                3                       /* started */
-       unsigned int tstate;                    /* one of above */
-       unsigned int origin;                    /* MTC start time */
-       unsigned int master;                    /* master volume controller */
-};
-
-extern struct dev *dev_list;
-
-void dev_dbg(struct dev *);
-int  dev_init(struct dev *);
-int  dev_run(struct dev *);
-int  dev_ref(struct dev *);
-void dev_unref(struct dev *);
-void dev_del(struct dev *);
-void dev_wakeup(struct dev *);
-void dev_drain(struct dev *);
-struct dev *dev_new(char *, unsigned int, unsigned int,
-    unsigned int, unsigned int, unsigned int);
-void dev_adjpar(struct dev *, unsigned int,
-    struct aparams *, struct aparams *);
-int  devctl_add(struct dev *, char *, unsigned int);
-void dev_midiattach(struct dev *, struct abuf *, struct abuf *);
-unsigned int dev_roundof(struct dev *, unsigned int);
-int dev_getpos(struct dev *);
-void dev_attach(struct dev *, char *, unsigned int,
-    struct abuf *, struct aparams *, unsigned int,
-    struct abuf *, struct aparams *, unsigned int,
-    unsigned int, int);
-void dev_setvol(struct dev *, struct abuf *, int);
-
-void dev_slotdbg(struct dev *, int);
-int  dev_slotnew(struct dev *, char *, struct ctl_ops *, void *, int);
-void dev_slotdel(struct dev *, int);
-void dev_slotvol(struct dev *, int, unsigned int);
-
-int  dev_slotstart(struct dev *, int);
-void dev_slotstop(struct dev *, int);
-void dev_mmcstart(struct dev *);
-void dev_mmcstop(struct dev *);
-void dev_loc(struct dev *, unsigned int);
-void dev_master(struct dev *, unsigned int);
-
-#endif /* !define(DEV_H) */
diff --git a/usr.bin/aucat/dsp.c b/usr.bin/aucat/dsp.c
new file mode 100644 (file)
index 0000000..927e00f
--- /dev/null
@@ -0,0 +1,863 @@
+/*     $OpenBSD: dsp.c,v 1.1 2015/01/21 08:43:55 ratchov Exp $ */
+/*
+ * Copyright (c) 2008-2012 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <string.h>
+#include "dsp.h"
+#include "utils.h"
+
+int aparams_ctltovol[128] = {
+           0,
+         256,    266,    276,    287,    299,    310,    323,    335,
+         348,    362,    376,    391,    406,    422,    439,    456,
+         474,    493,    512,    532,    553,    575,    597,    621,
+         645,    670,    697,    724,    753,    782,    813,    845,
+         878,    912,    948,    985,   1024,   1064,   1106,   1149,
+        1195,   1241,   1290,   1341,   1393,   1448,   1505,   1564,
+        1625,   1689,   1756,   1825,   1896,   1971,   2048,   2128,
+        2212,   2299,   2389,   2483,   2580,   2682,   2787,   2896,
+        3010,   3128,   3251,   3379,   3511,   3649,   3792,   3941,
+        4096,   4257,   4424,   4598,   4778,   4966,   5161,   5363,
+        5574,   5793,   6020,   6256,   6502,   6757,   7023,   7298,
+        7585,   7883,   8192,   8514,   8848,   9195,   9556,   9931,
+       10321,  10726,  11148,  11585,  12040,  12513,  13004,  13515,
+       14045,  14596,  15170,  15765,  16384,  17027,  17696,  18390,
+       19112,  19863,  20643,  21453,  22295,  23170,  24080,  25025,
+       26008,  27029,  28090,  29193,  30339,  31530,  32768
+};
+
+short dec_ulawmap[256] = {
+       -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
+       -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
+       -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
+       -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
+        -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
+        -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
+        -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
+        -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
+        -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
+        -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
+         -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
+         -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
+         -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
+         -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
+         -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
+          -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
+        32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
+        23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
+        15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
+        11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
+         7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
+         5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
+         3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
+         2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
+         1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
+         1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
+          876,    844,    812,    780,    748,    716,    684,    652,
+          620,    588,    556,    524,    492,    460,    428,    396,
+          372,    356,    340,    324,    308,    292,    276,    260,
+          244,    228,    212,    196,    180,    164,    148,    132,
+          120,    112,    104,     96,     88,     80,     72,     64,
+           56,     48,     40,     32,     24,     16,      8,      0
+};
+
+short dec_alawmap[256] = {
+        -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
+        -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
+        -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
+        -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
+       -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
+       -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
+       -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
+       -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
+         -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
+         -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
+          -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
+         -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
+        -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
+        -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
+         -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
+         -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
+         5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
+         7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
+         2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
+         3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
+        22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
+        30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
+        11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
+        15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
+          344,    328,    376,    360,    280,    264,    312,    296,
+          472,    456,    504,    488,    408,    392,    440,    424,
+           88,     72,    120,    104,     24,      8,     56,     40,
+          216,    200,    248,    232,    152,    136,    184,    168,
+         1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
+         1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
+          688,    656,    752,    720,    560,    528,    624,    592,
+          944,    912,   1008,    976,    816,    784,    880,    848
+};
+
+/*
+ * Generate a string corresponding to the encoding in par,
+ * return the length of the resulting string.
+ */
+int
+aparams_enctostr(struct aparams *par, char *ostr)
+{
+       char *p = ostr;
+
+       *p++ = par->sig ? 's' : 'u';
+       if (par->bits > 9)
+               *p++ = '0' + par->bits / 10;
+       *p++ = '0' + par->bits % 10;
+       if (par->bps > 1) {
+               *p++ = par->le ? 'l' : 'b';
+               *p++ = 'e';
+               if (par->bps != APARAMS_BPS(par->bits) ||
+                   par->bits < par->bps * 8) {
+                       *p++ = par->bps + '0';
+                       if (par->bits < par->bps * 8) {
+                               *p++ = par->msb ? 'm' : 'l';
+                               *p++ = 's';
+                               *p++ = 'b';
+                       }
+               }
+       }
+       *p++ = '\0';
+       return p - ostr - 1;
+}
+
+/*
+ * Parse an encoding string, examples: s8, u8, s16, s16le, s24be ...
+ * set *istr to the char following the encoding. Return the number
+ * of bytes consumed.
+ */
+int
+aparams_strtoenc(struct aparams *par, char *istr)
+{
+       char *p = istr;
+       int i, sig, bits, le, bps, msb;
+
+#define IS_SEP(c)                      \
+       (((c) < 'a' || (c) > 'z') &&    \
+        ((c) < 'A' || (c) > 'Z') &&    \
+        ((c) < '0' || (c) > '9'))
+
+       /*
+        * get signedness
+        */
+       if (*p == 's') {
+               sig = 1;
+       } else if (*p == 'u') {
+               sig = 0;
+       } else
+               return 0;
+       p++;
+
+       /*
+        * get number of bits per sample
+        */
+       bits = 0;
+       for (i = 0; i < 2; i++) {
+               if (*p < '0' || *p > '9')
+                       break;
+               bits = (bits * 10) + *p - '0';
+               p++;
+       }
+       if (bits < BITS_MIN || bits > BITS_MAX)
+               return 0;
+       bps = APARAMS_BPS(bits);
+       msb = 1;
+       le = ADATA_LE;
+
+       /*
+        * get (optional) endianness
+        */
+       if (p[0] == 'l' && p[1] == 'e') {
+               le = 1;
+               p += 2;
+       } else if (p[0] == 'b' && p[1] == 'e') {
+               le = 0;
+               p += 2;
+       } else if (IS_SEP(*p)) {
+               goto done;
+       } else
+               return 0;
+
+       /*
+        * get (optional) number of bytes
+        */
+       if (*p >= '0' && *p <= '9') {
+               bps = *p - '0';
+               if (bps < (bits + 7) / 8 ||
+                   bps > (BITS_MAX + 7) / 8)
+                       return 0;
+               p++;
+
+               /*
+                * get (optional) alignment
+                */
+               if (p[0] == 'm' && p[1] == 's' && p[2] == 'b') {
+                       msb = 1;
+                       p += 3;
+               } else if (p[0] == 'l' && p[1] == 's' && p[2] == 'b') {
+                       msb = 0;
+                       p += 3;
+               } else if (IS_SEP(*p)) {
+                       goto done;
+               } else
+                       return 0;
+       } else if (!IS_SEP(*p))
+               return 0;
+
+done:
+               par->msb = msb;
+       par->sig = sig;
+       par->bits = bits;
+       par->bps = bps;
+       par->le = le;
+       return p - istr;
+}
+
+/*
+ * Initialise parameters structure with the defaults natively supported
+ * by the machine.
+ */
+void
+aparams_init(struct aparams *par)
+{
+       par->bps = sizeof(adata_t);
+       par->bits = ADATA_BITS;
+       par->le = ADATA_LE;
+       par->sig = 1;
+       par->msb = 0;
+}
+
+/*
+ * log the given format/channels/encoding
+ */
+void
+aparams_log(struct aparams *par)
+{
+       char enc[ENCMAX];
+
+       aparams_enctostr(par, enc);
+       log_puts(enc);
+}
+
+/*
+ * return true if encoding corresponds to what we store in adata_t
+ */
+int
+aparams_native(struct aparams *par)
+{
+       return par->bps == sizeof(adata_t) && par->bits == ADATA_BITS &&
+           (par->bps == 1 || par->le == ADATA_LE) &&
+           (par->bits == par->bps * 8 || !par->msb);
+}
+
+/*
+ * resample the given number of frames
+ */
+int
+resamp_do(struct resamp *p, adata_t *in, adata_t *out, int todo)
+{
+       unsigned int nch;
+       adata_t *idata;
+       unsigned int oblksz;
+       unsigned int ifr;
+       int s, ds, diff;
+       adata_t *odata;
+       unsigned int iblksz;
+       unsigned int ofr;
+       unsigned int c;
+       adata_t *ctxbuf, *ctx;
+       unsigned int ctx_start;
+
+       /*
+        * Partially copy structures into local variables, to avoid
+        * unnecessary indirections; this also allows the compiler to
+        * order local variables more "cache-friendly".
+        */
+       idata = in;
+       odata = out;
+       diff = p->diff;
+       iblksz = p->iblksz;
+       oblksz = p->oblksz;
+       ctxbuf = p->ctx;
+       ctx_start = p->ctx_start;
+       nch = p->nch;
+       ifr = todo;
+       ofr = oblksz;
+
+       /*
+        * Start conversion.
+        */
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("resamp: copying ");
+               log_puti(todo);
+               log_puts(" frames, diff = ");
+               log_putu(diff);
+               log_puts("\n");
+       }
+#endif
+       for (;;) {
+               if (diff < 0) {
+                       if (ifr == 0)
+                               break;
+                       ctx_start ^= 1;
+                       ctx = ctxbuf + ctx_start;
+                       for (c = nch; c > 0; c--) {
+                               *ctx = *idata++;
+                               ctx += RESAMP_NCTX;
+                       }
+                       diff += oblksz;
+                       ifr--;
+               } else if (diff > 0) {
+                       if (ofr == 0)
+                               break;
+                       ctx = ctxbuf;
+                       for (c = nch; c > 0; c--) {
+                               s = ctx[ctx_start];
+                               ds = ctx[ctx_start ^ 1] - s;
+                               ctx += RESAMP_NCTX;
+                               *odata++ = s + ADATA_MULDIV(ds, diff, oblksz);
+                       }
+                       diff -= iblksz;
+                       ofr--;
+               } else {
+                       if (ifr == 0 || ofr == 0)
+                               break;
+                       ctx = ctxbuf + ctx_start;
+                       for (c = nch; c > 0; c--) {
+                               *odata++ = *ctx;
+                               ctx += RESAMP_NCTX;
+                       }
+                       ctx_start ^= 1;
+                       ctx = ctxbuf + ctx_start;
+                       for (c = nch; c > 0; c--) {
+                               *ctx = *idata++;
+                               ctx += RESAMP_NCTX;
+                       }
+                       diff -= iblksz;
+                       diff += oblksz;
+                       ifr--;
+                       ofr--;
+               }
+       }
+       p->diff = diff;
+       p->ctx_start = ctx_start;
+       return oblksz - ofr;
+}
+
+/*
+ * initialize resampler with ibufsz/obufsz factor and "nch" channels
+ */
+void
+resamp_init(struct resamp *p, unsigned int iblksz, unsigned int oblksz, int nch)
+{
+       unsigned int i;
+
+       p->iblksz = iblksz;
+       p->oblksz = oblksz;
+       p->diff = 0;
+       p->idelta = 0;
+       p->odelta = 0;
+       p->nch = nch;
+       p->ctx_start = 0;
+       for (i = 0; i < NCHAN_MAX * RESAMP_NCTX; i++)
+               p->ctx[i] = 0;
+#ifdef DEBUG
+       if (log_level >= 3) {
+               log_puts("resamp: ");
+               log_putu(iblksz);
+               log_puts("/");
+               log_putu(oblksz);
+               log_puts("\n");
+       }
+#endif
+}
+
+/*
+ * encode "todo" frames from native to foreign encoding
+ */
+void
+enc_do(struct conv *p, unsigned char *in, unsigned char *out, int todo)
+{
+       unsigned int f;
+       adata_t *idata;
+       unsigned int s;
+       unsigned int oshift;
+       unsigned int obias;
+       unsigned int obps;
+       unsigned int i;
+       unsigned char *odata;
+       int obnext;
+       int osnext;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("enc: copying ");
+               log_putu(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       /*
+        * Partially copy structures into local variables, to avoid
+        * unnecessary indirections; this also allows the compiler to
+        * order local variables more "cache-friendly".
+        */
+       idata = (adata_t *)in;
+       odata = out;
+       oshift = p->shift;
+       obias = p->bias;
+       obps = p->bps;
+       obnext = p->bnext;
+       osnext = p->snext;
+
+       /*
+        * Start conversion.
+        */
+       odata += p->bfirst;
+       for (f = todo * p->nch; f > 0; f--) {
+               /* convert adata to u32 */
+               s = (int)*idata++ + ADATA_UNIT;
+               s <<= 32 - ADATA_BITS;
+               /* convert u32 to uN */
+               s >>= oshift;
+               /* convert uN to sN */
+               s -= obias;
+               /* packetize sN */
+               for (i = obps; i > 0; i--) {
+                       *odata = (unsigned char)s;
+                       s >>= 8;
+                       odata += obnext;
+               }
+               odata += osnext;
+       }
+}
+
+/*
+ * store "todo" frames of silence in foreign encoding
+ */
+void
+enc_sil_do(struct conv *p, unsigned char *out, int todo)
+{
+       unsigned int f;
+       unsigned int s;
+       unsigned int oshift;
+       int obias;
+       unsigned int obps;
+       unsigned int i;
+       unsigned char *odata;
+       int obnext;
+       int osnext;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("enc: silence ");
+               log_putu(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       /*
+        * Partially copy structures into local variables, to avoid
+        * unnecessary indirections; this also allows the compiler to
+        * order local variables more "cache-friendly".
+        */
+       odata = out;
+       oshift = p->shift;
+       obias = p->bias;
+       obps = p->bps;
+       obnext = p->bnext;
+       osnext = p->snext;
+
+       /*
+        * Start conversion.
+        */
+       odata += p->bfirst;
+       for (f = todo * p->nch; f > 0; f--) {
+               s = ((1U << 31) >> oshift) - obias;
+               for (i = obps; i > 0; i--) {
+                       *odata = (unsigned char)s;
+                       s >>= 8;
+                       odata += obnext;
+               }
+               odata += osnext;
+       }
+}
+
+/*
+ * initialize encoder from native to foreign encoding
+ */
+void
+enc_init(struct conv *p, struct aparams *par, int nch)
+{
+       p->nch = nch;
+       p->bps = par->bps;
+       if (par->msb) {
+               p->shift = 32 - par->bps * 8;
+       } else {
+               p->shift = 32 - par->bits;
+       }
+       if (par->sig) {
+               p->bias = (1U << 31) >> p->shift;
+       } else {
+               p->bias = 0;
+       }       
+       if (!par->le) {
+               p->bfirst = par->bps - 1;
+               p->bnext = -1;
+               p->snext = 2 * par->bps;
+       } else {
+               p->bfirst = 0;
+               p->bnext = 1;
+               p->snext = 0;
+       }
+#ifdef DEBUG
+       if (log_level >= 3) {
+               log_puts("enc: ");
+               aparams_log(par);
+               log_puts(", ");
+               log_puti(p->nch);
+               log_puts(" channels\n");
+       }
+#endif
+}
+
+/*
+ * decode "todo" frames from from foreign to native encoding
+ */
+void
+dec_do(struct conv *p, unsigned char *in, unsigned char *out, int todo)
+{
+       unsigned int f;
+       unsigned int ibps;
+       unsigned int i;
+       unsigned int s = 0xdeadbeef;
+       unsigned char *idata;
+       int ibnext;
+       int isnext;
+       unsigned int ibias;
+       unsigned int ishift;
+       adata_t *odata;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("dec: copying ");
+               log_putu(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       /*
+        * Partially copy structures into local variables, to avoid
+        * unnecessary indirections; this also allows the compiler to
+        * order local variables more "cache-friendly".
+        */
+       idata = in;
+       odata = (adata_t *)out;
+       ibps = p->bps;
+       ibnext = p->bnext;
+       ibias = p->bias;
+       ishift = p->shift;
+       isnext = p->snext;
+
+       /*
+        * Start conversion.
+        */
+       idata += p->bfirst;
+       for (f = todo * p->nch; f > 0; f--) {
+               for (i = ibps; i > 0; i--) {
+                       s <<= 8;
+                       s |= *idata;
+                       idata += ibnext;
+               }
+               idata += isnext;
+               s += ibias;
+               s <<= ishift;
+               s >>= 32 - ADATA_BITS;
+               *odata++ = s - ADATA_UNIT;
+       }
+}
+
+/*
+ * convert a 32-bit float to adata_t, clipping to -1:1, boundaries
+ * excluded
+ */
+static inline int
+f32_to_adata(unsigned int x)
+{
+       unsigned int s, e, m, y;
+
+       s = (x >> 31);
+       e = (x >> 23) & 0xff;
+       m = (x << 8) | 0x80000000;
+       if (e < 127 - 24)
+               y = 0;
+       else if (e > 127 - 1)
+               y = ADATA_UNIT - 1;
+       else
+               y = m >> (127 + (32 - ADATA_BITS) - e);
+       return (y ^ -s) + s;
+}
+
+/*
+ * convert samples from little endian ieee 754 floats to adata_t
+ */
+void
+dec_do_float(struct conv *p, unsigned char *in, unsigned char *out, int todo)
+{
+       unsigned int f;
+       unsigned int i;
+       unsigned int s = 0xdeadbeef;
+       unsigned char *idata;
+       int ibnext;
+       int isnext;
+       adata_t *odata;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("dec_float: copying ");
+               log_putu(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       /*
+        * Partially copy structures into local variables, to avoid
+        * unnecessary indirections; this also allows the compiler to
+        * order local variables more "cache-friendly".
+        */
+       idata = in;
+       odata = (adata_t *)out;
+       ibnext = p->bnext;
+       isnext = p->snext;
+
+       /*
+        * Start conversion.
+        */
+       idata += p->bfirst;
+       for (f = todo * p->nch; f > 0; f--) {
+               for (i = 4; i > 0; i--) {
+                       s <<= 8;
+                       s |= *idata;
+                       idata += ibnext;
+               }
+               idata += isnext;
+               *odata++ = f32_to_adata(s);
+       }
+}
+
+/*
+ * convert samples from ulaw/alaw to adata_t
+ */
+void
+dec_do_ulaw(struct conv *p, unsigned char *in, unsigned char *out, int todo, int is_alaw)
+{
+       unsigned int f;
+       unsigned char *idata;
+       adata_t *odata;
+       short *map;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("dec_ulaw: copying ");
+               log_putu(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       map = is_alaw ? dec_alawmap : dec_ulawmap;
+       idata = in;
+       odata = (adata_t *)out;
+       for (f = todo * p->nch; f > 0; f--)
+               *odata++ = map[*idata++] << (ADATA_BITS - 16);
+}
+
+/*
+ * initialize decoder from foreign to native encoding
+ */
+void
+dec_init(struct conv *p, struct aparams *par, int nch)
+{
+       p->bps = par->bps;
+       p->nch = nch;
+       if (par->msb) {
+               p->shift = 32 - par->bps * 8;
+       } else {
+               p->shift = 32 - par->bits;
+       }
+       if (par->sig) {
+               p->bias = (1U << 31) >> p->shift;
+       } else {
+               p->bias = 0;
+       }       
+       if (par->le) {
+               p->bfirst = par->bps - 1;
+               p->bnext = -1;
+               p->snext = 2 * par->bps;
+       } else {
+               p->bfirst = 0;
+               p->bnext = 1;
+               p->snext = 0;
+       }
+#ifdef DEBUG
+       if (log_level >= 3) {
+               log_puts("dec: ");
+               aparams_log(par);
+               log_puts(", ");
+               log_puti(p->nch);
+               log_puts(" channels\n");
+       }
+#endif
+}
+
+/*
+ * mix "todo" input frames on the output with the given volume
+ */
+void
+cmap_add(struct cmap *p, void *in, void *out, int vol, int todo)
+{
+       adata_t *idata, *odata;
+       int i, j, nch, istart, inext, onext, ostart, y, v;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("cmap: adding ");
+               log_puti(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       idata = in;
+       odata = out;
+       ostart = p->ostart;
+       onext = p->onext;
+       istart = p->istart;
+       inext = p->inext;
+       nch = p->nch;
+       v = vol;
+
+       /*
+        * map/mix input on the output
+        */
+       for (i = todo; i > 0; i--) {
+               odata += ostart;
+               idata += istart;
+               for (j = nch; j > 0; j--) {
+                       y = *odata + ADATA_MUL(*idata, v);
+                       if (y >= ADATA_UNIT)
+                               y = ADATA_UNIT - 1;
+                       else if (y < -ADATA_UNIT)
+                               y = -ADATA_UNIT;
+                       *odata = y;
+                       idata++;
+                       odata++;
+               }
+               odata += onext;
+               idata += inext;
+       }
+}
+
+/*
+ * overwrite output with "todo" input frames with with the given volume
+ */
+void
+cmap_copy(struct cmap *p, void *in, void *out, int vol, int todo)
+{
+       adata_t *idata, *odata;
+       int i, j, nch, istart, inext, onext, ostart, v;
+
+#ifdef DEBUG
+       if (log_level >= 4) {
+               log_puts("cmap: copying ");
+               log_puti(todo);
+               log_puts(" frames\n");
+       }
+#endif
+       idata = in;
+       odata = out;
+       ostart = p->ostart;
+       onext = p->onext;
+       istart = p->istart;
+       inext = p->inext;
+       nch = p->nch;
+       v = vol;
+
+       /*
+        * copy to the output buffer
+        */
+       for (i = todo; i > 0; i--) {
+               idata += istart;
+               odata += ostart;
+               for (j = nch; j > 0; j--) {
+                       *odata = ADATA_MUL(*idata, v);
+                       odata++;
+                       idata++;
+               }
+               odata += onext;
+               idata += inext;
+       }
+}
+
+/*
+ * initialize channel mapper, to map a subset of input channel range
+ * into a subset of the output channel range
+ */
+void
+cmap_init(struct cmap *p,
+    int imin, int imax, int isubmin, int isubmax,
+    int omin, int omax, int osubmin, int osubmax)
+{
+       int cmin, cmax;
+
+       cmin = -NCHAN_MAX;
+       if (osubmin > cmin)
+               cmin = osubmin;
+       if (omin > cmin)
+               cmin = omin;
+       if (isubmin > cmin)
+               cmin = isubmin;
+       if (imin > cmin)
+               cmin = imin;
+
+       cmax = NCHAN_MAX;
+       if (osubmax < cmax)
+               cmax = osubmax;
+       if (omax < cmax)
+               cmax = omax;
+       if (isubmax < cmax)
+               cmax = isubmax;
+       if (imax < cmax)
+               cmax = imax;
+
+       p->ostart = cmin - omin;
+       p->onext = omax - cmax;
+       p->istart = cmin - imin;
+       p->inext = imax - cmax;
+       p->nch = cmax - cmin + 1;
+#ifdef DEBUG
+       if (log_level >= 3) {
+               log_puts("cmap: nch = ");
+               log_puti(p->nch);
+               log_puts(", ostart = ");
+               log_puti(p->ostart);
+               log_puts(", onext = ");
+               log_puti(p->onext);
+               log_puts(", istart = ");
+               log_puti(p->istart);
+               log_puts(", inext = ");
+               log_puti(p->inext);
+               log_puts("\n");
+       }
+#endif
+}
diff --git a/usr.bin/aucat/dsp.h b/usr.bin/aucat/dsp.h
new file mode 100644 (file)
index 0000000..1fc80c2
--- /dev/null
@@ -0,0 +1,163 @@
+/*     $OpenBSD: dsp.h,v 1.1 2015/01/21 08:43:55 ratchov Exp $ */
+/*
+ * Copyright (c) 2012 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#ifndef DSP_H
+#define DSP_H
+
+#include <sys/types.h>
+#include "defs.h"
+
+/*
+ * Samples are numbers in the interval [-1, 1[, note that 1, the upper
+ * boundary is excluded. We represent them as signed fixed point numbers
+ * of ADATA_BITS. We also assume that 2^(ADATA_BITS - 1) fits in a int.
+ */
+#ifndef ADATA_BITS
+#define ADATA_BITS                     16
+#endif
+#define ADATA_LE                       (BYTE_ORDER == LITTLE_ENDIAN)
+#define ADATA_UNIT                     (1 << (ADATA_BITS - 1))
+
+#if ADATA_BITS == 16
+
+#define ADATA_MUL(x,y)         (((int)(x) * (int)(y)) >> (ADATA_BITS - 1))
+#define ADATA_MULDIV(x,y,z)    ((int)(x) * (int)(y) / (int)(z))
+
+typedef short adata_t;
+
+#elif ADATA_BITS == 24
+
+#if defined(__i386__) && defined(__GNUC__)
+
+static inline int
+fp24_mul(int x, int a)
+{
+       int res;
+
+       asm volatile (
+               "imull  %2\n\t"
+               "shrdl $23, %%edx, %%eax\n\t"
+               : "=a" (res)
+               : "a" (x), "r" (a)
+               : "%edx"
+               );
+       return res;
+}
+
+static inline int
+fp24_muldiv(int x, int a, int b)
+{
+       int res;
+
+       asm volatile (
+               "imull %2\n\t"
+               "idivl %3\n\t"
+               : "=a" (res)
+               : "a" (x), "d" (a), "r" (b)
+               );
+       return res;
+}
+
+#define ADATA_MUL(x,y)         fp24_mul(x, y)
+#define ADATA_MULDIV(x,y,z)    fp24_muldiv(x, y, z);
+
+#elif defined(__amd64__) || defined(__sparc64__)
+
+#define ADATA_MUL(x,y)         \
+       ((int)(((long long)(x) * (long long)(y)) >> (ADATA_BITS - 1)))
+#define ADATA_MULDIV(x,y,z)    \
+       ((int)((long long)(x) * (long long)(y) / (long long)(z)))
+
+#else
+#error "no 24-bit code for this architecture"
+#endif
+
+typedef int adata_t;
+
+#else
+#error "only 16-bit and 24-bit precisions are supported"
+#endif
+
+/*
+ * Maximum size of the encording string (the longest possible
+ * encoding is ``s24le3msb'').
+ */
+#define ENCMAX 10
+
+/*
+ * Default bytes per sample for the given bits per sample.
+ */
+#define APARAMS_BPS(bits) (((bits) <= 8) ? 1 : (((bits) <= 16) ? 2 : 4))
+
+struct aparams {
+       unsigned int bps;               /* bytes per sample */
+       unsigned int bits;              /* actually used bits */
+       unsigned int le;                /* 1 if little endian, 0 if big endian */
+       unsigned int sig;               /* 1 if signed, 0 if unsigned */
+       unsigned int msb;               /* 1 if msb justified, 0 if lsb justified */
+};
+
+struct resamp {
+#define RESAMP_NCTX    2
+       unsigned int ctx_start;
+       adata_t ctx[NCHAN_MAX * RESAMP_NCTX];
+       unsigned int iblksz, oblksz;
+       int diff;
+       int idelta, odelta;             /* remainder of ipos/opos */
+       int nch;
+};
+
+struct conv {
+       int bfirst;                     /* bytes to skip at startup */
+       unsigned int bps;               /* bytes per sample */
+       unsigned int shift;             /* shift to get 32bit MSB */
+       unsigned int bias;                      /* bias of unsigned samples */
+       int bnext;                      /* to reach the next byte */
+       int snext;                      /* to reach the next sample */
+       int nch;
+};
+
+struct cmap {
+       int istart;
+       int inext;
+       int onext;
+       int ostart;
+       int nch;
+};
+
+#define MIDI_TO_ADATA(m)       (aparams_ctltovol[m] << (ADATA_BITS - 16))
+extern int aparams_ctltovol[128];
+
+void aparams_init(struct aparams *);
+void aparams_log(struct aparams *);
+int aparams_strtoenc(struct aparams *, char *);
+int aparams_enctostr(struct aparams *, char *);
+int aparams_native(struct aparams *);
+
+int resamp_do(struct resamp *, adata_t *, adata_t *, int);
+void resamp_init(struct resamp *, unsigned int, unsigned int, int);
+void enc_do(struct conv *, unsigned char *, unsigned char *, int);
+void enc_sil_do(struct conv *, unsigned char *, int);
+void enc_init(struct conv *, struct aparams *, int);
+void dec_do(struct conv *, unsigned char *, unsigned char *, int);
+void dec_do_float(struct conv *, unsigned char *, unsigned char *, int);
+void dec_do_ulaw(struct conv *, unsigned char *, unsigned char *, int, int);
+void dec_init(struct conv *, struct aparams *, int);
+void cmap_add(struct cmap *, void *, void *, int, int);
+void cmap_copy(struct cmap *, void *, void *, int, int);
+void cmap_init(struct cmap *, int, int, int, int, int, int, int, int);
+
+#endif /* !defined(DSP_H) */
diff --git a/usr.bin/aucat/file.c b/usr.bin/aucat/file.c
deleted file mode 100644 (file)
index b2e6a7f..0000000
+++ /dev/null
@@ -1,775 +0,0 @@
-/*     $OpenBSD: file.c,v 1.31 2013/11/18 17:37:45 ratchov Exp $       */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * non-blocking file i/o module: each file can be read or written (or
- * both). To achieve non-blocking io, we simply use the poll() syscall
- * in an event loop. If a read() or write() syscall return EAGAIN
- * (operation will block), then the file is marked as "for polling", else
- * the file is not polled again.
- *
- * the module also provides trivial timeout implementation,
- * derived from:
- *
- *     anoncvs@moule.caoua.org:/midish
- *
- *             midish/timo.c rev 1.18
- *             midish/mdep.c rev 1.71
- *
- * A timeout is used to schedule the call of a routine (the callback)
- * there is a global list of timeouts that is processed inside the
- * event loop. Timeouts work as follows:
- *
- *     first the timo structure must be initialized with timo_set()
- *
- *     then the timeout is scheduled (only once) with timo_add()
- *
- *     if the timeout expires, the call-back is called; then it can
- *     be scheduled again if needed. It's OK to reschedule it again
- *     from the callback
- *
- *     the timeout can be aborted with timo_del(), it is OK to try to
- *     abort a timout that has expired
- *
- */
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <signal.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <time.h>
-
-#include "abuf.h"
-#include "aproc.h"
-#include "conf.h"
-#include "file.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-#define MAXFDS 100
-#define TIMER_USEC 10000
-
-void timo_update(unsigned int);
-void timo_init(void);
-void timo_done(void);
-void file_sigalrm(int);
-
-struct timespec file_ts;
-struct filelist file_list;
-struct timo *timo_queue;
-unsigned int timo_abstime;
-int file_slowaccept = 0;
-#ifdef DEBUG
-long long file_wtime, file_utime;
-#endif
-
-/*
- * initialise a timeout structure, arguments are callback and argument
- * that will be passed to the callback
- */
-void
-timo_set(struct timo *o, void (*cb)(void *), void *arg)
-{
-       o->cb = cb;
-       o->arg = arg;
-       o->set = 0;
-}
-
-/*
- * schedule the callback in 'delta' 24-th of microseconds. The timeout
- * must not be already scheduled
- */
-void
-timo_add(struct timo *o, unsigned int delta)
-{
-       struct timo **i;
-       unsigned int val;
-       int diff;
-
-#ifdef DEBUG
-       if (o->set) {
-               dbg_puts("timo_add: already set\n");
-               dbg_panic();
-       }
-       if (delta == 0) {
-               dbg_puts("timo_add: zero timeout is evil\n");
-               dbg_panic();
-       }
-#endif
-       val = timo_abstime + delta;
-       for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
-               diff = (*i)->val - val;
-               if (diff > 0) {
-                       break;
-               }
-       }
-       o->set = 1;
-       o->val = val;
-       o->next = *i;
-       *i = o;
-}
-
-/*
- * abort a scheduled timeout
- */
-void
-timo_del(struct timo *o)
-{
-       struct timo **i;
-
-       for (i = &timo_queue; *i != NULL; i = &(*i)->next) {
-               if (*i == o) {
-                       *i = o->next;
-                       o->set = 0;
-                       return;
-               }
-       }
-#ifdef DEBUG
-       if (debug_level >= 4)
-               dbg_puts("timo_del: not found\n");
-#endif
-}
-
-/*
- * routine to be called by the timer when 'delta' 24-th of microsecond
- * elapsed. This routine updates time referece used by timeouts and
- * calls expired timeouts
- */
-void
-timo_update(unsigned int delta)
-{
-       struct timo *to;
-       int diff;
-
-       /*
-        * update time reference
-        */
-       timo_abstime += delta;
-
-       /*
-        * remove from the queue and run expired timeouts
-        */
-       while (timo_queue != NULL) {
-               /*
-                * there is no overflow here because + and - are
-                * modulo 2^32, they are the same for both signed and
-                * unsigned integers
-                */
-               diff = timo_queue->val - timo_abstime;
-               if (diff > 0)
-                       break;
-               to = timo_queue;
-               timo_queue = to->next;
-               to->set = 0;
-               to->cb(to->arg);
-       }
-}
-
-/*
- * initialize timeout queue
- */
-void
-timo_init(void)
-{
-       timo_queue = NULL;
-       timo_abstime = 0;
-}
-
-/*
- * destroy timeout queue
- */
-void
-timo_done(void)
-{
-#ifdef DEBUG
-       if (timo_queue != NULL) {
-               dbg_puts("timo_done: timo_queue not empty!\n");
-               dbg_panic();
-       }
-#endif
-       timo_queue = (struct timo *)0xdeadbeef;
-}
-
-#ifdef DEBUG
-void
-file_dbg(struct file *f)
-{
-       dbg_puts(f->ops->name);
-       dbg_puts("(");
-       dbg_puts(f->name);
-       dbg_puts("|");
-       if (f->state & FILE_ROK)
-               dbg_puts("r");
-       if (f->state & FILE_RINUSE)
-               dbg_puts("R");
-       if (f->state & FILE_WOK)
-               dbg_puts("w");
-       if (f->state & FILE_WINUSE)
-               dbg_puts("W");
-       if (f->state & FILE_EOF)
-               dbg_puts("e");
-       if (f->state & FILE_HUP)
-               dbg_puts("h");
-       if (f->state & FILE_ZOMB)
-               dbg_puts("Z");
-       dbg_puts(")");
-}
-#endif
-
-struct file *
-file_new(struct fileops *ops, char *name, unsigned int nfds)
-{
-       struct file *f;
-
-       LIST_FOREACH(f, &file_list, entry)
-               nfds += f->ops->nfds(f);
-       if (nfds > MAXFDS) {
-#ifdef DEBUG
-               if (debug_level >= 1) {
-                       dbg_puts(name);
-                       dbg_puts(": too many polled files\n");
-               }
-#endif
-               return NULL;
-       }
-       f = malloc(ops->size);
-       if (f == NULL)
-               err(1, "file_new: %s", ops->name);
-       f->ops = ops;
-       f->name = name;
-       f->state = 0;
-#ifdef DEBUG
-       f->cycles = 0;
-#endif
-       f->rproc = NULL;
-       f->wproc = NULL;
-       LIST_INSERT_HEAD(&file_list, f, entry);
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(f);
-               dbg_puts(": created\n");
-       }
-#endif
-       return f;
-}
-
-void
-file_del(struct file *f)
-{
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(f);
-               dbg_puts(": terminating...\n");
-       }
-#endif
-       if (f->state & (FILE_RINUSE | FILE_WINUSE)) {
-               f->state |= FILE_ZOMB;
-       } else {
-               LIST_REMOVE(f, entry);
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       file_dbg(f);
-                       dbg_puts(": destroyed\n");
-               }
-#endif
-               f->ops->close(f);
-               free(f);
-       }
-}
-
-int
-file_poll(void)
-{
-       nfds_t nfds, n;
-       short events, revents;
-       struct pollfd pfds[MAXFDS];
-       struct file *f, *fnext;
-       struct aproc *p;
-       struct timespec ts;
-#ifdef DEBUG
-       struct timespec sleepts;
-#endif
-       long long delta_nsec;
-       int res;
-
-       if (LIST_EMPTY(&file_list) && timo_queue == NULL) {
-#ifdef DEBUG
-               if (debug_level >= 3)
-                       dbg_puts("nothing to do...\n");
-#endif
-               return 0;
-       }
-       /*
-        * Fill the pfds[] array with files that are blocked on reading
-        * and/or writing, skipping those that are just waiting.
-        */
-#ifdef DEBUG
-       dbg_flush();
-       if (debug_level >= 4) 
-               dbg_puts("poll:");
-#endif
-       nfds = 0;
-       LIST_FOREACH(f, &file_list, entry) {
-               events = 0;
-               if (f->rproc && !(f->state & FILE_ROK))
-                       events |= POLLIN;
-               if (f->wproc && !(f->state & FILE_WOK))
-                       events |= POLLOUT;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       dbg_puts(" ");
-                       file_dbg(f);
-               }
-#endif
-               n = f->ops->pollfd(f, pfds + nfds, events);
-               if (n == 0) {
-                       f->pfd = NULL;
-                       continue;
-               }
-               f->pfd = pfds + nfds;
-               nfds += n;
-       }
-#ifdef DEBUG
-       if (debug_level >= 4) {
-               dbg_puts("\npfds[] =");
-               for (n = 0; n < nfds; n++) {
-                       dbg_puts(" ");
-                       dbg_putx(pfds[n].events);
-               }
-               dbg_puts("\n");
-       }
-#endif
-#ifdef DEBUG
-       clock_gettime(CLOCK_MONOTONIC, &sleepts);
-       file_utime += 1000000000LL * (sleepts.tv_sec - file_ts.tv_sec);
-       file_utime += sleepts.tv_nsec - file_ts.tv_nsec;
-#endif
-       res = poll(pfds, nfds, -1);
-       if (res < 0 && errno != EINTR)
-               err(1, "poll");
-       clock_gettime(CLOCK_MONOTONIC, &ts);
-#ifdef DEBUG
-       file_wtime += 1000000000LL * (ts.tv_sec - sleepts.tv_sec);
-       file_wtime += ts.tv_nsec - sleepts.tv_nsec;
-#endif
-       delta_nsec = 1000000000LL * (ts.tv_sec - file_ts.tv_sec);
-       delta_nsec += ts.tv_nsec - file_ts.tv_nsec;
-#ifdef DEBUG
-       if (delta_nsec < 0)
-               dbg_puts("file_poll: negative time interval\n");
-#endif
-       file_ts = ts;
-       if (delta_nsec >= 0 && delta_nsec < 1000000000LL)
-               timo_update(delta_nsec / 1000);
-       else {
-#ifdef DEBUG
-               if (debug_level >= 1)
-                       dbg_puts("ignored huge clock delta\n");
-#endif
-       }
-       if (res <= 0)
-               return 1;
-
-       f = LIST_FIRST(&file_list);
-       while (f != NULL) {
-               if (f->pfd == NULL) {
-                       f = LIST_NEXT(f, entry);
-                       continue;
-               }
-               revents = f->ops->revents(f, f->pfd);
-#ifdef DEBUG
-               if (revents) {
-                       f->cycles++;
-                       if (f->cycles > FILE_MAXCYCLES) {
-                               file_dbg(f);
-                               dbg_puts(": busy loop, disconnecting\n");
-                               revents = POLLHUP;
-                       }
-               }
-#endif
-               if (!(f->state & FILE_ZOMB) && (revents & POLLIN)) {
-                       revents &= ~POLLIN;
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(f);
-                               dbg_puts(": rok\n");
-                       }
-#endif
-                       f->state |= FILE_ROK;
-                       f->state |= FILE_RINUSE;
-                       for (;;) {
-                               p = f->rproc;
-                               if (!p)
-                                       break;
-#ifdef DEBUG
-                               if (debug_level >= 4) {
-                                       aproc_dbg(p);
-                                       dbg_puts(": in\n");
-                               }
-#endif
-                               if (!p->ops->in(p, NULL))
-                                       break;
-                       }
-                       f->state &= ~FILE_RINUSE;
-               }
-               if (!(f->state & FILE_ZOMB) && (revents & POLLOUT)) {
-                       revents &= ~POLLOUT;
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(f);
-                               dbg_puts(": wok\n");
-                       }
-#endif
-                       f->state |= FILE_WOK;
-                       f->state |= FILE_WINUSE;
-                       for (;;) {
-                               p = f->wproc;
-                               if (!p)
-                                       break;
-#ifdef DEBUG
-                               if (debug_level >= 4) {
-                                       aproc_dbg(p);
-                                       dbg_puts(": out\n");
-                               }
-#endif
-                               if (!p->ops->out(p, NULL))
-                                       break;
-                       }
-                       f->state &= ~FILE_WINUSE;
-               }
-               if (!(f->state & FILE_ZOMB) && (revents & POLLHUP)) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               file_dbg(f);
-                               dbg_puts(": disconnected\n");
-                       }
-#endif
-                       f->state |= (FILE_EOF | FILE_HUP);
-               }
-               if (!(f->state & FILE_ZOMB) && (f->state & FILE_EOF)) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               file_dbg(f);
-                               dbg_puts(": eof\n");
-                       }
-#endif
-                       p = f->rproc;
-                       if (p) {
-                               f->state |= FILE_RINUSE;
-#ifdef DEBUG
-                               if (debug_level >= 3) {
-                                       aproc_dbg(p);
-                                       dbg_puts(": eof\n");
-                               }
-#endif
-                               p->ops->eof(p, NULL);
-                               f->state &= ~FILE_RINUSE;
-                       }
-                       f->state &= ~FILE_EOF;
-               }
-               if (!(f->state & FILE_ZOMB) && (f->state & FILE_HUP)) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               file_dbg(f);
-                               dbg_puts(": hup\n");
-                       }
-#endif
-                       p = f->wproc;
-                       if (p) {
-                               f->state |= FILE_WINUSE;
-#ifdef DEBUG
-                               if (debug_level >= 3) {
-                                       aproc_dbg(p);
-                                       dbg_puts(": hup\n");
-                               }
-#endif
-                               p->ops->hup(p, NULL);
-                               f->state &= ~FILE_WINUSE;
-                       }
-                       f->state &= ~FILE_HUP;
-               }
-               fnext = LIST_NEXT(f, entry);
-               if (f->state & FILE_ZOMB)
-                       file_del(f);
-               f = fnext;
-       }
-       if (LIST_EMPTY(&file_list) && timo_queue == NULL) {
-#ifdef DEBUG
-               if (debug_level >= 3)
-                       dbg_puts("no files anymore...\n");
-#endif
-               return 0;
-       }
-       return 1;
-}
-
-/*
- * handler for SIGALRM, invoked periodically
- */
-void
-file_sigalrm(int i)
-{
-       /* nothing to do, we only want poll() to return EINTR */
-}
-
-
-void
-filelist_init(void)
-{
-       static struct sigaction sa;
-       struct itimerval it;
-       sigset_t set;
-
-       sigemptyset(&set);
-       (void)sigaddset(&set, SIGPIPE);
-       if (sigprocmask(SIG_BLOCK, &set, NULL))
-               err(1, "sigprocmask");
-       LIST_INIT(&file_list);
-       if (clock_gettime(CLOCK_MONOTONIC, &file_ts) < 0) {
-               perror("clock_gettime");
-               exit(1);
-       }
-        sa.sa_flags = SA_RESTART;
-        sa.sa_handler = file_sigalrm;
-        sigfillset(&sa.sa_mask);
-        if (sigaction(SIGALRM, &sa, NULL) < 0) {
-               perror("sigaction");
-               exit(1);
-       }
-       it.it_interval.tv_sec = 0;
-       it.it_interval.tv_usec = TIMER_USEC;
-       it.it_value.tv_sec = 0;
-       it.it_value.tv_usec = TIMER_USEC;
-       if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
-               perror("setitimer");
-               exit(1);
-       }
-       timo_init();
-#ifdef DEBUG
-       dbg_sync = 0;
-#endif
-}
-
-void
-filelist_done(void)
-{
-       struct itimerval it;
-#ifdef DEBUG
-       struct file *f;
-
-       if (!LIST_EMPTY(&file_list)) {
-               LIST_FOREACH(f, &file_list, entry) {
-                       file_dbg(f);
-                       dbg_puts(" not closed\n");
-               }
-               dbg_panic();
-       }
-       dbg_sync = 1;
-       dbg_flush();
-#endif
-       timerclear(&it.it_value);
-       timerclear(&it.it_interval);
-       if (setitimer(ITIMER_REAL, &it, NULL) < 0) {
-               perror("setitimer");
-               exit(1);
-       }
-       timo_done();
-}
-
-unsigned int
-file_read(struct file *f, unsigned char *data, unsigned int count)
-{
-       unsigned int n;
-#ifdef DEBUG
-       struct timespec ts0, ts1;
-       long us;
-
-       if (!(f->state & FILE_ROK)) {
-               file_dbg(f);
-               dbg_puts(": read: bad state\n");
-               dbg_panic();
-       }
-       clock_gettime(CLOCK_MONOTONIC, &ts0);
-#endif
-       n = f->ops->read(f, data, count);
-#ifdef DEBUG
-       if (n > 0)
-               f->cycles = 0;
-       clock_gettime(CLOCK_MONOTONIC, &ts1);
-       us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
-       us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
-       if (debug_level >= 4 || (debug_level >= 2 && us >= 5000)) {
-               dbg_puts(f->name);
-               dbg_puts(": read ");
-               dbg_putu(n);
-               dbg_puts(" bytes in ");
-               dbg_putu(us);
-               dbg_puts("us\n");
-       }
-#endif
-       return n;
-}
-
-unsigned int
-file_write(struct file *f, unsigned char *data, unsigned int count)
-{
-       unsigned int n;
-#ifdef DEBUG
-       struct timespec ts0, ts1;
-       long us;
-
-       if (!(f->state & FILE_WOK)) {
-               file_dbg(f);
-               dbg_puts(": write: bad state\n");
-               dbg_panic();
-       }
-       clock_gettime(CLOCK_MONOTONIC, &ts0);
-#endif
-       n = f->ops->write(f, data, count);
-#ifdef DEBUG
-       if (n > 0)
-               f->cycles = 0;
-       clock_gettime(CLOCK_MONOTONIC, &ts1);
-       us = 1000000L * (ts1.tv_sec - ts0.tv_sec);
-       us += (ts1.tv_nsec - ts0.tv_nsec) / 1000;
-       if (debug_level >= 4 || (debug_level >= 2 && us >= 5000)) {
-               dbg_puts(f->name);
-               dbg_puts(": wrote ");
-               dbg_putu(n);
-               dbg_puts(" bytes in ");
-               dbg_putu(us);
-               dbg_puts("us\n");
-       }
-#endif
-       return n;
-}
-
-void
-file_eof(struct file *f)
-{
-       struct aproc *p;
-
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(f);
-               dbg_puts(": eof requested\n");
-       }
-#endif
-       if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
-               p = f->rproc;
-               if (p) {
-                       f->state |= FILE_RINUSE;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               aproc_dbg(p);
-                               dbg_puts(": eof\n");
-                       }
-#endif
-                       p->ops->eof(p, NULL);
-                       f->state &= ~FILE_RINUSE;
-               }
-               if (f->state & FILE_ZOMB)
-                       file_del(f);
-       } else {
-               f->state &= ~FILE_ROK;
-               f->state |= FILE_EOF;
-       }
-}
-
-void
-file_hup(struct file *f)
-{
-       struct aproc *p;
-
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(f);
-               dbg_puts(": hup requested\n");
-       }
-#endif
-       if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
-               p = f->wproc;
-               if (p) {
-                       f->state |= FILE_WINUSE;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               aproc_dbg(p);
-                               dbg_puts(": hup\n");
-                       }
-#endif
-                       p->ops->hup(p, NULL);
-                       f->state &= ~FILE_WINUSE;
-               }
-               if (f->state & FILE_ZOMB)
-                       file_del(f);
-       } else {
-               f->state &= ~FILE_WOK;
-               f->state |= FILE_HUP;
-       }
-}
-
-void
-file_close(struct file *f)
-{
-       struct aproc *p;
-
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(f);
-               dbg_puts(": closing\n");
-       }
-#endif
-       if (f->wproc == NULL && f->rproc == NULL)
-               f->state |= FILE_ZOMB;
-       if (!(f->state & (FILE_RINUSE | FILE_WINUSE))) {
-               p = f->rproc;
-               if (p) {
-                       f->state |= FILE_RINUSE;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               aproc_dbg(p);
-                               dbg_puts(": eof\n");
-                       }
-#endif
-                       p->ops->eof(p, NULL);
-                       f->state &= ~FILE_RINUSE;
-               }
-               p = f->wproc;
-               if (p) {
-                       f->state |= FILE_WINUSE;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               aproc_dbg(p);
-                               dbg_puts(": hup\n");
-                       }
-#endif
-                       p->ops->hup(p, NULL);
-                       f->state &= ~FILE_WINUSE;
-               }
-               if (f->state & FILE_ZOMB)
-                       file_del(f);
-       } else {
-               f->state &= ~(FILE_ROK | FILE_WOK);
-               f->state |= (FILE_EOF | FILE_HUP);
-       }
-}
diff --git a/usr.bin/aucat/file.h b/usr.bin/aucat/file.h
deleted file mode 100644 (file)
index 723bdc7..0000000
+++ /dev/null
@@ -1,97 +0,0 @@
-/*     $OpenBSD: file.h,v 1.14 2012/04/11 06:05:43 ratchov Exp $       */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef FILE_H
-#define FILE_H
-
-#include <sys/queue.h>
-#include <sys/types.h>
-
-struct file;
-struct aproc;
-struct pollfd;
-
-struct timo {
-       struct timo *next;
-       unsigned int val;               /* time to wait before the callback */
-       unsigned int set;               /* true if the timeout is set */
-       void (*cb)(void *arg);          /* routine to call on expiration */
-       void *arg;                      /* argument to give to 'cb' */
-};
-
-struct fileops {
-       char *name;
-       size_t size;
-       void (*close)(struct file *);
-       unsigned int (*read)(struct file *, unsigned char *, unsigned int);
-       unsigned int (*write)(struct file *, unsigned char *, unsigned int);
-       void (*start)(struct file *, void (*)(void *, int), void *);
-       void (*stop)(struct file *);
-       int (*nfds)(struct file *);
-       int (*pollfd)(struct file *, struct pollfd *, int);
-       int (*revents)(struct file *, struct pollfd *);
-};
-
-struct file {
-       struct fileops *ops;
-       struct pollfd *pfd;             /* arg to poll(2) syscall */
-#define FILE_ROK       0x1             /* file readable */
-#define FILE_WOK       0x2             /* file writable */
-#define FILE_EOF       0x4             /* eof on the read end */
-#define FILE_HUP       0x8             /* hang-up on the write end */
-#define FILE_ZOMB      0x10            /* closed, but struct not freed */
-#define FILE_RINUSE    0x20            /* inside rproc->ops->in() */
-#define FILE_WINUSE    0x40            /* inside wproc->ops->out() */
-       unsigned int state;             /* one of above */
-#ifdef DEBUG
-#define FILE_MAXCYCLES 20
-       unsigned int cycles;            /* number of POLLIN/POLLOUT events */
-#endif
-       char *name;                     /* for debug purposes */
-       struct aproc *rproc, *wproc;    /* reader and/or writer */
-       LIST_ENTRY(file) entry;
-};
-
-LIST_HEAD(filelist,file);
-
-extern struct filelist file_list;
-extern int file_slowaccept;
-
-#ifdef DEBUG
-extern long long file_wtime, file_utime;
-#endif
-
-void timo_set(struct timo *, void (*)(void *), void *);
-void timo_add(struct timo *, unsigned int);
-void timo_del(struct timo *);
-
-void filelist_init(void);
-void filelist_done(void);
-void filelist_unlisten(void);
-
-struct file *file_new(struct fileops *, char *, unsigned int);
-void file_del(struct file *);
-void file_dbg(struct file *);
-
-void file_attach(struct file *, struct aproc *, struct aproc *);
-unsigned int file_read(struct file *, unsigned char *, unsigned int);
-unsigned int file_write(struct file *, unsigned char *, unsigned int);
-int file_poll(void);
-void file_eof(struct file *);
-void file_hup(struct file *);
-void file_close(struct file *);
-
-#endif /* !defined(FILE_H) */
diff --git a/usr.bin/aucat/headers.c b/usr.bin/aucat/headers.c
deleted file mode 100644 (file)
index b69e1c5..0000000
+++ /dev/null
@@ -1,292 +0,0 @@
-/*     $OpenBSD: headers.c,v 1.24 2015/01/16 06:40:05 deraadt Exp $    */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <err.h>
-#include <stdio.h>
-#include <stdint.h>
-#include <stdlib.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "aparams.h"
-#include "conf.h"
-#include "wav.h"
-
-/*
- * Encoding IDs used in .wav headers.
- */
-#define WAV_ENC_PCM    1
-#define WAV_ENC_ALAW   6
-#define WAV_ENC_ULAW   7
-#define WAV_ENC_EXT    0xfffe
-
-struct wavriff {
-       char magic[4];
-       uint32_t size;
-       char type[4];
-} __packed;
-
-struct wavchunk {
-       char id[4];
-       uint32_t size;
-} __packed;
-
-struct wavfmt {
-       uint16_t fmt;
-       uint16_t nch;
-       uint32_t rate;
-       uint32_t byterate;
-       uint16_t blkalign;
-       uint16_t bits;
-#define WAV_FMT_SIZE            16
-#define WAV_FMT_SIZE2          (16 + 2)
-#define WAV_FMT_EXT_SIZE       (16 + 24)
-       uint16_t extsize;
-       uint16_t valbits;
-       uint32_t chanmask;
-       uint16_t extfmt;
-       char     guid[14];
-} __packed;
-
-char wav_id_riff[4] = { 'R', 'I', 'F', 'F' };
-char wav_id_wave[4] = { 'W', 'A', 'V', 'E' };
-char wav_id_data[4] = { 'd', 'a', 't', 'a' };
-char wav_id_fmt[4] = { 'f', 'm', 't', ' ' };
-char wav_guid[14] = {
-       0x00, 0x00, 0x00, 0x00,
-       0x10, 0x00, 0x80, 0x00,
-       0x00, 0xAA, 0x00, 0x38,
-       0x9B, 0x71
-};
-
-int wav_readfmt(int, unsigned int, struct aparams *, short **);
-
-int
-wav_readfmt(int fd, unsigned int csize, struct aparams *par, short **map)
-{
-       struct wavfmt fmt;
-       unsigned int nch, cmax, rate, bits, bps, enc;
-
-       if (csize < WAV_FMT_SIZE) {
-               warnx("%u: bugus format chunk size", csize);
-               return 0;
-       }
-       if (csize > WAV_FMT_EXT_SIZE)
-               csize = WAV_FMT_EXT_SIZE;
-       if (read(fd, &fmt, csize) != csize) {
-               warn("riff_read: chunk");
-               return 0;
-       }
-       enc = letoh16(fmt.fmt);
-       bits = letoh16(fmt.bits);
-       if (enc == WAV_ENC_EXT) {
-               if (csize != WAV_FMT_EXT_SIZE) {
-                       warnx("missing extended format chunk in .wav file");
-                       return 0;
-               }
-               if (memcmp(fmt.guid, wav_guid, sizeof(wav_guid)) != 0) {
-                       warnx("unknown format (GUID) in .wav file");
-                       return 0;
-               }
-               bps = (bits + 7) / 8;
-               bits = letoh16(fmt.valbits);
-               enc = letoh16(fmt.extfmt);
-       } else
-               bps = (bits + 7) / 8;
-       switch (enc) {
-       case WAV_ENC_PCM:
-               *map = NULL;
-               break;
-       case WAV_ENC_ALAW:
-               *map = wav_alawmap;
-               break;
-       case WAV_ENC_ULAW:
-               *map = wav_ulawmap;
-               break;
-       default:
-               errx(1, "%u: unsupported encoding in .wav file", enc);
-       }
-       nch = letoh16(fmt.nch);
-       if (nch == 0) {
-               warnx("zero number of channels");
-               return 0;
-       }
-       cmax = par->cmin + nch - 1;
-       if (cmax >= NCHAN_MAX) {
-               warnx("%u:%u: bad range", par->cmin, cmax);
-               return 0;
-       }
-       rate = letoh32(fmt.rate);
-       if (rate < RATE_MIN || rate > RATE_MAX) {
-               warnx("%u: bad sample rate", rate);
-               return 0;
-       }
-       if (bits == 0 || bits > 32) {
-               warnx("%u: bad number of bits", bits);
-               return 0;
-       }
-       if (bits > bps * 8) {
-               warnx("%u: bits larger than bytes-per-sample", bps);
-               return 0;
-       }
-       if (enc == WAV_ENC_PCM) {
-               par->bps = bps;
-               par->bits = bits;
-               par->le = 1;
-               par->sig = (bits <= 8) ? 0 : 1; /* ask microsoft why... */
-               par->msb = 1;
-       } else {
-               if (bits != 8) {
-                       warnx("%u: mulaw/alaw encoding not 8-bit", bits);
-                       return 0;
-               }
-               par->bits = ADATA_BITS;
-               par->bps = sizeof(adata_t);
-               par->le = ADATA_LE;
-               par->sig = 1;
-               par->msb = 0;
-       }
-       par->cmax = cmax;
-       par->rate = rate;
-       return 1;
-}
-
-int
-wav_readhdr(int fd, struct aparams *par, off_t *startpos, off_t *datasz, short **map)
-{
-       struct wavriff riff;
-       struct wavchunk chunk;
-       unsigned int csize, rsize, pos = 0;
-       int fmt_done = 0;
-
-       if (lseek(fd, 0, SEEK_SET) < 0) {
-               warn("lseek: 0");
-               return 0;
-       }
-       if (read(fd, &riff, sizeof(riff)) != sizeof(riff)) {
-               warn("wav_readhdr: header");
-               return 0;
-       }
-       if (memcmp(&riff.magic, &wav_id_riff, 4) != 0 ||
-           memcmp(&riff.type, &wav_id_wave, 4)) {
-               warnx("not a wave file");
-               return 0;
-       }
-       rsize = letoh32(riff.size);
-       for (;;) {
-               if (pos + sizeof(struct wavchunk) > rsize) {
-                       warnx("missing data chunk");
-                       return 0;
-               }
-               if (read(fd, &chunk, sizeof(chunk)) != sizeof(chunk)) {
-                       warn("wav_readhdr: chunk");
-                       return 0;
-               }
-               csize = letoh32(chunk.size);
-               if (memcmp(chunk.id, wav_id_fmt, 4) == 0) {
-                       if (!wav_readfmt(fd, csize, par, map))
-                               return 0;
-                       fmt_done = 1;
-               } else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
-                       *startpos = pos + sizeof(riff) + sizeof(chunk);
-                       *datasz = csize;
-                       break;
-               } else {
-#ifdef DEBUG
-                       if (debug_level >= 2) 
-                               warnx("ignoring chunk <%.4s>\n", chunk.id);
-#endif
-               }
-
-               /*
-                * next chunk
-                */
-               pos += sizeof(struct wavchunk) + csize;
-               if (lseek(fd, sizeof(riff) + pos, SEEK_SET) < 0) {
-                       warn("lseek");
-                       return 0;
-               }
-       }
-       if (!fmt_done) {
-               warnx("missing format chunk");
-               return 0;
-       }
-       return 1;
-}
-
-/*
- * Write header and seek to start position
- */
-int
-wav_writehdr(int fd, struct aparams *par, off_t *startpos, off_t datasz)
-{
-       unsigned int nch = par->cmax - par->cmin + 1;
-       struct {
-               struct wavriff riff;
-               struct wavchunk fmt_hdr;
-               struct wavfmt fmt;
-               struct wavchunk data_hdr;
-       } __packed hdr;
-
-       /*
-        * Check that encoding is supported by .wav file format.
-        */
-       if (par->bits > 8 && !par->le) {
-               warnx("samples must be little endian");
-               return 0;
-       }
-       if (8 * par->bps - par->bits >= 8) {
-               warnx("padding must be less than 8 bits");
-               return 0;
-       }
-       if ((par->bits <= 8 && par->sig) || (par->bits > 8 && !par->sig)) {
-               warnx("samples with more (less) than 8 bits must be signed "
-                   "(unsigned)");
-               return 0;
-       }
-       if (8 * par->bps != par->bits && !par->msb) {
-               warnx("samples must be MSB justified");
-               return 0;
-       }
-
-       memcpy(hdr.riff.magic, wav_id_riff, 4);
-       memcpy(hdr.riff.type, wav_id_wave, 4);
-       hdr.riff.size = htole32(datasz + sizeof(hdr) - sizeof(hdr.riff));
-
-       memcpy(hdr.fmt_hdr.id, wav_id_fmt, 4);
-       hdr.fmt_hdr.size = htole32(sizeof(hdr.fmt));
-       hdr.fmt.fmt = htole16(1);
-       hdr.fmt.nch = htole16(nch);
-       hdr.fmt.rate = htole32(par->rate);
-       hdr.fmt.byterate = htole32(par->rate * par->bps * nch);
-       hdr.fmt.blkalign = par->bps * nch;
-       hdr.fmt.bits = htole16(par->bits);
-
-       memcpy(hdr.data_hdr.id, wav_id_data, 4);
-       hdr.data_hdr.size = htole32(datasz);
-
-       if (lseek(fd, 0, SEEK_SET) < 0) {
-               warn("wav_writehdr: lseek");
-               return 0;
-       }
-       if (write(fd, &hdr, sizeof(hdr)) != sizeof(hdr)) {
-               warn("wav_writehdr: write");
-               return 0;
-       }
-       *startpos = sizeof(hdr);
-       return 1;
-}
diff --git a/usr.bin/aucat/midi.c b/usr.bin/aucat/midi.c
deleted file mode 100644 (file)
index 6327267..0000000
+++ /dev/null
@@ -1,693 +0,0 @@
-/*     $OpenBSD: midi.c,v 1.46 2013/11/18 17:37:45 ratchov Exp $       */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-/*
- * TODO
- *
- * use shadow variables (to save NRPNs, LSB of controller) 
- * in the midi merger
- */
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "abuf.h"
-#include "aproc.h"
-#include "conf.h"
-#include "dev.h"
-#include "midi.h"
-#include "sysex.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-/*
- * input data rate is XFER / TIMO (in bytes per microsecond),
- * it must be slightly larger than the MIDI standard 3125 bytes/s
- */ 
-#define MIDITHRU_XFER 340
-#define MIDITHRU_TIMO 100000
-
-/*
- * masks to extract command and channel of status byte
- */
-#define MIDI_CMDMASK   0xf0
-#define MIDI_CHANMASK  0x0f
-
-/*
- * MIDI status bytes of voice messages
- */
-#define MIDI_NOFF      0x80            /* note off */
-#define MIDI_NON       0x90            /* note on */
-#define MIDI_KAT       0xa0            /* key after touch */
-#define MIDI_CTL       0xb0            /* controller */
-#define MIDI_PC                0xc0            /* program change */
-#define MIDI_CAT       0xd0            /* channel after touch */
-#define MIDI_BEND      0xe0            /* pitch bend */
-#define MIDI_ACK       0xfe            /* active sensing message */
-
-/*
- * MIDI controller numbers
- */
-#define MIDI_CTLVOL    7               /* volume */
-#define MIDI_CTLPAN    11              /* pan */
-
-void midi_cb(void *);
-void midi_msg_info(struct aproc *, int, unsigned char *);
-void midi_msg_vol(struct aproc *, int, unsigned char *);
-void midi_msg_master(struct aproc *, unsigned char *);
-void midi_copy(struct abuf *, struct abuf *, unsigned char *, unsigned int);
-void midi_send(struct aproc *, struct abuf *, unsigned char *, unsigned int);
-void midi_copy_dump(struct aproc *, struct abuf *);
-void midi_onvoice(struct aproc *, struct abuf *);
-void midi_onsysex(struct aproc *, struct abuf *);
-int midi_in(struct aproc *, struct abuf *);
-int midi_out(struct aproc *, struct abuf *);
-void midi_eof(struct aproc *, struct abuf *);
-void midi_hup(struct aproc *, struct abuf *);
-void midi_newin(struct aproc *, struct abuf *);
-void midi_done(struct aproc *);
-
-/*
- * length of voice and common messages (status byte included)
- */
-unsigned int voice_len[] = { 3, 3, 3, 3, 2, 2, 3 };
-unsigned int common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 };
-
-/*
- * call-back invoked periodically to implement throttling; at each invocation
- * gain more ``tickets'' for processing.  If one of the buffer was blocked by
- * the throttling mechanism, then run it
- */
-void
-midi_cb(void *addr)
-{
-       struct aproc *p = (struct aproc *)addr;
-       struct abuf *i, *inext;
-       unsigned int tickets;
-
-       timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
-       
-       for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, ient);
-               tickets = i->tickets;
-               i->tickets = MIDITHRU_XFER;
-               if (tickets == 0)
-                       abuf_run(i);
-       }
-}
-
-void
-midi_msg_info(struct aproc *p, int slot, unsigned char *msg)
-{
-       struct ctl_slot *s;
-       struct sysex *x = (struct sysex *)msg;
-
-       s = p->u.midi.dev->slot + slot;
-       memset(x, 0, sizeof(struct sysex));
-       x->start = SYSEX_START;
-       x->type = SYSEX_TYPE_EDU;
-       x->id0 = SYSEX_AUCAT;
-       x->id1 = SYSEX_AUCAT_MIXINFO;
-       if (*s->name != '\0') {
-               snprintf((char *)x->u.mixinfo.name,
-                   SYSEX_NAMELEN, "%s%u", s->name, s->unit);
-       }
-       x->u.mixinfo.chan = slot;
-       x->u.mixinfo.end = SYSEX_END;
-}
-
-void
-midi_msg_vol(struct aproc *p, int slot, unsigned char *msg)
-{
-       struct ctl_slot *s;
-
-       s = p->u.midi.dev->slot + slot; 
-       msg[0] = MIDI_CTL | slot;
-       msg[1] = MIDI_CTLVOL;
-       msg[2] = s->vol;
-}
-
-void
-midi_msg_master(struct aproc *p, unsigned char *msg)
-{
-       struct sysex *x = (struct sysex *)msg;
-
-       memset(x, 0, sizeof(struct sysex));
-       x->start = SYSEX_START;
-       x->type = SYSEX_TYPE_RT;
-       x->id0 = SYSEX_CONTROL;
-       x->id1 = SYSEX_MASTER;
-       x->u.master.fine = 0;
-       x->u.master.coarse = p->u.midi.dev->master;
-       x->u.master.end = SYSEX_END;
-}
-
-/*
- * send a message to the given output
- */
-void
-midi_copy(struct abuf *ibuf, struct abuf *obuf, unsigned char *msg,
-    unsigned int len)
-{
-       unsigned int ocount;
-       unsigned char *odata;
-
-       if (msg[0] == SYSEX_START)
-               obuf->w.midi.owner = ibuf;
-       while (len > 0) {
-               if (!ABUF_WOK(obuf)) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(obuf);
-                               dbg_puts(": overrun, discarding ");
-                               dbg_putu(obuf->used);
-                               dbg_puts(" bytes\n");
-                       }
-#endif
-                       abuf_rdiscard(obuf, obuf->used);
-                       if (obuf->w.midi.owner == ibuf)
-                               obuf->w.midi.owner = NULL;
-                       return;
-               }
-               odata = abuf_wgetblk(obuf, &ocount, 0);
-               if (ocount > len)
-                       ocount = len;
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(obuf);
-                       dbg_puts(": stored ");
-                       dbg_putu(ocount);
-                       dbg_puts(" bytes\n");
-               }
-#endif
-               memcpy(odata, msg, ocount);
-               abuf_wcommit(obuf, ocount);
-               len -= ocount;
-               msg += ocount;
-       }
-}
-
-/*
- * flush all buffers. Since most of the MIDI traffic is broadcasted to
- * all outputs, the flush is delayed to avoid flushing all outputs for
- * each message.
- */
-void
-midi_flush(struct aproc *p)
-{
-       struct abuf *i, *inext;
-
-       for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, oent);
-               if (ABUF_ROK(i))
-                       (void)abuf_flush(i);
-       }
-}
-
-/*
- * broadcast a message to all output buffers on the behalf of ibuf.
- * ie. don't sent back the message to the sender
- */
-void
-midi_send(struct aproc *p, struct abuf *ibuf, unsigned char *msg,
-    unsigned int len)
-{
-       struct abuf *i, *inext;
-
-       for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
-               inext = LIST_NEXT(i, oent);
-               if (i->duplex && i->duplex == ibuf)
-                       continue;
-               midi_copy(ibuf, i, msg, len);
-       }
-}
-
-/*
- * send a quarter frame MTC message
- */
-void
-midi_send_qfr(struct aproc *p, unsigned int rate, int delta)
-{
-       unsigned char buf[2];
-       unsigned int data;
-       int qfrlen;
-
-       p->u.midi.delta += delta * MTC_SEC;
-       qfrlen = rate * (MTC_SEC / (4 * p->u.midi.fps));
-       while (p->u.midi.delta >= qfrlen) {
-               switch (p->u.midi.qfr) {
-               case 0:
-                       data = p->u.midi.fr & 0xf;
-                       break;
-               case 1:
-                       data = p->u.midi.fr >> 4;
-                       break;
-               case 2:
-                       data = p->u.midi.sec & 0xf;
-                       break;
-               case 3:
-                       data = p->u.midi.sec >> 4;
-                       break;
-               case 4:
-                       data = p->u.midi.min & 0xf;
-                       break;
-               case 5:
-                       data = p->u.midi.min >> 4;
-                       break;
-               case 6:
-                       data = p->u.midi.hr & 0xf;
-                       break;
-               case 7:
-                       data = (p->u.midi.hr >> 4) | (p->u.midi.fps_id << 1);
-                       /*
-                        * tick messages are sent 2 frames ahead
-                        */
-                       p->u.midi.fr += 2;
-                       if (p->u.midi.fr < p->u.midi.fps)
-                               break;
-                       p->u.midi.fr -= p->u.midi.fps;
-                       p->u.midi.sec++;
-                       if (p->u.midi.sec < 60)
-                               break;
-                       p->u.midi.sec = 0;
-                       p->u.midi.min++;
-                       if (p->u.midi.min < 60)
-                               break;
-                       p->u.midi.min = 0;
-                       p->u.midi.hr++;
-                       if (p->u.midi.hr < 24)
-                               break;
-                       p->u.midi.hr = 0;
-                       break;
-               default:
-                       /* NOTREACHED */
-                       data = 0;
-               }
-               buf[0] = 0xf1;
-               buf[1] = (p->u.midi.qfr << 4) | data;
-               p->u.midi.qfr++;
-               p->u.midi.qfr &= 7;
-               midi_send(p, NULL, buf, 2);
-               p->u.midi.delta -= qfrlen;
-       }
-}
-
-/*
- * send a full frame MTC message
- */
-void
-midi_send_full(struct aproc *p, unsigned int origin, unsigned int rate,
-    unsigned int round, unsigned int pos)
-{
-       unsigned char buf[10];
-       unsigned int fps;
-
-       p->u.midi.delta = MTC_SEC * pos;
-       if (rate % (30 * 4 * round) == 0) {
-               p->u.midi.fps_id = MTC_FPS_30;
-               p->u.midi.fps = 30;
-       } else if (rate % (25 * 4 * round) == 0) {
-               p->u.midi.fps_id = MTC_FPS_25;
-               p->u.midi.fps = 25;
-       } else {
-               p->u.midi.fps_id = MTC_FPS_24;
-               p->u.midi.fps = 24;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               aproc_dbg(p);
-               dbg_puts(": mtc full frame at ");
-               dbg_puti(p->u.midi.delta);
-               dbg_puts(", ");
-               dbg_puti(p->u.midi.fps);
-               dbg_puts(" fps\n");
-       }
-#endif
-       fps = p->u.midi.fps;
-       p->u.midi.hr =  (origin / (3600 * MTC_SEC)) % 24;
-       p->u.midi.min = (origin / (60 * MTC_SEC))   % 60;
-       p->u.midi.sec = (origin / MTC_SEC)          % 60;
-       p->u.midi.fr =  (origin / (MTC_SEC / fps))  % fps;
-
-       buf[0] = 0xf0;
-       buf[1] = 0x7f;
-       buf[2] = 0x7f;
-       buf[3] = 0x01;
-       buf[4] = 0x01;
-       buf[5] = p->u.midi.hr | (p->u.midi.fps_id << 5);
-       buf[6] = p->u.midi.min;
-       buf[7] = p->u.midi.sec;
-       buf[8] = p->u.midi.fr;
-       buf[9] = 0xf7;
-       p->u.midi.qfr = 0;
-       midi_send(p, NULL, buf, 10);
-}
-
-void
-midi_copy_dump(struct aproc *p, struct abuf *obuf)
-{
-       unsigned int i;
-       unsigned char msg[sizeof(struct sysex)];
-       struct ctl_slot *s;
-
-       midi_msg_master(p, msg);
-       midi_copy(NULL, obuf, msg, SYSEX_SIZE(master));
-       for (i = 0, s = p->u.midi.dev->slot; i < CTL_NSLOT; i++, s++) {
-               midi_msg_info(p, i, msg);
-               midi_copy(NULL, obuf, msg, SYSEX_SIZE(mixinfo));
-               midi_msg_vol(p, i, msg);
-               midi_copy(NULL, obuf, msg, 3);
-       }
-       msg[0] = SYSEX_START;
-       msg[1] = SYSEX_TYPE_EDU;
-       msg[2] = 0;
-       msg[3] = SYSEX_AUCAT;
-       msg[4] = SYSEX_AUCAT_DUMPEND;
-       msg[5] = SYSEX_END;
-       midi_copy(NULL, obuf, msg, 6);
-}
-
-/*
- * notifty the mixer that volume changed, called by whom allocated the slot using
- * ctl_slotnew(). Note: it doesn't make sense to call this from within the
- * call-back.
- */
-void
-midi_send_vol(struct aproc *p, int slot, unsigned int vol)
-{
-       unsigned char msg[3];
-
-       midi_msg_vol(p, slot, msg);
-       midi_send(p, NULL, msg, 3);
-}
-
-void
-midi_send_master(struct aproc *p)
-{
-       unsigned char msg[sizeof(struct sysex)];
-       
-       midi_msg_master(p, msg);
-       midi_send(p, NULL, msg, SYSEX_SIZE(master));
-}
-
-void
-midi_send_slot(struct aproc *p, int slot)
-{
-       unsigned char msg[sizeof(struct sysex)];
-
-       midi_msg_info(p, slot, msg);
-       midi_send(p, NULL, msg, SYSEX_SIZE(mixinfo));
-}
-
-/*
- * handle a MIDI voice event received from ibuf
- */
-void
-midi_onvoice(struct aproc *p, struct abuf *ibuf)
-{
-       struct ctl_slot *slot;
-       unsigned int chan;
-#ifdef DEBUG
-       unsigned int i;
-
-       if (debug_level >= 3) {
-               abuf_dbg(ibuf);
-               dbg_puts(": got voice event:");
-               for (i = 0; i < ibuf->r.midi.idx; i++) {
-                       dbg_puts(" ");
-                       dbg_putx(ibuf->r.midi.msg[i]);
-               }
-               dbg_puts("\n");
-       }
-#endif
-       if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL &&
-           (ibuf->r.midi.msg[1] == MIDI_CTLVOL)) {
-               midi_send(p, ibuf, ibuf->r.midi.msg, 3);
-               chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
-               if (chan >= CTL_NSLOT)
-                       return;
-               slot = p->u.midi.dev->slot + chan;
-               slot->vol = ibuf->r.midi.msg[2];
-               if (slot->ops == NULL)
-                       return;
-               slot->ops->vol(slot->arg, slot->vol);
-       }
-}
-
-/*
- * handle a MIDI sysex received from ibuf
- */
-void
-midi_onsysex(struct aproc *p, struct abuf *ibuf)
-{
-       struct sysex *x;
-       unsigned int fps, len;
-#ifdef DEBUG
-       unsigned int i;
-
-       if (debug_level >= 3) {
-               abuf_dbg(ibuf);
-               dbg_puts(": got sysex:");
-               for (i = 0; i < ibuf->r.midi.idx; i++) {
-                       dbg_puts(" ");
-                       dbg_putx(ibuf->r.midi.msg[i]);
-               }
-               dbg_puts("\n");
-       }
-#endif
-       x = (struct sysex *)ibuf->r.midi.msg;
-       len = ibuf->r.midi.idx;
-       if (x->start != SYSEX_START)
-               return;
-       if (len < SYSEX_SIZE(empty))
-               return;
-       switch (x->type) {
-       case SYSEX_TYPE_RT:
-               if (x->id0 == SYSEX_CONTROL && x->id1 == SYSEX_MASTER) {
-                       if (len == SYSEX_SIZE(master)) {
-                               dev_master(p->u.midi.dev, x->u.master.coarse);
-                               midi_send(p, ibuf, (unsigned char *)x, len);
-                       }
-                       return;
-               }
-               if (x->id0 != SYSEX_MMC)
-                       return;
-               switch (x->id1) {
-               case SYSEX_MMC_STOP:
-                       if (len != SYSEX_SIZE(stop))
-                               return;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(ibuf);
-                               dbg_puts(": mmc stop\n");
-                       }
-#endif
-                       dev_mmcstop(p->u.midi.dev);
-                       break;
-               case SYSEX_MMC_START:
-                       if (len != SYSEX_SIZE(start))
-                               return;
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               abuf_dbg(ibuf);
-                               dbg_puts(": mmc start\n");
-                       }
-#endif
-                       dev_mmcstart(p->u.midi.dev);
-                       break;
-               case SYSEX_MMC_LOC:
-                       if (len != SYSEX_SIZE(loc) ||
-                           x->u.loc.len != SYSEX_MMC_LOC_LEN ||
-                           x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
-                               return;
-                       switch (x->u.loc.hr >> 5) {
-                       case MTC_FPS_24:
-                               fps = 24;
-                               break;
-                       case MTC_FPS_25:
-                               fps = 25;
-                               break;
-                       case MTC_FPS_30:
-                               fps = 30;
-                               break;
-                       default:
-                               /* XXX: should dev_mmcstop() here */
-                               return;
-                       }
-                       dev_loc(p->u.midi.dev,
-                           (x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
-                            x->u.loc.min * 60 * MTC_SEC +
-                            x->u.loc.sec * MTC_SEC +
-                            x->u.loc.fr * (MTC_SEC / fps) +
-                            x->u.loc.cent * (MTC_SEC / 100 / fps));
-                       break;
-               }
-               break;
-       case SYSEX_TYPE_EDU:
-               if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
-                       return;
-               if (len != SYSEX_SIZE(dumpreq))
-                       return;
-               if (ibuf->duplex)
-                       midi_copy_dump(p, ibuf->duplex);
-               break;
-       }
-}
-
-int
-midi_in(struct aproc *p, struct abuf *ibuf)
-{
-       unsigned char c, *idata;
-       unsigned int i, icount;
-
-       if (!ABUF_ROK(ibuf))
-               return 0;
-       if (ibuf->tickets == 0) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       abuf_dbg(ibuf);
-                       dbg_puts(": out of tickets, blocking\n");
-               }
-#endif
-               return 0;
-       }
-       idata = abuf_rgetblk(ibuf, &icount, 0);
-       if (icount > ibuf->tickets)
-               icount = ibuf->tickets;
-       ibuf->tickets -= icount;
-       for (i = 0; i < icount; i++) {
-               c = *idata++;
-               if (c >= 0xf8) {
-                       if (!p->u.midi.dev && c != MIDI_ACK)
-                               midi_send(p, ibuf, &c, 1);
-               } else if (c == SYSEX_END) {
-                       if (ibuf->r.midi.st == SYSEX_START) {
-                               ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
-                               if (!p->u.midi.dev) {
-                                       midi_send(p, ibuf,
-                                           ibuf->r.midi.msg, ibuf->r.midi.idx);
-                               } else
-                                       midi_onsysex(p, ibuf);
-                       }
-                       ibuf->r.midi.st = 0;
-                       ibuf->r.midi.idx = 0;
-               } else if (c >= 0xf0) {
-                       ibuf->r.midi.msg[0] = c;
-                       ibuf->r.midi.len = common_len[c & 7];
-                       ibuf->r.midi.st = c;
-                       ibuf->r.midi.idx = 1;
-               } else if (c >= 0x80) {
-                       ibuf->r.midi.msg[0] = c;
-                       ibuf->r.midi.len = voice_len[(c >> 4) & 7];
-                       ibuf->r.midi.st = c;
-                       ibuf->r.midi.idx = 1;
-               } else if (ibuf->r.midi.st) {
-                       if (ibuf->r.midi.idx == 0 &&
-                           ibuf->r.midi.st != SYSEX_START) {
-                               ibuf->r.midi.msg[ibuf->r.midi.idx++] =
-                                   ibuf->r.midi.st;
-                       }
-                       ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
-                       if (ibuf->r.midi.idx == ibuf->r.midi.len) {
-                               if (!p->u.midi.dev) {
-                                       midi_send(p, ibuf,
-                                           ibuf->r.midi.msg, ibuf->r.midi.idx);
-                               } else
-                                       midi_onvoice(p, ibuf);
-                               if (ibuf->r.midi.st >= 0xf0)
-                                       ibuf->r.midi.st = 0;
-                               ibuf->r.midi.idx = 0;
-                       } else if (ibuf->r.midi.idx == MIDI_MSGMAX) {
-                               if (!p->u.midi.dev) {
-                                       midi_send(p, ibuf,
-                                           ibuf->r.midi.msg, ibuf->r.midi.idx);
-                               }
-                               ibuf->r.midi.idx = 0;
-                       }
-               }
-       }
-       /*
-        * XXX: if the sysex is received byte by byte, partial messages
-        * won't be sent until the end byte is received. On the other
-        * hand we can't flush it here, since we would lose messages
-        * we parse
-        */
-       abuf_rdiscard(ibuf, icount);
-       midi_flush(p);
-       return 1;
-}
-
-int
-midi_out(struct aproc *p, struct abuf *obuf)
-{
-       return 0;
-}
-
-void
-midi_eof(struct aproc *p, struct abuf *ibuf)
-{
-       if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
-               aproc_del(p);
-}
-
-void
-midi_hup(struct aproc *p, struct abuf *obuf)
-{
-       if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
-               aproc_del(p);
-}
-
-void
-midi_newin(struct aproc *p, struct abuf *ibuf)
-{
-       ibuf->r.midi.used = 0;
-       ibuf->r.midi.len = 0;
-       ibuf->r.midi.idx = 0;
-       ibuf->r.midi.st = 0;
-       ibuf->tickets = MIDITHRU_XFER;
-}
-
-void
-midi_done(struct aproc *p)
-{
-       timo_del(&p->u.midi.timo);
-}
-
-struct aproc_ops midi_ops = {
-       "midi",
-       midi_in,
-       midi_out,
-       midi_eof,
-       midi_hup,
-       midi_newin,
-       NULL, /* newout */
-       NULL, /* ipos */
-       NULL, /* opos */
-       midi_done,
-};
-
-struct aproc *
-midi_new(char *name, struct dev *dev)
-{
-       struct aproc *p;
-
-       p = aproc_new(&midi_ops, name);
-       timo_set(&p->u.midi.timo, midi_cb, p);
-       timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
-       p->u.midi.dev = dev;
-       return p;
-}
diff --git a/usr.bin/aucat/midi.h b/usr.bin/aucat/midi.h
deleted file mode 100644 (file)
index 73a6fc8..0000000
+++ /dev/null
@@ -1,33 +0,0 @@
-/*     $OpenBSD: midi.h,v 1.13 2012/04/11 06:05:43 ratchov Exp $       */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef MIDI_H
-#define MIDI_H
-
-struct dev;
-
-struct aproc *midi_new(char *, struct dev *);
-
-void midi_ontick(struct aproc *, int);
-void midi_send_slot(struct aproc *, int);
-void midi_send_vol(struct aproc *, int, unsigned int);
-void midi_send_master(struct aproc *);
-void midi_send_full(struct aproc *, unsigned int, unsigned int,
-    unsigned int, unsigned int);
-void midi_send_qfr(struct aproc *, unsigned int, int);
-void midi_flush(struct aproc *);
-
-#endif /* !defined(MIDI_H) */
diff --git a/usr.bin/aucat/miofile.c b/usr.bin/aucat/miofile.c
deleted file mode 100644 (file)
index 0f205e4..0000000
+++ /dev/null
@@ -1,162 +0,0 @@
-/*     $OpenBSD: miofile.c,v 1.9 2012/06/27 06:46:44 ratchov Exp $     */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/types.h>
-#include <sys/time.h>
-
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-#include <sndio.h>
-
-#include "conf.h"
-#include "file.h"
-#include "miofile.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-struct miofile {
-       struct file file;
-       struct mio_hdl *hdl;
-};
-
-void miofile_close(struct file *);
-unsigned int miofile_read(struct file *, unsigned char *, unsigned int);
-unsigned int miofile_write(struct file *, unsigned char *, unsigned int);
-void miofile_start(struct file *);
-void miofile_stop(struct file *);
-int miofile_nfds(struct file *);
-int miofile_pollfd(struct file *, struct pollfd *, int);
-int miofile_revents(struct file *, struct pollfd *);
-
-struct fileops miofile_ops = {
-       "mio",
-       sizeof(struct miofile),
-       miofile_close,
-       miofile_read,
-       miofile_write,
-       NULL, /* start */
-       NULL, /* stop */
-       miofile_nfds,
-       miofile_pollfd,
-       miofile_revents
-};
-
-/*
- * open the device
- */
-struct miofile *
-miofile_new(struct fileops *ops, char *path, unsigned int mode)
-{
-       struct mio_hdl *hdl;
-       struct miofile *f;
-
-       hdl = mio_open(path, mode, 1);
-       if (hdl == NULL)
-               return NULL;
-       f = (struct miofile *)file_new(ops, path, mio_nfds(hdl));
-       if (f == NULL)
-               goto bad_close;
-       f->hdl = hdl;
-       return f;
- bad_close:
-       mio_close(hdl);
-       return NULL;
-}
-
-unsigned int
-miofile_read(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct miofile *f = (struct miofile *)file;
-       unsigned int n;
-       
-       n = mio_read(f->hdl, data, count);
-       if (n == 0) {
-               f->file.state &= ~FILE_ROK;
-               if (mio_eof(f->hdl)) {
-#ifdef DEBUG
-                       dbg_puts(f->file.name);
-                       dbg_puts(": failed to read from device\n");
-#endif
-                       file_eof(&f->file);
-               } else {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": reading blocked\n");
-                       }
-#endif
-               }
-               return 0;
-       }
-       return n;
-
-}
-
-unsigned int
-miofile_write(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct miofile *f = (struct miofile *)file;
-       unsigned int n;
-
-       n = mio_write(f->hdl, data, count);
-       if (n == 0) {
-               f->file.state &= ~FILE_WOK;
-               if (mio_eof(f->hdl)) {
-#ifdef DEBUG
-                       dbg_puts(f->file.name);
-                       dbg_puts(": failed to write on device\n");
-#endif
-                       file_hup(&f->file);
-               } else {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": writing blocked\n");
-                       }
-#endif
-               }
-               return 0;
-       }
-       return n;
-}
-
-int
-miofile_nfds(struct file *file)
-{
-       return mio_nfds(((struct miofile *)file)->hdl);
-}
-
-int
-miofile_pollfd(struct file *file, struct pollfd *pfd, int events)
-{
-       return mio_pollfd(((struct miofile *)file)->hdl, pfd, events);
-}
-
-int
-miofile_revents(struct file *file, struct pollfd *pfd)
-{
-       return mio_revents(((struct miofile *)file)->hdl, pfd);
-}
-
-void
-miofile_close(struct file *file)
-{
-       mio_close(((struct miofile *)file)->hdl);
-}
diff --git a/usr.bin/aucat/miofile.h b/usr.bin/aucat/miofile.h
deleted file mode 100644 (file)
index 5c59d4e..0000000
+++ /dev/null
@@ -1,28 +0,0 @@
-/*     $OpenBSD: miofile.h,v 1.3 2012/04/11 06:05:43 ratchov Exp $     */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef MIOFILE_H
-#define MIOFILE_H
-
-struct file;
-struct fileops;
-struct miofile;
-
-struct miofile *miofile_new(struct fileops *, char *, unsigned int);
-
-extern struct fileops miofile_ops;
-
-#endif /* !defined(MIOFILE_H) */
diff --git a/usr.bin/aucat/pipe.c b/usr.bin/aucat/pipe.c
deleted file mode 100644 (file)
index efe777a..0000000
+++ /dev/null
@@ -1,194 +0,0 @@
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/time.h>
-#include <sys/types.h>
-#include <sys/signal.h>
-
-#include <err.h>
-#include <errno.h>
-#include <fcntl.h>
-#include <poll.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <unistd.h>
-
-#include "conf.h"
-#include "pipe.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-struct fileops pipe_ops = {
-       "pipe",
-       sizeof(struct pipe),
-       pipe_close,
-       pipe_read,
-       pipe_write,
-       NULL, /* start */
-       NULL, /* stop */
-       pipe_nfds,
-       pipe_pollfd,
-       pipe_revents
-};
-
-struct pipe *
-pipe_new(struct fileops *ops, int fd, char *name)
-{
-       struct pipe *f;
-
-       f = (struct pipe *)file_new(ops, name, 1);
-       if (f == NULL)
-               return NULL;
-       f->fd = fd;
-       return f;
-}
-
-unsigned int
-pipe_read(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct pipe *f = (struct pipe *)file;
-       int n;
-       
-       while ((n = read(f->fd, data, count)) < 0) {
-               f->file.state &= ~FILE_ROK;
-               if (errno == EAGAIN) {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": reading blocked\n");
-                       }
-#endif
-               } else {
-                       warn("%s", f->file.name);
-                       file_eof(&f->file);
-               }
-               return 0;
-       }
-       if (n == 0) {
-               f->file.state &= ~FILE_ROK; /* XXX: already cleared in file_eof */
-               file_eof(&f->file);
-               return 0;
-       }
-       return n;
-}
-
-
-unsigned int
-pipe_write(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct pipe *f = (struct pipe *)file;
-       int n;
-
-       while ((n = write(f->fd, data, count)) < 0) {
-               f->file.state &= ~FILE_WOK;
-               if (errno == EAGAIN) {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": writing blocked\n");
-                       }
-#endif
-               } else {
-                       if (errno != EPIPE)
-                               warn("%s", f->file.name);
-                       file_hup(&f->file);
-               }
-               return 0;
-       }
-       return n;
-}
-
-int
-pipe_nfds(struct file *file) {
-       return 1;
-}
-
-int
-pipe_pollfd(struct file *file, struct pollfd *pfd, int events)
-{
-       struct pipe *f = (struct pipe *)file;
-
-       pfd->fd = f->fd;
-       pfd->events = events;
-       return (events != 0) ? 1 : 0;
-}
-
-int
-pipe_revents(struct file *f, struct pollfd *pfd)
-{
-       return pfd->revents;
-}
-
-void
-pipe_close(struct file *file)
-{
-       struct pipe *f = (struct pipe *)file;
-
-       close(f->fd);
-       file_slowaccept = 0;
-}
-
-off_t
-pipe_endpos(struct file *file)
-{
-       struct pipe *f = (struct pipe *)file;
-       off_t pos;
-
-       pos = lseek(f->fd, 0, SEEK_END);
-       if (pos < 0) {
-#ifdef DEBUG
-               file_dbg(&f->file);
-               dbg_puts(": couldn't get file size\n");
-#endif
-               return 0;
-       }
-       return pos;
-}
-
-int
-pipe_seek(struct file *file, off_t pos)
-{
-       struct pipe *f = (struct pipe *)file;
-       off_t newpos;
-       
-       newpos = lseek(f->fd, pos, SEEK_SET);
-       if (newpos < 0) {
-#ifdef DEBUG
-               file_dbg(&f->file);
-               dbg_puts(": couldn't seek\n");
-#endif
-               /* XXX: call eof() */
-               return 0;
-       }
-       return 1;
-}
-
-int
-pipe_trunc(struct file *file, off_t pos)
-{
-       struct pipe *f = (struct pipe *)file;
-
-       if (ftruncate(f->fd, pos) < 0) {
-#ifdef DEBUG
-               file_dbg(&f->file);
-               dbg_puts(": couldn't truncate file\n");
-#endif
-               /* XXX: call hup() */
-               return 0;
-       }
-       return 1;
-}
diff --git a/usr.bin/aucat/pipe.h b/usr.bin/aucat/pipe.h
deleted file mode 100644 (file)
index 02c7c44..0000000
+++ /dev/null
@@ -1,40 +0,0 @@
-/*     $OpenBSD: pipe.h,v 1.6 2012/04/11 06:05:43 ratchov Exp $        */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef PIPE_H
-#define PIPE_H
-
-#include "file.h"
-
-struct pipe {
-       struct file file;
-       int fd;                 /* file descriptor */
-};
-
-extern struct fileops pipe_ops;
-
-struct pipe *pipe_new(struct fileops *, int, char *);
-void pipe_close(struct file *);
-unsigned int pipe_read(struct file *, unsigned char *, unsigned int);
-unsigned int pipe_write(struct file *, unsigned char *, unsigned int);
-int pipe_nfds(struct file *);
-int pipe_pollfd(struct file *, struct pollfd *, int);
-int pipe_revents(struct file *, struct pollfd *);
-int pipe_seek(struct file *, off_t);
-int pipe_trunc(struct file *, off_t);
-off_t pipe_endpos(struct file *);
-
-#endif /* !defined(PIPE_H) */
diff --git a/usr.bin/aucat/siofile.c b/usr.bin/aucat/siofile.c
deleted file mode 100644 (file)
index f6a1e77..0000000
+++ /dev/null
@@ -1,484 +0,0 @@
-/*     $OpenBSD: siofile.c,v 1.13 2013/11/18 17:37:45 ratchov Exp $    */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <sys/time.h>
-#include <sys/types.h>
-
-#include <poll.h>
-#include <sndio.h>
-#include <stdio.h>
-#include <stdlib.h>
-#include <string.h>
-
-#include "aparams.h"
-#include "aproc.h"
-#include "abuf.h"
-#include "conf.h"
-#include "dev.h"
-#include "file.h"
-#include "siofile.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-struct siofile {
-       struct file file;
-       struct sio_hdl *hdl;
-       unsigned int wtickets, wbpf;
-       unsigned int rtickets, rbpf;
-       unsigned int bufsz;
-       int started;
-       void (*onmove)(void *, int);
-       void *arg;
-#ifdef DEBUG
-       long long wtime, utime;
-#endif
-};
-
-void siofile_close(struct file *);
-unsigned int siofile_read(struct file *, unsigned char *, unsigned int);
-unsigned int siofile_write(struct file *, unsigned char *, unsigned int);
-void siofile_start(struct file *, void (*)(void *, int), void *);
-void siofile_stop(struct file *);
-int siofile_nfds(struct file *);
-int siofile_pollfd(struct file *, struct pollfd *, int);
-int siofile_revents(struct file *, struct pollfd *);
-void siofile_cb(void *, int);
-
-struct fileops siofile_ops = {
-       "sio",
-       sizeof(struct siofile),
-       siofile_close,
-       siofile_read,
-       siofile_write,
-       siofile_start,
-       siofile_stop,
-       siofile_nfds,
-       siofile_pollfd,
-       siofile_revents
-};
-
-int wsio_out(struct aproc *, struct abuf *);
-int rsio_in(struct aproc *, struct abuf *);
-
-struct aproc_ops rsio_ops = {
-       "rsio",
-       rsio_in,
-       rfile_out,
-       rfile_eof,
-       rfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       aproc_ipos,
-       aproc_opos,
-       rfile_done
-};
-
-struct aproc_ops wsio_ops = {
-       "wsio",
-       wfile_in,
-       wsio_out,
-       wfile_eof,
-       wfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       aproc_ipos,
-       aproc_opos,
-       wfile_done
-};
-
-struct aproc *
-rsio_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&rsio_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->rproc = p;
-       return p;
-}
-
-struct aproc *
-wsio_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&wsio_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->wproc = p;
-       return p;
-}
-
-int
-wsio_out(struct aproc *p, struct abuf *obuf)
-{
-       struct siofile *f = (struct siofile *)p->u.io.file;
-
-       if (f->wtickets == 0) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       file_dbg(&f->file);
-                       dbg_puts(": no more write tickets\n");
-               }
-#endif
-               f->file.state &= ~FILE_WOK;
-               return 0;
-       }
-       return wfile_out(p, obuf);
-}
-
-int
-rsio_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct siofile *f = (struct siofile *)p->u.io.file;
-
-       if (f->rtickets == 0) {
-#ifdef DEBUG
-               if (debug_level >= 4) {
-                       file_dbg(&f->file);
-                       dbg_puts(": no more read tickets\n");
-               }
-#endif
-               f->file.state &= ~FILE_ROK;
-               return 0;
-       }
-       return rfile_in(p, ibuf);
-}
-
-void
-siofile_cb(void *addr, int delta)
-{
-       struct siofile *f = (struct siofile *)addr;
-       struct aproc *p;
-
-#ifdef DEBUG
-       if (delta < 0 || delta > (60 * RATE_MAX)) {
-               file_dbg(&f->file);
-               dbg_puts(": ");
-               dbg_puti(delta);
-               dbg_puts(": bogus sndio delta");
-               dbg_panic();
-       }
-       if (debug_level >= 4) {
-               file_dbg(&f->file);
-               dbg_puts(": tick, delta = ");
-               dbg_puti(delta);
-               dbg_puts(", load = ");
-               dbg_puti((file_utime - f->utime) / 1000);
-               dbg_puts(" + ");
-               dbg_puti((file_wtime - f->wtime) / 1000);
-               dbg_puts("\n");
-       }
-       f->wtime = file_wtime;
-       f->utime = file_utime;
-#endif
-       if (delta != 0) {
-               p = f->file.wproc;
-               if (p && p->ops->opos)
-                       p->ops->opos(p, NULL, delta);
-               p = f->file.rproc;
-               if (p && p->ops->ipos)
-                       p->ops->ipos(p, NULL, delta);
-       }
-       if (f->onmove)
-               f->onmove(f->arg, delta);
-       f->wtickets += delta * f->wbpf;
-       f->rtickets += delta * f->rbpf;
-}
-
-/*
- * Open the device.
- */
-struct siofile *
-siofile_new(struct fileops *ops, char *path, unsigned int *rmode,
-    struct aparams *ipar, struct aparams *opar,
-    unsigned int *bufsz, unsigned int *round)
-{
-       struct sio_par par;
-       struct sio_hdl *hdl;
-       struct siofile *f;
-       unsigned int mode = *rmode;
-
-       hdl = sio_open(path, mode, 1);
-       if (hdl == NULL) {
-               if (mode != (SIO_PLAY | SIO_REC))
-                       return NULL;
-               hdl = sio_open(path, SIO_PLAY, 1);
-               if (hdl != NULL)
-                       mode = SIO_PLAY;
-               else {
-                       hdl = sio_open(path, SIO_REC, 1);
-                       if (hdl != NULL)
-                               mode = SIO_REC;
-                       else
-                               return NULL;
-               }
-#ifdef DEBUG
-               if (debug_level >= 1) {
-                       dbg_puts("warning, device opened in ");
-                       dbg_puts(mode == SIO_PLAY ? "play-only" : "rec-only");
-                       dbg_puts(" mode\n");
-               }
-#endif
-       }
-
-       sio_initpar(&par);
-       if (mode & SIO_REC) {
-               par.bits = ipar->bits;
-               par.bps = ipar->bps;
-               par.sig = ipar->sig;
-               par.le = ipar->le;
-               par.msb = ipar->msb;
-               par.rate = ipar->rate;
-               par.rchan = ipar->cmax + 1;
-       } else {
-               par.bits = opar->bits;
-               par.bps = opar->bps;
-               par.sig = opar->sig;
-               par.le = opar->le;
-               par.msb = opar->msb;
-               par.rate = opar->rate;
-       }
-       if (mode & SIO_PLAY)
-               par.pchan = opar->cmax + 1;
-       if (*bufsz)
-               par.appbufsz = *bufsz;
-       if (*round)
-               par.round = *round;
-       if (!sio_setpar(hdl, &par))
-               goto bad_close;
-       if (!sio_getpar(hdl, &par))
-               goto bad_close;
-       if (mode & SIO_REC) {
-               ipar->bits = par.bits;
-               ipar->bps = par.bps;
-               ipar->sig = par.sig;
-               ipar->le = par.le;
-               ipar->msb = par.msb;
-               ipar->rate = par.rate;
-               ipar->cmin = 0;
-               ipar->cmax = par.rchan - 1;
-       }
-       if (mode & SIO_PLAY) {
-               opar->bits = par.bits;
-               opar->bps = par.bps;
-               opar->sig = par.sig;
-               opar->le = par.le;
-               opar->msb = par.msb;
-               opar->rate = par.rate;
-               opar->cmin = 0;
-               opar->cmax = par.pchan - 1;
-       }
-       *rmode = mode;
-       *bufsz = par.bufsz;
-       *round = par.round;
-       f = (struct siofile *)file_new(ops, path, sio_nfds(hdl));
-       if (f == NULL)
-               goto bad_close;
-       f->hdl = hdl;
-       f->started = 0;
-       f->wtickets = 0;
-       f->rtickets = 0;
-       f->wbpf = par.pchan * par.bps;
-       f->rbpf = par.rchan * par.bps;
-       f->bufsz = par.bufsz;
-       sio_onmove(f->hdl, siofile_cb, f);
-       return f;
- bad_close:
-       sio_close(hdl);
-       return NULL;
-}
-
-void
-siofile_start(struct file *file, void (*cb)(void *, int), void *arg)
-{
-       struct siofile *f = (struct siofile *)file;
-
-       if (!sio_start(f->hdl)) {
-#ifdef DEBUG
-               dbg_puts(f->file.name);
-               dbg_puts(": failed to start device\n");
-#endif
-               file_close(file);
-               return;
-       }
-       f->started = 1;
-       f->wtickets = f->bufsz * f->wbpf;
-       f->rtickets = 0;
-#ifdef DEBUG
-       f->wtime = file_wtime;
-       f->utime = file_utime;
-       if (debug_level >= 3) {
-               file_dbg(&f->file);
-               dbg_puts(": started\n");
-       }
-#endif
-       f->onmove = cb;
-       f->arg = arg;
-}
-
-void
-siofile_stop(struct file *file)
-{
-       struct siofile *f = (struct siofile *)file;
-
-       f->started = 0;
-       f->onmove = NULL;
-       if (!sio_eof(f->hdl) && !sio_stop(f->hdl)) {
-#ifdef DEBUG
-               dbg_puts(f->file.name);
-               dbg_puts(": failed to stop device\n");
-#endif
-               file_close(file);
-               return;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               file_dbg(&f->file);
-               dbg_puts(": stopped\n");
-       }
-#endif
-}
-
-unsigned int
-siofile_read(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct siofile *f = (struct siofile *)file;
-       unsigned int n;
-
-#ifdef DEBUG
-       if (f->rtickets == 0) {
-               file_dbg(&f->file);
-               dbg_puts(": called with no read tickets\n");
-       }
-#endif
-       if (count > f->rtickets)
-               count = f->rtickets;
-       n = f->started ? sio_read(f->hdl, data, count) : 0;
-       if (n == 0) {
-               f->file.state &= ~FILE_ROK;
-               if (sio_eof(f->hdl)) {
-#ifdef DEBUG
-                       dbg_puts(f->file.name);
-                       dbg_puts(": failed to read from device\n");
-#endif
-                       file_eof(&f->file);
-               } else {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": reading blocked\n");
-                       }
-#endif
-               }
-               return 0;
-       } else {
-               f->rtickets -= n;
-               if (f->rtickets == 0) {
-                       f->file.state &= ~FILE_ROK;
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": read tickets exhausted\n");
-                       }
-#endif
-               }
-       }
-       return n;
-
-}
-
-unsigned int
-siofile_write(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct siofile *f = (struct siofile *)file;
-       unsigned int n;
-
-#ifdef DEBUG
-       if (f->wtickets == 0) {
-               file_dbg(&f->file);
-               dbg_puts(": called with no write tickets\n");
-       }
-#endif
-       if (count > f->wtickets)
-               count = f->wtickets;
-       n = f->started ? sio_write(f->hdl, data, count) : 0;
-       if (n == 0) {
-               f->file.state &= ~FILE_WOK;
-               if (sio_eof(f->hdl)) {
-#ifdef DEBUG
-                       dbg_puts(f->file.name);
-                       dbg_puts(": failed to write on device\n");
-#endif
-                       file_hup(&f->file);
-               } else {
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": writing blocked\n");
-                       }
-#endif
-               }
-               return 0;
-       } else {
-               f->wtickets -= n;
-               if (f->wtickets == 0) {
-                       f->file.state &= ~FILE_WOK;
-#ifdef DEBUG
-                       if (debug_level >= 4) {
-                               file_dbg(&f->file);
-                               dbg_puts(": write tickets exhausted\n");
-                       }
-#endif
-               }
-       }
-       return n;
-}
-
-int
-siofile_nfds(struct file *file)
-{
-       return sio_nfds(((struct siofile *)file)->hdl);
-}
-
-int
-siofile_pollfd(struct file *file, struct pollfd *pfd, int events)
-{
-       struct siofile *f = (struct siofile *)file;
-
-       if (!f->started)
-               events &= ~(POLLIN | POLLOUT);
-       return sio_pollfd(((struct siofile *)file)->hdl, pfd, events);
-}
-
-int
-siofile_revents(struct file *file, struct pollfd *pfd)
-{
-       return sio_revents(((struct siofile *)file)->hdl, pfd);
-}
-
-void
-siofile_close(struct file *file)
-{
-       struct siofile *f = (struct siofile *)file;
-
-       if (f->started)
-               siofile_stop(&f->file);
-       sio_close(((struct siofile *)file)->hdl);
-}
diff --git a/usr.bin/aucat/siofile.h b/usr.bin/aucat/siofile.h
deleted file mode 100644 (file)
index 203a8ab..0000000
+++ /dev/null
@@ -1,32 +0,0 @@
-/*     $OpenBSD: siofile.h,v 1.6 2012/04/11 06:05:43 ratchov Exp $     */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef SIOFILE_H
-#define SIOFILE_H
-
-struct fileops;
-struct siofile;
-struct aparams;
-struct aproc;
-
-struct siofile *siofile_new(struct fileops *, char *, unsigned int *,
-    struct aparams *, struct aparams *, unsigned int *, unsigned int *);
-struct aproc *rsio_new(struct file *f);
-struct aproc *wsio_new(struct file *f);
-
-extern struct fileops siofile_ops;
-
-#endif /* !defined(SIOFILE_H) */
index d4c6a43..548a2fc 100644 (file)
@@ -1,4 +1,4 @@
-/*     $OpenBSD: sysex.h,v 1.3 2012/03/23 11:59:54 ratchov Exp $       */
+/*     $OpenBSD: sysex.h,v 1.4 2015/01/21 08:43:55 ratchov Exp $       */
 /*
  * Copyright (c) 2011 Alexandre Ratchov <alex@caoua.org>
  *
@@ -14,8 +14,8 @@
  * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
  * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
-#ifndef AUCAT_SYSEX_H
-#define AUCAT_SYSEX_H
+#ifndef SYSEX_H
+#define SYSEX_H
 
 #include <stdint.h>
 
 #define   SYSEX_MMC_LOC_CMD    0x01
 
 /*
- * aucat-specific messages, in the "edu" namespace
+ * sepcial "any" midi device number
  */
-#define SYSEX_AUCAT            0x23            /* aucat-specific */
-#define   SYSEX_AUCAT_MIXINFO  0x01            /* mixer info */
-#define   SYSEX_AUCAT_DUMPREQ  0x02            /* dump request */
-#define   SYSEX_AUCAT_DUMPEND  0x03            /* end of dump */
+#define SYSEX_DEV_ANY          0x7f
 
 /*
  * minimum size of sysex message we accept
@@ -59,9 +56,7 @@
 #define SYSEX_SIZE(m)  (5 + sizeof(struct sysex_ ## m))
 
 /*
- * all possible system exclusive messages we support. For aucat-specific
- * messages we use the same header as real-time messages to simplify the
- * message parser
+ * all possible system exclusive messages we support.
  */
 struct sysex {
        uint8_t start;
@@ -87,7 +82,10 @@ struct sysex {
                struct sysex_loc {
                        uint8_t len;
                        uint8_t cmd;
-                       uint8_t hr;
+#define MTC_FPS_24     0
+#define MTC_FPS_25     1
+#define MTC_FPS_30     3
+                       uint8_t hr;             /* MSB contain MTC_FPS */
                        uint8_t min;
                        uint8_t sec;
                        uint8_t fr;
@@ -101,20 +99,7 @@ struct sysex {
                        uint8_t fr;
                        uint8_t end;
                } full;
-               struct sysex_mixinfo {
-                       uint8_t chan;                   /* channel */
-                       uint8_t vol;                    /* current volume */
-#define SYSEX_NAMELEN  10                              /* \0 included */
-                       uint8_t name[SYSEX_NAMELEN];    /* stream name */
-                       uint8_t end;
-               } mixinfo;
-               struct sysex_dumpreq {
-                       uint8_t end;
-               } dumpreq;
-               struct sysex_dumpend {
-                       uint8_t end;
-               } dumpend;
        } u;
 };
 
-#endif /* !defined(AUCAT_SYSEX_H) */
+#endif /* !defined(SYSEX_H) */
diff --git a/usr.bin/aucat/utils.c b/usr.bin/aucat/utils.c
new file mode 100644 (file)
index 0000000..b4e1f31
--- /dev/null
@@ -0,0 +1,182 @@
+/*     $OpenBSD: utils.c,v 1.1 2015/01/21 08:43:55 ratchov Exp $       */
+/*
+ * Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+/*
+ * log_xxx() routines are used to quickly store traces into a trace buffer.
+ * This allows trances to be collected during time sensitive operations without
+ * disturbing them. The buffer can be flushed on standard error later, when
+ * slow syscalls are no longer disruptive, e.g. at the end of the poll() loop.
+ */
+#include <signal.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <fcntl.h>
+#include "utils.h"
+
+/*
+ * log buffer size
+ */
+#define LOG_BUFSZ      8192
+
+/*
+ * store a character in the log
+ */
+#define LOG_PUTC(c) do {                       \
+       if (log_used < LOG_BUFSZ)               \
+               log_buf[log_used++] = (c);      \
+} while (0)
+
+char log_buf[LOG_BUFSZ];       /* buffer where traces are stored */
+unsigned int log_used = 0;     /* bytes used in the buffer */
+unsigned int log_sync = 1;     /* if true, flush after each '\n' */
+
+/*
+ * write the log buffer on stderr
+ */
+void
+log_flush(void)
+{
+       if (log_used ==  0)
+               return;
+       write(STDERR_FILENO, log_buf, log_used);
+       log_used = 0;
+}
+
+/*
+ * store a string in the log
+ */
+void
+log_puts(char *msg)
+{
+       char *p = msg;
+       int c;
+
+       while ((c = *p++) != '\0') {
+               LOG_PUTC(c);
+               if (log_sync && c == '\n')
+                       log_flush();
+       }
+}
+
+/*
+ * store a hex in the log
+ */
+void
+log_putx(unsigned long num)
+{
+       char dig[sizeof(num) * 2], *p = dig, c;
+       unsigned int ndig;
+
+       if (num != 0) {
+               for (ndig = 0; num != 0; ndig++) {
+                       *p++ = num & 0xf;
+                       num >>= 4;
+               }
+               for (; ndig != 0; ndig--) {
+                       c = *(--p);
+                       c += (c < 10) ? '0' : 'a' - 10;
+                       LOG_PUTC(c);
+               }
+       } else 
+               LOG_PUTC('0');
+}
+
+/*
+ * store a unsigned decimal in the log
+ */
+void
+log_putu(unsigned long num)
+{
+       char dig[sizeof(num) * 3], *p = dig;
+       unsigned int ndig;
+
+       if (num != 0) {
+               for (ndig = 0; num != 0; ndig++) {
+                       *p++ = num % 10;
+                       num /= 10;
+               }
+               for (; ndig != 0; ndig--)
+                       LOG_PUTC(*(--p) + '0');
+       } else
+               LOG_PUTC('0');
+}
+
+/*
+ * store a signed decimal in the log
+ */
+void
+log_puti(long num)
+{
+       if (num < 0) {
+               LOG_PUTC('-');
+               num = -num;
+       }
+       log_putu(num);
+}
+
+/*
+ * abort program execution after a fatal error
+ */
+void
+panic(void)
+{
+       log_flush();
+       (void)kill(getpid(), SIGABRT);
+       _exit(1);
+}
+
+/*
+ * allocate a (small) abount of memory, and abort if it fails
+ */
+void *
+xmalloc(size_t size)
+{
+       void *p;
+       
+       p = malloc(size);
+       if (p == NULL) {
+               log_puts("failed to allocate ");
+               log_putx(size);
+               log_puts(" bytes\n");
+               panic();
+       }
+       return p;
+}
+
+/*
+ * free memory allocated with xmalloc()
+ */
+void
+xfree(void *p)
+{
+       free(p);
+}
+
+/*
+ * xmalloc-style strdup(3)
+ */
+char *
+xstrdup(char *s)
+{
+       size_t size;
+       void *p;
+
+       size = strlen(s) + 1;
+       p = xmalloc(size);
+       memcpy(p, s, size);
+       return p;
+}
diff --git a/usr.bin/aucat/utils.h b/usr.bin/aucat/utils.h
new file mode 100644 (file)
index 0000000..951df5e
--- /dev/null
@@ -0,0 +1,46 @@
+/*     $OpenBSD: utils.h,v 1.1 2015/01/21 08:43:55 ratchov Exp $       */
+/*
+ * Copyright (c) 2003-2012 Alexandre Ratchov <alex@caoua.org>
+ *
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#ifndef UTILS_H
+#define UTILS_H
+
+#include <stddef.h>
+
+void log_puts(char *);
+void log_putx(unsigned long);
+void log_putu(unsigned long);
+void log_puti(long);
+void panic(void);
+void log_flush(void);
+
+void *xmalloc(size_t);
+char *xstrdup(char *);
+void xfree(void *);
+
+/*
+ * Log levels:
+ *
+ * 0 - fatal errors: bugs, asserts, internal errors.
+ * 1 - warnings: bugs in clients, failed allocations, non-fatal errors.
+ * 2 - misc information (hardware parameters, incoming clients)
+ * 3 - structural changes (eg. new streams, new parameters ...)
+ * 4 - data blocks and messages
+ */
+extern unsigned int log_level;
+extern unsigned int log_sync;
+
+#endif
diff --git a/usr.bin/aucat/wav.c b/usr.bin/aucat/wav.c
deleted file mode 100644 (file)
index 36c36d2..0000000
+++ /dev/null
@@ -1,1059 +0,0 @@
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-
-#include <fcntl.h>
-#include <stdlib.h>
-#include <stdio.h>
-#include <string.h>
-#include <unistd.h>
-
-#include "abuf.h"
-#include "aproc.h"
-#include "conf.h"
-#include "dev.h"
-#include "midi.h"
-#include "wav.h"
-#ifdef DEBUG
-#include "dbg.h"
-#endif
-
-void wav_dbg(struct wav *);
-void wav_conv(unsigned char *, unsigned int, short *);
-unsigned int wav_read(struct file *, unsigned char *, unsigned int);
-unsigned int wav_write(struct file *, unsigned char *, unsigned int);
-void wav_close(struct file *);
-int wav_attach(struct wav *, int);
-void wav_midiattach(struct wav *);
-void wav_allocbuf(struct wav *);
-void wav_freebuf(struct wav *);
-void wav_reset(struct wav *);
-void wav_exit(struct wav *);
-int wav_init(struct wav *);
-int wav_seekmmc(struct wav *);
-int wav_rdata(struct wav *);
-int wav_wdata(struct wav *);
-void wav_setvol(void *, unsigned int);
-void wav_startreq(void *);
-void wav_stopreq(void *);
-void wav_locreq(void *, unsigned int);
-void wav_quitreq(void *);
-int wav_autohdr(char *, struct dev *, unsigned int *, unsigned int *);
-void rwav_done(struct aproc *);
-int rwav_in(struct aproc *, struct abuf *);
-int rwav_out(struct aproc *, struct abuf *);
-struct aproc *rwav_new(struct file *);
-void wwav_done(struct aproc *);
-int wwav_in(struct aproc *, struct abuf *);
-int wwav_out(struct aproc *, struct abuf *);
-struct aproc *wwav_new(struct file *);
-
-short wav_ulawmap[256] = {
-       -32124, -31100, -30076, -29052, -28028, -27004, -25980, -24956,
-       -23932, -22908, -21884, -20860, -19836, -18812, -17788, -16764,
-       -15996, -15484, -14972, -14460, -13948, -13436, -12924, -12412,
-       -11900, -11388, -10876, -10364,  -9852,  -9340,  -8828,  -8316,
-        -7932,  -7676,  -7420,  -7164,  -6908,  -6652,  -6396,  -6140,
-        -5884,  -5628,  -5372,  -5116,  -4860,  -4604,  -4348,  -4092,
-        -3900,  -3772,  -3644,  -3516,  -3388,  -3260,  -3132,  -3004,
-        -2876,  -2748,  -2620,  -2492,  -2364,  -2236,  -2108,  -1980,
-        -1884,  -1820,  -1756,  -1692,  -1628,  -1564,  -1500,  -1436,
-        -1372,  -1308,  -1244,  -1180,  -1116,  -1052,   -988,   -924,
-         -876,   -844,   -812,   -780,   -748,   -716,   -684,   -652,
-         -620,   -588,   -556,   -524,   -492,   -460,   -428,   -396,
-         -372,   -356,   -340,   -324,   -308,   -292,   -276,   -260,
-         -244,   -228,   -212,   -196,   -180,   -164,   -148,   -132,
-         -120,   -112,   -104,    -96,    -88,    -80,    -72,    -64,
-          -56,    -48,    -40,    -32,    -24,    -16,     -8,      0,
-        32124,  31100,  30076,  29052,  28028,  27004,  25980,  24956,
-        23932,  22908,  21884,  20860,  19836,  18812,  17788,  16764,
-        15996,  15484,  14972,  14460,  13948,  13436,  12924,  12412,
-        11900,  11388,  10876,  10364,   9852,   9340,   8828,   8316,
-         7932,   7676,   7420,   7164,   6908,   6652,   6396,   6140,
-         5884,   5628,   5372,   5116,   4860,   4604,   4348,   4092,
-         3900,   3772,   3644,   3516,   3388,   3260,   3132,   3004,
-         2876,   2748,   2620,   2492,   2364,   2236,   2108,   1980,
-         1884,   1820,   1756,   1692,   1628,   1564,   1500,   1436,
-         1372,   1308,   1244,   1180,   1116,   1052,    988,    924,
-          876,    844,    812,    780,    748,    716,    684,    652,
-          620,    588,    556,    524,    492,    460,    428,    396,
-          372,    356,    340,    324,    308,    292,    276,    260,
-          244,    228,    212,    196,    180,    164,    148,    132,
-          120,    112,    104,     96,     88,     80,     72,     64,
-           56,     48,     40,     32,     24,     16,      8,      0
-};
-
-short wav_alawmap[256] = {
-        -5504,  -5248,  -6016,  -5760,  -4480,  -4224,  -4992,  -4736,
-        -7552,  -7296,  -8064,  -7808,  -6528,  -6272,  -7040,  -6784,
-        -2752,  -2624,  -3008,  -2880,  -2240,  -2112,  -2496,  -2368,
-        -3776,  -3648,  -4032,  -3904,  -3264,  -3136,  -3520,  -3392,
-       -22016, -20992, -24064, -23040, -17920, -16896, -19968, -18944,
-       -30208, -29184, -32256, -31232, -26112, -25088, -28160, -27136,
-       -11008, -10496, -12032, -11520,  -8960,  -8448,  -9984,  -9472,
-       -15104, -14592, -16128, -15616, -13056, -12544, -14080, -13568,
-         -344,   -328,   -376,   -360,   -280,   -264,   -312,   -296,
-         -472,   -456,   -504,   -488,   -408,   -392,   -440,   -424,
-          -88,    -72,   -120,   -104,    -24,     -8,    -56,    -40,
-         -216,   -200,   -248,   -232,   -152,   -136,   -184,   -168,
-        -1376,  -1312,  -1504,  -1440,  -1120,  -1056,  -1248,  -1184,
-        -1888,  -1824,  -2016,  -1952,  -1632,  -1568,  -1760,  -1696,
-         -688,   -656,   -752,   -720,   -560,   -528,   -624,   -592,
-         -944,   -912,  -1008,   -976,   -816,   -784,   -880,   -848,
-         5504,   5248,   6016,   5760,   4480,   4224,   4992,   4736,
-         7552,   7296,   8064,   7808,   6528,   6272,   7040,   6784,
-         2752,   2624,   3008,   2880,   2240,   2112,   2496,   2368,
-         3776,   3648,   4032,   3904,   3264,   3136,   3520,   3392,
-        22016,  20992,  24064,  23040,  17920,  16896,  19968,  18944,
-        30208,  29184,  32256,  31232,  26112,  25088,  28160,  27136,
-        11008,  10496,  12032,  11520,   8960,   8448,   9984,   9472,
-        15104,  14592,  16128,  15616,  13056,  12544,  14080,  13568,
-          344,    328,    376,    360,    280,    264,    312,    296,
-          472,    456,    504,    488,    408,    392,    440,    424,
-           88,     72,    120,    104,     24,      8,     56,     40,
-          216,    200,    248,    232,    152,    136,    184,    168,
-         1376,   1312,   1504,   1440,   1120,   1056,   1248,   1184,
-         1888,   1824,   2016,   1952,   1632,   1568,   1760,   1696,
-          688,    656,    752,    720,    560,    528,    624,    592,
-          944,    912,   1008,    976,    816,    784,    880,    848
-};
-
-/*
- * Max data of a .wav file. The total file size must be smaller than
- * 2^31, and we also have to leave some space for the headers (around 40
- * bytes).
- */
-#define WAV_DATAMAX    (0x7fff0000)
-
-struct fileops wav_ops = {
-       "wav",
-       sizeof(struct wav),
-       wav_close,
-       wav_read,
-       wav_write,
-       NULL, /* start */
-       NULL, /* stop */
-       pipe_nfds,
-       pipe_pollfd,
-       pipe_revents
-};
-
-struct wav *wav_list = NULL;
-
-int rwav_in(struct aproc *, struct abuf *);
-int rwav_out(struct aproc *, struct abuf *);
-void rwav_eof(struct aproc *, struct abuf *);
-void rwav_hup(struct aproc *, struct abuf *);
-void rwav_done(struct aproc *);
-struct aproc *rwav_new(struct file *);
-
-int wwav_in(struct aproc *, struct abuf *);
-int wwav_out(struct aproc *, struct abuf *);
-void wwav_eof(struct aproc *, struct abuf *);
-void wwav_hup(struct aproc *, struct abuf *);
-void wwav_done(struct aproc *);
-struct aproc *wwav_new(struct file *);
-
-void wav_setvol(void *, unsigned int);
-void wav_startreq(void *);
-void wav_stopreq(void *);
-void wav_locreq(void *, unsigned int);
-void wav_quitreq(void *);
-
-struct ctl_ops ctl_wavops = {
-       wav_setvol,
-       wav_startreq,
-       wav_stopreq,
-       wav_locreq,
-       wav_quitreq
-};
-
-struct aproc_ops rwav_ops = {
-       "rwav",
-       rwav_in,
-       rwav_out,
-       rfile_eof,
-       rfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       NULL, /* ipos */
-       NULL, /* opos */
-       rwav_done
-};
-
-struct aproc_ops wwav_ops = {
-       "wwav",
-       wwav_in,
-       wwav_out,
-       wfile_eof,
-       wfile_hup,
-       NULL, /* newin */
-       NULL, /* newout */
-       NULL, /* ipos */
-       NULL, /* opos */
-       wwav_done
-};
-
-#ifdef DEBUG
-/*
- * print the given wav structure
- */
-void
-wav_dbg(struct wav *f)
-{
-       static char *pstates[] = { "cfg", "ini", "sta", "rdy", "run", "mid" };
-
-       dbg_puts("wav(");
-       if (f->slot >= 0) {
-               dbg_puts(f->dev->slot[f->slot].name);
-               dbg_putu(f->dev->slot[f->slot].unit);
-       } else
-               dbg_puts(f->pipe.file.name);
-       dbg_puts(")/");
-       dbg_puts(pstates[f->pstate]);
-}
-#endif
-
-/*
- * convert ``count'' samples using the given char->short map
- */
-void
-wav_conv(unsigned char *data, unsigned int count, short *map)
-{
-       unsigned int i;
-       unsigned char *iptr;
-       adata_t *optr;
-
-       iptr = data + count;
-       optr = (adata_t *)data + count;
-       for (i = count; i > 0; i--) {
-               --optr;
-               --iptr;
-               *optr = (adata_t)(map[*iptr]) << (ADATA_BITS - 16);
-       }
-}
-
-/*
- * read method of the file structure
- */
-unsigned int
-wav_read(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct wav *f = (struct wav *)file;
-       unsigned int n;
-
-       if (f->map)
-               count /= sizeof(adata_t);
-       if (f->rbytes >= 0 && count > f->rbytes) {
-               count = f->rbytes; /* file->rbytes fits in count */
-               if (count == 0) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               wav_dbg(f);
-                               dbg_puts(": read complete\n");
-                       }
-#endif
-                       if (!f->mmc)
-                               file_eof(&f->pipe.file);
-                       return 0;
-               }
-       }
-       n = pipe_read(file, data, count);
-       if (n == 0)
-               return 0;
-       if (f->rbytes >= 0)
-               f->rbytes -= n;
-       if (f->map) {
-               wav_conv(data, n, f->map);
-               n *= sizeof(adata_t);
-       }
-       return n;
-}
-
-/*
- * write method of the file structure
- */
-unsigned int
-wav_write(struct file *file, unsigned char *data, unsigned int count)
-{
-       struct wav *f = (struct wav *)file;
-       unsigned int n;
-
-       if (f->wbytes >= 0 && count > f->wbytes) {
-               count = f->wbytes; /* wbytes fits in count */
-               if (count == 0) {
-#ifdef DEBUG
-                       if (debug_level >= 3) {
-                               wav_dbg(f);
-                               dbg_puts(": write complete\n");
-                       }
-#endif
-                       file_hup(&f->pipe.file);
-                       return 0;
-               }
-       }
-       n = pipe_write(file, data, count);
-       if (f->wbytes >= 0)
-               f->wbytes -= n;
-       f->endpos += n;
-       return n;
-}
-
-/*
- * close method of the file structure
- */
-void
-wav_close(struct file *file)
-{
-       struct wav *f = (struct wav *)file, **pf;
-
-       if (f->mode & MODE_RECMASK) {
-               pipe_trunc(&f->pipe.file, f->endpos);
-               if (f->hdr == HDR_WAV) {
-                       wav_writehdr(f->pipe.fd,
-                           &f->hpar,
-                           &f->startpos,
-                           f->endpos - f->startpos);
-               }
-       }
-       pipe_close(file);
-       if (f->pstate != WAV_CFG)
-               dev_unref(f->dev);
-       for (pf = &wav_list; *pf != f; pf = &(*pf)->next) {
-#ifdef DEBUG
-               if (*pf == NULL) {
-                       dbg_puts("wav_close: not on list\n");
-                       dbg_panic();
-               }
-#endif
-       }
-       *pf = f->next;
-}
-
-/*
- * attach play (rec) abuf structure to the device and
- * switch to the ``RUN'' state; the play abug must not be empty
- */
-int
-wav_attach(struct wav *f, int force)
-{
-       struct abuf *rbuf = NULL, *wbuf = NULL;
-       struct dev *d = f->dev;
-
-       if (f->mode & MODE_PLAY)
-               rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
-       if (f->mode & MODE_RECMASK)
-               wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
-       f->pstate = WAV_RUN;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               wav_dbg(f);
-               dbg_puts(": attaching\n");
-       }
-#endif
-
-       /*
-        * start the device (dev_getpos() and dev_attach() must
-        * be called on a started device
-        */
-       dev_wakeup(d);
-
-       dev_attach(d, f->pipe.file.name, f->mode,
-           rbuf, &f->hpar, f->join ? d->opar.cmax - d->opar.cmin + 1 : 0,
-           wbuf, &f->hpar, f->join ? d->ipar.cmax - d->ipar.cmin + 1 : 0,
-           f->xrun, f->maxweight);
-       if (f->mode & MODE_PLAY)
-               dev_setvol(d, rbuf, MIDI_TO_ADATA(f->vol));
-       return 1;
-}
-
-/*
- * allocate buffers, so client can start filling write-end.
- */
-void
-wav_midiattach(struct wav *f)
-{
-       struct abuf *rbuf = NULL, *wbuf = NULL;
-       
-       if (f->mode & MODE_MIDIOUT) {
-               rbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
-               aproc_setout(f->pipe.file.rproc, rbuf);
-       }
-       if (f->mode & MODE_MIDIIN) {
-               wbuf = abuf_new(MIDI_BUFSZ, &aparams_none);
-               aproc_setin(f->pipe.file.wproc, wbuf);
-       }
-       f->pstate = WAV_MIDI;
-       dev_midiattach(f->dev, rbuf, wbuf);
-}
-
-/*
- * allocate the play (rec) abuf structure; if this is a
- * file to record, then attach it to the device
- *
- * XXX: buffer size should be larger than dev_bufsz, because
- *     in non-server mode we don't prime play buffers with
- *     silence
- */
-void
-wav_allocbuf(struct wav *f)
-{
-       struct abuf *buf;
-       struct dev *d = f->dev;
-       unsigned int nfr;
-
-       f->pstate = WAV_START;
-       if (f->mode & MODE_PLAY) {
-               nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
-               buf = abuf_new(nfr, &f->hpar);
-               aproc_setout(f->pipe.file.rproc, buf);
-               abuf_fill(buf);
-               if (!ABUF_WOK(buf) || (f->pipe.file.state & FILE_EOF))
-                       f->pstate = WAV_READY;
-       }
-       if (f->mode & MODE_RECMASK) {
-               nfr = 2 * d->bufsz * f->hpar.rate / d->rate;
-               buf = abuf_new(nfr, &f->hpar);
-               aproc_setin(f->pipe.file.wproc, buf);
-               f->pstate = WAV_READY;
-       }
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               wav_dbg(f);
-               dbg_puts(": allocating buffers\n");
-       }
-#endif
-       if (f->pstate == WAV_READY && dev_slotstart(d, f->slot))
-               (void)wav_attach(f, 0);
-}
-
-/*
- * free abuf structure and switch to the ``INIT'' state
- */
-void
-wav_freebuf(struct wav *f)
-{
-       struct abuf *rbuf = NULL, *wbuf = NULL;
-
-       if (f->mode & MODE_PLAY)
-               rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
-       if (f->mode & MODE_RECMASK)
-               wbuf = LIST_FIRST(&f->pipe.file.wproc->ins);
-       f->pstate = WAV_INIT;
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               wav_dbg(f);
-               dbg_puts(": freeing buffers\n");
-       }
-#endif
-       if (rbuf || wbuf)
-               dev_slotstop(f->dev, f->slot);
-       if (rbuf)
-               abuf_eof(rbuf);
-       if (wbuf)
-               abuf_hup(wbuf);
-}
-
-/*
- * switch to the ``INIT'' state performing
- * necessary actions to reach it
- */
-void
-wav_reset(struct wav *f)
-{
-       switch (f->pstate) {
-       case WAV_START:
-       case WAV_READY:
-               if (dev_slotstart(f->dev, f->slot))
-                       (void)wav_attach(f, 1);
-               /* PASSTHROUGH */
-       case WAV_RUN:
-               wav_freebuf(f);
-               /* PASSTHROUGH */
-       case WAV_INIT:
-               /* nothing yet */
-               break;
-#ifdef DEBUG
-       case WAV_MIDI:
-               dbg_puts("wav_reset: in midi mode\n");
-               dbg_panic();
-#endif
-       }
-}
-
-/*
- * terminate the wav reader/writer
- */
-void
-wav_exit(struct wav *f)
-{
-       /* XXX: call file_close() ? */
-       if (f->mode & (MODE_PLAY | MODE_MIDIOUT)) {
-               aproc_del(f->pipe.file.rproc);
-       } else if (f->mode & (MODE_RECMASK | MODE_MIDIIN)) {
-               aproc_del(f->pipe.file.wproc);
-       }
-}
-
-/*
- * allocate the device
- */
-int
-wav_init(struct wav *f)
-{
-       if (!dev_ref(f->dev)) {
-               wav_exit(f);
-               return 0;
-       }
-       if (!f->mmc)
-               f->dev->autostart = 1;
-       if (f->mode & MODE_MIDIMASK) {
-               wav_midiattach(f);
-               return 1;
-       }
-       f->slot = dev_slotnew(f->dev, "wav", &ctl_wavops, f, 1);
-       f->pstate = WAV_INIT;
-       if ((f->mode & f->dev->mode) != f->mode) {
-#ifdef DEBUG
-               if (debug_level >= 1) {
-                       wav_dbg(f);
-                       dbg_puts(": ");
-                       dbg_puts(": operation not supported by device\n");
-               }
-#endif
-               wav_exit(f);
-               return 0;
-       }
-       wav_allocbuf(f);
-       return 1;
-}
-
-/*
- * seek to f->mmcpos and prepare to start, close
- * the file on error.
- */
-int
-wav_seekmmc(struct wav *f)
-{
-       /*
-        * don't go beyond the end-of-file, if so
-        * put it in INIT state so it dosn't start
-        */
-       if (f->mmcpos > f->endpos && !(f->mode & MODE_RECMASK)) {
-               wav_reset(f);
-               /*
-                * don't make other stream wait for us
-                */
-               if (f->slot >= 0)
-                       dev_slotstart(f->dev, f->slot);
-               return 0;
-       }
-       if (!pipe_seek(&f->pipe.file, f->mmcpos)) {
-               wav_exit(f);
-               return 0;
-       }
-       if ((f->mode & MODE_RECMASK) && f->mmcpos > f->endpos)
-               f->endpos = f->mmcpos;
-       if (f->hdr == HDR_WAV)
-               f->wbytes = WAV_DATAMAX - f->mmcpos;
-       f->rbytes = f->endpos - f->mmcpos;
-       wav_reset(f);
-       wav_allocbuf(f);
-       return 1;
-}
-
-/*
- * read samples from the file and possibly start it
- */
-int
-wav_rdata(struct wav *f)
-{
-       struct aproc *p;
-       struct abuf *obuf;
-
-       p = f->pipe.file.rproc;
-       obuf = LIST_FIRST(&p->outs);
-       if (obuf == NULL)
-               return 0;
-       if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
-               return 0;
-       if (!rfile_do(p, obuf->len, NULL))
-               return 0;
-       switch (f->pstate) {
-       case WAV_START:
-               if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
-                       f->pstate = WAV_READY;
-               /* PASSTHROUGH */
-       case WAV_READY:
-               if (dev_slotstart(f->dev, f->slot))
-                       (void)wav_attach(f, 0);
-               break;
-       case WAV_RUN:
-               break;
-       case WAV_MIDI:
-               return 1;
-#ifdef DEBUG
-       default:
-               wav_dbg(f);
-               dbg_puts(": bad state\n");
-               dbg_panic();
-#endif
-       }
-       if (f->rbytes == 0 && f->mmc) {
-#ifdef DEBUG
-               if (debug_level >= 3) {
-                       wav_dbg(f);
-                       dbg_puts(": trying to restart\n");
-               }
-#endif
-               if (!wav_seekmmc(f))
-                       return 0;
-       }
-       return 1;
-}
-
-int
-wav_wdata(struct wav *f)
-{
-       struct aproc *p;
-       struct abuf *ibuf;
-
-       if (!(f->pipe.file.state & FILE_WOK))
-               return 0;
-       p = f->pipe.file.wproc;
-       ibuf = LIST_FIRST(&p->ins);
-       if (ibuf == NULL)
-               return 0;
-       if (!ABUF_ROK(ibuf))
-               return 0;
-       if (!wfile_do(p, ibuf->len, NULL))
-               return 0;
-       return 1;
-}
-
-/*
- * callback to set the volume, invoked by the MIDI control code
- */
-void
-wav_setvol(void *arg, unsigned int vol)
-{
-       struct wav *f = (struct wav *)arg;
-       struct abuf *rbuf;
-
-       f->vol = vol;
-       if ((f->mode & MODE_PLAY) && f->pstate == WAV_RUN) {
-               rbuf = LIST_FIRST(&f->pipe.file.rproc->outs);
-               dev_setvol(f->dev, rbuf, MIDI_TO_ADATA(vol));
-       }
-}
-
-/*
- * callback to start the stream, invoked by the MIDI control code
- */
-void
-wav_startreq(void *arg)
-{
-       struct wav *f = (struct wav *)arg;
-
-       switch (f->pstate) {
-       case WAV_INIT:
-#ifdef DEBUG
-               if (debug_level >= 2) {
-                       wav_dbg(f);
-                       dbg_puts(": skipped (failed to seek)\n");
-               }
-#endif
-               return;
-       case WAV_READY:
-               if (f->mode & MODE_RECMASK)
-                       f->endpos = f->mmcpos + f->startpos;
-               (void)wav_attach(f, 0);
-               break;
-#ifdef DEBUG
-       default:
-               wav_dbg(f);
-               dbg_puts(": not in READY state\n");
-               dbg_panic();
-               break;
-#endif
-       }
-}
-
-/*
- * callback to stop the stream, invoked by the MIDI control code
- */
-void
-wav_stopreq(void *arg)
-{
-       struct wav *f = (struct wav *)arg;
-
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               wav_dbg(f);
-               dbg_puts(": stopping");
-               if (f->pstate != WAV_INIT && (f->mode & MODE_RECMASK)) {
-                       dbg_puts(", ");
-                       dbg_putu(f->endpos);
-                       dbg_puts(" bytes recorded");
-               }
-               dbg_puts("\n");
-       }
-#endif
-       if (!f->mmc) {
-               wav_exit(f);
-               return;
-       }
-       (void)wav_seekmmc(f);
-}
-
-/*
- * callback to relocate the stream, invoked by the MIDI control code
- * on a stopped stream
- */
-void
-wav_locreq(void *arg, unsigned int mmc)
-{
-       struct wav *f = (struct wav *)arg;
-
-#ifdef DEBUG
-       if (f->pstate == WAV_RUN) {
-               wav_dbg(f);
-               dbg_puts(": in RUN state\n");
-               dbg_panic();
-       }
-#endif
-       f->mmcpos = f->startpos + 
-           ((off_t)mmc * f->hpar.rate / MTC_SEC) * aparams_bpf(&f->hpar);
-       (void)wav_seekmmc(f);
-}
-
-/*
- * Callback invoked when slot is gone
- */
-void
-wav_quitreq(void *arg)
-{
-       struct wav *f = (struct wav *)arg;
-
-#ifdef DEBUG
-       if (debug_level >= 3) {
-               wav_dbg(f);
-               dbg_puts(": slot gone\n");
-       }
-#endif
-       if (f->pstate != WAV_RUN)
-               wav_exit(f);
-}
-
-/*
- * determine the header by the file name
- */
-int
-wav_autohdr(char *name, struct dev *dev, unsigned int *hdr, unsigned int *mode)
-{
-       char *ext;
-
-       if (dev->reqmode & MODE_THRU)
-               *mode &= MODE_MIDIMASK;
-       if (*hdr == HDR_AUTO) {
-               ext = strrchr(name, '.');
-               if (ext != NULL) {
-                       ext++;
-                       if (strcasecmp(ext, "wav") == 0) {
-                               *hdr = HDR_WAV;
-                               *mode &= ~MODE_MIDIMASK;
-                       } else if (strcasecmp(ext, "syx") == 0) {
-                               *hdr = HDR_RAW;
-                               *mode &= ~MODE_AUDIOMASK;
-                       }
-               } else
-                       *hdr = HDR_RAW;
-       }
-       if (*mode & MODE_AUDIOMASK)
-               *mode &= ~MODE_MIDIMASK;
-       if (*mode == 0) {
-#ifdef DEBUG
-               if (debug_level >= 1) {
-                       dbg_puts(name);
-                       dbg_puts(": requested mode not supported\n");
-               }
-#endif
-               return 0;
-       }
-       return 1;
-}
-
-/*
- * create a file reader in the ``INIT'' state
- */
-struct wav *
-wav_new_in(struct fileops *ops, struct dev *dev,
-    unsigned int mode, char *name, unsigned int hdr,
-    struct aparams *par, unsigned int xrun,
-    unsigned int volctl, int mmc, int join)
-{
-       int fd;
-       struct wav *f;
-
-       if (!wav_autohdr(name, dev, &hdr, &mode))
-               return NULL;
-       if (strcmp(name, "-") == 0) {
-               fd = STDIN_FILENO;
-               if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
-                       perror(name);
-       } else {
-               fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
-               if (fd < 0) {
-                       perror(name);
-                       return NULL;
-               }
-       }
-       f = (struct wav *)pipe_new(ops, fd, name);
-       if (f == NULL) {
-               close(fd);
-               return NULL;
-       }
-       f->mode = mode;
-       f->pstate = WAV_CFG;
-       f->endpos = f->startpos = 0;
-       f->next = wav_list;
-       wav_list = f;
-       if (hdr == HDR_WAV) {
-               if (!wav_readhdr(f->pipe.fd, par,
-                       &f->startpos, &f->rbytes, &f->map)) {
-                       file_del((struct file *)f);
-                       return NULL;
-               }
-               f->endpos = f->startpos + f->rbytes;
-       } else {
-               f->endpos = pipe_endpos(&f->pipe.file);
-               if (f->endpos > 0) {
-                       if (!pipe_seek(&f->pipe.file, 0)) {
-                               file_del((struct file *)f);
-                               return NULL;
-                       }
-                       f->rbytes = f->endpos;
-               } else
-                       f->rbytes = -1;
-               f->map = NULL;
-       }
-       f->dev = dev;
-       f->mmc = mmc;
-       f->join = join;
-       f->mode = mode;
-       f->hpar = *par;
-       f->hdr = hdr;
-       f->xrun = xrun;
-       f->maxweight = MIDI_TO_ADATA(volctl);
-       f->slot = -1;
-       rwav_new((struct file *)f);
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               dbg_puts(name);
-               dbg_puts(":");
-               if (f->mode & MODE_PLAY) {
-                       dbg_puts(" playing ");
-                       aparams_dbg(par);
-                       dbg_puts(" ");
-                       dbg_putu(f->startpos);
-                       dbg_puts("..");
-                       dbg_putu(f->endpos);
-                       if (f->mmc)
-                               dbg_puts(", mmc");
-               }
-               if (f->mode & MODE_MIDIOUT)
-                       dbg_puts(" midi/out");
-               dbg_puts("\n");
-       }
-#endif
-       return f;
-}
-
-/*
- * create a file writer in the ``INIT'' state
- */
-struct wav *
-wav_new_out(struct fileops *ops, struct dev *dev,
-    unsigned int mode, char *name, unsigned int hdr,
-    struct aparams *par, unsigned int xrun, int mmc, int join)
-{
-       int fd;
-       struct wav *f;
-
-       if (!wav_autohdr(name, dev, &hdr, &mode))
-               return NULL;
-       if (strcmp(name, "-") == 0) {
-               fd = STDOUT_FILENO;
-               if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0)
-                       perror(name);
-       } else {
-               fd = open(name,
-                   O_WRONLY | O_TRUNC | O_CREAT | O_NONBLOCK, 0666);
-               if (fd < 0) {
-                       perror(name);
-                       return NULL;
-               }
-       }
-       f = (struct wav *)pipe_new(ops, fd, name);
-       if (f == NULL) {
-               close(fd);
-               return NULL;
-       }
-       f->mode = mode;
-       f->pstate = WAV_CFG;
-       f->mmcpos = f->endpos = f->startpos = 0;
-       f->next = wav_list;
-       wav_list = f;
-       if (hdr == HDR_WAV) {
-               par->le = 1;
-               par->sig = (par->bits <= 8) ? 0 : 1;
-               par->bps = (par->bits + 7) / 8;
-               if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) {
-                       file_del((struct file *)f);
-                       return NULL;
-               }
-               f->wbytes = WAV_DATAMAX;
-               f->endpos = f->startpos;
-       } else
-               f->wbytes = -1;
-       f->dev = dev;
-       f->mmc = mmc;
-       f->join = join;
-       f->hpar = *par;
-       f->hdr = hdr;
-       f->xrun = xrun;
-       wwav_new((struct file *)f);
-#ifdef DEBUG
-       if (debug_level >= 2) {
-               dbg_puts(name);
-               dbg_puts(":");
-               if (f->mode & MODE_RECMASK) {
-                       dbg_puts(" recording ");
-                       aparams_dbg(par);
-                       if (f->mmc)
-                               dbg_puts(", mmc");
-               }
-               if (f->mode & MODE_MIDIIN)
-                       dbg_puts(" midi/in");
-               dbg_puts("\n");
-       }
-#endif
-       return f;
-}
-
-void
-rwav_done(struct aproc *p)
-{
-       struct wav *f = (struct wav *)p->u.io.file;
-
-       if (f->slot >= 0)
-               dev_slotdel(f->dev, f->slot);
-       f->slot = -1;
-       rfile_done(p);
-}
-
-int
-rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
-{
-       struct wav *f = (struct wav *)p->u.io.file;
-       struct abuf *obuf;
-
-       if (!wav_rdata(f))
-               return 0;
-       obuf = LIST_FIRST(&p->outs);
-       if (obuf && f->pstate >= WAV_RUN) {
-               if (!abuf_flush(obuf))
-                       return 0;
-       }
-       return 1;
-}
-
-int
-rwav_out(struct aproc *p, struct abuf *obuf)
-{
-       struct wav *f = (struct wav *)p->u.io.file;
-
-       if (f->pipe.file.state & FILE_RINUSE)
-               return 0;
-       for (;;) {
-               if (!wav_rdata(f))
-                       return 0;
-       }
-       return 1;
-}
-
-struct aproc *
-rwav_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&rwav_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->rproc = p;
-       return p;
-}
-
-void
-wwav_done(struct aproc *p)
-{
-       struct wav *f = (struct wav *)p->u.io.file;
-
-       if (f->slot >= 0)
-               dev_slotdel(f->dev, f->slot);
-       f->slot = -1;
-       wfile_done(p);
-}
-
-int
-wwav_in(struct aproc *p, struct abuf *ibuf)
-{
-       struct wav *f = (struct wav *)p->u.io.file;
-
-       if (f->pipe.file.state & FILE_WINUSE)
-               return 0;
-       for (;;) {
-               if (!wav_wdata(f))
-                       return 0;
-       }
-       return 1;
-}
-
-int
-wwav_out(struct aproc *p, struct abuf *obuf_dummy)
-{
-       struct abuf *ibuf = LIST_FIRST(&p->ins);
-       struct wav *f = (struct wav *)p->u.io.file;
-
-       if (ibuf && f->pstate == WAV_RUN) {
-               if (!abuf_fill(ibuf))
-                       return 0;
-       }
-       if (!wav_wdata(f))
-               return 0;
-       return 1;
-}
-
-struct aproc *
-wwav_new(struct file *f)
-{
-       struct aproc *p;
-
-       p = aproc_new(&wwav_ops, f->name);
-       p->u.io.file = f;
-       p->u.io.partial = 0;
-       f->wproc = p;
-       return p;
-}
diff --git a/usr.bin/aucat/wav.h b/usr.bin/aucat/wav.h
deleted file mode 100644 (file)
index 2e9ca34..0000000
+++ /dev/null
@@ -1,76 +0,0 @@
-/*     $OpenBSD: wav.h,v 1.13 2012/04/11 06:05:43 ratchov Exp $        */
-/*
- * Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
- *
- * Permission to use, copy, modify, and distribute this software for any
- * purpose with or without fee is hereby granted, provided that the above
- * copyright notice and this permission notice appear in all copies.
- *
- * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
- * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
- * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
- * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
- * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
- * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
- * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
- */
-#ifndef WAV_H
-#define WAV_H
-
-#include <sys/types.h>
-
-#include "aparams.h"
-#include "pipe.h"
-
-struct wav {
-       struct pipe pipe;
-       struct wav *next;
-#define HDR_AUTO       0       /* guess by looking at the file name */
-#define HDR_RAW                1       /* no headers, ie openbsd native ;-) */
-#define HDR_WAV                2       /* microsoft riff wave */
-       unsigned int hdr;       /* HDR_RAW or HDR_WAV */
-       unsigned int xrun;      /* xrun policy */
-       struct aparams hpar;    /* parameters to write on the header */
-       off_t rbytes;           /* bytes to read, -1 if no limit */
-       off_t wbytes;           /* bytes to write, -1 if no limit */
-       off_t startpos;         /* beginning of the data chunk */
-       off_t endpos;           /* end of the data chunk */
-       off_t mmcpos;           /* play/rec start point set by MMC */
-       short *map;             /* mulaw/alaw -> s16 conversion table */
-       int slot;               /* mixer ctl slot number */
-       int mmc;                /* use MMC control */
-       int join;               /* join/expand channels */
-       unsigned int vol;       /* current volume */
-       unsigned int maxweight; /* dynamic range when vol == 127 */
-#define WAV_CFG                0       /* parameters read from headers */
-#define WAV_INIT       1       /* not trying to do anything */
-#define WAV_START      2       /* buffer allocated */
-#define WAV_READY      3       /* buffer filled enough */
-#define WAV_RUN                4       /* buffer attached to device */
-#define WAV_MIDI       5       /* midi "syx" file */
-       unsigned int pstate;    /* one of above */
-       unsigned int mode;      /* bitmap of MODE_* */
-       struct dev *dev;        /* device playing or recording */
-};
-
-extern struct fileops wav_ops;
-struct wav *wav_list;
-
-struct wav *wav_new_in(struct fileops *, struct dev *,
-    unsigned int, char *, unsigned int, struct aparams *,
-    unsigned int, unsigned int, int, int);
-struct wav *wav_new_out(struct fileops *, struct dev *,
-    unsigned int, char *, unsigned int, struct aparams *,
-    unsigned int, int, int);
-unsigned int wav_read(struct file *, unsigned char *, unsigned int);
-unsigned int wav_write(struct file *, unsigned char *, unsigned int);
-void wav_close(struct file *);
-int wav_readhdr(int, struct aparams *, off_t *, off_t *, short **);
-int wav_writehdr(int, struct aparams *, off_t *, off_t);
-void wav_conv(unsigned char *, unsigned int, short *);
-int wav_init(struct wav *);
-
-extern short wav_ulawmap[256];
-extern short wav_alawmap[256];
-
-#endif /* !defined(WAV_H) */