summaryrefslogtreecommitdiff
path: root/usr.bin
diff options
context:
space:
mode:
Diffstat (limited to 'usr.bin')
-rw-r--r--usr.bin/aucat/abuf.c113
-rw-r--r--usr.bin/aucat/abuf.h29
-rw-r--r--usr.bin/aucat/amsg.h5
-rw-r--r--usr.bin/aucat/aproc.c729
-rw-r--r--usr.bin/aucat/aproc.h57
-rw-r--r--usr.bin/aucat/aucat.174
-rw-r--r--usr.bin/aucat/aucat.c299
-rw-r--r--usr.bin/aucat/conf.h15
-rw-r--r--usr.bin/aucat/dev.c366
-rw-r--r--usr.bin/aucat/dev.h22
-rw-r--r--usr.bin/aucat/file.c23
-rw-r--r--usr.bin/aucat/headers.c22
-rw-r--r--usr.bin/aucat/legacy.c6
-rw-r--r--usr.bin/aucat/midi.c220
-rw-r--r--usr.bin/aucat/midi.h6
-rw-r--r--usr.bin/aucat/midicat.118
-rw-r--r--usr.bin/aucat/opt.c42
-rw-r--r--usr.bin/aucat/opt.h11
-rw-r--r--usr.bin/aucat/pipe.c51
-rw-r--r--usr.bin/aucat/pipe.h5
-rw-r--r--usr.bin/aucat/siofile.c166
-rw-r--r--usr.bin/aucat/siofile.h7
-rw-r--r--usr.bin/aucat/sock.c338
-rw-r--r--usr.bin/aucat/sock.h11
-rw-r--r--usr.bin/aucat/wav.c740
-rw-r--r--usr.bin/aucat/wav.h29
26 files changed, 2398 insertions, 1006 deletions
diff --git a/usr.bin/aucat/abuf.c b/usr.bin/aucat/abuf.c
index 4d14626ee7f..a206a775d0b 100644
--- a/usr.bin/aucat/abuf.c
+++ b/usr.bin/aucat/abuf.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: abuf.c,v 1.18 2010/01/11 13:06:32 ratchov Exp $ */
+/* $OpenBSD: abuf.c,v 1.19 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -105,12 +105,9 @@ abuf_new(unsigned nfr, struct aparams *par)
/*
* fill fifo pointers
*/
- buf->len = len;
+ buf->len = nfr;
buf->used = 0;
buf->start = 0;
- buf->abspos = 0;
- buf->silence = 0;
- buf->drop = 0;
buf->rproc = NULL;
buf->wproc = NULL;
buf->duplex = NULL;
@@ -161,9 +158,6 @@ abuf_clear(struct abuf *buf)
#endif
buf->used = 0;
buf->start = 0;
- buf->abspos = 0;
- buf->silence = 0;
- buf->drop = 0;
}
/*
@@ -191,7 +185,7 @@ abuf_rgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
if (count > used)
count = used;
*rsize = count;
- return (unsigned char *)buf + sizeof(struct abuf) + start;
+ return (unsigned char *)buf + sizeof(struct abuf) + start * buf->bpf;
}
/*
@@ -213,7 +207,6 @@ abuf_rdiscard(struct abuf *buf, unsigned count)
buf->start += count;
if (buf->start >= buf->len)
buf->start -= buf->len;
- buf->abspos += count;
}
/*
@@ -260,7 +253,7 @@ abuf_wgetblk(struct abuf *buf, unsigned *rsize, unsigned ofs)
if (count > avail)
count = avail;
*rsize = count;
- return (unsigned char *)buf + sizeof(struct abuf) + end;
+ return (unsigned char *)buf + sizeof(struct abuf) + end * buf->bpf;
}
/*
@@ -271,47 +264,17 @@ int
abuf_flush_do(struct abuf *buf)
{
struct aproc *p;
- unsigned count;
- if (buf->drop > 0) {
- count = buf->drop;
- if (count > buf->used)
- count = buf->used;
- if (count == 0) {
-#ifdef DEBUG
- if (debug_level >= 4) {
- abuf_dbg(buf);
- dbg_puts(": flush: no data to drop\n");
- }
-#endif
- return 0;
- }
- abuf_rdiscard(buf, count);
- buf->drop -= count;
-#ifdef DEBUG
- if (debug_level >= 4) {
- abuf_dbg(buf);
- dbg_puts(": flush: dropped ");
- dbg_putu(count);
- dbg_puts(", to drop = ");
- dbg_putu(buf->drop);
- dbg_puts("\n");
- }
-#endif
- } else {
- p = buf->rproc;
- if (!p)
- return 0;
+ p = buf->rproc;
+ if (!p)
+ return 0;
#ifdef DEBUG
- if (debug_level >= 4) {
- aproc_dbg(p);
- dbg_puts(": in\n");
- }
-#endif
- if (!p->ops->in(p, buf))
- return 0;
+ if (debug_level >= 4) {
+ aproc_dbg(p);
+ dbg_puts(": in\n");
}
- return 1;
+#endif
+ return p->ops->in(p, buf);
}
/*
@@ -322,51 +285,17 @@ int
abuf_fill_do(struct abuf *buf)
{
struct aproc *p;
- unsigned char *data;
- unsigned count;
-
- if (buf->silence > 0) {
- data = abuf_wgetblk(buf, &count, 0);
- if (count >= buf->silence)
- count = buf->silence;
- if (count == 0) {
-#ifdef DEBUG
- if (debug_level >= 4) {
- abuf_dbg(buf);
- dbg_puts(": fill: no space for silence\n");
- }
-#endif
- return 0;
- }
- memset(data, 0, count);
- abuf_wcommit(buf, count);
- buf->silence -= count;
-#ifdef DEBUG
- if (debug_level >= 4) {
- abuf_dbg(buf);
- dbg_puts(": fill: inerted ");
- dbg_putu(count);
- dbg_puts(", remaining silence = ");
- dbg_putu(buf->silence);
- dbg_puts("\n");
- }
-#endif
- p = buf->wproc;
- } else {
- p = buf->wproc;
- if (!p)
- return 0;
+
+ p = buf->wproc;
+ if (!p)
+ return 0;
#ifdef DEBUG
- if (debug_level >= 4) {
- aproc_dbg(p);
- dbg_puts(": out\n");
- }
-#endif
- if (!p->ops->out(p, buf)) {
- return 0;
- }
+ if (debug_level >= 4) {
+ aproc_dbg(p);
+ dbg_puts(": out\n");
}
- return 1;
+#endif
+ return p->ops->out(p, buf);
}
/*
diff --git a/usr.bin/aucat/abuf.h b/usr.bin/aucat/abuf.h
index 23c2e8ffde4..a69495261b0 100644
--- a/usr.bin/aucat/abuf.h
+++ b/usr.bin/aucat/abuf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: abuf.h,v 1.19 2009/10/09 16:49:48 ratchov Exp $ */
+/* $OpenBSD: abuf.h,v 1.20 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -39,9 +39,6 @@ struct abuf {
unsigned start; /* offset where data starts */
unsigned used; /* valid data */
unsigned len; /* size of the ring */
- unsigned abspos; /* frame number of the start position */
- unsigned silence; /* silence to insert on next write */
- unsigned drop; /* bytes to drop on next read */
struct aproc *rproc; /* reader */
struct aproc *wproc; /* writer */
struct abuf *duplex; /* link to buffer of the other direction */
@@ -56,8 +53,9 @@ struct abuf {
int weight; /* dynamic range */
int maxweight; /* max dynamic range allowed */
unsigned vol; /* volume within the dynamic range */
- unsigned done; /* bytes ready */
+ unsigned done; /* frames ready */
unsigned xrun; /* underrun policy */
+ int drop; /* frames to drop on next read */
} mix;
struct {
unsigned st; /* MIDI running status */
@@ -73,11 +71,12 @@ struct abuf {
*/
union {
struct {
- unsigned todo; /* bytes to process */
+ unsigned todo; /* frames to process */
} mix;
struct {
- unsigned done; /* bytes copied */
+ unsigned done; /* frames copied */
unsigned xrun; /* overrun policy */
+ int silence; /* silence to add on next write */
} sub;
} w;
};
@@ -86,12 +85,12 @@ struct abuf {
* 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 >= (b)->bpf)
+#define ABUF_ROK(b) ((b)->used > 0)
/*
* there's room for at least one frame
*/
-#define ABUF_WOK(b) ((b)->len - (b)->used >= (b)->bpf)
+#define ABUF_WOK(b) ((b)->len - (b)->used > 0)
/*
* the buffer is empty and has no writer anymore
@@ -105,18 +104,6 @@ struct abuf {
*/
#define ABUF_HUP(b) (!ABUF_WOK(b) && (b)->rproc == NULL)
-/*
- * similar to !ABUF_WOK, but is used for file i/o, where
- * operation may not involve an integer number of frames
- */
-#define ABUF_FULL(b) ((b)->used == (b)->len)
-
-/*
- * same as !ABUF_ROK, but used for files, where
- * operations are byte orientated, not frame-oriented
- */
-#define ABUF_EMPTY(b) ((b)->used == 0)
-
struct abuf *abuf_new(unsigned, struct aparams *);
void abuf_del(struct abuf *);
void abuf_dbg(struct abuf *);
diff --git a/usr.bin/aucat/amsg.h b/usr.bin/aucat/amsg.h
index fa971543c30..7da19f2e55e 100644
--- a/usr.bin/aucat/amsg.h
+++ b/usr.bin/aucat/amsg.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: amsg.h,v 1.12 2009/10/22 21:41:30 ratchov Exp $ */
+/* $OpenBSD: amsg.h,v 1.13 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -87,7 +87,8 @@ struct amsg {
#define AMSG_REC 0x2 /* audio recording */
#define AMSG_MIDIIN 0x4 /* MIDI thru input */
#define AMSG_MIDIOUT 0x8 /* MIDI thru output */
-#define AMSG_MIXER 0x10 /* MIDI mixer */
+#define AMSG_MON 0x10 /* audio monitoring */
+#define AMSG_RECMASK (AMSG_REC | AMSG_MON) /* can record ? */
uint16_t proto; /* protocol type */
#define AMSG_VERSION 1
uint8_t version; /* protocol version */
diff --git a/usr.bin/aucat/aproc.c b/usr.bin/aucat/aproc.c
index 598cd16c9d6..4f71392a335 100644
--- a/usr.bin/aucat/aproc.c
+++ b/usr.bin/aucat/aproc.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aproc.c,v 1.48 2010/01/17 19:17:23 ratchov Exp $ */
+/* $OpenBSD: aproc.c,v 1.49 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -48,6 +48,18 @@
#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)
+
#ifdef DEBUG
void
aproc_dbg(struct aproc *p)
@@ -275,20 +287,40 @@ aproc_depend(struct aproc *p, struct aproc *dep)
}
int
-rfile_in(struct aproc *p, struct abuf *ibuf_dummy)
+rfile_do(struct aproc *p, unsigned todo, unsigned *done)
{
struct abuf *obuf = LIST_FIRST(&p->obuflist);
struct file *f = p->u.io.file;
unsigned char *data;
- unsigned count;
+ unsigned n, count, off;
- if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
- return 0;
+ off = p->u.io.partial;
data = abuf_wgetblk(obuf, &count, 0);
- count = file_read(f, data, count);
- if (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->obuflist);
+ 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;
- abuf_wcommit(obuf, count);
if (!abuf_flush(obuf))
return 0;
return 1;
@@ -298,18 +330,13 @@ int
rfile_out(struct aproc *p, struct abuf *obuf)
{
struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
if (f->state & FILE_RINUSE)
return 0;
- if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
+ if (!ABUF_WOK(obuf) || !(f->state & FILE_ROK))
return 0;
- data = abuf_wgetblk(obuf, &count, 0);
- count = file_read(f, data, count);
- if (count == 0)
+ if (!rfile_do(p, obuf->len, NULL))
return 0;
- abuf_wcommit(obuf, count);
return 1;
}
@@ -322,6 +349,12 @@ rfile_done(struct aproc *p)
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
*/
@@ -329,11 +362,18 @@ rfile_done(struct aproc *p)
if (obuf)
abuf_eof(obuf);
if (f->wproc) {
- f->rproc = NULL;
aproc_del(f->wproc);
} else
file_del(f);
- p->u.io.file = NULL;
+
+#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
@@ -368,6 +408,7 @@ rfile_new(struct file *f)
p = aproc_new(&rfile_ops, f->name);
p->u.io.file = f;
+ p->u.io.partial = 0;
f->rproc = p;
return p;
}
@@ -381,6 +422,12 @@ wfile_done(struct aproc *p)
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
*/
@@ -388,29 +435,54 @@ wfile_done(struct aproc *p)
if (ibuf)
abuf_hup(ibuf);
if (f->rproc) {
- f->wproc = NULL;
aproc_del(f->rproc);
} else
file_del(f);
- p->u.io.file = NULL;
+#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_in(struct aproc *p, struct abuf *ibuf)
+wfile_do(struct aproc *p, unsigned todo, unsigned *done)
{
+ struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
struct file *f = p->u.io.file;
unsigned char *data;
- unsigned count;
+ unsigned 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_EMPTY(ibuf) || !(f->state & FILE_WOK))
+ if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK))
return 0;
- data = abuf_rgetblk(ibuf, &count, 0);
- count = file_write(f, data, count);
- if (count == 0)
+ if (!wfile_do(p, ibuf->len, NULL))
return 0;
- abuf_rdiscard(ibuf, count);
return 1;
}
@@ -419,22 +491,13 @@ wfile_out(struct aproc *p, struct abuf *obuf_dummy)
{
struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
if (!abuf_fill(ibuf))
return 0;
- if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
- return 0;
- data = abuf_rgetblk(ibuf, &count, 0);
- if (count == 0) {
- /* XXX: this can't happen, right ? */
+ if (!ABUF_ROK(ibuf) || !(f->state & FILE_WOK))
return 0;
- }
- count = file_write(f, data, count);
- if (count == 0)
+ if (!wfile_do(p, ibuf->len, NULL))
return 0;
- abuf_rdiscard(ibuf, count);
return 1;
}
@@ -470,45 +533,83 @@ wfile_new(struct file *f)
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 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 given amount of silence (or less if there's not enough
- * space), and crank mixitodo accordingly.
+ * space), and crank w.mix.todo accordingly.
*/
void
-mix_bzero(struct abuf *obuf, unsigned zcount)
+mix_bzero(struct abuf *obuf)
{
short *odata;
unsigned ocount;
+ odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.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(zcount);
+ dbg_putu(obuf->w.mix.todo);
dbg_puts(")\n");
}
#endif
- odata = (short *)abuf_wgetblk(obuf, &ocount, obuf->w.mix.todo);
- ocount -= ocount % obuf->bpf;
- if (ocount > zcount)
- ocount = zcount;
- memset(odata, 0, ocount);
- obuf->w.mix.todo += ocount;
}
/*
* Mix an input block over an output block.
*/
-void
+unsigned
mix_badd(struct abuf *ibuf, struct abuf *obuf)
{
short *idata, *odata;
unsigned i, j, icnt, onext, ostart;
- unsigned scount, icount, ocount, zcount;
+ unsigned scount, icount, ocount;
int vol;
#ifdef DEBUG
@@ -518,31 +619,37 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf)
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
/*
- * Calculate the maximum we can read.
+ * Insert silence for xrun correction
*/
- idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
- icount /= ibuf->bpf;
- if (icount == 0)
- return;
+ if (ibuf->r.mix.drop < 0) {
+ icount = -ibuf->r.mix.drop;
+ ocount = obuf->len - obuf->used;
+ if (ocount > obuf->w.mix.todo)
+ ocount = obuf->w.mix.todo;
+ scount = (icount < ocount) ? icount : ocount;
+ ibuf->r.mix.done += scount;
+ ibuf->r.mix.drop += scount;
+ }
/*
- * Zero-fill if necessary.
+ * Calculate the maximum we can read.
*/
- zcount = ibuf->r.mix.done + icount * obuf->bpf;
- if (zcount > obuf->w.mix.todo)
- mix_bzero(obuf, zcount - obuf->w.mix.todo);
+ idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
+ if (icount == 0)
+ return 0;
/*
* Calculate the maximum we can write.
*/
odata = (short *)abuf_wgetblk(obuf, &ocount, ibuf->r.mix.done);
- ocount /= obuf->bpf;
if (ocount == 0)
- return;
+ return 0;
vol = (ibuf->r.mix.weight * ibuf->r.mix.vol) >> ADATA_SHIFT;
ostart = ibuf->cmin - obuf->cmin;
@@ -558,30 +665,30 @@ mix_badd(struct abuf *ibuf, struct abuf *obuf)
}
odata += onext;
}
- abuf_rdiscard(ibuf, scount * ibuf->bpf);
- ibuf->r.mix.done += scount * obuf->bpf;
+ abuf_rdiscard(ibuf, scount);
+ ibuf->r.mix.done += scount;
#ifdef DEBUG
if (debug_level >= 4) {
abuf_dbg(ibuf);
dbg_puts(": badd: done = ");
- dbg_putu(scount);
- dbg_puts(", todo = ");
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 abuf *i, struct abuf *obuf)
+mix_xrun(struct aproc *p, struct abuf *i)
{
- unsigned fdrop;
+ struct abuf *obuf = LIST_FIRST(&p->obuflist);
+ unsigned fdrop, remain;
if (i->r.mix.done > 0)
return 1;
@@ -589,22 +696,34 @@ mix_xrun(struct abuf *i, struct abuf *obuf)
abuf_hup(i);
return 0;
}
- mix_bzero(obuf, obuf->len);
- fdrop = obuf->w.mix.todo / obuf->bpf;
+ 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->drop / i->bpf);
+ dbg_putu(i->r.mix.drop);
dbg_puts("\n");
}
#endif
- i->r.mix.done += fdrop * obuf->bpf;
+ i->r.mix.done += fdrop;
if (i->r.mix.xrun == XRUN_SYNC)
- i->drop += fdrop * i->bpf;
+ 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
@@ -613,7 +732,7 @@ mix_xrun(struct abuf *i, struct abuf *obuf)
dbg_puts(": full-duplex resync\n");
}
#endif
- i->duplex->drop += fdrop * i->duplex->bpf;
+ sub_silence(i->duplex, -(int)fdrop);
abuf_ipos(i->duplex, -(int)fdrop);
}
}
@@ -625,6 +744,8 @@ mix_in(struct aproc *p, struct abuf *ibuf)
{
struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
unsigned odone;
+ unsigned maxwrite;
+ unsigned scount;
#ifdef DEBUG
if (debug_level >= 4) {
@@ -640,27 +761,50 @@ mix_in(struct aproc *p, struct abuf *ibuf)
dbg_puts("\n");
}
#endif
- if (!ABUF_ROK(ibuf))
+ if (!MIX_ROK(ibuf))
return 0;
- odone = obuf->len;
+ mix_bzero(obuf);
+ scount = 0;
+ odone = obuf->w.mix.todo;
for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
inext = LIST_NEXT(i, ient);
- if (!abuf_fill(i))
+ if (i->r.mix.drop >= 0 && !abuf_fill(i))
continue; /* eof */
- mix_badd(i, obuf);
+ mix_drop(i, 0);
+ scount += mix_badd(i, obuf);
if (odone > i->r.mix.done)
odone = i->r.mix.done;
}
- if (LIST_EMPTY(&p->ibuflist) || odone == 0)
+ if (LIST_EMPTY(&p->ibuflist) || scount == 0)
return 0;
- p->u.mix.lat += odone / obuf->bpf;
- LIST_FOREACH(i, &p->ibuflist, ient) {
- i->r.mix.done -= odone;
+#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;
+ p->u.mix.abspos += odone;
+ LIST_FOREACH(i, &p->ibuflist, 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 */
}
- abuf_wcommit(obuf, odone);
- obuf->w.mix.todo -= odone;
- if (!abuf_flush(obuf))
- return 0; /* hup */
return 1;
}
@@ -669,6 +813,8 @@ mix_out(struct aproc *p, struct abuf *obuf)
{
struct abuf *i, *inext;
unsigned odone;
+ unsigned maxwrite;
+ unsigned scount;
#ifdef DEBUG
if (debug_level >= 4) {
@@ -686,18 +832,34 @@ mix_out(struct aproc *p, struct abuf *obuf)
#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;
+ mix_bzero(obuf);
+ scount = 0;
odone = obuf->len;
for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
inext = LIST_NEXT(i, ient);
- if (!abuf_fill(i))
+ if (i->r.mix.drop >= 0 && !abuf_fill(i))
continue; /* eof */
- if (!ABUF_ROK(i)) {
+ mix_drop(i, 0);
+ if (maxwrite > 0 && !MIX_ROK(i)) {
if (p->flags & APROC_DROP) {
- if (!mix_xrun(i, obuf))
+ if (!mix_xrun(p, i))
continue;
}
} else
- mix_badd(i, obuf);
+ scount += mix_badd(i, obuf);
if (odone > i->r.mix.done)
odone = i->r.mix.done;
}
@@ -708,25 +870,31 @@ mix_out(struct aproc *p, struct abuf *obuf)
}
if (!(p->flags & APROC_DROP))
return 0;
- mix_bzero(obuf, obuf->len);
odone = obuf->w.mix.todo;
- p->u.mix.idle += odone / obuf->bpf;
+ p->u.mix.idle += odone;
}
- if (odone == 0)
- return 0;
- p->u.mix.lat += odone / obuf->bpf;
- LIST_FOREACH(i, &p->ibuflist, ient) {
- i->r.mix.done -= odone;
+ if (maxwrite > 0) {
+ if (odone > maxwrite)
+ odone = maxwrite;
+ p->u.mix.lat += odone;
+ p->u.mix.abspos += odone;
+ LIST_FOREACH(i, &p->ibuflist, 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);
}
- abuf_wcommit(obuf, odone);
- obuf->w.mix.todo -= odone;
+ if (scount == 0)
+ return 0;
return 1;
}
void
mix_eof(struct aproc *p, struct abuf *ibuf)
{
- struct abuf *i, *obuf = LIST_FIRST(&p->obuflist);
+ struct abuf *i, *inext, *obuf = LIST_FIRST(&p->obuflist);
unsigned odone;
mix_setmaster(p);
@@ -742,8 +910,11 @@ mix_eof(struct aproc *p, struct abuf *ibuf)
* Find a blocked input.
*/
odone = obuf->len;
- LIST_FOREACH(i, &p->ibuflist, ient) {
- if (ABUF_ROK(i) && i->r.mix.done < obuf->w.mix.todo) {
+ for (i = LIST_FIRST(&p->ibuflist); i != NULL; i = inext) {
+ inext = LIST_NEXT(i, ient);
+ if (!abuf_fill(i))
+ continue;
+ if (MIX_ROK(i) && i->r.mix.done < obuf->w.mix.todo) {
abuf_run(i);
return;
}
@@ -781,6 +952,7 @@ mix_newin(struct aproc *p, struct abuf *ibuf)
ibuf->r.mix.weight = ADATA_UNIT;
ibuf->r.mix.maxweight = ADATA_UNIT;
ibuf->r.mix.xrun = XRUN_IGNORE;
+ ibuf->r.mix.drop = 0;
}
void
@@ -790,8 +962,8 @@ mix_newout(struct aproc *p, struct abuf *obuf)
if (debug_level >= 3) {
aproc_dbg(p);
dbg_puts(": newin, will use ");
- dbg_putu(obuf->len / obuf->bpf);
- dbg_puts(" fr\n");
+ dbg_putu(obuf->len);
+ dbg_puts("\n");
}
#endif
obuf->w.mix.todo = 0;
@@ -800,6 +972,7 @@ mix_newout(struct aproc *p, struct abuf *obuf)
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);
@@ -807,13 +980,14 @@ mix_opos(struct aproc *p, struct abuf *obuf, int delta)
dbg_puti(p->u.mix.lat);
dbg_puts("/");
dbg_puti(p->u.mix.maxlat);
- dbg_puts(" fr\n");
+ dbg_puts("\n");
}
#endif
- p->u.mix.lat -= delta;
- if (p->u.mix.ctl)
+ if (APROC_OK(p->u.mix.ctl))
ctl_ontick(p->u.mix.ctl, delta);
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 = {
@@ -830,14 +1004,16 @@ struct aproc_ops mix_ops = {
};
struct aproc *
-mix_new(char *name, int maxlat, struct aproc *ctl)
+mix_new(char *name, int maxlat, unsigned round, struct aproc *ctl)
{
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.abspos = 0;
p->u.mix.ctl = ctl;
return p;
}
@@ -895,6 +1071,7 @@ mix_clear(struct aproc *p)
struct abuf *obuf = LIST_FIRST(&p->obuflist);
p->u.mix.lat = 0;
+ p->u.mix.abspos = 0;
obuf->w.mix.todo = 0;
}
@@ -907,16 +1084,19 @@ mix_prime(struct aproc *p)
for (;;) {
if (!ABUF_WOK(obuf))
break;
- todo = (p->u.mix.maxlat - p->u.mix.lat) * obuf->bpf;
+ todo = p->u.mix.maxlat - p->u.mix.lat;
if (todo == 0)
break;
- mix_bzero(obuf, obuf->len);
+ mix_bzero(obuf);
count = obuf->w.mix.todo;
if (count > todo)
count = todo;
obuf->w.mix.todo -= count;
- p->u.mix.lat += count / obuf->bpf;
+ p->u.mix.lat += count;
+ p->u.mix.abspos += count;
abuf_wcommit(obuf, count);
+ if (APROC_OK(p->u.mix.mon))
+ mon_snoop(p->u.mix.mon, obuf, 0, count);
abuf_flush(obuf);
}
#ifdef DEBUG
@@ -932,6 +1112,45 @@ mix_prime(struct aproc *p)
}
/*
+ * Append as much as possible silence on the writer end
+ */
+void
+sub_silence(struct abuf *buf, int extra)
+{
+ unsigned char *data;
+ unsigned 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
@@ -941,12 +1160,21 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
unsigned i, j, ocnt, inext, istart;
unsigned icount, ocount, scount;
+ /*
+ * 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 = (short *)abuf_rgetblk(ibuf, &icount, obuf->w.sub.done);
- icount /= ibuf->bpf;
if (icount == 0)
return;
odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
- ocount /= obuf->bpf;
if (ocount == 0)
return;
istart = obuf->cmin - ibuf->cmin;
@@ -962,14 +1190,14 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
}
idata += inext;
}
- abuf_wcommit(obuf, scount * obuf->bpf);
- obuf->w.sub.done += scount * ibuf->bpf;
+ 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(" fr\n");
+ dbg_puts("\n");
}
#endif
}
@@ -978,9 +1206,10 @@ sub_bcopy(struct abuf *ibuf, struct abuf *obuf)
* Handle buffer overruns. Return 0 if the stream died.
*/
int
-sub_xrun(struct abuf *ibuf, struct abuf *i)
+sub_xrun(struct aproc *p, struct abuf *i)
{
- unsigned fdrop;
+ struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
+ unsigned fdrop, remain;
if (i->w.sub.done > 0)
return 1;
@@ -988,20 +1217,35 @@ sub_xrun(struct abuf *ibuf, struct abuf *i)
abuf_eof(i);
return 0;
}
- fdrop = ibuf->used / ibuf->bpf;
+ fdrop = ibuf->used;
#ifdef DEBUG
if (debug_level >= 3) {
abuf_dbg(i);
dbg_puts(": overrun, silence ");
dbg_putu(fdrop);
dbg_puts(" + ");
- dbg_putu(i->silence / i->bpf);
+ dbg_putu(i->w.sub.silence);
dbg_puts("\n");
}
#endif
+ i->w.sub.done += fdrop;
if (i->w.sub.xrun == XRUN_SYNC)
- i->silence += fdrop * i->bpf;
+ 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
@@ -1010,11 +1254,10 @@ sub_xrun(struct abuf *ibuf, struct abuf *i)
dbg_puts(": full-duplex resync\n");
}
#endif
- i->duplex->silence += fdrop * i->duplex->bpf;
+ mix_drop(i->duplex, -(int)fdrop);
abuf_opos(i->duplex, -(int)fdrop);
}
}
- i->w.sub.done += fdrop * ibuf->bpf;
return 1;
}
@@ -1029,9 +1272,10 @@ sub_in(struct aproc *p, struct abuf *ibuf)
idone = ibuf->len;
for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
inext = LIST_NEXT(i, oent);
- if (!ABUF_WOK(i)) {
+ sub_silence(i, 0);
+ if (!SUB_WOK(i)) {
if (p->flags & APROC_DROP) {
- if (!sub_xrun(ibuf, i))
+ if (!sub_xrun(p, i))
continue;
}
} else
@@ -1049,7 +1293,7 @@ sub_in(struct aproc *p, struct abuf *ibuf)
if (!(p->flags & APROC_DROP))
return 0;
idone = ibuf->used;
- p->u.sub.idle += idone / ibuf->bpf;
+ p->u.sub.idle += idone;
}
if (idone == 0)
return 0;
@@ -1057,7 +1301,9 @@ sub_in(struct aproc *p, struct abuf *ibuf)
i->w.sub.done -= idone;
}
abuf_rdiscard(ibuf, idone);
- p->u.sub.lat -= idone / ibuf->bpf;
+ abuf_opos(ibuf, idone);
+ p->u.sub.lat -= idone;
+ p->u.sub.abspos += idone;
return 1;
}
@@ -1068,13 +1314,14 @@ sub_out(struct aproc *p, struct abuf *obuf)
struct abuf *i, *inext;
unsigned idone;
- if (!ABUF_WOK(obuf))
+ if (!SUB_WOK(obuf))
return 0;
if (!abuf_fill(ibuf))
return 0; /* eof */
idone = ibuf->len;
for (i = LIST_FIRST(&p->obuflist); 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;
@@ -1087,7 +1334,9 @@ sub_out(struct aproc *p, struct abuf *obuf)
i->w.sub.done -= idone;
}
abuf_rdiscard(ibuf, idone);
- p->u.sub.lat -= idone / ibuf->bpf;
+ abuf_opos(ibuf, idone);
+ p->u.sub.lat -= idone;
+ p->u.sub.abspos += idone;
return 1;
}
@@ -1100,7 +1349,7 @@ sub_eof(struct aproc *p, struct abuf *ibuf)
void
sub_hup(struct aproc *p, struct abuf *obuf)
{
- struct abuf *i, *ibuf = LIST_FIRST(&p->ibuflist);
+ struct abuf *i, *inext, *ibuf = LIST_FIRST(&p->ibuflist);
unsigned idone;
if (!aproc_inuse(p)) {
@@ -1114,8 +1363,11 @@ sub_hup(struct aproc *p, struct abuf *obuf)
* Find a blocked output.
*/
idone = ibuf->len;
- LIST_FOREACH(i, &p->obuflist, oent) {
- if (ABUF_WOK(i) && i->w.sub.done < ibuf->used) {
+ for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
+ inext = LIST_NEXT(i, oent);
+ if (!abuf_flush(i))
+ continue;
+ if (SUB_WOK(i) && i->w.sub.done < ibuf->used) {
abuf_run(i);
return;
}
@@ -1144,6 +1396,7 @@ 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
@@ -1157,10 +1410,10 @@ sub_ipos(struct aproc *p, struct abuf *ibuf, int delta)
dbg_puti(p->u.sub.lat);
dbg_puts("/");
dbg_puti(p->u.sub.maxlat);
- dbg_puts(" fr\n");
+ dbg_puts("\n");
}
#endif
- if (p->u.sub.ctl)
+ if (APROC_OK(p->u.sub.ctl))
ctl_ontick(p->u.sub.ctl, delta);
aproc_ipos(p, ibuf, delta);
}
@@ -1179,14 +1432,16 @@ struct aproc_ops sub_ops = {
};
struct aproc *
-sub_new(char *name, int maxlat, struct aproc *ctl)
+sub_new(char *name, int maxlat, unsigned round, struct aproc *ctl)
{
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;
+ p->u.sub.abspos = 0;
p->u.sub.ctl = ctl;
return p;
}
@@ -1194,7 +1449,8 @@ sub_new(char *name, int maxlat, struct aproc *ctl)
void
sub_clear(struct aproc *p)
{
- p->u.mix.lat = 0;
+ p->u.sub.lat = 0;
+ p->u.sub.abspos = 0;
}
/*
@@ -1221,12 +1477,10 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
* Calculate max frames readable at once from the input buffer.
*/
idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
- ifr = icount / ibuf->bpf;
- icount = ifr * ibuf->bpf;
+ ifr = icount;
odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
- ofr = ocount / obuf->bpf;
- ocount = ofr * obuf->bpf;
+ ofr = ocount;
/*
* Partially copy structures into local variables, to avoid
@@ -1258,6 +1512,8 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
#endif
for (;;) {
if (diff < 0) {
+ if (ifr == 0)
+ break;
ctx_start ^= 1;
ctx = ctxbuf + ctx_start;
for (c = inch; c > 0; c--) {
@@ -1265,9 +1521,10 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
ctx += RESAMP_NCTX;
}
diff += oblksz;
- if (--ifr == 0)
- break;
+ ifr--;
} else {
+ if (ofr == 0)
+ break;
ctx = ctxbuf;
for (c = onch; c > 0; c--) {
s1 = ctx[ctx_start];
@@ -1276,8 +1533,7 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
*odata++ = s1 + (s2 - s1) * diff / (int)oblksz;
}
diff -= iblksz;
- if (--ofr == 0)
- break;
+ ofr--;
}
}
p->u.resamp.diff = diff;
@@ -1297,8 +1553,8 @@ resamp_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
/*
* Update FIFO pointers.
*/
- icount -= ifr * ibuf->bpf;
- ocount -= ofr * obuf->bpf;
+ icount -= ifr;
+ ocount -= ofr;
abuf_rdiscard(ibuf, icount);
abuf_wcommit(obuf, ocount);
}
@@ -1421,11 +1677,9 @@ cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
* Calculate max frames readable at once from the input buffer.
*/
idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
- icount /= ibuf->bpf;
if (icount == 0)
return;
odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
- ocount /= obuf->bpf;
if (ocount == 0)
return;
scount = icount < ocount ? icount : ocount;
@@ -1456,8 +1710,8 @@ cmap_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
dbg_puts(" fr\n");
}
#endif
- abuf_rdiscard(ibuf, scount * ibuf->bpf);
- abuf_wcommit(obuf, scount * obuf->bpf);
+ abuf_rdiscard(ibuf, scount);
+ abuf_wcommit(obuf, scount);
}
int
@@ -1555,11 +1809,9 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
* Calculate max frames readable at once from the input buffer.
*/
idata = (short *)abuf_rgetblk(ibuf, &icount, 0);
- icount /= ibuf->bpf;
if (icount == 0)
return;
odata = abuf_wgetblk(obuf, &ocount, 0);
- ocount /= obuf->bpf;
if (ocount == 0)
return;
scount = (icount < ocount) ? icount : ocount;
@@ -1569,7 +1821,7 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
aproc_dbg(p);
dbg_puts(": bcopy ");
dbg_putu(scount);
- dbg_puts(" fr * ");
+ dbg_puts(" fr / ");
dbg_putu(nch);
dbg_puts(" ch\n");
}
@@ -1605,8 +1857,8 @@ enc_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
/*
* Update FIFO pointers.
*/
- abuf_rdiscard(ibuf, scount * ibuf->bpf);
- abuf_wcommit(obuf, scount * obuf->bpf);
+ abuf_rdiscard(ibuf, scount);
+ abuf_wcommit(obuf, scount);
}
int
@@ -1715,11 +1967,9 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
* Calculate max frames readable at once from the input buffer.
*/
idata = abuf_rgetblk(ibuf, &icount, 0);
- icount /= ibuf->bpf;
if (icount == 0)
return;
odata = (short *)abuf_wgetblk(obuf, &ocount, 0);
- ocount /= obuf->bpf;
if (ocount == 0)
return;
scount = (icount < ocount) ? icount : ocount;
@@ -1729,7 +1979,7 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
aproc_dbg(p);
dbg_puts(": bcopy ");
dbg_putu(scount);
- dbg_puts(" fr * ");
+ dbg_puts(" fr / ");
dbg_putu(nch);
dbg_puts(" ch\n");
}
@@ -1765,8 +2015,8 @@ dec_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf)
/*
* Update FIFO pointers.
*/
- abuf_rdiscard(ibuf, scount * ibuf->bpf);
- abuf_wcommit(obuf, scount * obuf->bpf);
+ abuf_rdiscard(ibuf, scount);
+ abuf_wcommit(obuf, scount);
}
int
@@ -1852,3 +2102,168 @@ dec_new(char *name, struct aparams *par)
#endif
return p;
}
+
+/*
+ * Commit and flush part of the output buffer
+ */
+void
+mon_flush(struct aproc *p)
+{
+ struct abuf *obuf = LIST_FIRST(&p->obuflist);
+ unsigned 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 pos, unsigned todo)
+{
+ struct abuf *obuf = LIST_FIRST(&p->obuflist);
+ unsigned scount, icount, ocount;
+ short *idata, *odata;
+
+#ifdef DEBUG
+ if (debug_level >= 4) {
+ aproc_dbg(p);
+ dbg_puts(": snoop ");
+ 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 = (short *)abuf_rgetblk(ibuf, &icount, pos);
+ odata = (short *)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 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
index 7128dac55ab..6b2947c852b 100644
--- a/usr.bin/aucat/aproc.h
+++ b/usr.bin/aucat/aproc.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: aproc.h,v 1.29 2010/01/11 13:06:32 ratchov Exp $ */
+/* $OpenBSD: aproc.h,v 1.30 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -130,26 +130,37 @@ struct aproc {
union { /* follow type-specific data */
struct { /* file/device io */
struct file *file; /* file to read/write */
+ unsigned partial; /* bytes of partial frame */
} io;
struct {
unsigned idle; /* frames since idleing */
+ unsigned round; /* block size, for xruns */
int lat; /* current latency */
int maxlat; /* max latency allowed */
- struct aproc *ctl;
+ unsigned abspos; /* frames produced */
+ struct aproc *ctl; /* MIDI control/sync */
+ struct aproc *mon; /* snoop output */
} mix;
struct {
unsigned idle; /* frames since idleing */
+ unsigned round; /* block size, for xruns */
int lat; /* current latency */
int maxlat; /* max latency allowed */
+ unsigned abspos; /* frames consumed */
struct aproc *ctl;
} sub;
struct {
+ int delta; /* time position */
+ unsigned bufsz; /* buffer size (latency) */
+ unsigned pending; /* uncommited samples */
+ } mon;
+ struct {
#define RESAMP_NCTX 2
unsigned ctx_start;
short ctx[NCHAN_MAX * RESAMP_NCTX];
unsigned iblksz, oblksz;
int diff;
- int idelta, odelta; /* remainder of resamp_[io]pos */
+ int idelta, odelta; /* remainder of resamp_xpos */
} resamp;
struct {
short ctx[NCHAN_MAX];
@@ -191,6 +202,8 @@ struct aproc {
struct ctl_ops {
void (*vol)(void *, unsigned);
void (*start)(void *);
+ void (*stop)(void *);
+ void (*loc)(void *, unsigned);
} *ops;
void *arg;
unsigned unit;
@@ -203,6 +216,18 @@ struct aproc {
} 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 *);
@@ -210,18 +235,40 @@ void aproc_setin(struct aproc *, struct abuf *);
void aproc_setout(struct aproc *, struct abuf *);
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, struct aproc *);
-struct aproc *sub_new(char *, int, struct aproc *);
+struct aproc *mix_new(char *, int, unsigned, struct aproc *);
+struct aproc *sub_new(char *, int, unsigned, struct aproc *);
struct aproc *resamp_new(char *, unsigned, unsigned);
struct aproc *cmap_new(char *, struct aparams *, struct aparams *);
struct aproc *enc_new(char *, struct aparams *);
struct aproc *dec_new(char *, struct aparams *);
+struct aproc *mon_new(char *, unsigned);
+
+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, unsigned *);
+
+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, unsigned *);
void mix_setmaster(struct aproc *);
void mix_clear(struct aproc *);
void mix_prime(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, unsigned);
+void mon_clear(struct aproc *);
#endif /* !defined(APROC_H) */
diff --git a/usr.bin/aucat/aucat.1 b/usr.bin/aucat/aucat.1
index d069144947d..e03e10364cc 100644
--- a/usr.bin/aucat/aucat.1
+++ b/usr.bin/aucat/aucat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: aucat.1,v 1.63 2009/11/04 08:24:58 jmc Exp $
+.\" $OpenBSD: aucat.1,v 1.64 2010/04/03 17:40:33 ratchov Exp $
.\"
.\" Copyright (c) 2006 Alexandre Ratchov <alex@caoua.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: November 4 2009 $
+.Dd $Mdocdate: April 3 2010 $
.Dt AUCAT 1
.Os
.Sh NAME
@@ -33,6 +33,7 @@
.Op Fl i Ar file
.Op Fl m Ar mode
.Op Fl o Ar file
+.Op Fl q Ar device
.Op Fl r Ar rate
.Op Fl s Ar name
.Op Fl t Ar mode
@@ -57,7 +58,7 @@ which does not convert on the fly and supports playback of .au files.
The options are as follows:
.Bl -tag -width Ds
.It Fl b Ar nframes
-The buffer size in frames.
+The buffer size of the audio device in frames.
A frame consists of one sample for each channel in the stream.
This is the number of frames that will be buffered before being played
and thus controls the playback latency.
@@ -105,15 +106,21 @@ but other names can be used with the
.Fl s
option.
.It Fl m Ar mode
-Set the server mode.
+Set the stream mode.
Valid modes are
.Ar play ,
.Ar rec ,
and
-.Ar duplex ,
-for play-only, record-only, and full-duplex, respectively.
+.Ar mon ,
+corresponding to playback, recording and monitoring.
+A monitoring stream is a fake recording stream corresponding to
+the mix of all playback streams.
+Multiple modes can be specified, separated by commas,
+but the same stream cannot be used for both recording and monitoring.
The default is
-.Ar duplex .
+.\" no spaces allowed between modes
+.Ar play,rec
+(i.e., full-duplex).
.It Fl n
Loopback mode.
Instead of using an audio device, send input streams
@@ -125,6 +132,11 @@ Add this file to the list of files in which to store recorded samples.
If the option argument is
.Sq -
then standard output will be used.
+.It Fl q Ar device
+The
+.Xr sndio 7
+MIDI device to use for controlling stream volumes or
+to start multiple streams synchronously.
.It Fl r Ar rate
Sample rate in Hertz of the playback or record stream.
The default is 44100Hz.
@@ -475,6 +487,54 @@ behave normally, while streams connected to
wait for the MMC start signal and start synchronously.
Regardless of which device a stream is connected to,
its playback volume knob is exposed.
+.Pp
+If
+.Nm
+is used to play and record audio files, it offers
+similar MIDI control.
+.Nm
+can open a
+.Xr sndio 7
+MIDI device allowing MIDI hardware or software
+to control playback and recording in real time.
+.Pp
+A MIDI channel is assigned to each stream, and the volume
+is changed using the standard volume controller (number 7).
+Streams created with
+.Fl t Ar slave
+are controlled by the following MMC (MIDI Machine Control) messages:
+.Bl -tag -width relocateXXX -offset -indent
+.It start
+Start all streams synchronously.
+By default, streams are created in stopped state.
+.It stop
+Playback or recording is stopped, and
+the stream is rewinded back to the starting position.
+.It relocate
+Streams are relocated to the requested time postion
+relative to the beginning of the stream, at which playback
+and recording must start.
+If the requested position is beyond the end of file,
+the stream is temporarly disabled until a valid postion is requested.
+.El
+.Pp
+For instance, the following command will play a file on the
+.Va aucat:0.mmc
+audio device, and let full control to MIDI software or hardware
+connected to the
+.Va midithru:0
+MIDI device:
+.Bd -literal -offset indent
+$ aucat -f aucat:0.mmc -t slave -q midithru:0 -i file.wav
+.Ed
+.Pp
+At this stage,
+.Nm
+will start, stop and relocate automatically following all user
+actions in the MIDI sequencer.
+Note that the sequencer must use
+.Va aucat:0
+as MTC source, i.e., the audio server, not the audio player.
.Sh LEGACY MODE
If neither
.Fl i
diff --git a/usr.bin/aucat/aucat.c b/usr.bin/aucat/aucat.c
index f7a06997f4d..e2bebf47668 100644
--- a/usr.bin/aucat/aucat.c
+++ b/usr.bin/aucat/aucat.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: aucat.c,v 1.80 2010/01/14 17:43:55 ratchov Exp $ */
+/* $OpenBSD: aucat.c,v 1.81 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -43,9 +43,6 @@
#include "dbg.h"
#endif
-#define MODE_PLAY 1
-#define MODE_REC 2
-
#define PROG_AUCAT "aucat"
#define PROG_MIDICAT "midicat"
@@ -159,16 +156,33 @@ opt_xrun(void)
errx(1, "%s: bad underrun/overrun policy", optarg);
}
-int
+unsigned
opt_mode(void)
{
- if (strcmp("play", optarg) == 0)
- return MODE_PLAY;
- if (strcmp("rec", optarg) == 0)
- return MODE_REC;
- if (strcmp("duplex", optarg) == 0)
- return MODE_PLAY | MODE_REC;
- errx(1, "%s: bad mode", optarg);
+ unsigned mode = 0;
+ char *p = optarg;
+ size_t len;
+
+ for (p = optarg; *p != NULL; p++) {
+ len = strcspn(p, ",");
+ if (strncmp("play", p, len) == 0) {
+ mode |= MODE_PLAY;
+ } else if (strncmp("rec", p, len) == 0) {
+ mode |= MODE_REC;
+ } else if (strncmp("mon", p, len) == 0) {
+ mode |= MODE_MON;
+ } else if (strncmp("duplex", p, len) == 0) {
+ /* XXX: backward compat, remove this */
+ mode |= MODE_REC | MODE_PLAY;
+ } else
+ errx(1, "%s: bad mode", optarg);
+ p += len;
+ if (*p == '\0')
+ break;
+ }
+ if (mode == 0)
+ errx(1, "empty mode");
+ return mode;
}
/*
@@ -183,6 +197,7 @@ struct farg {
int hdr; /* header format */
int xrun; /* overrun/underrun policy */
int mmc; /* MMC mode */
+ unsigned mode;
};
SLIST_HEAD(farglist, farg);
@@ -194,7 +209,7 @@ SLIST_HEAD(farglist, farg);
void
farg_add(struct farglist *list,
struct aparams *ipar, struct aparams *opar, unsigned vol,
- int hdr, int xrun, int mmc, char *name)
+ int hdr, int xrun, int mmc, unsigned mode, char *name)
{
struct farg *fa;
size_t namelen;
@@ -212,12 +227,15 @@ farg_add(struct farglist *list,
}
} else
fa->hdr = hdr;
+ if (mmc && xrun == XRUN_IGNORE)
+ xrun = XRUN_SYNC;
fa->xrun = xrun;
fa->ipar = *ipar;
fa->opar = *opar;
fa->vol = vol;
fa->name = name;
fa->mmc = mmc;
+ fa->mode = mode;
SLIST_INSERT_HEAD(list, fa, entry);
}
@@ -287,28 +305,61 @@ getbasepath(char *base, size_t size)
}
void
+stopall(char *base)
+{
+ struct file *f;
+
+ restart:
+ LIST_FOREACH(f, &file_list, entry) {
+ /*
+ * skip connected streams (handled by dev_done())
+ */
+ if (APROC_OK(dev_mix) && f->rproc &&
+ aproc_depend(dev_mix, f->rproc))
+ continue;
+ if (APROC_OK(dev_sub) && f->wproc &&
+ aproc_depend(f->wproc, dev_sub))
+ continue;
+ if (APROC_OK(dev_midi)) {
+ if (f->rproc && aproc_depend(dev_midi, f->rproc))
+ continue;
+ if (f->wproc && aproc_depend(f->wproc, dev_midi))
+ continue;
+ }
+ /*
+ * kill anything else
+ */
+ file_close(f);
+ goto restart;
+ }
+}
+
+void
aucat_usage(void)
{
(void)fputs("usage: " PROG_AUCAT " [-dlnu] [-b nframes] "
- "[-C min:max] [-c min:max] [-e enc] [-f device]\n"
- "\t[-h fmt] [-i file] [-m mode] [-o file] [-r rate] [-s name]\n"
- "\t[-t mode] [-U unit] [-v volume] [-x policy] [-z nframes]\n",
+ "[-C min:max] [-c min:max] [-e enc]\n\t"
+ "[-f device] [-h fmt] [-i file] [-m mode]"
+ "[-o file] [-q device]\n\t"
+ "[-r rate] [-s name] [-t mode] [-U unit] "
+ "[-v volume] [-x policy]\n\t"
+ "[-z nframes]\n",
stderr);
}
int
aucat_main(int argc, char **argv)
{
- int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, suspend = 0, unit;
+ int c, u_flag, d_flag, l_flag, n_flag, hdr, xrun, unit;
struct farg *fa;
- struct farglist ifiles, ofiles, sfiles;
+ struct farglist ifiles, ofiles, sfiles, qfiles;
struct aparams ipar, opar, dipar, dopar;
char base[PATH_MAX], path[PATH_MAX], *file;
unsigned bufsz, round, mode;
char *devpath;
const char *str;
unsigned volctl;
- int mmc;
+ int mmc, autostart;
aparams_init(&ipar, 0, 1, 44100);
aparams_init(&opar, 0, 1, 44100);
@@ -322,14 +373,16 @@ aucat_main(int argc, char **argv)
SLIST_INIT(&ifiles);
SLIST_INIT(&ofiles);
SLIST_INIT(&sfiles);
+ SLIST_INIT(&qfiles);
hdr = HDR_AUTO;
xrun = XRUN_IGNORE;
volctl = MIDI_MAXCTL;
- mode = 0;
+ mode = MODE_PLAY | MODE_REC;
bufsz = 0;
round = 0;
+ autostart = 1;
- while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:lus:U:t:z:")) != -1) {
+ while ((c = getopt(argc, argv, "dnb:c:C:e:r:h:x:v:i:o:f:m:luq:s:U:t:z:")) != -1) {
switch (c) {
case 'd':
#ifdef DEBUG
@@ -352,6 +405,8 @@ aucat_main(int argc, char **argv)
break;
case 't':
mmc = opt_mmc();
+ if (mmc)
+ autostart = 0;
break;
case 'c':
opt_ch(&ipar);
@@ -379,18 +434,22 @@ aucat_main(int argc, char **argv)
if (strcmp(file, "-") == 0)
file = NULL;
farg_add(&ifiles, &ipar, &opar, volctl,
- hdr, xrun, 0, file);
+ hdr, xrun, mmc, mode & MODE_PLAY, file);
break;
case 'o':
file = optarg;
if (strcmp(file, "-") == 0)
file = NULL;
farg_add(&ofiles, &ipar, &opar, volctl,
- hdr, xrun, 0, file);
+ hdr, xrun, mmc, mode & MODE_RECMASK, file);
break;
case 's':
farg_add(&sfiles, &ipar, &opar, volctl,
- hdr, xrun, mmc, optarg);
+ hdr, xrun, mmc, mode, optarg);
+ break;
+ case 'q':
+ farg_add(&qfiles, &aparams_none, &aparams_none,
+ 0, HDR_RAW, 0, 0, 0, optarg);
break;
case 'f':
if (devpath)
@@ -401,6 +460,7 @@ aucat_main(int argc, char **argv)
break;
case 'l':
l_flag = 1;
+ autostart = 0;
break;
case 'u':
u_flag = 1;
@@ -451,22 +511,12 @@ aucat_main(int argc, char **argv)
if (!l_flag && (!SLIST_EMPTY(&sfiles) || unit >= 0))
errx(1, "can't use -s or -U without -l");
- if ((l_flag || mode != 0) &&
- (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
- errx(1, "can't use -l, -m and -s with -o or -i");
- if (!mode) {
- if (l_flag || !SLIST_EMPTY(&ifiles))
- mode |= MODE_PLAY;
- if (l_flag || !SLIST_EMPTY(&ofiles))
- mode |= MODE_REC;
- if (!mode) {
- aucat_usage();
- exit(1);
- }
- }
+ if (l_flag && (!SLIST_EMPTY(&ofiles) || !SLIST_EMPTY(&ifiles)))
+ errx(1, "can't use -l, and -s with -o or -i");
if (n_flag) {
- if (devpath != NULL || l_flag)
- errx(1, "can't use -n with -f or -l");
+ if (devpath != NULL || !SLIST_EMPTY(&qfiles) ||
+ l_flag || !autostart)
+ errx(1, "can't use -n with -f, -q, -t or -l");
if (SLIST_EMPTY(&ifiles) || SLIST_EMPTY(&ofiles))
errx(1, "both -i and -o are required with -n");
}
@@ -476,28 +526,43 @@ aucat_main(int argc, char **argv)
*/
if (l_flag && SLIST_EMPTY(&sfiles)) {
farg_add(&sfiles, &dopar, &dipar,
- volctl, HDR_RAW, XRUN_IGNORE, mmc, DEFAULT_OPT);
+ volctl, HDR_RAW, XRUN_IGNORE, mmc, mode, DEFAULT_OPT);
}
- if (!u_flag) {
- /*
- * Calculate "best" device parameters. Iterate over all
- * inputs and outputs and find the maximum sample rate
- * and channel number.
- */
- aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
- aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
- SLIST_FOREACH(fa, &ifiles, entry) {
+ /*
+ * Check modes and calculate "best" device parameters. Iterate over all
+ * inputs and outputs and find the maximum sample rate and channel
+ * number.
+ */
+ mode = 0;
+ aparams_init(&dipar, dipar.cmin, dipar.cmax, dipar.rate);
+ aparams_init(&dopar, dopar.cmin, dopar.cmax, dopar.rate);
+ SLIST_FOREACH(fa, &ifiles, entry) {
+ if (fa->mode == 0)
+ errx(1, "%s: not in play mode", fa->name);
+ mode |= fa->mode;
+ if (!u_flag)
aparams_grow(&dopar, &fa->ipar);
- }
- SLIST_FOREACH(fa, &ofiles, entry) {
+ }
+ SLIST_FOREACH(fa, &ofiles, entry) {
+ if (fa->mode == 0)
+ errx(1, "%s: not in rec/mon mode", fa->name);
+ if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON))
+ errx(1, "%s: can't record and monitor", fa->name);
+ mode |= fa->mode;
+ if (!u_flag)
aparams_grow(&dipar, &fa->opar);
- }
- SLIST_FOREACH(fa, &sfiles, entry) {
+ }
+ SLIST_FOREACH(fa, &sfiles, entry) {
+ if ((fa->mode & MODE_REC) && (fa->mode & MODE_MON))
+ errx(1, "%s: can't record and monitor", fa->name);
+ mode |= fa->mode;
+ if (!u_flag) {
aparams_grow(&dopar, &fa->ipar);
aparams_grow(&dipar, &fa->opar);
}
}
+
if (!round)
round = ((mode & MODE_REC) ? dipar.rate : dopar.rate) / 15;
if (!bufsz)
@@ -516,12 +581,13 @@ aucat_main(int argc, char **argv)
* the other half is for the socket/files.
*/
if (n_flag) {
+ if (mode & MODE_MON)
+ errx(1, "monitoring not allowed in loopback mode");
dev_loopinit(&dipar, &dopar, bufsz);
} else {
- if (!dev_init(devpath,
- (mode & MODE_REC) ? &dipar : NULL,
- (mode & MODE_PLAY) ? &dopar : NULL,
- bufsz, round)) {
+ if ((mode & MODE_MON) && !(mode & MODE_PLAY))
+ errx(1, "no playback stream to monitor");
+ if (!dev_init(devpath, mode, &dipar, &dopar, bufsz, round)) {
errx(1, "%s: can't open device",
devpath ? devpath : "<default>");
}
@@ -530,26 +596,33 @@ aucat_main(int argc, char **argv)
/*
* Create buffers for all input and output pipes.
*/
+ while (!SLIST_EMPTY(&qfiles)) {
+ fa = SLIST_FIRST(&qfiles);
+ SLIST_REMOVE_HEAD(&qfiles, entry);
+ if (!dev_thruadd(fa->name, 1, 1))
+ errx(1, "%s: can't open device", fa->name);
+ free(fa);
+ }
while (!SLIST_EMPTY(&ifiles)) {
fa = SLIST_FIRST(&ifiles);
SLIST_REMOVE_HEAD(&ifiles, entry);
- if (!wav_new_in(&wav_ops, fa->name,
- fa->hdr, &fa->ipar, fa->xrun, fa->vol))
+ if (!wav_new_in(&wav_ops, fa->mode, fa->name,
+ fa->hdr, &fa->ipar, fa->xrun, fa->vol, fa->mmc))
exit(1);
free(fa);
}
while (!SLIST_EMPTY(&ofiles)) {
fa = SLIST_FIRST(&ofiles);
SLIST_REMOVE_HEAD(&ofiles, entry);
- if (!wav_new_out(&wav_ops, fa->name,
- fa->hdr, &fa->opar, fa->xrun))
+ if (!wav_new_out(&wav_ops, fa->mode, fa->name,
+ fa->hdr, &fa->opar, fa->xrun, fa->mmc))
free(fa);
}
while (!SLIST_EMPTY(&sfiles)) {
fa = SLIST_FIRST(&sfiles);
SLIST_REMOVE_HEAD(&sfiles, entry);
opt_new(fa->name, &fa->opar, &fa->ipar,
- MIDI_TO_ADATA(fa->vol), fa->mmc);
+ MIDI_TO_ADATA(fa->vol), fa->mmc, fa->mode);
free(fa);
}
if (l_flag) {
@@ -559,6 +632,14 @@ aucat_main(int argc, char **argv)
if (!d_flag && daemon(0, 0) < 0)
err(1, "daemon");
}
+ if (autostart) {
+ /*
+ * inject artificial mmc start
+ */
+ ctl_start(dev_midi);
+ }
+ if (l_flag)
+ dev_prime();
/*
* Loop, start audio.
@@ -567,57 +648,48 @@ aucat_main(int argc, char **argv)
if (quit_flag) {
break;
}
- if ((dev_mix && LIST_EMPTY(&dev_mix->obuflist)) ||
- (dev_sub && LIST_EMPTY(&dev_sub->ibuflist))) {
+ if ((APROC_OK(dev_mix) && LIST_EMPTY(&dev_mix->obuflist)) ||
+ (APROC_OK(dev_sub) && LIST_EMPTY(&dev_sub->ibuflist))) {
fprintf(stderr, "device disappeared, terminating\n");
break;
}
+ if (!l_flag && ctl_idle(dev_midi))
+ break;
if (!file_poll())
break;
- if ((!dev_mix || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
- (!dev_sub || dev_sub->u.sub.idle > 2 * dev_bufsz) &&
- ((dev_mix || dev_sub) && dev_midi->u.ctl.tstate != CTL_RUN)) {
- if (!l_flag)
- break;
- if (!suspend) {
-#ifdef DEBUG
- if (debug_level >= 2)
- dbg_puts("suspending\n");
-#endif
- suspend = 1;
+ if ((!APROC_OK(dev_mix) || dev_mix->u.mix.idle > 2 * dev_bufsz) &&
+ (!APROC_OK(dev_sub) || dev_sub->u.sub.idle > 2 * dev_bufsz) &&
+ (!APROC_OK(dev_submon) || dev_submon->u.sub.idle > 2 * dev_bufsz) &&
+ (!APROC_OK(dev_midi) || dev_midi->u.ctl.tstate != CTL_RUN)) {
+ if (dev_pstate == DEV_RUN) {
+ dev_pstate = DEV_INIT;
dev_stop();
dev_clear();
- dev_prime();
+ /*
+ * priming buffer in non-server mode is not
+ * ok, because it will insert silence and
+ * break synchronization
+ */
+ if (l_flag)
+ dev_prime();
}
}
- if ((dev_mix && dev_mix->u.mix.idle == 0) ||
- (dev_sub && dev_sub->u.sub.idle == 0) ||
- ((dev_mix || dev_sub) && dev_midi->u.ctl.tstate == CTL_RUN)) {
- if (suspend) {
-#ifdef DEBUG
- if (debug_level >= 2)
- dbg_puts("resuming\n");
-#endif
- suspend = 0;
- dev_start();
- }
+ /*
+ * move device state machine
+ * XXX: move this to dev.c
+ */
+ if (dev_pstate == DEV_START) {
+ dev_pstate = DEV_RUN;
+ dev_start();
}
}
+ stopall(base);
+ dev_done();
+ filelist_done();
if (l_flag) {
- filelist_unlisten();
- if (rmdir(base) < 0)
+ if (rmdir(base) < 0 && errno != ENOTEMPTY)
warn("rmdir(\"%s\")", base);
}
- if (suspend) {
-#ifdef DEBUG
- if (debug_level >= 2)
- dbg_puts("resuming to drain\n");
-#endif
- suspend = 0;
- dev_start();
- }
- dev_done();
- filelist_done();
unsetsig();
return 0;
}
@@ -625,8 +697,8 @@ aucat_main(int argc, char **argv)
void
midicat_usage(void)
{
- (void)fputs("usage: " PROG_MIDICAT " [-dl] [-f device] "
- "[-i file] [-o file] [-U unit]\n",
+ (void)fputs("usage: " PROG_MIDICAT " [-dl] "
+ "[-i file] [-o file] [-q device] [-U unit]\n",
stderr);
}
int
@@ -648,7 +720,7 @@ midicat_main(int argc, char **argv)
SLIST_INIT(&ifiles);
SLIST_INIT(&ofiles);
- while ((c = getopt(argc, argv, "di:o:lf:U:")) != -1) {
+ while ((c = getopt(argc, argv, "di:o:lf:q:U:")) != -1) {
switch (c) {
case 'd':
#ifdef DEBUG
@@ -659,15 +731,17 @@ midicat_main(int argc, char **argv)
break;
case 'i':
farg_add(&ifiles, &aparams_none, &aparams_none,
- 0, HDR_RAW, 0, 0, optarg);
+ 0, HDR_RAW, 0, 0, 0, optarg);
break;
case 'o':
farg_add(&ofiles, &aparams_none, &aparams_none,
- 0, HDR_RAW, 0, 0, optarg);
+ 0, HDR_RAW, 0, 0, 0, optarg);
break;
- case 'f':
+ /* XXX: backward compat, remove this */
+ case 'f':
+ case 'q':
farg_add(&dfiles, &aparams_none, &aparams_none,
- 0, HDR_RAW, 0, 0, optarg);
+ 0, HDR_RAW, 0, 0, 0, optarg);
break;
case 'l':
l_flag = 1;
@@ -703,12 +777,12 @@ midicat_main(int argc, char **argv)
filelist_init();
dev_thruinit();
- if (!l_flag)
+ if (!l_flag && APROC_OK(dev_midi))
dev_midi->flags |= APROC_QUIT;
if ((!SLIST_EMPTY(&ifiles) || !SLIST_EMPTY(&ofiles)) &&
SLIST_EMPTY(&dfiles)) {
farg_add(&dfiles, &aparams_none, &aparams_none,
- 0, HDR_RAW, 0, 0, NULL);
+ 0, HDR_RAW, 0, 0, 0, NULL);
}
while (!SLIST_EMPTY(&dfiles)) {
fa = SLIST_FIRST(&dfiles);
@@ -767,7 +841,6 @@ midicat_main(int argc, char **argv)
dev_midiattach(NULL, buf);
free(fa);
}
-
/*
* loop, start processing
*/
@@ -778,13 +851,13 @@ midicat_main(int argc, char **argv)
if (!file_poll())
break;
}
+ stopall(base);
+ dev_done();
+ filelist_done();
if (l_flag) {
- filelist_unlisten();
- if (rmdir(base) < 0)
+ if (rmdir(base) < 0 && errno != ENOTEMPTY)
warn("rmdir(\"%s\")", base);
}
- dev_done();
- filelist_done();
unsetsig();
return 0;
}
diff --git a/usr.bin/aucat/conf.h b/usr.bin/aucat/conf.h
index 9f23921c760..66b7b9ee2b4 100644
--- a/usr.bin/aucat/conf.h
+++ b/usr.bin/aucat/conf.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: conf.h,v 1.12 2010/01/10 21:47:41 ratchov Exp $ */
+/* $OpenBSD: conf.h,v 1.13 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -31,19 +31,6 @@ extern int debug_level;
#endif
/*
- * Number of blocks in the device play/record buffers. Because Sun API
- * cannot notify apps of the current positions, we have to use all N
- * buffers devices blocks plus one extra block, to make write() block,
- * so that poll() can return the exact postition.
- */
-#define DEV_NBLK 2
-
-/*
- * Number of blocks in the wav-file i/o buffers.
- */
-#define WAV_NBLK 6
-
-/*
* socket and option names
*/
#define DEFAULT_MIDITHRU "midithru"
diff --git a/usr.bin/aucat/dev.c b/usr.bin/aucat/dev.c
index 8e3a2e4fe45..683ba1b6c5a 100644
--- a/usr.bin/aucat/dev.c
+++ b/usr.bin/aucat/dev.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: dev.c,v 1.43 2010/01/16 23:18:31 ratchov Exp $ */
+/* $OpenBSD: dev.c,v 1.44 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -27,13 +27,15 @@
#include "miofile.h"
#include "siofile.h"
#include "midi.h"
+#include "opt.h"
#ifdef DEBUG
#include "dbg.h"
#endif
+unsigned dev_pstate;
unsigned dev_bufsz, dev_round, dev_rate;
struct aparams dev_ipar, dev_opar;
-struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play;
+struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play, *dev_submon, *dev_mon;
struct aproc *dev_midi;
/*
@@ -101,6 +103,14 @@ dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
struct aparams par;
unsigned cmin, cmax, rate;
+ /*
+ * in principle we don't need control, but the start-stop mechanism
+ * depend on it and it's simpler to reuse this mechanism rather than
+ * dealing with lots of special cases
+ */
+ dev_midi = ctl_new("ctl");
+ dev_midi->refs++;
+
cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin;
cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax;
rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate;
@@ -112,11 +122,14 @@ dev_loopinit(struct aparams *dipar, struct aparams *dopar, unsigned bufsz)
dev_rate = rate;
dev_rec = NULL;
dev_play = NULL;
+ dev_mon = NULL;
+ dev_submon = NULL;
+ dev_pstate = DEV_INIT;
buf = abuf_new(dev_bufsz, &par);
- dev_mix = mix_new("mix", dev_bufsz, NULL);
+ dev_mix = mix_new("mix", dev_bufsz, 1, NULL);
dev_mix->refs++;
- dev_sub = sub_new("sub", dev_bufsz, NULL);
+ dev_sub = sub_new("sub", dev_bufsz, 1, NULL);
dev_sub->refs++;
aproc_setout(dev_mix, buf);
aproc_setin(dev_sub, buf);
@@ -140,14 +153,13 @@ dev_roundof(unsigned newrate)
* setup.
*/
int
-dev_init(char *devpath,
+dev_init(char *devpath, unsigned mode,
struct aparams *dipar, struct aparams *dopar, unsigned bufsz, unsigned round)
{
struct file *f;
struct aparams ipar, opar;
struct aproc *conv;
struct abuf *buf;
- unsigned nfr, ibufsz, obufsz;
dev_midi = ctl_new("ctl");
dev_midi->refs++;
@@ -157,13 +169,13 @@ dev_init(char *devpath,
* limit the block size to 1/4 of the requested buffer.
*/
dev_round = round;
- dev_bufsz = (bufsz + 3) / 4 + (dev_round - 1);
- dev_bufsz -= dev_bufsz % dev_round;
+ dev_bufsz = bufsz;
f = (struct file *)siofile_new(&siofile_ops, devpath,
- dipar, dopar, &dev_bufsz, &dev_round);
+ mode & (MODE_PLAY | MODE_REC), dipar, dopar,
+ &dev_bufsz, &dev_round);
if (f == NULL)
return 0;
- if (dipar) {
+ if (mode & MODE_REC) {
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts("hw recording ");
@@ -173,7 +185,7 @@ dev_init(char *devpath,
#endif
dev_rate = dipar->rate;
}
- if (dopar) {
+ if (mode & MODE_PLAY) {
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts("hw playing ");
@@ -183,33 +195,19 @@ dev_init(char *devpath,
#endif
dev_rate = dopar->rate;
}
- ibufsz = obufsz = dev_bufsz;
- bufsz = (bufsz > dev_bufsz) ? bufsz - dev_bufsz : 0;
-
- /*
- * Use 1/8 of the buffer for the mixer/converters. Since we
- * already consumed 1/4 for the device, bufsz represents the
- * remaining 3/4. So 1/8 is 1/6 of 3/4.
- */
- nfr = (bufsz + 5) / 6;
- nfr += dev_round - 1;
- nfr -= nfr % dev_round;
- if (nfr == 0)
- nfr = dev_round;
/*
* Create record chain.
*/
- if (dipar) {
+ if (mode & MODE_REC) {
aparams_init(&ipar, dipar->cmin, dipar->cmax, dipar->rate);
/*
* Create the read end.
*/
- dev_rec = rfile_new(f);
+ dev_rec = rsio_new(f);
dev_rec->refs++;
- buf = abuf_new(nfr, dipar);
+ buf = abuf_new(dev_bufsz, dipar);
aproc_setout(dev_rec, buf);
- ibufsz += nfr;
/*
* Append a converter, if needed.
@@ -217,9 +215,8 @@ dev_init(char *devpath,
if (!aparams_eqenc(dipar, &ipar)) {
conv = dec_new("rec", dipar);
aproc_setin(conv, buf);
- buf = abuf_new(nfr, &ipar);
+ buf = abuf_new(dev_round, &ipar);
aproc_setout(conv, buf);
- ibufsz += nfr;
}
dev_ipar = ipar;
@@ -227,7 +224,8 @@ dev_init(char *devpath,
* Append a "sub" to which clients will connect.
* Link it to the controller only in record-only mode
*/
- dev_sub = sub_new("rec", ibufsz, dopar ? NULL : dev_midi);
+ dev_sub = sub_new("rec", dev_bufsz, dev_round,
+ dopar ? NULL : dev_midi);
dev_sub->refs++;
aproc_setin(dev_sub, buf);
} else {
@@ -238,16 +236,15 @@ dev_init(char *devpath,
/*
* Create play chain.
*/
- if (dopar) {
+ if (mode & MODE_PLAY) {
aparams_init(&opar, dopar->cmin, dopar->cmax, dopar->rate);
/*
* Create the write end.
*/
- dev_play = wfile_new(f);
+ dev_play = wsio_new(f);
dev_play->refs++;
- buf = abuf_new(nfr, dopar);
+ buf = abuf_new(dev_bufsz, dopar);
aproc_setin(dev_play, buf);
- obufsz += nfr;
/*
* Append a converter, if needed.
@@ -255,23 +252,50 @@ dev_init(char *devpath,
if (!aparams_eqenc(&opar, dopar)) {
conv = enc_new("play", dopar);
aproc_setout(conv, buf);
- buf = abuf_new(nfr, &opar);
+ buf = abuf_new(dev_round, &opar);
aproc_setin(conv, buf);
- obufsz += nfr;
}
dev_opar = opar;
/*
* Append a "mix" to which clients will connect.
*/
- dev_mix = mix_new("play", obufsz, dev_midi);
+ dev_mix = mix_new("play", dev_bufsz, dev_round, dev_midi);
dev_mix->refs++;
aproc_setout(dev_mix, buf);
} else {
dev_play = NULL;
dev_mix = NULL;
}
- dev_bufsz = (dopar) ? obufsz : ibufsz;
+
+ /*
+ * Create monitoring chain
+ */
+ if (mode & MODE_MON) {
+ dev_mon = mon_new("mon", dev_bufsz);
+ dev_mon->refs++;
+ buf = abuf_new(dev_bufsz, &dev_opar);
+ aproc_setout(dev_mon, buf);
+
+ /*
+ * Append a "sub" to which clients will connect.
+ * Link it to the controller only in record-only mode
+ */
+ dev_submon = sub_new("mon", dev_bufsz, dev_round, NULL);
+ dev_submon->refs++;
+ aproc_setin(dev_submon, buf);
+
+ /*
+ * Attack to the mixer
+ */
+ dev_mix->u.mix.mon = dev_mon;
+ dev_mon->refs++;
+ } else {
+ dev_submon = NULL;
+ if (APROC_OK(dev_mix))
+ dev_mix->u.mix.mon = NULL;
+ }
+
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts("device block size is ");
@@ -281,7 +305,7 @@ dev_init(char *devpath,
dbg_puts(" blocks\n");
}
#endif
- dev_start();
+ dev_pstate = DEV_INIT;
return 1;
}
@@ -310,6 +334,11 @@ dev_done(void)
* after each call to file_eof().
*/
dev_mix->flags |= APROC_QUIT;
+ if (APROC_OK(dev_mix->u.mix.mon)) {
+ dev_mix->u.mix.mon->refs--;
+ aproc_del(dev_mix->u.mix.mon);
+ dev_mix->u.mix.mon = NULL;
+ }
restart_mix:
LIST_FOREACH(f, &file_list, entry) {
if (f->rproc != NULL &&
@@ -318,7 +347,7 @@ dev_done(void)
goto restart_mix;
}
}
- } else if (dev_sub) {
+ } else if (dev_sub || dev_submon) {
/*
* Same as above, but since there's no mixer,
* we generate EOF on the record-end of the
@@ -327,7 +356,8 @@ dev_done(void)
restart_sub:
LIST_FOREACH(f, &file_list, entry) {
if (f->rproc != NULL &&
- aproc_depend(dev_sub, f->rproc)) {
+ (aproc_depend(dev_sub, f->rproc) ||
+ aproc_depend(dev_submon, f->rproc))) {
file_eof(f);
goto restart_sub;
}
@@ -347,32 +377,37 @@ dev_done(void)
}
}
if (dev_mix) {
- dev_mix->refs--;
- if (dev_mix->flags & APROC_ZOMB)
+ if (--dev_mix->refs == 0 && (dev_mix->flags & APROC_ZOMB))
aproc_del(dev_mix);
dev_mix = NULL;
}
if (dev_play) {
- dev_play->refs--;
- if (dev_play->flags & APROC_ZOMB)
+ if (--dev_play->refs == 0 && (dev_play->flags & APROC_ZOMB))
aproc_del(dev_play);
dev_play = NULL;
}
if (dev_sub) {
- dev_sub->refs--;
- if (dev_sub->flags & APROC_ZOMB)
+ if (--dev_sub->refs == 0 && (dev_sub->flags & APROC_ZOMB))
aproc_del(dev_sub);
dev_sub = NULL;
}
if (dev_rec) {
- dev_rec->refs--;
- if (dev_rec->flags & APROC_ZOMB)
+ if (--dev_rec->refs == 0 && (dev_rec->flags & APROC_ZOMB))
aproc_del(dev_rec);
dev_rec = NULL;
}
+ if (dev_submon) {
+ if (--dev_submon->refs == 0 && (dev_submon->flags & APROC_ZOMB))
+ aproc_del(dev_submon);
+ dev_submon = NULL;
+ }
+ if (dev_mon) {
+ if (--dev_mon->refs == 0 && (dev_mon->flags & APROC_ZOMB))
+ aproc_del(dev_mon);
+ dev_mon = NULL;
+ }
if (dev_midi) {
- dev_midi->refs--;
- if (dev_midi->flags & APROC_ZOMB)
+ if (--dev_midi->refs == 0 && (dev_midi->flags & APROC_ZOMB))
aproc_del(dev_midi);
dev_midi = NULL;
}
@@ -390,49 +425,64 @@ dev_start(void)
{
struct file *f;
- if (dev_mix)
+#ifdef DEBUG
+ if (debug_level >= 2)
+ dbg_puts("starting audio device\n");
+#endif
+ if (APROC_OK(dev_mix))
dev_mix->flags |= APROC_DROP;
- if (dev_sub)
+ if (APROC_OK(dev_sub))
dev_sub->flags |= APROC_DROP;
- if (dev_play && dev_play->u.io.file) {
+ if (APROC_OK(dev_submon))
+ dev_submon->flags |= APROC_DROP;
+ if (APROC_OK(dev_play) && dev_play->u.io.file) {
f = dev_play->u.io.file;
f->ops->start(f);
- } else if (dev_rec && dev_rec->u.io.file) {
+ } else if (APROC_OK(dev_rec) && dev_rec->u.io.file) {
f = dev_rec->u.io.file;
f->ops->start(f);
}
}
/*
- * Pause the device.
+ * Pause the device. This may trigger context switches,
+ * so it shouldn't be called from aproc methods
*/
void
dev_stop(void)
{
struct file *f;
- if (dev_play && dev_play->u.io.file) {
+ if (APROC_OK(dev_play) && dev_play->u.io.file) {
f = dev_play->u.io.file;
f->ops->stop(f);
- } else if (dev_rec && dev_rec->u.io.file) {
+ } else if (APROC_OK(dev_rec) && dev_rec->u.io.file) {
f = dev_rec->u.io.file;
f->ops->stop(f);
}
- if (dev_mix)
+ if (APROC_OK(dev_mix))
dev_mix->flags &= ~APROC_DROP;
- if (dev_sub)
+ if (APROC_OK(dev_sub))
dev_sub->flags &= ~APROC_DROP;
+ if (APROC_OK(dev_submon))
+ dev_submon->flags &= ~APROC_DROP;
+#ifdef DEBUG
+ if (debug_level >= 2)
+ dbg_puts("audio device stopped\n");
+#endif
}
/*
* Find the end points connected to the mix/sub.
*/
int
-dev_getep(struct abuf **sibuf, struct abuf **sobuf)
+dev_getep(unsigned mode, struct abuf **sibuf, struct abuf **sobuf)
{
struct abuf *ibuf, *obuf;
- if (sibuf && *sibuf) {
+ if (mode & MODE_PLAY) {
+ if (!APROC_OK(dev_mix))
+ return 0;
ibuf = *sibuf;
for (;;) {
if (!ibuf || !ibuf->rproc) {
@@ -450,7 +500,9 @@ dev_getep(struct abuf **sibuf, struct abuf **sobuf)
}
*sibuf = ibuf;
}
- if (sobuf && *sobuf) {
+ if (mode & MODE_REC) {
+ if (!APROC_OK(dev_sub))
+ return 0;
obuf = *sobuf;
for (;;) {
if (!obuf || !obuf->wproc) {
@@ -468,6 +520,26 @@ dev_getep(struct abuf **sibuf, struct abuf **sobuf)
}
*sobuf = obuf;
}
+ if (mode & MODE_MON) {
+ if (!APROC_OK(dev_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 == dev_submon)
+ break;
+ obuf = LIST_FIRST(&obuf->wproc->ibuflist);
+ }
+ *sobuf = obuf;
+ }
return 1;
}
@@ -476,45 +548,38 @@ dev_getep(struct abuf **sibuf, struct abuf **sobuf)
* them underruns/overruns).
*/
void
-dev_sync(struct abuf *ibuf, struct abuf *obuf)
+dev_sync(unsigned mode, struct abuf *ibuf, struct abuf *obuf)
{
- struct abuf *pbuf, *rbuf;
int delta;
- if (!dev_mix || !dev_sub)
+ if (!dev_getep(mode, &ibuf, &obuf))
return;
- pbuf = LIST_FIRST(&dev_mix->obuflist);
- if (!pbuf)
- return;
- rbuf = LIST_FIRST(&dev_sub->ibuflist);
- if (!rbuf)
- return;
- if (!dev_getep(&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.
*/
- delta =
- rbuf->bpf * (pbuf->abspos + pbuf->used) -
- pbuf->bpf * rbuf->abspos;
- delta /= pbuf->bpf * rbuf->bpf;
+ if (APROC_OK(dev_mix) && APROC_OK(dev_sub)) {
+ delta = dev_mix->u.mix.abspos - dev_sub->u.sub.abspos;
+ } else if (APROC_OK(dev_mix)) {
+ delta = dev_mix->u.mix.lat;
+ } else
+ delta = 0;
#ifdef DEBUG
if (debug_level >= 3) {
dbg_puts("syncing device, delta = ");
dbg_putu(delta);
- dbg_puts(": ");
- abuf_dbg(pbuf);
- dbg_puts(" abspos = ");
- dbg_putu(pbuf->abspos);
- dbg_puts(" used = ");
- dbg_putu(pbuf->used);
- dbg_puts(" <---> ");
- abuf_dbg(rbuf);
- dbg_puts(" abspos = ");
- dbg_putu(rbuf->abspos);
+ dbg_puts(" ");
+ if (APROC_OK(dev_mix)) {
+ aproc_dbg(dev_mix);
+ dbg_puts(": abspos = ");
+ dbg_putu(dev_mix->u.mix.abspos);
+ }
+ if (APROC_OK(dev_sub)) {
+ aproc_dbg(dev_sub);
+ dbg_puts(": abspos = ");
+ dbg_putu(dev_sub->u.sub.abspos);
+ }
dbg_puts("\n");
}
#endif
@@ -523,19 +588,15 @@ dev_sync(struct abuf *ibuf, struct abuf *obuf)
* The play chain is ahead (most cases) drop some of
* the recorded input, to get both in sync.
*/
- if (obuf) {
- obuf->drop += delta * obuf->bpf;
- abuf_ipos(obuf, -delta);
- }
+ if (mode & MODE_RECMASK)
+ sub_silence(obuf, -delta);
} else if (delta < 0) {
/*
* The record chain is ahead (should never happen,
* right?) then insert silence to play.
*/
- if (ibuf) {
- ibuf->silence += -delta * ibuf->bpf;
- abuf_opos(ibuf, delta);
- }
+ if (mode & MODE_PLAY)
+ mix_drop(ibuf, delta);
}
}
@@ -550,23 +611,20 @@ dev_getpos(void)
int plat = 0, rlat = 0;
int delta;
- if (dev_mix) {
+ if (APROC_OK(dev_mix)) {
pbuf = LIST_FIRST(&dev_mix->obuflist);
if (!pbuf)
return 0;
plat = -dev_mix->u.mix.lat;
}
- if (dev_sub) {
+ if (APROC_OK(dev_sub)) {
rbuf = LIST_FIRST(&dev_sub->ibuflist);
if (!rbuf)
return 0;
rlat = -dev_sub->u.sub.lat;
}
- if (dev_mix && dev_sub) {
- delta =
- rbuf->bpf * (pbuf->abspos + pbuf->used) -
- pbuf->bpf * rbuf->abspos;
- delta /= pbuf->bpf * rbuf->bpf;
+ if (APROC_OK(dev_mix) && APROC_OK(dev_sub)) {
+ delta = dev_mix->u.mix.abspos - dev_sub->u.sub.abspos;
if (delta > 0)
rlat -= delta;
else if (delta < 0)
@@ -581,7 +639,7 @@ dev_getpos(void)
}
#endif
}
- return dev_mix ? plat : rlat;
+ return APROC_OK(dev_mix) ? plat : rlat;
}
/*
@@ -591,16 +649,25 @@ dev_getpos(void)
* and rec.
*/
void
-dev_attach(char *name,
- struct abuf *ibuf, struct aparams *sipar, unsigned underrun,
- struct abuf *obuf, struct aparams *sopar, unsigned overrun, int vol)
+dev_attach(char *name, unsigned mode,
+ struct abuf *ibuf, struct aparams *sipar,
+ struct abuf *obuf, struct aparams *sopar,
+ unsigned xrun, int vol)
{
struct abuf *pbuf = NULL, *rbuf = NULL;
struct aparams ipar, opar;
struct aproc *conv;
unsigned round, nblk;
- if (ibuf) {
+#ifdef DEBUG
+ if ((!APROC_OK(dev_mix) && (mode & MODE_PLAY)) ||
+ (!APROC_OK(dev_sub) && (mode & MODE_REC)) ||
+ (!APROC_OK(dev_submon) && (mode & MODE_MON))) {
+ dbg_puts("mode beyond device mode, not attaching\n");
+ return;
+ }
+#endif
+ if (mode & MODE_PLAY) {
ipar = *sipar;
pbuf = LIST_FIRST(&dev_mix->obuflist);
nblk = (dev_bufsz / dev_round + 3) / 4;
@@ -633,13 +700,11 @@ dev_attach(char *name,
aproc_setout(conv, ibuf);
}
aproc_setin(dev_mix, ibuf);
- if (dev_mix->u.mix.lat > 0)
- abuf_opos(ibuf, -dev_mix->u.mix.lat);
- ibuf->r.mix.xrun = underrun;
+ ibuf->r.mix.xrun = xrun;
ibuf->r.mix.maxweight = vol;
mix_setmaster(dev_mix);
}
- if (obuf) {
+ if (mode & MODE_REC) {
opar = *sopar;
rbuf = LIST_FIRST(&dev_sub->ibuflist);
round = dev_roundof(opar.rate);
@@ -672,19 +737,58 @@ dev_attach(char *name,
aproc_setin(conv, obuf);
}
aproc_setout(dev_sub, obuf);
- if (dev_sub->u.sub.lat > 0)
- abuf_ipos(obuf, -dev_sub->u.sub.lat);
- obuf->w.sub.xrun = overrun;
+ obuf->w.sub.xrun = xrun;
+ }
+ if (mode & MODE_MON) {
+ opar = *sopar;
+ rbuf = LIST_FIRST(&dev_submon->ibuflist);
+ round = dev_roundof(opar.rate);
+ nblk = (dev_bufsz / dev_round + 3) / 4;
+ if (!aparams_eqenc(&opar, &dev_opar)) {
+ conv = enc_new(name, &opar);
+ opar.bps = dev_opar.bps;
+ opar.bits = dev_opar.bits;
+ opar.sig = dev_opar.sig;
+ opar.le = dev_opar.le;
+ opar.msb = dev_opar.msb;
+ aproc_setout(conv, obuf);
+ obuf = abuf_new(nblk * round, &opar);
+ aproc_setin(conv, obuf);
+ }
+ if (!aparams_subset(&opar, &dev_opar)) {
+ conv = cmap_new(name, &dev_opar, &opar);
+ opar.cmin = dev_opar.cmin;
+ opar.cmax = dev_opar.cmax;
+ aproc_setout(conv, obuf);
+ obuf = abuf_new(nblk * round, &opar);
+ aproc_setin(conv, obuf);
+ }
+ if (!aparams_eqrate(&opar, &dev_opar)) {
+ conv = resamp_new(name, dev_round, round);
+ opar.rate = dev_opar.rate;
+ round = dev_round;
+ aproc_setout(conv, obuf);
+ obuf = abuf_new(nblk * round, &opar);
+ aproc_setin(conv, obuf);
+ }
+ aproc_setout(dev_submon, obuf);
+ obuf->w.sub.xrun = xrun;
}
/*
* Sync play to record.
*/
- if (ibuf && obuf) {
+ if ((mode & MODE_PLAY) && (mode & MODE_RECMASK)) {
ibuf->duplex = obuf;
obuf->duplex = ibuf;
}
- dev_sync(ibuf, obuf);
+ dev_sync(mode, ibuf, obuf);
+
+ /*
+ * Start device if not already started
+ */
+ if (dev_pstate == DEV_INIT)
+ dev_pstate = DEV_START;
}
/*
@@ -701,7 +805,7 @@ dev_setvol(struct abuf *ibuf, int vol)
dbg_puts("\n");
}
#endif
- if (!dev_getep(&ibuf, NULL)) {
+ if (!dev_getep(MODE_PLAY, &ibuf, NULL)) {
return;
}
ibuf->r.mix.vol = vol;
@@ -716,7 +820,7 @@ dev_clear(void)
{
struct abuf *buf;
- if (dev_mix) {
+ if (APROC_OK(dev_mix)) {
#ifdef DEBUG
if (!LIST_EMPTY(&dev_mix->ibuflist)) {
dbg_puts("play end not idle, can't clear device\n");
@@ -730,7 +834,7 @@ dev_clear(void)
}
mix_clear(dev_mix);
}
- if (dev_sub) {
+ if (APROC_OK(dev_sub)) {
#ifdef DEBUG
if (!LIST_EMPTY(&dev_sub->obuflist)) {
dbg_puts("record end not idle, can't clear device\n");
@@ -744,6 +848,22 @@ dev_clear(void)
}
sub_clear(dev_sub);
}
+ if (APROC_OK(dev_submon)) {
+#ifdef DEBUG
+ dbg_puts("clearing monitor\n");
+ if (!LIST_EMPTY(&dev_submon->obuflist)) {
+ dbg_puts("monitoring end not idle, can't clear device\n");
+ dbg_panic();
+ }
+#endif
+ buf = LIST_FIRST(&dev_submon->ibuflist);
+ while (buf) {
+ abuf_clear(buf);
+ buf = LIST_FIRST(&buf->wproc->ibuflist);
+ }
+ sub_clear(dev_submon);
+ mon_clear(dev_mon);
+ }
}
/*
@@ -753,7 +873,7 @@ dev_clear(void)
void
dev_prime(void)
{
- if (dev_mix) {
+ if (APROC_OK(dev_mix)) {
#ifdef DEBUG
if (!LIST_EMPTY(&dev_mix->ibuflist)) {
dbg_puts("play end not idle, can't prime device\n");
diff --git a/usr.bin/aucat/dev.h b/usr.bin/aucat/dev.h
index c346bb26719..f9a97d31921 100644
--- a/usr.bin/aucat/dev.h
+++ b/usr.bin/aucat/dev.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: dev.h,v 1.17 2010/01/11 13:06:32 ratchov Exp $ */
+/* $OpenBSD: dev.h,v 1.18 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -21,25 +21,33 @@ struct aproc;
struct aparams;
struct abuf;
+#define DEV_INIT 0
+#define DEV_START 1
+#define DEV_RUN 2
+#define DEV_STOP 3
+
+extern unsigned dev_pstate;
extern unsigned dev_bufsz, dev_round, dev_rate;
extern struct aparams dev_ipar, dev_opar;
-extern struct aproc *dev_mix, *dev_sub, *dev_midi;
+extern struct aproc *dev_mix, *dev_sub, *dev_midi, *dev_submon, *dev_mon;
void dev_thruinit(void);
int dev_thruadd(char *, int, int);
void dev_midiattach(struct abuf *, struct abuf *);
unsigned dev_roundof(unsigned);
void dev_loopinit(struct aparams *, struct aparams *, unsigned);
-int dev_init(char *, struct aparams *, struct aparams *, unsigned, unsigned);
+int dev_init(char *, unsigned,
+ struct aparams *, struct aparams *, unsigned, unsigned);
void dev_start(void);
void dev_stop(void);
void dev_run(int);
void dev_done(void);
-int dev_getep(struct abuf **, struct abuf **);
-void dev_sync(struct abuf *, struct abuf *);
+int dev_getep(unsigned, struct abuf **, struct abuf **);
+void dev_sync(unsigned, struct abuf *, struct abuf *);
+unsigned dev_getmode(void);
int dev_getpos(void);
-void dev_attach(char *,
- struct abuf *, struct aparams *, unsigned,
+void dev_attach(char *, unsigned,
+ struct abuf *, struct aparams *,
struct abuf *, struct aparams *, unsigned, int);
void dev_setvol(struct abuf *, int);
void dev_clear(void);
diff --git a/usr.bin/aucat/file.c b/usr.bin/aucat/file.c
index e60f1154e15..af37e199fa0 100644
--- a/usr.bin/aucat/file.c
+++ b/usr.bin/aucat/file.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: file.c,v 1.15 2010/01/10 21:47:41 ratchov Exp $ */
+/* $OpenBSD: file.c,v 1.16 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -63,8 +63,6 @@
#define MAXFDS 100
-extern struct fileops listen_ops, pipe_ops;
-
struct timeval file_tv;
struct filelist file_list;
struct timo *timo_queue;
@@ -520,23 +518,6 @@ filelist_done(void)
timo_done();
}
-/*
- * Close all listening sockets.
- *
- * XXX: remove this
- */
-void
-filelist_unlisten(void)
-{
- struct file *f, *fnext;
-
- for (f = LIST_FIRST(&file_list); f != NULL; f = fnext) {
- fnext = LIST_NEXT(f, entry);
- if (f->ops == &listen_ops)
- file_del(f);
- }
-}
-
unsigned
file_read(struct file *f, unsigned char *data, unsigned count)
{
@@ -676,6 +657,8 @@ file_close(struct file *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) {
diff --git a/usr.bin/aucat/headers.c b/usr.bin/aucat/headers.c
index e9a8ed256dc..7859e29a436 100644
--- a/usr.bin/aucat/headers.c
+++ b/usr.bin/aucat/headers.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: headers.c,v 1.10 2010/01/10 21:47:41 ratchov Exp $ */
+/* $OpenBSD: headers.c,v 1.11 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -129,7 +129,7 @@ wav_readfmt(int fd, unsigned csize, struct aparams *par, short **map)
}
int
-wav_readhdr(int fd, struct aparams *par, off_t *datasz, short **map)
+wav_readhdr(int fd, struct aparams *par, off_t *startpos, off_t *datasz, short **map)
{
struct wavriff riff;
struct wavchunk chunk;
@@ -161,6 +161,7 @@ wav_readhdr(int fd, struct aparams *par, off_t *datasz, short **map)
return 0;
fmt_done = 1;
} else if (memcmp(chunk.id, wav_id_data, 4) == 0) {
+ *startpos = pos;
*datasz = csize;
break;
} else {
@@ -186,10 +187,12 @@ wav_readhdr(int fd, struct aparams *par, off_t *datasz, short **map)
return 1;
}
+/*
+ * Write header and seek to start position
+ */
int
-wav_writehdr(int fd, struct aparams *par)
+wav_writehdr(int fd, struct aparams *par, off_t *startpos, off_t datasz)
{
- off_t datasz;
unsigned nch = par->cmax - par->cmin + 1;
struct {
struct wavriff riff;
@@ -198,16 +201,6 @@ wav_writehdr(int fd, struct aparams *par)
struct wavchunk data_hdr;
} hdr;
- datasz = lseek(fd, 0, SEEK_CUR);
- if (datasz < 0) {
- warn("wav_writehdr: lseek(end)");
- return 0;
- }
- if (datasz >= sizeof(hdr))
- datasz -= sizeof(hdr);
- else
- datasz = 0;
-
/*
* Check that encoding is supported by .wav file format.
*/
@@ -253,5 +246,6 @@ wav_writehdr(int fd, struct aparams *par)
warn("wav_writehdr: write");
return 0;
}
+ *startpos = sizeof(hdr);
return 1;
}
diff --git a/usr.bin/aucat/legacy.c b/usr.bin/aucat/legacy.c
index 23977b7f35e..5f7a3655137 100644
--- a/usr.bin/aucat/legacy.c
+++ b/usr.bin/aucat/legacy.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: legacy.c,v 1.8 2009/07/25 10:54:29 ratchov Exp $ */
+/* $OpenBSD: legacy.c,v 1.9 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 1997 Kenneth Stailey. All rights reserved.
*
@@ -64,7 +64,7 @@ legacy_play(char *dev, char *aufile)
struct sio_par spar, par;
struct aparams apar;
ssize_t rd;
- off_t datasz;
+ off_t datasz, dummy;
char buf[5120];
size_t readsz;
int fd, fmt = FMT_RAW;
@@ -96,7 +96,7 @@ legacy_play(char *dev, char *aufile)
if (read(fd, &chan, sizeof(chan)) == sizeof(chan))
chan = ntohl(chan);
} else if (!strncmp(magic, "RIFF", 4) &&
- wav_readhdr(fd, &apar, &datasz, &map)) {
+ wav_readhdr(fd, &apar, &dummy, &datasz, &map)) {
fmt = FMT_WAV;
}
diff --git a/usr.bin/aucat/midi.c b/usr.bin/aucat/midi.c
index d0403a38728..8244a4cba3f 100644
--- a/usr.bin/aucat/midi.c
+++ b/usr.bin/aucat/midi.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: midi.c,v 1.16 2010/01/16 23:21:56 ratchov Exp $ */
+/* $OpenBSD: midi.c,v 1.17 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -132,7 +132,7 @@ thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c)
if (debug_level >= 4) {
aproc_dbg(p);
dbg_puts(": ");
- dbg_putu(c);
+ dbg_putx(c);
dbg_puts(": flushing realtime message\n");
}
#endif
@@ -350,16 +350,15 @@ ctl_slotdbg(struct aproc *p, int slot)
{
struct ctl_slot *s;
- aproc_dbg(p);
if (slot < 0) {
- dbg_puts("/none");
+ dbg_puts("none");
} else {
s = p->u.ctl.slot + slot;
dbg_puts(s->name);
dbg_putu(s->unit);
- dbg_puts("=");
+ dbg_puts("(");
dbg_putu(s->vol);
- dbg_puts("/");
+ dbg_puts(")/");
switch (s->tstate) {
case CTL_OFF:
dbg_puts("off");
@@ -394,7 +393,7 @@ ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len
for (i = LIST_FIRST(&p->obuflist); i != NULL; i = inext) {
inext = LIST_NEXT(i, oent);
- if (i->duplex == ibuf)
+ if (i->duplex && i->duplex == ibuf)
continue;
itodo = len;
idata = msg;
@@ -639,8 +638,10 @@ ctl_trystart(struct aproc *p, int caller)
if (p->u.ctl.tstate != CTL_START) {
#ifdef DEBUG
- aproc_dbg(p);
- dbg_puts(": not in starting state\n");
+ if (debug_level >= 3) {
+ ctl_slotdbg(p, caller);
+ dbg_puts(": server not started, delayd\n");
+ }
#endif
return 0;
}
@@ -649,8 +650,10 @@ ctl_trystart(struct aproc *p, int caller)
continue;
if (s->tstate != CTL_OFF && s->tstate != CTL_START) {
#ifdef DEBUG
- ctl_slotdbg(p, i);
- dbg_puts(": not ready to start, start delayed\n");
+ if (debug_level >= 3) {
+ ctl_slotdbg(p, i);
+ dbg_puts(": not ready, server delayed\n");
+ }
#endif
return 0;
}
@@ -660,8 +663,10 @@ ctl_trystart(struct aproc *p, int caller)
continue;
if (s->tstate == CTL_START) {
#ifdef DEBUG
- ctl_slotdbg(p, i);
- dbg_puts(": started\n");
+ if (debug_level >= 3) {
+ ctl_slotdbg(p, i);
+ dbg_puts(": started\n");
+ }
#endif
s->tstate = CTL_RUN;
s->ops->start(s->arg);
@@ -671,10 +676,10 @@ ctl_trystart(struct aproc *p, int caller)
p->u.ctl.slot[caller].tstate = CTL_RUN;
p->u.ctl.tstate = CTL_RUN;
p->u.ctl.delta = MTC_SEC * dev_getpos();
- if (dev_rate % (30 * 4 * dev_round)) {
+ if (dev_rate % (30 * 4 * dev_round) == 0) {
p->u.ctl.fps_id = MTC_FPS_30;
p->u.ctl.fps = 30;
- } else if (dev_rate % (25 * 4 * dev_round)) {
+ } else if (dev_rate % (25 * 4 * dev_round) == 0) {
p->u.ctl.fps_id = MTC_FPS_25;
p->u.ctl.fps = 25;
} else {
@@ -682,13 +687,17 @@ ctl_trystart(struct aproc *p, int caller)
p->u.ctl.fps = 24;
}
#ifdef DEBUG
- ctl_slotdbg(p, caller);
- dbg_puts(": started server at ");
- dbg_puti(p->u.ctl.delta);
- dbg_puts(", ");
- dbg_puti(p->u.ctl.fps);
- dbg_puts(" mtc fps\n");
+ if (debug_level >= 3) {
+ ctl_slotdbg(p, caller);
+ dbg_puts(": started server at ");
+ dbg_puti(p->u.ctl.delta);
+ dbg_puts(", ");
+ dbg_puti(p->u.ctl.fps);
+ dbg_puts(" mtc fps\n");
+ }
#endif
+ if (dev_pstate == DEV_INIT)
+ dev_pstate = DEV_START;
ctl_full(p);
return 1;
}
@@ -702,8 +711,15 @@ ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr)
int idx;
struct ctl_slot *s;
- if (p == NULL)
+ if (!APROC_OK(p)) {
+#ifdef DEBUG
+ if (debug_level >= 1) {
+ dbg_puts(who);
+ dbg_puts(": MIDI control not available\n");
+ }
+#endif
return -1;
+ }
idx = ctl_getidx(p, who);
if (idx < 0)
return -1;
@@ -726,7 +742,7 @@ ctl_slotdel(struct aproc *p, int index)
unsigned i;
struct ctl_slot *s;
- if (p == NULL)
+ if (!APROC_OK(p))
return;
p->u.ctl.slot[index].ops = NULL;
if (!(p->flags & APROC_QUIT))
@@ -779,7 +795,7 @@ ctl_slotvol(struct aproc *p, int slot, unsigned vol)
{
unsigned char msg[3];
- if (p == NULL)
+ if (!APROC_OK(p))
return;
#ifdef DEBUG
if (debug_level >= 3) {
@@ -807,7 +823,7 @@ ctl_slotstart(struct aproc *p, int slot)
{
struct ctl_slot *s = p->u.ctl.slot + slot;
- if (p == NULL)
+ if (!APROC_OK(p))
return 1;
if (s->tstate == CTL_OFF || p->u.ctl.tstate == CTL_OFF)
return 1;
@@ -831,7 +847,7 @@ ctl_slotstop(struct aproc *p, int slot)
{
struct ctl_slot *s = p->u.ctl.slot + slot;
- if (p == NULL)
+ if (!APROC_OK(p))
return;
/*
* tag the stream as not trying to start,
@@ -842,6 +858,118 @@ ctl_slotstop(struct aproc *p, int slot)
}
/*
+ * start all slots simultaneously
+ */
+void
+ctl_start(struct aproc *p)
+{
+ if (!APROC_OK(p))
+ return;
+ if (p->u.ctl.tstate == CTL_STOP) {
+ p->u.ctl.tstate = CTL_START;
+ (void)ctl_trystart(p, -1);
+#ifdef DEBUG
+ } else {
+ if (debug_level >= 3) {
+ aproc_dbg(p);
+ dbg_puts(": ignoring mmc start\n");
+ }
+#endif
+ }
+}
+
+/*
+ * stop all slots simultaneously
+ */
+void
+ctl_stop(struct aproc *p)
+{
+ unsigned i;
+ struct ctl_slot *s;
+
+ if (!APROC_OK(p))
+ return;
+ switch (p->u.ctl.tstate) {
+ case CTL_START:
+ p->u.ctl.tstate = CTL_STOP;
+ return;
+ case CTL_RUN:
+ p->u.ctl.tstate = CTL_STOP;
+ break;
+ default:
+#ifdef DEBUG
+ if (debug_level >= 3) {
+ aproc_dbg(p);
+ dbg_puts(": ignored mmc stop\n");
+ }
+#endif
+ return;
+ }
+ for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
+ if (!s->ops)
+ continue;
+ if (s->tstate == CTL_RUN) {
+#ifdef DEBUG
+ if (debug_level >= 3) {
+ ctl_slotdbg(p, i);
+ dbg_puts(": requested to stop\n");
+ }
+#endif
+ s->ops->stop(s->arg);
+ }
+ }
+}
+
+/*
+ * relocate all slots simultaneously
+ */
+void
+ctl_loc(struct aproc *p, unsigned origin)
+{
+ unsigned i, tstate;
+ struct ctl_slot *s;
+
+ if (!APROC_OK(p))
+ return;
+#ifdef DEBUG
+ if (debug_level >= 2) {
+ dbg_puts("server relocated to ");
+ dbg_putu(origin);
+ dbg_puts("\n");
+ }
+#endif
+ tstate = p->u.ctl.tstate;
+ if (tstate == CTL_RUN)
+ ctl_stop(p);
+ p->u.ctl.origin = origin;
+ for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
+ if (!s->ops)
+ continue;
+ s->ops->loc(s->arg, p->u.ctl.origin);
+ }
+ if (tstate == CTL_RUN)
+ ctl_start(p);
+}
+
+/*
+ * check if there are controlled streams
+ */
+int
+ctl_idle(struct aproc *p)
+{
+ unsigned i;
+ struct ctl_slot *s;
+
+ if (!APROC_OK(p))
+ return 1;
+ for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
+ if (s->ops)
+ return 0;
+ }
+ return 1;
+}
+
+/*
* handle a MIDI event received from ibuf
*/
void
@@ -883,41 +1011,21 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
switch (ibuf->r.midi.msg[4]) {
case 0x01: /* mmc stop */
#ifdef DEBUG
- if (debug_level >= 1) {
+ if (debug_level >= 3) {
abuf_dbg(ibuf);
dbg_puts(": mmc stop\n");
}
#endif
- if (p->u.ctl.tstate == CTL_RUN ||
- p->u.ctl.tstate == CTL_START)
- p->u.ctl.tstate = CTL_STOP;
-#ifdef DEBUG
- else {
- if (debug_level >= 1) {
- aproc_dbg(p);
- dbg_puts(": ignored mmc stop\n");
- }
- }
-#endif
+ ctl_stop(p);
break;
case 0x02: /* mmc start */
#ifdef DEBUG
- if (debug_level >= 1) {
+ if (debug_level >= 3) {
abuf_dbg(ibuf);
dbg_puts(": mmc start\n");
}
#endif
- if (p->u.ctl.tstate == CTL_STOP) {
- p->u.ctl.tstate = CTL_START;
- (void)ctl_trystart(p, -1);
-#ifdef DEBUG
- } else {
- if (debug_level >= 1) {
- abuf_dbg(ibuf);
- dbg_puts(": ignoring mmc start\n");
- }
-#endif
- }
+ ctl_start(p);
break;
}
}
@@ -943,20 +1051,12 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
p->u.ctl.origin = 0;
return;
}
- p->u.ctl.origin =
+ ctl_loc(p,
(ibuf->r.midi.msg[7] & 0x1f) * 3600 * MTC_SEC +
ibuf->r.midi.msg[8] * 60 * MTC_SEC +
ibuf->r.midi.msg[9] * MTC_SEC +
ibuf->r.midi.msg[10] * (MTC_SEC / fps) +
- ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps);
-#ifdef DEBUG
- if (debug_level >= 1) {
- aproc_dbg(p);
- dbg_puts(": relocated to ");
- dbg_putu(p->u.ctl.origin);
- dbg_puts("\n");
- }
-#endif
+ ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps));
}
}
diff --git a/usr.bin/aucat/midi.h b/usr.bin/aucat/midi.h
index 54f73d4ae0b..4b5cdf183df 100644
--- a/usr.bin/aucat/midi.h
+++ b/usr.bin/aucat/midi.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: midi.h,v 1.5 2009/11/03 21:31:37 ratchov Exp $ */
+/* $OpenBSD: midi.h,v 1.6 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -27,4 +27,8 @@ int ctl_slotstart(struct aproc *, int);
void ctl_slotstop(struct aproc *, int);
void ctl_ontick(struct aproc *, int);
+void ctl_stop(struct aproc *);
+void ctl_start(struct aproc *);
+int ctl_idle(struct aproc *);
+
#endif /* !defined(MIDI_H) */
diff --git a/usr.bin/aucat/midicat.1 b/usr.bin/aucat/midicat.1
index 0f20eb0df28..3befc6a3bbf 100644
--- a/usr.bin/aucat/midicat.1
+++ b/usr.bin/aucat/midicat.1
@@ -1,4 +1,4 @@
-.\" $OpenBSD: midicat.1,v 1.6 2009/10/22 21:14:10 ratchov Exp $
+.\" $OpenBSD: midicat.1,v 1.7 2010/04/03 17:40:33 ratchov Exp $
.\"
.\" Copyright (c) 2006 Alexandre Ratchov <alex@caoua.org>
.\"
@@ -14,7 +14,7 @@
.\" ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
.\" OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
.\"
-.Dd $Mdocdate: October 22 2009 $
+.Dd $Mdocdate: April 3 2010 $
.Dt MIDICAT 1
.Os
.Sh NAME
@@ -23,9 +23,9 @@
.Sh SYNOPSIS
.Nm midicat
.Op Fl dl
-.Op Fl f Ar device
.Op Fl i Ar file
.Op Fl o Ar file
+.Op Fl q Ar device
.Op Fl U Ar unit
.Sh DESCRIPTION
The
@@ -45,13 +45,6 @@ If this option is specified,
.Nm
will run in the foreground and log to
.Em stderr .
-.It Fl f Ar device
-The
-.Xr midi 4
-device or
-.Nm
-socket to use for MIDI input/output.
-In server mode, devices are subscribed to the MIDI thru box.
.It Fl i Ar file
Send contents of this file to the device.
If the option argument is
@@ -71,6 +64,11 @@ Store received data from the device into this file.
If the option argument is
.Sq -
then standard output will be used.
+.It Fl q Ar device
+The
+.Xr sndio 7
+MIDI device to use for MIDI input/output.
+In server mode, devices are subscribed to the MIDI thru box.
.It Fl U Ar unit
Use the given unit number when creating a software MIDI thru box.
Only one
diff --git a/usr.bin/aucat/opt.c b/usr.bin/aucat/opt.c
index 3c7e8959765..c4fd6e6c3c1 100644
--- a/usr.bin/aucat/opt.c
+++ b/usr.bin/aucat/opt.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: opt.c,v 1.4 2010/01/10 21:47:41 ratchov Exp $ */
+/* $OpenBSD: opt.c,v 1.5 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -27,8 +27,8 @@
struct optlist opt_list = SLIST_HEAD_INITIALIZER(&opt_list);
void
-opt_new(char *name,
- struct aparams *wpar, struct aparams *rpar, int maxweight, int mmc)
+opt_new(char *name, struct aparams *wpar, struct aparams *rpar,
+ int maxweight, int mmc, unsigned mode)
{
struct opt *o;
unsigned len;
@@ -54,21 +54,39 @@ opt_new(char *name,
exit(1);
}
memcpy(o->name, name, len + 1);
- o->wpar = *wpar;
- o->rpar = *rpar;
+ if (mode & MODE_RECMASK)
+ o->wpar = (mode & MODE_MON) ? *rpar : *wpar;
+ if (mode & MODE_PLAY)
+ o->rpar = *rpar;
o->maxweight = maxweight;
o->mmc = mmc;
+ o->mode = mode;
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts(o->name);
- dbg_puts(": rec ");
- aparams_dbg(&o->wpar);
- dbg_puts(", play ");
- aparams_dbg(&o->rpar);
- dbg_puts(", vol ");
- dbg_putu(o->maxweight);
+ dbg_puts(":");
+ if (mode & MODE_REC) {
+ dbg_puts(" rec=");
+ dbg_putu(o->wpar.cmin);
+ dbg_puts(":");
+ dbg_putu(o->wpar.cmax);
+ }
+ if (mode & MODE_PLAY) {
+ dbg_puts(" play=");
+ dbg_putu(o->rpar.cmin);
+ dbg_puts(":");
+ dbg_putu(o->rpar.cmax);
+ dbg_puts(" vol=");
+ dbg_putu(o->maxweight);
+ }
+ if (mode & MODE_MON) {
+ dbg_puts(" mon=");
+ dbg_putu(o->wpar.cmin);
+ dbg_puts(":");
+ dbg_putu(o->wpar.cmax);
+ }
if (o->mmc)
- dbg_puts(", mmc");
+ dbg_puts(" mmc");
dbg_puts("\n");
}
#endif
diff --git a/usr.bin/aucat/opt.h b/usr.bin/aucat/opt.h
index 081f1763680..3572d560397 100644
--- a/usr.bin/aucat/opt.h
+++ b/usr.bin/aucat/opt.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: opt.h,v 1.2 2009/11/03 21:31:37 ratchov Exp $ */
+/* $OpenBSD: opt.h,v 1.3 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -28,11 +28,18 @@ struct opt {
struct aparams wpar; /* template for clients write params */
struct aparams rpar; /* template for clients read params */
int mmc; /* true if MMC control enabled */
+#define MODE_PLAY 0x1 /* allowed to play */
+#define MODE_REC 0x2 /* allowed to rec */
+#define MODE_MIDIIN 0x4 /* allowed to read midi */
+#define MODE_MIDIOUT 0x8 /* allowed to write midi */
+#define MODE_MON 0x10 /* allowed to monitor */
+#define MODE_RECMASK (MODE_REC | MODE_MON)
+ unsigned mode; /* bitmap of above */
};
SLIST_HEAD(optlist,opt);
-void opt_new(char *, struct aparams *, struct aparams *, int, int);
+void opt_new(char *, struct aparams *, struct aparams *, int, int, unsigned);
struct opt *opt_byname(char *);
#endif /* !defined(OPT_H) */
diff --git a/usr.bin/aucat/pipe.c b/usr.bin/aucat/pipe.c
index 76f98baa832..065f6f0ad7a 100644
--- a/usr.bin/aucat/pipe.c
+++ b/usr.bin/aucat/pipe.c
@@ -139,3 +139,54 @@ pipe_close(struct file *file)
close(f->fd);
}
+
+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
index b648cdfe963..b2f986f92bd 100644
--- a/usr.bin/aucat/pipe.h
+++ b/usr.bin/aucat/pipe.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: pipe.h,v 1.2 2009/07/25 10:52:19 ratchov Exp $ */
+/* $OpenBSD: pipe.h,v 1.3 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -33,5 +33,8 @@ unsigned pipe_write(struct file *, unsigned char *, unsigned);
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
index 9188e1a24ce..ae225460bb1 100644
--- a/usr.bin/aucat/siofile.c
+++ b/usr.bin/aucat/siofile.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: siofile.c,v 1.1 2010/01/13 10:02:52 ratchov Exp $ */
+/* $OpenBSD: siofile.c,v 1.2 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -26,6 +26,7 @@
#include "aparams.h"
#include "aproc.h"
+#include "abuf.h"
#include "conf.h"
#include "dev.h"
#include "file.h"
@@ -37,6 +38,9 @@
struct siofile {
struct file file;
struct sio_hdl *hdl;
+ unsigned wtickets, wbpf;
+ unsigned rtickets, rbpf;
+ unsigned bufsz;
int started;
};
@@ -62,6 +66,95 @@ struct fileops siofile_ops = {
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)
{
@@ -70,12 +163,18 @@ siofile_cb(void *addr, int delta)
#ifdef DEBUG
if (delta < 0 || delta > (60 * RATE_MAX)) {
- dbg_puts(f->file.name);
+ 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("\n");
+ }
#endif
if (delta != 0) {
p = f->file.wproc;
@@ -87,31 +186,27 @@ siofile_cb(void *addr, int delta)
if (p && p->ops->ipos)
p->ops->ipos(p, NULL, delta);
}
+ f->wtickets += delta * f->wbpf;
+ f->rtickets += delta * f->rbpf;
}
/*
* Open the device.
*/
struct siofile *
-siofile_new(struct fileops *ops, char *path,
+siofile_new(struct fileops *ops, char *path, unsigned mode,
struct aparams *ipar, struct aparams *opar,
unsigned *bufsz, unsigned *round)
{
struct sio_par par;
struct sio_hdl *hdl;
struct siofile *f;
- int mode;
- mode = 0;
- if (ipar)
- mode |= SIO_REC;
- if (opar)
- mode |= SIO_PLAY;
hdl = sio_open(path, mode, 1);
if (hdl == NULL)
return NULL;
sio_initpar(&par);
- if (ipar) {
+ if (mode & SIO_REC) {
par.bits = ipar->bits;
par.bps = ipar->bps;
par.sig = ipar->sig;
@@ -127,7 +222,7 @@ siofile_new(struct fileops *ops, char *path,
par.msb = opar->msb;
par.rate = opar->rate;
}
- if (opar)
+ if (mode & SIO_PLAY)
par.pchan = opar->cmax - opar->cmin + 1;
par.appbufsz = *bufsz;
par.round = *round;
@@ -135,7 +230,7 @@ siofile_new(struct fileops *ops, char *path,
goto bad_close;
if (!sio_getpar(hdl, &par))
goto bad_close;
- if (ipar) {
+ if (mode & SIO_REC) {
ipar->bits = par.bits;
ipar->bps = par.bps;
ipar->sig = par.sig;
@@ -144,7 +239,7 @@ siofile_new(struct fileops *ops, char *path,
ipar->rate = par.rate;
ipar->cmax = ipar->cmin + par.rchan - 1;
}
- if (opar) {
+ if (mode & SIO_PLAY) {
opar->bits = par.bits;
opar->bps = par.bps;
opar->sig = par.sig;
@@ -162,6 +257,11 @@ siofile_new(struct fileops *ops, char *path,
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:
@@ -183,6 +283,8 @@ siofile_start(struct file *file)
return;
}
f->started = 1;
+ f->wtickets = f->bufsz * f->wbpf;
+ f->rtickets = 0;
#ifdef DEBUG
if (debug_level >= 3) {
file_dbg(&f->file);
@@ -219,6 +321,14 @@ siofile_read(struct file *file, unsigned char *data, unsigned count)
struct siofile *f = (struct siofile *)file;
unsigned 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;
@@ -237,6 +347,17 @@ siofile_read(struct file *file, unsigned char *data, unsigned count)
#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;
@@ -248,6 +369,14 @@ siofile_write(struct file *file, unsigned char *data, unsigned count)
struct siofile *f = (struct siofile *)file;
unsigned 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;
@@ -266,6 +395,17 @@ siofile_write(struct file *file, unsigned char *data, unsigned count)
#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;
}
diff --git a/usr.bin/aucat/siofile.h b/usr.bin/aucat/siofile.h
index 6caf538cfc5..bb8cb5dd801 100644
--- a/usr.bin/aucat/siofile.h
+++ b/usr.bin/aucat/siofile.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: siofile.h,v 1.1 2010/01/13 10:02:52 ratchov Exp $ */
+/* $OpenBSD: siofile.h,v 1.2 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -20,9 +20,12 @@
struct fileops;
struct siofile;
struct aparams;
+struct aproc;
-struct siofile *siofile_new(struct fileops *, char *,
+struct siofile *siofile_new(struct fileops *, char *, unsigned,
struct aparams *, struct aparams *, unsigned *, unsigned *);
+struct aproc *rsio_new(struct file *f);
+struct aproc *wsio_new(struct file *f);
extern struct fileops siofile_ops;
diff --git a/usr.bin/aucat/sock.c b/usr.bin/aucat/sock.c
index e4d11bb6bb9..4086e1ba478 100644
--- a/usr.bin/aucat/sock.c
+++ b/usr.bin/aucat/sock.c
@@ -1,4 +1,4 @@
-/* $OpenBSD: sock.c,v 1.39 2010/01/15 22:17:44 ratchov Exp $ */
+/* $OpenBSD: sock.c,v 1.40 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -14,12 +14,6 @@
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
*/
-/*
- * TODO:
- *
- * change f->bufsz to contain only socket-side buffer,
- * because it's less error prone
- */
#include <stdio.h>
#include <stdlib.h>
@@ -36,7 +30,7 @@
#include "dbg.h"
#endif
-int sock_attach(struct sock *, int);
+void sock_attach(struct sock *, int);
int sock_read(struct sock *);
int sock_write(struct sock *);
int sock_execmsg(struct sock *);
@@ -59,11 +53,11 @@ struct fileops sock_ops = {
void
sock_dbg(struct sock *f)
{
- static char *pstates[] = { "hel", "ini", "sta", "run", "mid" };
+ static char *pstates[] = { "hel", "ini", "sta", "rdy", "run", "mid" };
static char *rstates[] = { "rdat", "rmsg", "rret" };
static char *wstates[] = { "widl", "wmsg", "wdat" };
- if (f->slot >= 0 && dev_midi) {
+ if (f->slot >= 0 && APROC_OK(dev_midi)) {
dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
} else
@@ -79,10 +73,14 @@ sock_dbg(struct sock *f)
void sock_setvol(void *, unsigned);
void sock_startreq(void *);
+void sock_stopreq(void *);
+void sock_locreq(void *, unsigned);
struct ctl_ops ctl_sockops = {
sock_setvol,
- sock_startreq
+ sock_startreq,
+ sock_stopreq,
+ sock_locreq
};
void
@@ -158,7 +156,7 @@ rsock_opos(struct aproc *p, struct abuf *obuf, int delta)
{
struct sock *f = (struct sock *)p->u.io.file;
- if (f->mode & AMSG_REC)
+ if (f->mode & AMSG_RECMASK)
return;
f->delta += delta;
@@ -257,7 +255,7 @@ wsock_ipos(struct aproc *p, struct abuf *obuf, int delta)
{
struct sock *f = (struct sock *)p->u.io.file;
- if (!(f->mode & AMSG_REC))
+ if (!(f->mode & AMSG_RECMASK))
return;
f->delta += delta;
@@ -306,9 +304,9 @@ sock_new(struct fileops *ops, int fd)
f->mode = 0;
f->opt = opt_byname("default");
if (f->opt) {
- if (dev_sub)
+ if (f->opt->mode & MODE_RECMASK)
f->wpar = f->opt->wpar;
- if (dev_mix)
+ if (f->opt->mode & MODE_PLAY)
f->rpar = f->opt->rpar;
}
f->xrun = AMSG_IGNORE;
@@ -316,17 +314,20 @@ sock_new(struct fileops *ops, int fd)
f->round = dev_round;
f->delta = 0;
f->tickpending = 0;
+ f->startpending = 0;
f->vol = f->lastvol = MIDI_MAXCTL;
f->slot = -1;
wproc = aproc_new(&wsock_ops, f->pipe.file.name);
wproc->u.io.file = &f->pipe.file;
+ wproc->u.io.partial = 0;
f->pipe.file.wproc = wproc;
f->wstate = SOCK_WIDLE;
f->wtodo = 0xdeadbeef;
rproc = aproc_new(&rsock_ops, f->pipe.file.name);
rproc->u.io.file = &f->pipe.file;
+ rproc->u.io.partial = 0;
f->pipe.file.rproc = rproc;
f->rstate = SOCK_RMSG;
f->rtodo = sizeof(struct amsg);
@@ -357,6 +358,7 @@ sock_freebuf(struct sock *f)
if (wbuf)
abuf_hup(wbuf);
f->tickpending = 0;
+ f->startpending = 0;
}
/*
@@ -367,28 +369,40 @@ sock_allocbuf(struct sock *f)
{
struct abuf *rbuf = NULL, *wbuf = NULL;
+ f->pstate = SOCK_START;
if (f->mode & AMSG_PLAY) {
rbuf = abuf_new(f->bufsz, &f->rpar);
aproc_setout(f->pipe.file.rproc, rbuf);
+ if (!ABUF_WOK(rbuf) || (f->pipe.file.state & FILE_EOF))
+ f->pstate = SOCK_READY;
}
- if (f->mode & AMSG_REC) {
+ if (f->mode & AMSG_RECMASK) {
wbuf = abuf_new(f->bufsz, &f->wpar);
aproc_setin(f->pipe.file.wproc, wbuf);
- f->walign = dev_round * wbuf->bpf;
+ f->walign = f->round;
}
f->delta = 0;
+ f->wmax = 0;
+ f->rmax = f->bufsz;
f->tickpending = 0;
+ f->startpending = 0;
#ifdef DEBUG
if (debug_level >= 3) {
sock_dbg(f);
dbg_puts(": allocating ");
dbg_putu(f->bufsz);
- dbg_puts(" fr buffers\n");
+ dbg_puts(" fr buffers, rmax = ");
+ dbg_putu(f->rmax);
+ dbg_puts("\n");
}
#endif
- f->pstate = SOCK_START;
- if (!(f->mode & AMSG_PLAY) && ctl_slotstart(dev_midi, f->slot))
- (void)sock_attach(f, 0);
+ if (f->mode & AMSG_PLAY) {
+ f->pstate = SOCK_START;
+ } else {
+ f->pstate = SOCK_READY;
+ if (ctl_slotstart(dev_midi, f->slot))
+ (void)sock_attach(f, 0);
+ }
}
/*
@@ -423,9 +437,9 @@ sock_startreq(void *arg)
struct sock *f = (struct sock *)arg;
#ifdef DEBUG
- if (f->pstate != SOCK_START) {
+ if (f->pstate != SOCK_READY) {
sock_dbg(f);
- dbg_puts(": not in START state\n");
+ dbg_puts(": not in READY state\n");
dbg_panic();
}
#endif
@@ -433,9 +447,41 @@ sock_startreq(void *arg)
}
/*
+ * Callback invoked by MMC stop
+ */
+void
+sock_stopreq(void *arg)
+{
+#ifdef DEBUG
+ struct sock *f = (struct sock *)arg;
+
+ if (debug_level >= 3) {
+ sock_dbg(f);
+ dbg_puts(": ignored STOP signal\n");
+ }
+#endif
+}
+
+/*
+ * Callback invoked by MMC relocate, ignored
+ */
+void
+sock_locreq(void *arg, unsigned mmcpos)
+{
+#ifdef DEBUG
+ struct sock *f = (struct sock *)arg;
+
+ if (debug_level >= 3) {
+ sock_dbg(f);
+ dbg_puts(": ignored RELOCATE signal\n");
+ }
+#endif
+}
+
+/*
* Attach play and/or record buffers to dev_mix and/or dev_sub.
*/
-int
+void
sock_attach(struct sock *f, int force)
{
struct abuf *rbuf, *wbuf;
@@ -448,23 +494,30 @@ sock_attach(struct sock *f, int force)
* the buffer isn't completely filled.
*/
if (!force && rbuf && ABUF_WOK(rbuf))
- return 0;
+ return;
+ /*
+ * get the current position, the origin is when
+ * the first sample is played/recorded
+ */
+ f->delta = dev_getpos() * (int)f->round / (int)dev_round;
+ f->startpending = 1;
+ f->pstate = SOCK_RUN;
#ifdef DEBUG
if (debug_level >= 3) {
sock_dbg(f);
- dbg_puts(": attaching to device\n");
+ dbg_puts(": attaching at ");
+ dbg_puti(f->delta);
+ dbg_puts("\n");
}
#endif
- f->pstate = SOCK_RUN;
-
/*
- * Attach them to the device.
+ * We dont check whether the device is dying,
+ * because dev_xxx() functions are supposed to
+ * work (i.e., not to crash)
*/
- dev_attach(f->pipe.file.name,
- (f->mode & AMSG_PLAY) ? rbuf : NULL, &f->rpar, f->xrun,
- (f->mode & AMSG_REC) ? wbuf : NULL, &f->wpar, f->xrun,
- f->opt->maxweight);
+ dev_attach(f->pipe.file.name, f->mode,
+ rbuf, &f->rpar, wbuf, &f->wpar, f->xrun, f->opt->maxweight);
if (f->mode & AMSG_PLAY)
dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
@@ -475,7 +528,6 @@ sock_attach(struct sock *f, int force)
if (!sock_write(f))
break;
}
- return 1;
}
void
@@ -483,6 +535,7 @@ sock_reset(struct sock *f)
{
switch (f->pstate) {
case SOCK_START:
+ case SOCK_READY:
if (ctl_slotstart(dev_midi, f->slot)) {
(void)sock_attach(f, 1);
f->pstate = SOCK_RUN;
@@ -584,8 +637,7 @@ sock_rdata(struct sock *f)
{
struct aproc *p;
struct abuf *obuf;
- unsigned char *data;
- unsigned count, n;
+ unsigned n;
#ifdef DEBUG
if (f->pstate != SOCK_MIDI && f->rtodo == 0) {
@@ -598,17 +650,20 @@ sock_rdata(struct sock *f)
obuf = LIST_FIRST(&p->obuflist);
if (obuf == NULL)
return 0;
- if (ABUF_FULL(obuf) || !(f->pipe.file.state & FILE_ROK))
- return 0;
- data = abuf_wgetblk(obuf, &count, 0);
- if (f->pstate != SOCK_MIDI && count > f->rtodo)
- count = f->rtodo;
- n = file_read(&f->pipe.file, data, count);
- if (n == 0)
+ if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
return 0;
- abuf_wcommit(obuf, n);
- if (f->pstate != SOCK_MIDI)
+ if (f->pstate == SOCK_MIDI) {
+ if (!rfile_do(p, obuf->len, NULL))
+ return 0;
+ } else {
+ if (!rfile_do(p, f->rtodo, &n))
+ return 0;
f->rtodo -= n;
+ if (f->pstate == SOCK_START) {
+ if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF))
+ f->pstate = SOCK_READY;
+ }
+ }
return 1;
}
@@ -621,10 +676,7 @@ sock_wdata(struct sock *f)
{
struct aproc *p;
struct abuf *ibuf;
- unsigned char *data;
- unsigned count, n;
-#define ZERO_MAX 0x1000
- static unsigned char zero[ZERO_MAX];
+ unsigned n;
#ifdef DEBUG
if (f->pstate != SOCK_MIDI && f->wtodo == 0) {
@@ -637,32 +689,22 @@ sock_wdata(struct sock *f)
return 0;
p = f->pipe.file.wproc;
ibuf = LIST_FIRST(&p->ibuflist);
- if (ibuf) {
- if (ABUF_EMPTY(ibuf))
- return 0;
- data = abuf_rgetblk(ibuf, &count, 0);
- if (f->pstate != SOCK_MIDI && count > f->wtodo)
- count = f->wtodo;
- n = file_write(&f->pipe.file, data, count);
- if (n == 0)
+#ifdef DEBUG
+ if (f->pstate != SOCK_MIDI && ibuf == NULL) {
+ sock_dbg(f);
+ dbg_puts(": attempted to write on detached buffer\n");
+ dbg_panic();
+ }
+#endif
+ if (ibuf == NULL)
+ return 0;
+ if (!ABUF_ROK(ibuf))
+ return 0;
+ if (f->pstate == SOCK_MIDI) {
+ if (!wfile_do(p, ibuf->len, NULL))
return 0;
- abuf_rdiscard(ibuf, n);
- if (f->pstate != SOCK_MIDI)
- f->wtodo -= n;
} else {
- if (f->pstate == SOCK_MIDI)
- return 0;
- /*
- * There's no dev_detach() routine yet,
- * so now we abruptly destroy the buffer.
- * Until we implement dev_detach, complete
- * the packet with zeros...
- */
- count = ZERO_MAX;
- if (count > f->wtodo)
- count = f->wtodo;
- n = file_write(&f->pipe.file, zero, count);
- if (n == 0)
+ if (!wfile_do(p, f->wtodo, &n))
return 0;
f->wtodo -= n;
}
@@ -720,7 +762,7 @@ sock_setpar(struct sock *f)
f->rpar.le = f->wpar.le = p->le ? 1 : 0;
if (AMSG_ISSET(p->msb))
f->rpar.msb = f->wpar.msb = p->msb ? 1 : 0;
- if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_REC)) {
+ if (AMSG_ISSET(p->rchan) && (f->mode & AMSG_RECMASK)) {
if (p->rchan < 1)
p->rchan = 1;
if (p->rchan > NCHAN_MAX)
@@ -835,8 +877,8 @@ sock_setpar(struct sock *f)
}
if (AMSG_ISSET(p->appbufsz)) {
rate = (f->mode & AMSG_PLAY) ? f->rpar.rate : f->wpar.rate;
- min = 2;
- max = 2 + rate / dev_round;
+ min = 1;
+ max = 1 + rate / dev_round;
min *= f->round;
max *= f->round;
p->appbufsz += f->round - 1;
@@ -857,7 +899,7 @@ sock_setpar(struct sock *f)
}
#ifdef DEBUG
if (debug_level >= 2) {
- if (f->slot >= -1 && dev_midi) {
+ if (f->slot >= 0 && dev_midi) {
dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
} else
@@ -868,7 +910,7 @@ sock_setpar(struct sock *f)
dbg_puts(", play = ");
aparams_dbg(&f->rpar);
}
- if (f->mode & AMSG_REC) {
+ if (f->mode & AMSG_RECMASK) {
dbg_puts(", rec:");
aparams_dbg(&f->wpar);
}
@@ -928,7 +970,7 @@ sock_hello(struct sock *f)
/*
* XXX : dev_midi can no longer be NULL, right ?
*/
- if (dev_midi && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
+ if (APROC_OK(dev_midi) && (p->proto & (AMSG_MIDIIN | AMSG_MIDIOUT))) {
if (p->proto & ~(AMSG_MIDIIN | AMSG_MIDIOUT)) {
#ifdef DEBUG
if (debug_level >= 1) {
@@ -948,9 +990,9 @@ sock_hello(struct sock *f)
f->opt = opt_byname(p->opt);
if (f->opt == NULL)
return 0;
- if (dev_sub)
+ if (f->opt->mode & MODE_RECMASK)
f->wpar = f->opt->wpar;
- if (dev_mix)
+ if (f->opt->mode & MODE_PLAY)
f->rpar = f->opt->rpar;
if (f->opt->mmc)
f->xrun = AMSG_SYNC;
@@ -968,7 +1010,7 @@ sock_hello(struct sock *f)
}
f->mode = 0;
if (p->proto & AMSG_PLAY) {
- if (!dev_mix) {
+ if (!APROC_OK(dev_mix) || !(f->opt->mode & MODE_PLAY)) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -980,7 +1022,8 @@ sock_hello(struct sock *f)
f->mode |= AMSG_PLAY;
}
if (p->proto & AMSG_REC) {
- if (!dev_sub) {
+ if (!(APROC_OK(dev_sub) && (f->opt->mode & MODE_REC)) &&
+ !(APROC_OK(dev_submon) && (f->opt->mode & MODE_MON))) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -989,9 +1032,9 @@ sock_hello(struct sock *f)
#endif
return 0;
}
- f->mode |= AMSG_REC;
+ f->mode |= (f->opt->mode & MODE_MON) ? AMSG_MON : AMSG_REC;
}
- if (dev_midi) {
+ if (APROC_OK(dev_midi)) {
f->slot = ctl_slotnew(dev_midi,
p->who, &ctl_sockops, f,
f->opt->mmc);
@@ -1017,6 +1060,7 @@ int
sock_execmsg(struct sock *f)
{
struct amsg *m = &f->rmsg;
+ struct abuf *obuf;
switch (m->cmd) {
case AMSG_DATA:
@@ -1026,7 +1070,8 @@ sock_execmsg(struct sock *f)
dbg_puts(": DATA message\n");
}
#endif
- if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
+ if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
+ f->pstate != SOCK_READY) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -1046,8 +1091,8 @@ sock_execmsg(struct sock *f)
aproc_del(f->pipe.file.rproc);
return 0;
}
- if (f->pstate == SOCK_START &&
- ABUF_FULL(LIST_FIRST(&f->pipe.file.rproc->obuflist))) {
+ obuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
+ if (f->pstate == SOCK_START && !ABUF_WOK(obuf)) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -1057,8 +1102,31 @@ sock_execmsg(struct sock *f)
aproc_del(f->pipe.file.rproc);
return 0;
}
+ if (m->u.data.size % obuf->bpf != 0) {
+#ifdef DEBUG
+ if (debug_level >= 1) {
+ sock_dbg(f);
+ dbg_puts(": unaligned data chunk\n");
+ }
+#endif
+ aproc_del(f->pipe.file.rproc);
+ return 0;
+ }
f->rstate = SOCK_RDATA;
- f->rtodo = m->u.data.size;
+ f->rtodo = m->u.data.size / obuf->bpf;
+#ifdef DEBUG
+ if (f->rtodo > f->rmax && debug_level >= 2) {
+ sock_dbg(f);
+ dbg_puts(": received past current position, rtodo = ");
+ dbg_putu(f->rtodo);
+ dbg_puts(", rmax = ");
+ dbg_putu(f->rmax);
+ dbg_puts("\n");
+ aproc_del(f->pipe.file.rproc);
+ return 0;
+ }
+#endif
+ f->rmax -= f->rtodo;
if (f->rtodo == 0) {
#ifdef DEBUG
if (debug_level >= 1) {
@@ -1098,7 +1166,8 @@ sock_execmsg(struct sock *f)
dbg_puts(": STOP message\n");
}
#endif
- if (f->pstate != SOCK_RUN && f->pstate != SOCK_START) {
+ if (f->pstate != SOCK_RUN &&
+ f->pstate != SOCK_START && f->pstate != SOCK_READY) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -1107,11 +1176,18 @@ sock_execmsg(struct sock *f)
#endif
aproc_del(f->pipe.file.rproc);
return 0;
+ /*
+ * XXX: device could have desappeared at this point,
+ * see how this is fixed in wav.c
+ */
}
- if (f->pstate == SOCK_START &&
+ if ((f->pstate == SOCK_START || f->pstate == SOCK_READY) &&
ctl_slotstart(dev_midi, f->slot))
(void)sock_attach(f, 1);
- sock_freebuf(f);
+ if (f->wstate != SOCK_WDATA || f->wtodo == 0)
+ sock_freebuf(f);
+ else
+ f->pstate = SOCK_STOP;
AMSG_INIT(m);
m->cmd = AMSG_ACK;
f->rstate = SOCK_RRET;
@@ -1161,14 +1237,24 @@ sock_execmsg(struct sock *f)
AMSG_INIT(m);
m->cmd = AMSG_GETPAR;
m->u.par.legacy_mode = f->mode;
- m->u.par.bits = f->rpar.bits;
- m->u.par.bps = f->rpar.bps;
- m->u.par.sig = f->rpar.sig;
- m->u.par.le = f->rpar.le;
- m->u.par.msb = f->rpar.msb;
- m->u.par.rate = f->rpar.rate;
- m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
- m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
+ if (f->mode & AMSG_PLAY) {
+ m->u.par.bits = f->rpar.bits;
+ m->u.par.bps = f->rpar.bps;
+ m->u.par.sig = f->rpar.sig;
+ m->u.par.le = f->rpar.le;
+ m->u.par.msb = f->rpar.msb;
+ m->u.par.rate = f->rpar.rate;
+ m->u.par.pchan = f->rpar.cmax - f->rpar.cmin + 1;
+ }
+ if (f->mode & AMSG_RECMASK) {
+ m->u.par.bits = f->wpar.bits;
+ m->u.par.bps = f->wpar.bps;
+ m->u.par.sig = f->wpar.sig;
+ m->u.par.le = f->wpar.le;
+ m->u.par.msb = f->wpar.msb;
+ m->u.par.rate = f->wpar.rate;
+ m->u.par.rchan = f->wpar.cmax - f->wpar.cmin + 1;
+ }
m->u.par.appbufsz = f->bufsz;
m->u.par.bufsz =
f->bufsz + (dev_bufsz / dev_round) * f->round;
@@ -1196,9 +1282,9 @@ sock_execmsg(struct sock *f)
AMSG_INIT(m);
m->cmd = AMSG_GETCAP;
m->u.cap.rate = dev_rate;
- m->u.cap.pchan = dev_mix ?
+ m->u.cap.pchan = (f->opt->mode & MODE_PLAY) ?
(f->opt->rpar.cmax - f->opt->rpar.cmin + 1) : 0;
- m->u.cap.rchan = dev_sub ?
+ m->u.cap.rchan = (f->opt->mode & (MODE_PLAY | MODE_REC)) ?
(f->opt->wpar.cmax - f->opt->wpar.cmin + 1) : 0;
m->u.cap.bits = sizeof(short) * 8;
m->u.cap.bps = sizeof(short);
@@ -1212,8 +1298,8 @@ sock_execmsg(struct sock *f)
dbg_puts(": SETVOL message\n");
}
#endif
- if (f->pstate != SOCK_RUN &&
- f->pstate != SOCK_START && f->pstate != SOCK_INIT) {
+ if (f->pstate != SOCK_RUN && f->pstate != SOCK_START &&
+ f->pstate != SOCK_INIT && f->pstate != SOCK_READY) {
#ifdef DEBUG
if (debug_level >= 1) {
sock_dbg(f);
@@ -1321,7 +1407,7 @@ sock_buildmsg(struct sock *f)
{
struct aproc *p;
struct abuf *ibuf;
- unsigned size;
+ unsigned size, max;
if (f->pstate == SOCK_MIDI) {
#ifdef DEBUG
@@ -1338,7 +1424,7 @@ sock_buildmsg(struct sock *f)
/*
* If pos changed, build a MOVE message.
*/
- if (f->tickpending) {
+ if ((f->tickpending && f->delta > 0) || f->startpending) {
#ifdef DEBUG
if (debug_level >= 4) {
sock_dbg(f);
@@ -1347,6 +1433,9 @@ sock_buildmsg(struct sock *f)
dbg_puts("\n");
}
#endif
+ f->wmax += f->delta;
+ if (f->delta > 0)
+ f->rmax += f->delta;
AMSG_INIT(&f->wmsg);
f->wmsg.cmd = AMSG_MOVE;
f->wmsg.u.ts.delta = f->delta;
@@ -1354,6 +1443,7 @@ sock_buildmsg(struct sock *f)
f->wstate = SOCK_WMSG;
f->delta = 0;
f->tickpending = 0;
+ f->startpending = 0;
return 1;
}
@@ -1384,17 +1474,29 @@ sock_buildmsg(struct sock *f)
p = f->pipe.file.wproc;
ibuf = LIST_FIRST(&p->ibuflist);
if (ibuf && ABUF_ROK(ibuf)) {
- size = ibuf->used - (ibuf->used % ibuf->bpf);
- if (size > AMSG_DATAMAX)
- size = AMSG_DATAMAX - (AMSG_DATAMAX % ibuf->bpf);
+#ifdef DEBUG
+ if (ibuf->used > f->wmax && debug_level >= 3) {
+ sock_dbg(f);
+ dbg_puts(": attempt to send past current position\n");
+ }
+#endif
+ max = AMSG_DATAMAX / ibuf->bpf;
+ size = ibuf->used;
if (size > f->walign)
size = f->walign;
+ if (size > f->wmax)
+ size = f->wmax;
+ if (size > max)
+ size = max;
+ if (size == 0)
+ return 0;
f->walign -= size;
+ f->wmax -= size;
if (f->walign == 0)
- f->walign = dev_round * ibuf->bpf;
+ f->walign = f->round;
AMSG_INIT(&f->wmsg);
f->wmsg.cmd = AMSG_DATA;
- f->wmsg.u.data.size = size;
+ f->wmsg.u.data.size = size * ibuf->bpf;
f->wtodo = sizeof(struct amsg);
f->wstate = SOCK_WMSG;
return 1;
@@ -1440,9 +1542,11 @@ sock_read(struct sock *f)
f->rtodo = sizeof(struct amsg);
}
/*
- * XXX: have to way that the buffer is full before starting
+ * XXX: sock_attach() may not start if there's not enough
+ * samples queues, if so ctl_slotstart() will trigger
+ * other streams, but this one won't start.
*/
- if (f->pstate == SOCK_START && ctl_slotstart(dev_midi, f->slot))
+ if (f->pstate == SOCK_READY && ctl_slotstart(dev_midi, f->slot))
(void)sock_attach(f, 0);
break;
case SOCK_RRET:
@@ -1525,8 +1629,12 @@ sock_write(struct sock *f)
f->wtodo = 0xdeadbeef;
break;
}
+ /*
+ * XXX: why not set f->wtodo in sock_wmsg() ?
+ */
f->wstate = SOCK_WDATA;
- f->wtodo = f->wmsg.u.data.size;
+ f->wtodo = f->wmsg.u.data.size /
+ LIST_FIRST(&f->pipe.file.wproc->ibuflist)->bpf;
/* PASSTHROUGH */
case SOCK_WDATA:
if (!sock_wdata(f))
@@ -1535,6 +1643,8 @@ sock_write(struct sock *f)
break;
f->wstate = SOCK_WIDLE;
f->wtodo = 0xdeadbeef;
+ if (f->pstate == SOCK_STOP)
+ sock_freebuf(f);
/* PASSTHROUGH */
case SOCK_WIDLE:
if (!sock_return(f))
diff --git a/usr.bin/aucat/sock.h b/usr.bin/aucat/sock.h
index 6ce36e7acac..bc5bfa2607d 100644
--- a/usr.bin/aucat/sock.h
+++ b/usr.bin/aucat/sock.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: sock.h,v 1.12 2010/01/15 22:17:44 ratchov Exp $ */
+/* $OpenBSD: sock.h,v 1.13 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -30,6 +30,8 @@ struct sock {
* to decode/encode messages in the stream.
*/
struct amsg rmsg, wmsg; /* messages being sent/received */
+ unsigned wmax; /* max frames we're allowed to write */
+ unsigned rmax; /* max frames we're allowed to read */
unsigned rtodo; /* input bytes not read yet */
unsigned wtodo; /* output bytes not written yet */
#define SOCK_RDATA 0 /* data chunk being read */
@@ -43,14 +45,17 @@ struct sock {
#define SOCK_HELLO 0 /* waiting for HELLO message */
#define SOCK_INIT 1 /* parameter negotiation */
#define SOCK_START 2 /* filling play buffers */
-#define SOCK_RUN 3 /* attached to the mix / sub */
-#define SOCK_MIDI 4 /* raw byte stream (midi) */
+#define SOCK_READY 3 /* play buffers full */
+#define SOCK_RUN 4 /* attached to the mix / sub */
+#define SOCK_STOP 5 /* draining rec buffers */
+#define SOCK_MIDI 6 /* raw byte stream (midi) */
unsigned pstate; /* one of the above */
unsigned mode; /* a set of AMSG_PLAY, AMSG_REC */
struct aparams rpar; /* read (ie play) parameters */
struct aparams wpar; /* write (ie rec) parameters */
int delta; /* pos. change to send */
int tickpending; /* delta waiting to be transmitted */
+ int startpending; /* initial delta waiting to be transmitted */
unsigned walign; /* align data packets to this */
unsigned bufsz; /* total buffer size */
unsigned round; /* block size */
diff --git a/usr.bin/aucat/wav.c b/usr.bin/aucat/wav.c
index e811c61aa6b..af7a3de9982 100644
--- a/usr.bin/aucat/wav.c
+++ b/usr.bin/aucat/wav.c
@@ -23,7 +23,9 @@
#include "aproc.h"
#include "conf.h"
#include "dev.h"
+#include "midi.h"
#include "wav.h"
+#include "opt.h"
#ifdef DEBUG
#include "dbg.h"
#endif
@@ -123,19 +125,33 @@ 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);
+void wav_startreq(void *);
+void wav_stopreq(void *);
+void wav_locreq(void *, unsigned);
+
+struct ctl_ops ctl_wavops = {
+ wav_setvol,
+ wav_startreq,
+ wav_stopreq,
+ wav_locreq
+};
struct aproc_ops rwav_ops = {
"rwav",
rwav_in,
rwav_out,
- rwav_eof,
- rwav_hup,
+ rfile_eof,
+ rfile_hup,
NULL, /* newin */
NULL, /* newout */
NULL, /* ipos */
@@ -147,8 +163,8 @@ struct aproc_ops wwav_ops = {
"wwav",
wwav_in,
wwav_out,
- wwav_eof,
- wwav_hup,
+ wfile_eof,
+ wfile_hup,
NULL, /* newin */
NULL, /* newout */
NULL, /* ipos */
@@ -156,189 +172,466 @@ struct aproc_ops wwav_ops = {
wwav_done
};
-struct aproc *
-rwav_new(struct file *f)
+#ifdef DEBUG
+/*
+ * print the given wav structure
+ */
+void
+wav_dbg(struct wav *f)
{
- struct aproc *p;
+ static char *pstates[] = { "ini", "sta", "rdy", "run", "fai" };
- p = aproc_new(&rwav_ops, f->name);
- p->u.io.file = f;
- f->rproc = p;
- return p;
+ dbg_puts("wav(");
+ if (f->slot >= 0 && APROC_OK(dev_midi)) {
+ dbg_puts(dev_midi->u.ctl.slot[f->slot].name);
+ dbg_putu(dev_midi->u.ctl.slot[f->slot].unit);
+ } else
+ dbg_puts(f->pipe.file.name);
+ dbg_puts(")/");
+ dbg_puts(pstates[f->pstate]);
}
+#endif
-int
-rwav_in(struct aproc *p, struct abuf *ibuf_dummy)
+/*
+ * convert ``count'' samples using the given char->short map
+ */
+void
+wav_conv(unsigned char *data, unsigned count, short *map)
{
- struct abuf *obuf = LIST_FIRST(&p->obuflist);
- struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
+ unsigned i;
+ unsigned char *iptr;
+ short *optr;
- if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
- return 0;
- data = abuf_wgetblk(obuf, &count, 0);
- count = file_read(f, data, count);
- if (count == 0)
- return 0;
- abuf_wcommit(obuf, count);
- if (!abuf_flush(obuf))
- return 0;
- return 1;
+ iptr = data + count;
+ optr = (short *)data + count;
+ for (i = count; i > 0; i--) {
+ --optr;
+ --iptr;
+ *optr = map[*iptr];
+ }
}
-int
-rwav_out(struct aproc *p, struct abuf *obuf)
+/*
+ * read method of the file structure
+ */
+unsigned
+wav_read(struct file *file, unsigned char *data, unsigned count)
{
- struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
+ struct wav *f = (struct wav *)file;
+ unsigned n;
- if (f->state & FILE_RINUSE)
- return 0;
- if (ABUF_FULL(obuf) || !(f->state & FILE_ROK))
- return 0;
- data = abuf_wgetblk(obuf, &count, 0);
- count = file_read(f, data, count);
- if (count == 0)
+ if (f->map)
+ count /= sizeof(short);
+ 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->tr)
+ file_eof(&f->pipe.file);
+ return 0;
+ }
+ }
+ n = pipe_read(file, data, count);
+ if (n == 0)
return 0;
- abuf_wcommit(obuf, count);
- return 1;
+ if (f->rbytes >= 0)
+ f->rbytes -= n;
+ if (f->map) {
+ wav_conv(data, n, f->map);
+ n *= sizeof(short);
+ }
+ return n;
}
-void
-rwav_done(struct aproc *p)
+/*
+ * write method of the file structure
+ */
+unsigned
+wav_write(struct file *file, unsigned char *data, unsigned count)
{
- struct file *f = p->u.io.file;
- struct abuf *obuf;
+ struct wav *f = (struct wav *)file;
+ unsigned n;
- if (f == NULL)
- return;
- /*
- * all buffers must be detached before deleting f->wproc,
- * because otherwise it could trigger this code again
- */
- obuf = LIST_FIRST(&p->obuflist);
- if (obuf)
- abuf_eof(obuf);
- if (f->wproc) {
- f->rproc = NULL;
- aproc_del(f->wproc);
- } else
- file_del(f);
- p->u.io.file = NULL;
+ 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
-rwav_eof(struct aproc *p, struct abuf *ibuf_dummy)
+wav_close(struct file *file)
+{
+ struct wav *f = (struct wav *)file;
+
+ 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);
+}
+
+/*
+ * 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)
{
- aproc_del(p);
+ struct abuf *rbuf = NULL, *wbuf = NULL;
+
+ if (f->mode & MODE_PLAY)
+ rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
+ if (f->mode & MODE_RECMASK)
+ wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
+ f->pstate = WAV_RUN;
+#ifdef DEBUG
+ if (debug_level >= 3) {
+ wav_dbg(f);
+ dbg_puts(": attaching\n");
+ }
+#endif
+ dev_attach(f->pipe.file.name, f->mode,
+ rbuf, &f->hpar, wbuf, &f->hpar, f->xrun, f->maxweight);
+ if (f->mode & MODE_PLAY)
+ dev_setvol(rbuf, MIDI_TO_ADATA(f->vol));
+ return 1;
}
+/*
+ * 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
-rwav_hup(struct aproc *p, struct abuf *obuf)
+wav_allocbuf(struct wav *f)
{
- aproc_del(p);
+ struct abuf *buf;
+ unsigned nfr;
+
+ f->pstate = WAV_START;
+ if (f->mode & MODE_PLAY) {
+ nfr = 2 * dev_bufsz * f->hpar.rate / dev_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 * dev_bufsz * f->hpar.rate / dev_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 && ctl_slotstart(dev_midi, f->slot))
+ (void)wav_attach(f, 0);
}
-struct aproc *
-wwav_new(struct file *f)
+/*
+ * free abuf structure and switch to the ``INIT'' state
+ */
+void
+wav_freebuf(struct wav *f)
{
- struct aproc *p;
+ struct abuf *rbuf = NULL, *wbuf = NULL;
- p = aproc_new(&wwav_ops, f->name);
- p->u.io.file = f;
- f->wproc = p;
- return p;
+ if (f->mode & MODE_PLAY)
+ rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist);
+ if (f->mode & MODE_RECMASK)
+ wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist);
+ f->pstate = WAV_INIT;
+#ifdef DEBUG
+ if (debug_level >= 3) {
+ wav_dbg(f);
+ dbg_puts(": freeing buffers\n");
+ }
+#endif
+ if (rbuf || wbuf)
+ ctl_slotstop(dev_midi, f->slot);
+ if (rbuf)
+ abuf_eof(rbuf);
+ if (wbuf)
+ abuf_hup(wbuf);
}
+/*
+ * switch to the ``INIT'' state performing
+ * necessary actions to reach it
+ */
void
-wwav_done(struct aproc *p)
+wav_reset(struct wav *f)
{
- struct file *f = p->u.io.file;
- struct abuf *ibuf;
+ switch (f->pstate) {
+ case WAV_START:
+ case WAV_READY:
+ if (ctl_slotstart(dev_midi, f->slot))
+ (void)wav_attach(f, 1);
+ /* PASSTHROUGH */
+ case WAV_RUN:
+ wav_freebuf(f);
+ f->pstate = WAV_INIT;
+ /* PASSTHROUGH */
+ case WAV_INIT:
+ case WAV_FAILED:
+ /* nothing yet */
+ break;
+ }
+}
- if (f == NULL)
- return;
+/*
+ * terminate the wav reader/writer
+ */
+void
+wav_exit(struct wav *f)
+{
+ if (f->mode & MODE_PLAY) {
+ aproc_del(f->pipe.file.rproc);
+ } else if (f->mode & MODE_RECMASK) {
+ aproc_del(f->pipe.file.wproc);
+ }
+}
+
+/*
+ * seek to f->mmcpos and prepare to start, close
+ * the file on error.
+ */
+int
+wav_seekmmc(struct wav *f)
+{
/*
- * all buffers must be detached before deleting f->rproc,
- * because otherwise it could trigger this code again
+ * don't go beyond the end-of-file, if so
+ * put it in INIT state so it dosn't start
*/
- ibuf = LIST_FIRST(&p->ibuflist);
- if (ibuf)
- abuf_hup(ibuf);
- if (f->rproc) {
- f->wproc = NULL;
- aproc_del(f->rproc);
- } else
- file_del(f);
- p->u.io.file = NULL;
+ if (f->mmcpos > f->endpos) {
+ wav_reset(f);
+ f->pstate = WAV_FAILED;
+ /*
+ * don't make other stream wait for us
+ */
+ if (f->slot >= 0)
+ ctl_slotstart(dev_midi, f->slot);
+ return 0;
+ }
+ if (!pipe_seek(&f->pipe.file, f->mmcpos)) {
+ wav_exit(f);
+ return 0;
+ }
+ 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
-wwav_in(struct aproc *p, struct abuf *ibuf)
+wav_rdata(struct wav *f)
{
- struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
+ struct aproc *p;
+ struct abuf *obuf;
- if (f->state & FILE_WINUSE)
+ p = f->pipe.file.rproc;
+ obuf = LIST_FIRST(&p->obuflist);
+ if (obuf == NULL)
return 0;
- if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
+ if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK))
return 0;
- data = abuf_rgetblk(ibuf, &count, 0);
- count = file_write(f, data, count);
- if (count == 0)
+ if (!rfile_do(p, obuf->len, NULL))
return 0;
- abuf_rdiscard(ibuf, count);
+ 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 (ctl_slotstart(dev_midi, f->slot))
+ (void)wav_attach(f, 0);
+ break;
+#ifdef DEBUG
+ case WAV_RUN:
+ break;
+ default:
+ wav_dbg(f);
+ dbg_puts(": bad state\n");
+ dbg_panic();
+#endif
+ }
+ if (f->rbytes == 0 && f->tr) {
+#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
-wwav_out(struct aproc *p, struct abuf *obuf_dummy)
+wav_wdata(struct wav *f)
{
- struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
- struct file *f = p->u.io.file;
- unsigned char *data;
- unsigned count;
+ struct aproc *p;
+ struct abuf *ibuf;
- if (!abuf_fill(ibuf))
+ if (!(f->pipe.file.state & FILE_WOK))
return 0;
- if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK))
+ p = f->pipe.file.wproc;
+ ibuf = LIST_FIRST(&p->ibuflist);
+ if (ibuf == NULL)
return 0;
- data = abuf_rgetblk(ibuf, &count, 0);
- if (count == 0) {
- /* XXX: this can't happen, right ? */
+ if (!ABUF_ROK(ibuf))
return 0;
- }
- count = file_write(f, data, count);
- if (count == 0)
+ if (!wfile_do(p, ibuf->len, NULL))
return 0;
- abuf_rdiscard(ibuf, count);
return 1;
}
+/*
+ * callback to set the volume, invoked by the MIDI control code
+ */
+void
+wav_setvol(void *arg, unsigned 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->obuflist);
+ dev_setvol(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_FAILED:
+#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->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
-wwav_eof(struct aproc *p, struct abuf *ibuf)
+wav_stopreq(void *arg)
{
- aproc_del(p);
+ struct wav *f = (struct wav *)arg;
+
+#ifdef DEBUG
+ if (debug_level >= 2) {
+ wav_dbg(f);
+ dbg_puts(": stopping");
+ if (f->pstate != WAV_FAILED && (f->mode & MODE_RECMASK)) {
+ dbg_puts(", ");
+ dbg_putu(f->endpos);
+ dbg_puts(" bytes recorded");
+ }
+ dbg_puts("\n");
+ }
+#endif
+ if (!f->tr) {
+ wav_exit(f);
+ return;
+ }
+ (void)wav_seekmmc(f);
}
+/*
+ * callback to relocate the stream, invoked by the MIDI control code
+ * on a stopped stream
+ */
void
-wwav_hup(struct aproc *p, struct abuf *obuf_dummy)
+wav_locreq(void *arg, unsigned mmc)
{
- aproc_del(p);
+ 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);
}
+/*
+ * create a file reader in the ``INIT'' state
+ */
struct wav *
-wav_new_in(struct fileops *ops, char *name, unsigned hdr,
- struct aparams *par, unsigned xrun, unsigned volctl)
+wav_new_in(struct fileops *ops, unsigned mode, char *name, unsigned hdr,
+ struct aparams *par, unsigned xrun, unsigned volctl, int tr)
{
int fd;
struct wav *f;
- struct aproc *p;
- struct abuf *buf;
- unsigned nfr;
if (name != NULL) {
fd = open(name, O_RDONLY | O_NONBLOCK, 0666);
@@ -356,43 +649,59 @@ wav_new_in(struct fileops *ops, char *name, unsigned hdr,
if (f == NULL)
return NULL;
if (hdr == HDR_WAV) {
- if (!wav_readhdr(f->pipe.fd, par, &f->rbytes, &f->map)) {
+ if (!wav_readhdr(f->pipe.fd, par, &f->startpos, &f->rbytes, &f->map)) {
file_del((struct file *)f);
return NULL;
}
- f->hpar = *par;
+ f->endpos = f->startpos + f->rbytes;
} else {
- f->rbytes = -1;
+ f->startpos = 0;
+ 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->tr = tr;
+ f->mode = mode;
+ f->hpar = *par;
f->hdr = 0;
- nfr = dev_bufsz * par->rate / dev_rate;
- buf = abuf_new(nfr, par);
- p = rwav_new((struct file *)f);
- aproc_setout(p, buf);
- abuf_fill(buf); /* XXX: move this in dev_attach() ? */
- dev_attach(name, buf, par, xrun, NULL, NULL, 0, ADATA_UNIT);
- dev_setvol(buf, MIDI_TO_ADATA(volctl));
+ f->xrun = xrun;
+ f->maxweight = MIDI_TO_ADATA(volctl);
+ f->slot = ctl_slotnew(dev_midi, "play", &ctl_wavops, f, 1);
+ rwav_new((struct file *)f);
+ wav_allocbuf(f);
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts(name);
dbg_puts(": playing ");
+ dbg_putu(f->startpos);
+ dbg_puts("..");
+ dbg_putu(f->endpos);
+ dbg_puts(": playing ");
aparams_dbg(par);
+ if (f->tr)
+ dbg_puts(", mmc");
dbg_puts("\n");
}
#endif
return f;
}
+/*
+ * create a file writer in the ``INIT'' state
+ */
struct wav *
-wav_new_out(struct fileops *ops, char *name, unsigned hdr,
- struct aparams *par, unsigned xrun)
+wav_new_out(struct fileops *ops, unsigned mode, char *name, unsigned hdr,
+ struct aparams *par, unsigned xrun, int tr)
{
int fd;
struct wav *f;
- struct aproc *p;
- struct abuf *buf;
- unsigned nfr;
if (name == NULL) {
name = "stdout";
@@ -414,20 +723,24 @@ wav_new_out(struct fileops *ops, char *name, unsigned hdr,
par->le = 1;
par->sig = (par->bits <= 8) ? 0 : 1;
par->bps = (par->bits + 7) / 8;
- if (!wav_writehdr(f->pipe.fd, par)) {
+ if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) {
file_del((struct file *)f);
return NULL;
}
- f->hpar = *par;
f->wbytes = WAV_DATAMAX;
- } else
+ f->endpos = f->startpos;
+ } else {
f->wbytes = -1;
+ f->startpos = f->endpos = 0;
+ }
+ f->tr = tr;
+ f->mode = mode;
+ f->hpar = *par;
f->hdr = hdr;
- nfr = dev_bufsz * par->rate / dev_rate;
- p = wwav_new((struct file *)f);
- buf = abuf_new(nfr, par);
- aproc_setin(p, buf);
- dev_attach(name, NULL, NULL, 0, buf, par, xrun, 0);
+ f->xrun = xrun;
+ f->slot = ctl_slotnew(dev_midi, "rec", &ctl_wavops, f, 1);
+ wwav_new((struct file *)f);
+ wav_allocbuf(f);
#ifdef DEBUG
if (debug_level >= 2) {
dbg_puts(name);
@@ -440,86 +753,107 @@ wav_new_out(struct fileops *ops, char *name, unsigned hdr,
}
void
-wav_conv(unsigned char *data, unsigned count, short *map)
+rwav_done(struct aproc *p)
{
- unsigned i;
- unsigned char *iptr;
- short *optr;
+ struct wav *f = (struct wav *)p->u.io.file;
- iptr = data + count;
- optr = (short *)data + count;
- for (i = count; i > 0; i--) {
- --optr;
- --iptr;
- *optr = map[*iptr];
+ if (f->slot >= 0)
+ ctl_slotdel(dev_midi, 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->obuflist);
+ if (obuf && f->pstate >= WAV_RUN) {
+ if (!abuf_flush(obuf))
+ return 0;
}
+ return 1;
}
-unsigned
-wav_read(struct file *file, unsigned char *data, unsigned count)
+int
+rwav_out(struct aproc *p, struct abuf *obuf)
{
- struct wav *f = (struct wav *)file;
- unsigned n;
+ struct wav *f = (struct wav *)p->u.io.file;
- if (f->map)
- count /= sizeof(short);
- if (f->rbytes >= 0 && count > f->rbytes) {
- count = f->rbytes; /* file->rbytes fits in count */
- if (count == 0) {
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(&f->pipe.file);
- dbg_puts(": read complete\n");
- }
-#endif
- file_eof(&f->pipe.file);
+ if (f->pipe.file.state & FILE_RINUSE)
+ return 0;
+ for (;;) {
+ if (!wav_rdata(f))
return 0;
- }
}
- n = pipe_read(file, data, count);
- if (n == 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)
+ ctl_slotdel(dev_midi, 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;
- if (f->rbytes >= 0)
- f->rbytes -= n;
- if (f->map) {
- wav_conv(data, n, f->map);
- n *= sizeof(short);
+ for (;;) {
+ if (!wav_wdata(f))
+ return 0;
}
- return n;
+ return 1;
}
-unsigned
-wav_write(struct file *file, unsigned char *data, unsigned count)
+int
+wwav_out(struct aproc *p, struct abuf *obuf_dummy)
{
- struct wav *f = (struct wav *)file;
- unsigned n;
+ struct abuf *ibuf = LIST_FIRST(&p->ibuflist);
+ struct wav *f = (struct wav *)p->u.io.file;
- if (f->wbytes >= 0 && count > f->wbytes) {
- count = f->wbytes; /* wbytes fits in count */
- if (count == 0) {
-#ifdef DEBUG
- if (debug_level >= 3) {
- file_dbg(&f->pipe.file);
- dbg_puts(": write complete\n");
- }
-#endif
- file_hup(&f->pipe.file);
+ if (ibuf && f->pstate == WAV_RUN) {
+ if (!abuf_fill(ibuf))
return 0;
- }
}
- n = pipe_write(file, data, count);
- if (f->wbytes >= 0)
- f->wbytes -= n;
- return n;
+ if (!wav_wdata(f))
+ return 0;
+ return 1;
}
-void
-wav_close(struct file *file)
+struct aproc *
+wwav_new(struct file *f)
{
- struct wav *f = (struct wav *)file;
+ struct aproc *p;
- if (f->hdr == HDR_WAV)
- wav_writehdr(f->pipe.fd, &f->hpar);
- pipe_close(file);
+ 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
index 921637e9e1a..4543d1a89da 100644
--- a/usr.bin/aucat/wav.h
+++ b/usr.bin/aucat/wav.h
@@ -1,4 +1,4 @@
-/* $OpenBSD: wav.h,v 1.5 2010/01/05 10:18:12 ratchov Exp $ */
+/* $OpenBSD: wav.h,v 1.6 2010/04/03 17:40:33 ratchov Exp $ */
/*
* Copyright (c) 2008 Alexandre Ratchov <alex@caoua.org>
*
@@ -28,23 +28,38 @@ struct wav {
#define HDR_RAW 1 /* no headers, ie openbsd native ;-) */
#define HDR_WAV 2 /* microsoft riff wave */
unsigned hdr; /* HDR_RAW or HDR_WAV */
+ unsigned 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 tr; /* use MMC control */
+ unsigned vol; /* current volume */
+ unsigned maxweight; /* dynamic range when vol == 127 */
+#define WAV_INIT 0 /* not trying to do anything */
+#define WAV_START 1 /* buffer allocated */
+#define WAV_READY 2 /* buffer filled enough */
+#define WAV_RUN 3 /* buffer attached to device */
+#define WAV_FAILED 4 /* failed to seek */
+ unsigned pstate; /* one of above */
+ unsigned mode; /* bitmap of MODE_* */
};
extern struct fileops wav_ops;
-struct wav *wav_new_in(struct fileops *, char *, unsigned,
- struct aparams *, unsigned, unsigned);
-struct wav *wav_new_out(struct fileops *, char *, unsigned,
- struct aparams *, unsigned);
+struct wav *wav_new_in(struct fileops *, unsigned, char *, unsigned,
+ struct aparams *, unsigned, unsigned, int);
+struct wav *wav_new_out(struct fileops *, unsigned, char *, unsigned,
+ struct aparams *, unsigned, int);
unsigned wav_read(struct file *, unsigned char *, unsigned);
unsigned wav_write(struct file *, unsigned char *, unsigned);
void wav_close(struct file *);
-int wav_readhdr(int, struct aparams *, off_t *, short **);
-int wav_writehdr(int, struct aparams *);
+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, short *);
/* legacy */