Merge branch 'master' into mixer

This commit is contained in:
Alexandre Ratchov 2018-06-19 07:52:50 +02:00
commit bc32c07bcd
8 changed files with 311 additions and 334 deletions

View File

@ -33,7 +33,8 @@ void
usage(void) usage(void)
{ {
fprintf(stderr, fprintf(stderr,
"usage: rec [-b size] [-c nchan] [-e enc] [-r rate]\n"); "usage: rec [-b size] [-c nchan] [-e enc] [-n nbytes] "
"[-r rate] [-x xrun]\n");
} }
int int
@ -42,7 +43,7 @@ main(int argc, char **argv)
int ch; int ch;
struct sio_hdl *hdl; struct sio_hdl *hdl;
size_t bufsz; size_t bufsz;
ssize_t n; ssize_t n, nbytes;
/* /*
* defaults parameters * defaults parameters
@ -52,18 +53,19 @@ main(int argc, char **argv)
par.bits = 16; par.bits = 16;
par.rchan = 2; par.rchan = 2;
par.rate = 48000; par.rate = 48000;
nbytes = -1;
while ((ch = getopt(argc, argv, "r:c:e:b:x:")) != -1) { while ((ch = getopt(argc, argv, "b:c:e:n:r:x:")) != -1) {
switch(ch) { switch (ch) {
case 'r': case 'b':
if (sscanf(optarg, "%u", &par.rate) != 1) { if (sscanf(optarg, "%u", &par.appbufsz) != 1) {
fprintf(stderr, "%s: bad rate\n", optarg); fprintf(stderr, "%s: bad buf size\n", optarg);
exit(1); exit(1);
} }
break; break;
case 'c': case 'c':
if (sscanf(optarg, "%u", &par.rchan) != 1) { if (sscanf(optarg, "%u", &par.rchan) != 1) {
fprintf(stderr, "%s: channels number\n", optarg); fprintf(stderr, "%s: bad channels number\n", optarg);
exit(1); exit(1);
} }
break; break;
@ -73,9 +75,15 @@ main(int argc, char **argv)
exit(1); exit(1);
} }
break; break;
case 'b': case 'n':
if (sscanf(optarg, "%u", &par.appbufsz) != 1) { if (sscanf(optarg, "%zu", &nbytes) != 1) {
fprintf(stderr, "%s: bad buf size\n", optarg); fprintf(stderr, "%s: bad bytes count\n", optarg);
exit(1);
}
break;
case 'r':
if (sscanf(optarg, "%u", &par.rate) != 1) {
fprintf(stderr, "%s: bad rate\n", optarg);
exit(1); exit(1);
} }
break; break;
@ -123,12 +131,16 @@ main(int argc, char **argv)
fprintf(stderr, "sio_start() failed\n"); fprintf(stderr, "sio_start() failed\n");
exit(1); exit(1);
} }
for (;;) { while (nbytes != 0) {
n = sio_read(hdl, buf, bufsz); n = bufsz;
if (nbytes >= 0 && n > nbytes)
n = nbytes;
n = sio_read(hdl, buf, n);
if (n == 0) { if (n == 0) {
fprintf(stderr, "sio_write: failed\n"); fprintf(stderr, "sio_write: failed\n");
exit(1); exit(1);
} }
nbytes -= n;
readpos += n; readpos += n;
if (tick) { if (tick) {
fprintf(stderr, fprintf(stderr,

View File

@ -24,6 +24,7 @@
#include "dsp.h" #include "dsp.h"
#include "siofile.h" #include "siofile.h"
#include "midi.h" #include "midi.h"
#include "opt.h"
#include "sysex.h" #include "sysex.h"
#include "utils.h" #include "utils.h"
@ -73,11 +74,12 @@ void dev_mmcstop(struct dev *);
void dev_mmcloc(struct dev *, unsigned int); void dev_mmcloc(struct dev *, unsigned int);
void slot_log(struct slot *); void slot_log(struct slot *);
struct slot *slot_new(struct dev *, char *, struct slotops *, void *, int);
void slot_del(struct slot *); void slot_del(struct slot *);
void slot_setvol(struct slot *, unsigned int); void slot_setvol(struct slot *, unsigned int);
void slot_attach(struct slot *); void slot_attach(struct slot *);
void slot_ready(struct slot *); void slot_ready(struct slot *);
void slot_allocbufs(struct slot *);
void slot_freebufs(struct slot *);
void slot_start(struct slot *); void slot_start(struct slot *);
void slot_detach(struct slot *); void slot_detach(struct slot *);
void slot_stop(struct slot *); void slot_stop(struct slot *);
@ -133,9 +135,6 @@ slot_log(struct slot *s)
static char *pstates[] = { static char *pstates[] = {
"ini", "sta", "rdy", "run", "stp", "mid" "ini", "sta", "rdy", "run", "stp", "mid"
}; };
static char *tstates[] = {
"off", "sta", "run", "stp"
};
#endif #endif
log_puts(s->name); log_puts(s->name);
log_putu(s->unit); log_putu(s->unit);
@ -146,8 +145,6 @@ slot_log(struct slot *s)
if (s->ops) { if (s->ops) {
log_puts(",pst="); log_puts(",pst=");
log_puts(pstates[s->pstate]); log_puts(pstates[s->pstate]);
log_puts(",mmc=");
log_puts(tstates[s->tstate]);
} }
} }
#endif #endif
@ -624,11 +621,12 @@ dev_mix_adjvol(struct dev *d)
{ {
unsigned int n; unsigned int n;
struct slot *i, *j; struct slot *i, *j;
int weight; int jcmax, icmax, weight;
for (i = d->slot_list; i != NULL; i = i->next) { for (i = d->slot_list; i != NULL; i = i->next) {
if (!(i->mode & MODE_PLAY)) if (!(i->mode & MODE_PLAY))
continue; continue;
icmax = i->opt->pmin + i->mix.nch - 1;
weight = ADATA_UNIT; weight = ADATA_UNIT;
if (d->autovol) { if (d->autovol) {
/* /*
@ -639,14 +637,15 @@ dev_mix_adjvol(struct dev *d)
for (j = d->slot_list; j != NULL; j = j->next) { for (j = d->slot_list; j != NULL; j = j->next) {
if (!(j->mode & MODE_PLAY)) if (!(j->mode & MODE_PLAY))
continue; continue;
if (i->mix.slot_cmin <= j->mix.slot_cmax && jcmax = j->opt->pmin + j->mix.nch - 1;
i->mix.slot_cmax >= j->mix.slot_cmin) if (i->opt->pmin <= jcmax &&
icmax >= j->opt->pmin)
n++; n++;
} }
weight /= n; weight /= n;
} }
if (weight > i->mix.maxweight) if (weight > i->opt->maxweight)
weight = i->mix.maxweight; weight = i->opt->maxweight;
i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master)); i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master));
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
@ -654,7 +653,7 @@ dev_mix_adjvol(struct dev *d)
log_puts(": set weight: "); log_puts(": set weight: ");
log_puti(i->mix.weight); log_puti(i->mix.weight);
log_puts("/"); log_puts("/");
log_puti(i->mix.maxweight); log_puti(i->opt->maxweight);
log_puts("\n"); log_puts("\n");
} }
#endif #endif
@ -833,15 +832,17 @@ dev_cycle(struct dev *d)
* layer, so s->mix.buf.used == 0 and we can * layer, so s->mix.buf.used == 0 and we can
* destroy the buffer * destroy the buffer
*/ */
s->pstate = SLOT_INIT;
abuf_done(&s->mix.buf);
if (s->mix.decbuf)
xfree(s->mix.decbuf);
if (s->mix.resampbuf)
xfree(s->mix.resampbuf);
s->ops->eof(s->arg);
*ps = s->next; *ps = s->next;
s->pstate = SLOT_INIT;
s->ops->eof(s->arg);
slot_freebufs(s);
dev_mix_adjvol(d); dev_mix_adjvol(d);
#ifdef DEBUG
if (log_level >= 3) {
slot_log(s);
log_puts(": drained\n");
}
#endif
continue; continue;
} }
@ -975,6 +976,7 @@ dev_new(char *path, struct aparams *par,
d = xmalloc(sizeof(struct dev)); d = xmalloc(sizeof(struct dev));
d->path = xstrdup(path); d->path = xstrdup(path);
d->num = dev_sndnum++; d->num = dev_sndnum++;
d->opt_list = NULL;
/* /*
* XXX: below, we allocate a midi input buffer, since we don't * XXX: below, we allocate a midi input buffer, since we don't
@ -1000,7 +1002,6 @@ dev_new(char *path, struct aparams *par,
d->slot[i].unit = i; d->slot[i].unit = i;
d->slot[i].ops = NULL; d->slot[i].ops = NULL;
d->slot[i].vol = MIDI_MAXCTL; d->slot[i].vol = MIDI_MAXCTL;
d->slot[i].tstate = MMC_OFF;
d->slot[i].serial = d->serial++; d->slot[i].serial = d->serial++;
strlcpy(d->slot[i].name, "prog", SLOT_NAMEMAX); strlcpy(d->slot[i].name, "prog", SLOT_NAMEMAX);
} }
@ -1287,6 +1288,8 @@ dev_del(struct dev *d)
log_puts(": deleting\n"); log_puts(": deleting\n");
} }
#endif #endif
while (d->opt_list != NULL)
opt_del(d, d->opt_list);
if (d->pstate != DEV_CFG) if (d->pstate != DEV_CFG)
dev_close(d); dev_close(d);
for (p = &dev_list; *p != d; p = &(*p)->next) { for (p = &dev_list; *p != d; p = &(*p)->next) {
@ -1358,9 +1361,9 @@ dev_sync_attach(struct dev *d)
} }
for (i = 0; i < DEV_NSLOT; i++) { for (i = 0; i < DEV_NSLOT; i++) {
s = d->slot + i; s = d->slot + i;
if (!s->ops || s->tstate == MMC_OFF) if (!s->ops || !s->opt->mmc)
continue; continue;
if (s->tstate != MMC_START || s->pstate != SLOT_READY) { if (s->pstate != SLOT_READY) {
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
slot_log(s); slot_log(s);
@ -1374,18 +1377,10 @@ dev_sync_attach(struct dev *d)
return; return;
for (i = 0; i < DEV_NSLOT; i++) { for (i = 0; i < DEV_NSLOT; i++) {
s = d->slot + i; s = d->slot + i;
if (!s->ops) if (!s->ops || !s->opt->mmc)
continue; continue;
if (s->tstate == MMC_START) { slot_attach(s);
#ifdef DEBUG s->pstate = SLOT_RUN;
if (log_level >= 3) {
slot_log(s);
log_puts(": started\n");
}
#endif
s->tstate = MMC_RUN;
slot_attach(s);
}
} }
d->tstate = MMC_RUN; d->tstate = MMC_RUN;
dev_midi_full(d); dev_midi_full(d);
@ -1455,11 +1450,140 @@ dev_mmcloc(struct dev *d, unsigned int origin)
dev_mmcstart(d); dev_mmcstart(d);
} }
/*
* allocate buffers & conversion chain
*/
void
slot_allocbufs(struct slot *s)
{
unsigned int dev_nch;
struct dev *d = s->dev;
if (s->mode & MODE_PLAY) {
s->mix.bpf = s->par.bps * s->mix.nch;
abuf_init(&s->mix.buf, s->appbufsz * s->mix.bpf);
dev_nch = s->opt->pmax - s->opt->pmin + 1;
s->mix.decbuf = NULL;
s->mix.resampbuf = NULL;
s->mix.join = 1;
s->mix.expand = 1;
if (s->opt->dup) {
if (dev_nch > s->mix.nch)
s->mix.expand = dev_nch / s->mix.nch;
else if (dev_nch < s->mix.nch)
s->mix.join = s->mix.nch / dev_nch;
}
cmap_init(&s->mix.cmap,
s->opt->pmin, s->opt->pmin + s->mix.nch - 1,
s->opt->pmin, s->opt->pmin + s->mix.nch - 1,
0, d->pchan - 1,
s->opt->pmin, s->opt->pmax);
if (!aparams_native(&s->par)) {
dec_init(&s->mix.dec, &s->par, s->mix.nch);
s->mix.decbuf =
xmalloc(s->round * s->mix.nch * sizeof(adata_t));
}
if (s->rate != d->rate) {
resamp_init(&s->mix.resamp, s->round, d->round,
s->mix.nch);
s->mix.resampbuf =
xmalloc(d->round * s->mix.nch * sizeof(adata_t));
}
}
if (s->mode & MODE_RECMASK) {
s->sub.bpf = s->par.bps * s->sub.nch;
abuf_init(&s->sub.buf, s->appbufsz * s->sub.bpf);
dev_nch = s->opt->rmax - s->opt->rmin + 1;
s->sub.encbuf = NULL;
s->sub.resampbuf = NULL;
s->sub.join = 1;
s->sub.expand = 1;
if (s->opt->dup) {
if (dev_nch > s->sub.nch)
s->sub.join = dev_nch / s->sub.nch;
else if (dev_nch < s->sub.nch)
s->sub.expand = s->sub.nch / dev_nch;
}
cmap_init(&s->sub.cmap,
0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
s->opt->rmin, s->opt->rmax,
s->opt->rmin, s->opt->rmin + s->sub.nch - 1,
s->opt->rmin, s->opt->rmin + s->sub.nch - 1);
if (s->rate != d->rate) {
resamp_init(&s->sub.resamp, d->round, s->round,
s->sub.nch);
s->sub.resampbuf =
xmalloc(d->round * s->sub.nch * sizeof(adata_t));
}
if (!aparams_native(&s->par)) {
enc_init(&s->sub.enc, &s->par, s->sub.nch);
s->sub.encbuf =
xmalloc(s->round * s->sub.nch * sizeof(adata_t));
}
/*
* cmap_copy() doesn't write samples in all channels,
* for instance when mono->stereo conversion is
* disabled. So we have to prefill cmap_copy() output
* with silence.
*/
if (s->sub.resampbuf) {
memset(s->sub.resampbuf, 0,
d->round * s->sub.nch * sizeof(adata_t));
} else if (s->sub.encbuf) {
memset(s->sub.encbuf, 0,
s->round * s->sub.nch * sizeof(adata_t));
} else {
memset(s->sub.buf.data, 0,
s->appbufsz * s->sub.nch * sizeof(adata_t));
}
}
#ifdef DEBUG
if (log_level >= 3) {
slot_log(s);
log_puts(": allocated ");
log_putu(s->appbufsz);
log_puts("/");
log_putu(SLOT_BUFSZ(s));
log_puts(" fr buffers\n");
}
#endif
}
/*
* free buffers & conversion chain
*/
void
slot_freebufs(struct slot *s)
{
if (s->mode & MODE_RECMASK) {
abuf_done(&s->sub.buf);
if (s->sub.encbuf)
xfree(s->sub.encbuf);
if (s->sub.resampbuf)
xfree(s->sub.resampbuf);
}
if (s->mode & MODE_PLAY) {
abuf_done(&s->mix.buf);
if (s->mix.decbuf)
xfree(s->mix.decbuf);
if (s->mix.resampbuf)
xfree(s->mix.resampbuf);
}
}
/* /*
* allocate a new slot and register the given call-backs * allocate a new slot and register the given call-backs
*/ */
struct slot * struct slot *
slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode) slot_new(struct dev *d, struct opt *opt, char *who,
struct slotops *ops, void *arg, int mode)
{ {
char *p; char *p;
char name[SLOT_NAMEMAX]; char name[SLOT_NAMEMAX];
@ -1554,6 +1678,17 @@ slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode)
#endif #endif
found: found:
if ((mode & MODE_REC) && (opt->mode & MODE_MON)) {
mode |= MODE_MON;
mode &= ~MODE_REC;
}
if ((mode & opt->mode) != mode) {
if (log_level >= 1) {
slot_log(s);
log_puts(": requested mode not allowed\n");
}
return 0;
}
if (!dev_ref(d)) if (!dev_ref(d))
return NULL; return NULL;
dev_label(d, s - d->slot); dev_label(d, s - d->slot);
@ -1566,29 +1701,34 @@ found:
return 0; return 0;
} }
s->dev = d; s->dev = d;
s->opt = opt;
s->ops = ops; s->ops = ops;
s->arg = arg; s->arg = arg;
s->pstate = SLOT_INIT; s->pstate = SLOT_INIT;
s->tstate = MMC_OFF;
s->mode = mode; s->mode = mode;
aparams_init(&s->par); aparams_init(&s->par);
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY)
s->mix.slot_cmin = s->mix.dev_cmin = 0; s->mix.nch = s->opt->pmax - s->opt->pmin + 1;
s->mix.slot_cmax = s->mix.dev_cmax = d->pchan - 1; if (s->mode & MODE_RECMASK)
} s->sub.nch = s->opt->rmax - s->opt->rmin + 1;
if (s->mode & MODE_RECMASK) { s->xrun = s->opt->mmc ? XRUN_SYNC : XRUN_IGNORE;
s->sub.slot_cmin = s->sub.dev_cmin = 0;
s->sub.slot_cmax = s->sub.dev_cmax =
((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1;
}
s->xrun = XRUN_IGNORE;
s->dup = 0;
s->appbufsz = d->bufsz; s->appbufsz = d->bufsz;
s->round = d->round; s->round = d->round;
s->rate = d->rate; s->rate = d->rate;
s->mix.maxweight = ADATA_UNIT;
dev_midi_slotdesc(d, s); dev_midi_slotdesc(d, s);
dev_midi_vol(d, s); dev_midi_vol(d, s);
#ifdef DEBUG
if (log_level >= 3) {
slot_log(s);
log_puts(": using ");
dev_log(d);
log_puts(".");
log_puts(opt->name);
log_puts(", mode = ");
log_putx(mode);
log_puts("\n");
}
#endif
return s; return s;
} }
@ -1631,8 +1771,6 @@ slot_setvol(struct slot *s, unsigned int vol)
} }
#endif #endif
s->vol = vol; s->vol = vol;
if (s->ops == NULL)
return;
s->mix.vol = MIDI_TO_ADATA(s->vol); s->mix.vol = MIDI_TO_ADATA(s->vol);
} }
@ -1643,7 +1781,6 @@ void
slot_attach(struct slot *s) slot_attach(struct slot *s)
{ {
struct dev *d = s->dev; struct dev *d = s->dev;
unsigned int slot_nch, dev_nch;
long long pos; long long pos;
int startpos; int startpos;
@ -1665,7 +1802,6 @@ slot_attach(struct slot *s)
s->delta = startpos + pos / (int)d->round; s->delta = startpos + pos / (int)d->round;
s->delta_rem = pos % d->round; s->delta_rem = pos % d->round;
s->pstate = SLOT_RUN;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 2) { if (log_level >= 2) {
slot_log(s); slot_log(s);
@ -1691,91 +1827,10 @@ slot_attach(struct slot *s)
#endif #endif
s->next = d->slot_list; s->next = d->slot_list;
d->slot_list = s; d->slot_list = s;
s->skip = 0;
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY) {
slot_nch = s->mix.slot_cmax - s->mix.slot_cmin + 1;
dev_nch = s->mix.dev_cmax - s->mix.dev_cmin + 1;
s->mix.decbuf = NULL;
s->mix.resampbuf = NULL;
s->mix.join = 1;
s->mix.expand = 1;
if (s->dup) {
if (dev_nch > slot_nch)
s->mix.expand = dev_nch / slot_nch;
else if (dev_nch < slot_nch)
s->mix.join = slot_nch / dev_nch;
}
cmap_init(&s->mix.cmap,
s->mix.slot_cmin, s->mix.slot_cmax,
s->mix.slot_cmin, s->mix.slot_cmax,
0, d->pchan - 1,
s->mix.dev_cmin, s->mix.dev_cmax);
if (!aparams_native(&s->par)) {
dec_init(&s->mix.dec, &s->par, slot_nch);
s->mix.decbuf =
xmalloc(s->round * slot_nch * sizeof(adata_t));
}
if (s->rate != d->rate) {
resamp_init(&s->mix.resamp, s->round, d->round,
slot_nch);
s->mix.resampbuf =
xmalloc(d->round * slot_nch * sizeof(adata_t));
}
s->mix.vol = MIDI_TO_ADATA(s->vol); s->mix.vol = MIDI_TO_ADATA(s->vol);
dev_mix_adjvol(d); dev_mix_adjvol(d);
} }
if (s->mode & MODE_RECMASK) {
slot_nch = s->sub.slot_cmax - s->sub.slot_cmin + 1;
dev_nch = s->sub.dev_cmax - s->sub.dev_cmin + 1;
s->sub.encbuf = NULL;
s->sub.resampbuf = NULL;
s->sub.join = 1;
s->sub.expand = 1;
if (s->dup) {
if (dev_nch > slot_nch)
s->sub.join = dev_nch / slot_nch;
else if (dev_nch < slot_nch)
s->sub.expand = slot_nch / dev_nch;
}
cmap_init(&s->sub.cmap,
0, ((s->mode & MODE_MON) ? d->pchan : d->rchan) - 1,
s->sub.dev_cmin, s->sub.dev_cmax,
s->sub.slot_cmin, s->sub.slot_cmax,
s->sub.slot_cmin, s->sub.slot_cmax);
if (s->rate != d->rate) {
resamp_init(&s->sub.resamp, d->round, s->round,
slot_nch);
s->sub.resampbuf =
xmalloc(d->round * slot_nch * sizeof(adata_t));
}
if (!aparams_native(&s->par)) {
enc_init(&s->sub.enc, &s->par, slot_nch);
s->sub.encbuf =
xmalloc(s->round * slot_nch * sizeof(adata_t));
}
/*
* cmap_copy() doesn't write samples in all channels,
* for instance when mono->stereo conversion is
* disabled. So we have to prefill cmap_copy() output
* with silence.
*/
if (s->sub.resampbuf) {
memset(s->sub.resampbuf, 0,
d->round * slot_nch * sizeof(adata_t));
} else if (s->sub.encbuf) {
memset(s->sub.encbuf, 0,
s->round * slot_nch * sizeof(adata_t));
} else {
memset(s->sub.buf.data, 0,
s->appbufsz * slot_nch * sizeof(adata_t));
}
/*
* N-th recorded block is the N-th played block
*/
s->sub.prime = -startpos / (int)s->round;
}
} }
/* /*
@ -1791,12 +1846,11 @@ slot_ready(struct slot *s)
*/ */
if (s->dev->pstate == DEV_CFG) if (s->dev->pstate == DEV_CFG)
return; return;
if (s->tstate == MMC_OFF) if (!s->opt->mmc) {
slot_attach(s); slot_attach(s);
else { s->pstate = SLOT_RUN;
s->tstate = MMC_START; } else
dev_sync_attach(s->dev); dev_sync_attach(s->dev);
}
} }
/* /*
@ -1806,59 +1860,43 @@ slot_ready(struct slot *s)
void void
slot_start(struct slot *s) slot_start(struct slot *s)
{ {
unsigned int bufsz;
#ifdef DEBUG #ifdef DEBUG
struct dev *d = s->dev;
if (s->pstate != SLOT_INIT) { if (s->pstate != SLOT_INIT) {
slot_log(s); slot_log(s);
log_puts(": slot_start: wrong state\n"); log_puts(": slot_start: wrong state\n");
panic(); panic();
} }
#endif
bufsz = s->appbufsz;
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY) {
#ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
slot_log(s); slot_log(s);
log_puts(": playing "); log_puts(": playing ");
aparams_log(&s->par); aparams_log(&s->par);
log_puts(" -> "); log_puts(" -> ");
aparams_log(&d->par); aparams_log(&s->dev->par);
log_puts("\n"); log_puts("\n");
} }
#endif
s->mix.bpf = s->par.bps *
(s->mix.slot_cmax - s->mix.slot_cmin + 1);
abuf_init(&s->mix.buf, bufsz * s->mix.bpf);
} }
if (s->mode & MODE_RECMASK) { if (s->mode & MODE_RECMASK) {
#ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
slot_log(s); slot_log(s);
log_puts(": recording "); log_puts(": recording ");
aparams_log(&s->par); aparams_log(&s->par);
log_puts(" <- "); log_puts(" <- ");
aparams_log(&d->par); aparams_log(&s->dev->par);
log_puts("\n"); log_puts("\n");
}
} }
#endif #endif
s->sub.bpf = s->par.bps * slot_allocbufs(s);
(s->sub.slot_cmax - s->sub.slot_cmin + 1);
abuf_init(&s->sub.buf, bufsz * s->sub.bpf); if (s->mode & MODE_RECMASK) {
/*
* N-th recorded block is the N-th played block
*/
s->sub.prime = -dev_getpos(s->dev) / s->dev->round;
} }
s->mix.weight = MIDI_TO_ADATA(MIDI_MAXCTL); s->skip = 0;
#ifdef DEBUG
if (log_level >= 3) {
slot_log(s);
log_puts(": allocated ");
log_putu(s->appbufsz);
log_puts("/");
log_putu(SLOT_BUFSZ(s));
log_puts(" fr buffers\n");
}
#endif
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY) {
s->pstate = SLOT_START; s->pstate = SLOT_START;
} else { } else {
@ -1891,19 +1929,8 @@ slot_detach(struct slot *s)
#endif #endif
} }
*ps = s->next; *ps = s->next;
if (s->mode & MODE_RECMASK) { if (s->mode & MODE_PLAY)
if (s->sub.encbuf)
xfree(s->sub.encbuf);
if (s->sub.resampbuf)
xfree(s->sub.resampbuf);
}
if (s->mode & MODE_PLAY) {
if (s->mix.decbuf)
xfree(s->mix.decbuf);
if (s->mix.resampbuf)
xfree(s->mix.resampbuf);
dev_mix_adjvol(s->dev); dev_mix_adjvol(s->dev);
}
} }
/* /*
@ -1920,37 +1947,37 @@ slot_stop(struct slot *s)
} }
#endif #endif
if (s->pstate == SLOT_START) { if (s->pstate == SLOT_START) {
if (s->mode & MODE_PLAY) { /*
s->pstate = SLOT_READY; * If in rec-only mode, we're already in the READY or
slot_ready(s); * RUN states. We're here because the play buffer was
} else * not full enough, try to start so it's drained.
s->pstate = SLOT_INIT; */
s->pstate = SLOT_READY;
slot_ready(s);
} }
if (s->mode & MODE_RECMASK)
abuf_done(&s->sub.buf); if (s->pstate == SLOT_RUN) {
if (s->pstate == SLOT_READY) { if (s->mode & MODE_PLAY) {
/*
* Don't detach, dev_cycle() will do it for us
* when the buffer is drained.
*/
s->pstate = SLOT_STOP;
return;
}
slot_detach(s);
} else {
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
slot_log(s); slot_log(s);
log_puts(": not drained (blocked by mmc)\n"); log_puts(": not drained (blocked by mmc)\n");
} }
#endif #endif
if (s->mode & MODE_PLAY)
abuf_done(&s->mix.buf);
s->ops->eof(s->arg);
s->pstate = SLOT_INIT;
} else {
/* s->pstate == SLOT_RUN */
if (s->mode & MODE_PLAY)
s->pstate = SLOT_STOP;
else {
slot_detach(s);
s->pstate = SLOT_INIT;
s->ops->eof(s->arg);
}
} }
if (s->tstate != MMC_OFF)
s->tstate = MMC_STOP; s->pstate = SLOT_INIT;
s->ops->eof(s->arg);
slot_freebufs(s);
} }
void void

View File

@ -44,16 +44,15 @@ struct slot {
struct slotops *ops; /* client callbacks */ struct slotops *ops; /* client callbacks */
struct slot *next; /* next on the play list */ struct slot *next; /* next on the play list */
struct dev *dev; /* device this belongs to */ struct dev *dev; /* device this belongs to */
struct opt *opt; /* config used */
void *arg; /* user data for callbacks */ void *arg; /* user data for callbacks */
struct aparams par; /* socket side params */ struct aparams par; /* socket side params */
struct { struct {
int weight; /* dynamic range */ int weight; /* dynamic range */
int maxweight; /* max dynamic range allowed */
unsigned int vol; /* volume within the vol */ unsigned int vol; /* volume within the vol */
struct abuf buf; /* socket side buffer */ struct abuf buf; /* socket side buffer */
int bpf; /* byte per frame */ int bpf; /* byte per frame */
int slot_cmin, slot_cmax; /* slot source chans */ int nch; /* number of play chans */
int dev_cmin, dev_cmax; /* device destination chans */
struct cmap cmap; /* channel mapper state */ struct cmap cmap; /* channel mapper state */
struct resamp resamp; /* resampler state */ struct resamp resamp; /* resampler state */
struct conv dec; /* format decoder params */ struct conv dec; /* format decoder params */
@ -65,8 +64,7 @@ struct slot {
struct abuf buf; /* socket side buffer */ struct abuf buf; /* socket side buffer */
int prime; /* initial cycles to skip */ int prime; /* initial cycles to skip */
int bpf; /* byte per frame */ int bpf; /* byte per frame */
int slot_cmin, slot_cmax; /* slot destination chans */ int nch; /* number of rec chans */
int dev_cmin, dev_cmax; /* device source chans */
struct cmap cmap; /* channel mapper state */ struct cmap cmap; /* channel mapper state */
struct resamp resamp; /* buffer for resampling */ struct resamp resamp; /* buffer for resampling */
struct conv enc; /* buffer for encoding */ struct conv enc; /* buffer for encoding */
@ -76,7 +74,6 @@ struct slot {
} sub; } sub;
int xrun; /* underrun policy */ int xrun; /* underrun policy */
int skip; /* cycles to skip (for xrun) */ int skip; /* cycles to skip (for xrun) */
int dup; /* mono-to-stereo and alike */
#define SLOT_BUFSZ(s) \ #define SLOT_BUFSZ(s) \
((s)->appbufsz + (s)->dev->bufsz / (s)->dev->round * (s)->round) ((s)->appbufsz + (s)->dev->bufsz / (s)->dev->round * (s)->round)
int appbufsz; /* slot-side buffer size */ int appbufsz; /* slot-side buffer size */
@ -97,7 +94,18 @@ struct slot {
unsigned int unit; /* instance of name */ unsigned int unit; /* instance of name */
unsigned int serial; /* global unique number */ unsigned int serial; /* global unique number */
unsigned int vol; /* current (midi) volume */ unsigned int vol; /* current (midi) volume */
unsigned int tstate; /* mmc state */ };
struct opt {
struct opt *next;
#define OPT_NAMEMAX 11
char name[OPT_NAMEMAX + 1];
int maxweight; /* max dynamic range for clients */
int pmin, pmax; /* play channels */
int rmin, rmax; /* recording channels */
int mmc; /* true if MMC control enabled */
int dup; /* true if join/expand enabled */
int mode; /* bitmap of MODE_XXX */
}; };
/* /*
@ -137,6 +145,7 @@ struct ctlslot {
struct dev { struct dev {
struct dev *next; struct dev *next;
struct slot *slot_list; /* audio streams attached */ struct slot *slot_list; /* audio streams attached */
struct opt *opt_list;
struct midi *midi; struct midi *midi;
/* /*
@ -217,7 +226,6 @@ struct dev {
/* /*
* MIDI machine control (MMC) * MIDI machine control (MMC)
*/ */
#define MMC_OFF 0 /* ignore MMC messages */
#define MMC_STOP 1 /* stopped, can't start */ #define MMC_STOP 1 /* stopped, can't start */
#define MMC_START 2 /* attempting to start */ #define MMC_START 2 /* attempting to start */
#define MMC_RUN 3 /* started */ #define MMC_RUN 3 /* started */
@ -268,7 +276,8 @@ void dev_midi_vol(struct dev *, struct slot *);
* sio_open(3) like interface for clients * sio_open(3) like interface for clients
*/ */
void slot_log(struct slot *); void slot_log(struct slot *);
struct slot *slot_new(struct dev *, char *, struct slotops *, void *, int); struct slot *slot_new(struct dev *, struct opt *, char *,
struct slotops *, void *, int);
void slot_del(struct slot *); void slot_del(struct slot *);
void slot_setvol(struct slot *, unsigned int); void slot_setvol(struct slot *, unsigned int);
void slot_start(struct slot *); void slot_start(struct slot *);

View File

@ -20,13 +20,11 @@
#include "opt.h" #include "opt.h"
#include "utils.h" #include "utils.h"
struct opt *opt_list = NULL;
/* /*
* create a new audio sub-device "configuration" * create a new audio sub-device "configuration"
*/ */
struct opt * struct opt *
opt_new(char *name, struct dev *dev, opt_new(struct dev *d, char *name,
int pmin, int pmax, int rmin, int rmax, int pmin, int pmax, int rmin, int rmax,
int maxweight, int mmc, int dup, unsigned int mode) int maxweight, int mmc, int dup, unsigned int mode)
{ {
@ -34,7 +32,9 @@ opt_new(char *name, struct dev *dev,
unsigned int len; unsigned int len;
char c; char c;
if (opt_byname(name, dev->num)) { if (opt_byname(d, name)) {
dev_log(d);
log_puts(".");
log_puts(name); log_puts(name);
log_puts(": already defined\n"); log_puts(": already defined\n");
return NULL; return NULL;
@ -66,12 +66,11 @@ opt_new(char *name, struct dev *dev,
o->mmc = mmc; o->mmc = mmc;
o->dup = dup; o->dup = dup;
o->mode = mode; o->mode = mode;
o->dev = dev;
memcpy(o->name, name, len + 1); memcpy(o->name, name, len + 1);
o->next = opt_list; o->next = d->opt_list;
opt_list = o; d->opt_list = o;
if (log_level >= 2) { if (log_level >= 2) {
dev_log(o->dev); dev_log(d);
log_puts("."); log_puts(".");
log_puts(o->name); log_puts(o->name);
log_puts(":"); log_puts(":");
@ -107,13 +106,11 @@ opt_new(char *name, struct dev *dev,
} }
struct opt * struct opt *
opt_byname(char *name, unsigned int num) opt_byname(struct dev *d, char *name)
{ {
struct opt *o; struct opt *o;
for (o = opt_list; o != NULL; o = o->next) { for (o = d->opt_list; o != NULL; o = o->next) {
if (o->dev->num != num)
continue;
if (strcmp(name, o->name) == 0) if (strcmp(name, o->name) == 0)
return o; return o;
} }
@ -121,11 +118,11 @@ opt_byname(char *name, unsigned int num)
} }
void void
opt_del(struct opt *o) opt_del(struct dev *d, struct opt *o)
{ {
struct opt **po; struct opt **po;
for (po = &opt_list; *po != o; po = &(*po)->next) { for (po = &d->opt_list; *po != o; po = &(*po)->next) {
#ifdef DEBUG #ifdef DEBUG
if (*po == NULL) { if (*po == NULL) {
log_puts("opt_del: not on list\n"); log_puts("opt_del: not on list\n");

View File

@ -19,24 +19,9 @@
struct dev; struct dev;
struct opt { struct opt *opt_new(struct dev *, char *, int, int, int, int,
struct opt *next;
#define OPT_NAMEMAX 11
char name[OPT_NAMEMAX + 1];
int maxweight; /* max dynamic range for clients */
int pmin, pmax; /* play channels */
int rmin, rmax; /* recording channels */
int mmc; /* true if MMC control enabled */
int dup; /* true if join/expand enabled */
int mode; /* bitmap of MODE_XXX */
struct dev *dev; /* device to which we're attached */
};
extern struct opt *opt_list;
struct opt *opt_new(char *, struct dev *, int, int, int, int,
int, int, int, unsigned int); int, int, int, unsigned int);
void opt_del(struct opt *); void opt_del(struct dev *, struct opt *);
struct opt *opt_byname(char *, unsigned int); struct opt *opt_byname(struct dev *, char *);
#endif /* !defined(OPT_H) */ #endif /* !defined(OPT_H) */

View File

@ -325,7 +325,7 @@ mkopt(char *path, struct dev *d,
{ {
struct opt *o; struct opt *o;
o = opt_new(path, d, pmin, pmax, rmin, rmax, o = opt_new(d, path, pmin, pmax, rmin, rmax,
MIDI_TO_ADATA(vol), mmc, dup, mode); MIDI_TO_ADATA(vol), mmc, dup, mode);
if (o == NULL) if (o == NULL)
return NULL; return NULL;
@ -466,7 +466,7 @@ main(int argc, char **argv)
if (dev_list == NULL) if (dev_list == NULL)
mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol); mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol);
for (d = dev_list; d != NULL; d = d->next) { for (d = dev_list; d != NULL; d = d->next) {
if (opt_byname("default", d->num)) if (opt_byname(d, "default"))
continue; continue;
if (mkopt("default", d, pmin, pmax, rmin, rmax, if (mkopt("default", d, pmin, pmax, rmin, rmax,
mode, vol, mmc, dup) == NULL) mode, vol, mmc, dup) == NULL)
@ -534,8 +534,6 @@ main(int argc, char **argv)
; /* nothing */ ; /* nothing */
midi_done(); midi_done();
while (opt_list != NULL)
opt_del(opt_list);
while (dev_list) while (dev_list)
dev_del(dev_list); dev_del(dev_list);
while (port_list) while (port_list)

View File

@ -285,7 +285,6 @@ sock_new(int fd)
f = xmalloc(sizeof(struct sock)); f = xmalloc(sizeof(struct sock));
f->pstate = SOCK_AUTH; f->pstate = SOCK_AUTH;
f->opt = NULL;
f->slot = NULL; f->slot = NULL;
f->port = NULL; f->port = NULL;
f->midi = NULL; f->midi = NULL;
@ -646,21 +645,18 @@ sock_setpar(struct sock *f)
rchan = 1; rchan = 1;
else if (rchan > NCHAN_MAX) else if (rchan > NCHAN_MAX)
rchan = NCHAN_MAX; rchan = NCHAN_MAX;
s->sub.slot_cmin = f->opt->rmin; s->sub.nch = rchan;
s->sub.slot_cmax = f->opt->rmin + rchan - 1;
s->sub.dev_cmin = f->opt->rmin;
s->sub.dev_cmax = f->opt->rmax;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
sock_log(f); sock_log(f);
log_puts(": recording channels "); log_puts(": recording channels ");
log_putu(s->sub.dev_cmin); log_putu(s->opt->rmin);
log_puts(":"); log_puts(":");
log_putu(s->sub.dev_cmax); log_putu(s->opt->rmax);
log_puts(" -> "); log_puts(" -> ");
log_putu(s->sub.slot_cmin); log_putu(s->opt->rmin);
log_puts(":"); log_puts(":");
log_putu(s->sub.slot_cmax); log_putu(s->opt->rmin + s->sub.nch - 1);
log_puts("\n"); log_puts("\n");
} }
#endif #endif
@ -670,21 +666,18 @@ sock_setpar(struct sock *f)
pchan = 1; pchan = 1;
else if (pchan > NCHAN_MAX) else if (pchan > NCHAN_MAX)
pchan = NCHAN_MAX; pchan = NCHAN_MAX;
s->mix.slot_cmin = f->opt->pmin; s->mix.nch = pchan;
s->mix.slot_cmax = f->opt->pmin + pchan - 1;
s->mix.dev_cmin = f->opt->pmin;
s->mix.dev_cmax = f->opt->pmax;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
sock_log(f); sock_log(f);
log_puts(": playback channels "); log_puts(": playback channels ");
log_putu(s->mix.slot_cmin); log_putu(s->opt->pmin);
log_puts(":"); log_puts(":");
log_putu(s->mix.slot_cmax); log_putu(s->opt->pmin + s->mix.nch - 1);
log_puts(" -> "); log_puts(" -> ");
log_putu(s->mix.dev_cmin); log_putu(s->opt->pmin);
log_puts(":"); log_puts(":");
log_putu(s->mix.dev_cmax); log_putu(s->opt->pmax);
log_puts("\n"); log_puts("\n");
} }
#endif #endif
@ -733,7 +726,7 @@ sock_setpar(struct sock *f)
return 0; return 0;
} }
s->xrun = p->xrun; s->xrun = p->xrun;
if (f->opt->mmc && s->xrun == XRUN_IGNORE) if (s->opt->mmc && s->xrun == XRUN_IGNORE)
s->xrun = XRUN_SYNC; s->xrun = XRUN_SYNC;
#ifdef DEBUG #ifdef DEBUG
if (log_level >= 3) { if (log_level >= 3) {
@ -790,9 +783,9 @@ int
sock_hello(struct sock *f) sock_hello(struct sock *f)
{ {
struct amsg_hello *p = &f->rmsg.u.hello; struct amsg_hello *p = &f->rmsg.u.hello;
struct slot *s;
struct port *c; struct port *c;
struct dev *d; struct dev *d;
struct opt *opt;
unsigned int mode; unsigned int mode;
mode = ntohs(p->mode); mode = ntohs(p->mode);
@ -889,54 +882,16 @@ sock_hello(struct sock *f)
f->ctlsyncpending = 0; f->ctlsyncpending = 0;
return 1; return 1;
} }
f->opt = opt_byname(p->opt, p->devnum); d = dev_bynum(p->devnum);
if (f->opt == NULL) if (d == NULL)
return 0; return 0;
#ifdef DEBUG opt = opt_byname(d, p->opt);
if (log_level >= 3) { if (opt == NULL)
sock_log(f);
log_puts(": using ");
dev_log(f->opt->dev);
log_puts(".");
log_puts(f->opt->name);
log_puts(", mode = ");
log_putx(mode);
log_puts("\n");
}
#endif
if ((mode & MODE_REC) && (f->opt->mode & MODE_MON)) {
mode |= MODE_MON;
mode &= ~MODE_REC;
}
if ((mode & f->opt->mode) != mode) {
if (log_level >= 1) {
sock_log(f);
log_puts(": requested mode not allowed\n");
}
return 0; return 0;
} f->slot = slot_new(d, opt, p->who, &sock_slotops, f, mode);
s = slot_new(f->opt->dev, p->who, &sock_slotops, f, mode); if (f->slot == NULL)
if (s == NULL)
return 0; return 0;
f->midi = NULL; f->midi = NULL;
if (s->mode & MODE_PLAY) {
s->mix.slot_cmin = s->mix.dev_cmin = f->opt->pmin;
s->mix.slot_cmax = s->mix.dev_cmax = f->opt->pmax;
}
if (s->mode & MODE_RECMASK) {
s->sub.slot_cmin = s->sub.dev_cmin = f->opt->rmin;
s->sub.slot_cmax = s->sub.dev_cmax = f->opt->rmax;
}
if (f->opt->mmc) {
s->xrun = XRUN_SYNC;
s->tstate = MMC_STOP;
} else {
s->xrun = XRUN_IGNORE;
s->tstate = MMC_OFF;
}
s->mix.maxweight = f->opt->maxweight;
s->dup = f->opt->dup;
f->slot = s;
return 1; return 1;
} }
@ -1089,15 +1044,15 @@ sock_execmsg(struct sock *f)
aparams_log(&s->par); aparams_log(&s->par);
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY) {
log_puts(", play "); log_puts(", play ");
log_puti(s->mix.slot_cmin); log_puti(s->opt->pmin);
log_puts(":"); log_puts(":");
log_puti(s->mix.slot_cmax); log_puti(s->opt->pmin + s->mix.nch - 1);
} }
if (s->mode & MODE_RECMASK) { if (s->mode & MODE_RECMASK) {
log_puts(", rec "); log_puts(", rec ");
log_puti(s->sub.slot_cmin); log_puti(s->opt->rmin);
log_puts(":"); log_puts(":");
log_puti(s->sub.slot_cmax); log_puti(s->opt->rmin + s->sub.nch - 1);
} }
log_puts(", "); log_puts(", ");
log_putu(s->appbufsz / s->round); log_putu(s->appbufsz / s->round);
@ -1200,14 +1155,10 @@ sock_execmsg(struct sock *f)
m->u.par.sig = s->par.sig; m->u.par.sig = s->par.sig;
m->u.par.le = s->par.le; m->u.par.le = s->par.le;
m->u.par.msb = s->par.msb; m->u.par.msb = s->par.msb;
if (s->mode & MODE_PLAY) { if (s->mode & MODE_PLAY)
m->u.par.pchan = htons(s->mix.slot_cmax - m->u.par.pchan = htons(s->mix.nch);
s->mix.slot_cmin + 1); if (s->mode & MODE_RECMASK)
} m->u.par.rchan = htons(s->sub.nch);
if (s->mode & MODE_RECMASK) {
m->u.par.rchan = htons(s->sub.slot_cmax -
s->sub.slot_cmin + 1);
}
m->u.par.rate = htonl(s->rate); m->u.par.rate = htonl(s->rate);
m->u.par.appbufsz = htonl(s->appbufsz); m->u.par.appbufsz = htonl(s->appbufsz);
m->u.par.bufsz = htonl(SLOT_BUFSZ(s)); m->u.par.bufsz = htonl(SLOT_BUFSZ(s));

View File

@ -19,7 +19,6 @@
#include "amsg.h" #include "amsg.h"
struct opt;
struct file; struct file;
struct slot; struct slot;
struct midi; struct midi;
@ -56,7 +55,6 @@ struct sock {
unsigned int walign; /* align written data to this */ unsigned int walign; /* align written data to this */
unsigned int ralign; /* read data is aligned to this */ unsigned int ralign; /* read data is aligned to this */
int lastvol; /* last volume */ int lastvol; /* last volume */
struct opt *opt; /* "subdevice" definition */
struct slot *slot; /* audio device slot number */ struct slot *slot; /* audio device slot number */
struct midi *midi; /* midi endpoint */ struct midi *midi; /* midi endpoint */
struct port *port; /* midi port */ struct port *port; /* midi port */