diff --git a/examples/rec.c b/examples/rec.c index 326f7f5..0343e44 100644 --- a/examples/rec.c +++ b/examples/rec.c @@ -33,7 +33,8 @@ void usage(void) { 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 @@ -42,7 +43,7 @@ main(int argc, char **argv) int ch; struct sio_hdl *hdl; size_t bufsz; - ssize_t n; + ssize_t n, nbytes; /* * defaults parameters @@ -52,18 +53,19 @@ main(int argc, char **argv) par.bits = 16; par.rchan = 2; par.rate = 48000; + nbytes = -1; - while ((ch = getopt(argc, argv, "r:c:e:b:x:")) != -1) { - switch(ch) { - case 'r': - if (sscanf(optarg, "%u", &par.rate) != 1) { - fprintf(stderr, "%s: bad rate\n", optarg); + while ((ch = getopt(argc, argv, "b:c:e:n:r:x:")) != -1) { + switch (ch) { + case 'b': + if (sscanf(optarg, "%u", &par.appbufsz) != 1) { + fprintf(stderr, "%s: bad buf size\n", optarg); exit(1); } break; case 'c': if (sscanf(optarg, "%u", &par.rchan) != 1) { - fprintf(stderr, "%s: channels number\n", optarg); + fprintf(stderr, "%s: bad channels number\n", optarg); exit(1); } break; @@ -73,9 +75,15 @@ main(int argc, char **argv) exit(1); } break; - case 'b': - if (sscanf(optarg, "%u", &par.appbufsz) != 1) { - fprintf(stderr, "%s: bad buf size\n", optarg); + case 'n': + if (sscanf(optarg, "%zu", &nbytes) != 1) { + 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); } break; @@ -123,12 +131,16 @@ main(int argc, char **argv) fprintf(stderr, "sio_start() failed\n"); exit(1); } - for (;;) { - n = sio_read(hdl, buf, bufsz); + while (nbytes != 0) { + n = bufsz; + if (nbytes >= 0 && n > nbytes) + n = nbytes; + n = sio_read(hdl, buf, n); if (n == 0) { fprintf(stderr, "sio_write: failed\n"); exit(1); } + nbytes -= n; readpos += n; if (tick) { fprintf(stderr, diff --git a/sndiod/dev.c b/sndiod/dev.c index 324a563..252da90 100644 --- a/sndiod/dev.c +++ b/sndiod/dev.c @@ -24,6 +24,7 @@ #include "dsp.h" #include "siofile.h" #include "midi.h" +#include "opt.h" #include "sysex.h" #include "utils.h" @@ -73,11 +74,12 @@ void dev_mmcstop(struct dev *); void dev_mmcloc(struct dev *, unsigned int); void slot_log(struct slot *); -struct slot *slot_new(struct dev *, char *, struct slotops *, void *, int); void slot_del(struct slot *); void slot_setvol(struct slot *, unsigned int); void slot_attach(struct slot *); void slot_ready(struct slot *); +void slot_allocbufs(struct slot *); +void slot_freebufs(struct slot *); void slot_start(struct slot *); void slot_detach(struct slot *); void slot_stop(struct slot *); @@ -133,9 +135,6 @@ slot_log(struct slot *s) static char *pstates[] = { "ini", "sta", "rdy", "run", "stp", "mid" }; - static char *tstates[] = { - "off", "sta", "run", "stp" - }; #endif log_puts(s->name); log_putu(s->unit); @@ -146,8 +145,6 @@ slot_log(struct slot *s) if (s->ops) { log_puts(",pst="); log_puts(pstates[s->pstate]); - log_puts(",mmc="); - log_puts(tstates[s->tstate]); } } #endif @@ -624,11 +621,12 @@ dev_mix_adjvol(struct dev *d) { unsigned int n; struct slot *i, *j; - int weight; + int jcmax, icmax, weight; for (i = d->slot_list; i != NULL; i = i->next) { if (!(i->mode & MODE_PLAY)) continue; + icmax = i->opt->pmin + i->mix.nch - 1; weight = ADATA_UNIT; if (d->autovol) { /* @@ -639,14 +637,15 @@ dev_mix_adjvol(struct dev *d) for (j = d->slot_list; j != NULL; j = j->next) { if (!(j->mode & MODE_PLAY)) continue; - if (i->mix.slot_cmin <= j->mix.slot_cmax && - i->mix.slot_cmax >= j->mix.slot_cmin) + jcmax = j->opt->pmin + j->mix.nch - 1; + if (i->opt->pmin <= jcmax && + icmax >= j->opt->pmin) n++; } weight /= n; } - if (weight > i->mix.maxweight) - weight = i->mix.maxweight; + if (weight > i->opt->maxweight) + weight = i->opt->maxweight; i->mix.weight = ADATA_MUL(weight, MIDI_TO_ADATA(d->master)); #ifdef DEBUG if (log_level >= 3) { @@ -654,7 +653,7 @@ dev_mix_adjvol(struct dev *d) log_puts(": set weight: "); log_puti(i->mix.weight); log_puts("/"); - log_puti(i->mix.maxweight); + log_puti(i->opt->maxweight); log_puts("\n"); } #endif @@ -833,15 +832,17 @@ dev_cycle(struct dev *d) * layer, so s->mix.buf.used == 0 and we can * 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; + s->pstate = SLOT_INIT; + s->ops->eof(s->arg); + slot_freebufs(s); dev_mix_adjvol(d); +#ifdef DEBUG + if (log_level >= 3) { + slot_log(s); + log_puts(": drained\n"); + } +#endif continue; } @@ -975,6 +976,7 @@ dev_new(char *path, struct aparams *par, d = xmalloc(sizeof(struct dev)); d->path = xstrdup(path); d->num = dev_sndnum++; + d->opt_list = NULL; /* * 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].ops = NULL; d->slot[i].vol = MIDI_MAXCTL; - d->slot[i].tstate = MMC_OFF; d->slot[i].serial = d->serial++; strlcpy(d->slot[i].name, "prog", SLOT_NAMEMAX); } @@ -1287,6 +1288,8 @@ dev_del(struct dev *d) log_puts(": deleting\n"); } #endif + while (d->opt_list != NULL) + opt_del(d, d->opt_list); if (d->pstate != DEV_CFG) dev_close(d); 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++) { s = d->slot + i; - if (!s->ops || s->tstate == MMC_OFF) + if (!s->ops || !s->opt->mmc) continue; - if (s->tstate != MMC_START || s->pstate != SLOT_READY) { + if (s->pstate != SLOT_READY) { #ifdef DEBUG if (log_level >= 3) { slot_log(s); @@ -1374,18 +1377,10 @@ dev_sync_attach(struct dev *d) return; for (i = 0; i < DEV_NSLOT; i++) { s = d->slot + i; - if (!s->ops) + if (!s->ops || !s->opt->mmc) continue; - if (s->tstate == MMC_START) { -#ifdef DEBUG - if (log_level >= 3) { - slot_log(s); - log_puts(": started\n"); - } -#endif - s->tstate = MMC_RUN; - slot_attach(s); - } + slot_attach(s); + s->pstate = SLOT_RUN; } d->tstate = MMC_RUN; dev_midi_full(d); @@ -1455,11 +1450,140 @@ dev_mmcloc(struct dev *d, unsigned int origin) 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 */ 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 name[SLOT_NAMEMAX]; @@ -1554,6 +1678,17 @@ slot_new(struct dev *d, char *who, struct slotops *ops, void *arg, int mode) #endif 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)) return NULL; dev_label(d, s - d->slot); @@ -1566,29 +1701,34 @@ found: return 0; } s->dev = d; + s->opt = opt; s->ops = ops; s->arg = arg; s->pstate = SLOT_INIT; - s->tstate = MMC_OFF; s->mode = mode; aparams_init(&s->par); - if (s->mode & MODE_PLAY) { - s->mix.slot_cmin = s->mix.dev_cmin = 0; - s->mix.slot_cmax = s->mix.dev_cmax = d->pchan - 1; - } - if (s->mode & MODE_RECMASK) { - 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; + if (s->mode & MODE_PLAY) + s->mix.nch = s->opt->pmax - s->opt->pmin + 1; + if (s->mode & MODE_RECMASK) + s->sub.nch = s->opt->rmax - s->opt->rmin + 1; + s->xrun = s->opt->mmc ? XRUN_SYNC : XRUN_IGNORE; s->appbufsz = d->bufsz; s->round = d->round; s->rate = d->rate; - s->mix.maxweight = ADATA_UNIT; dev_midi_slotdesc(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; } @@ -1631,8 +1771,6 @@ slot_setvol(struct slot *s, unsigned int vol) } #endif s->vol = vol; - if (s->ops == NULL) - return; s->mix.vol = MIDI_TO_ADATA(s->vol); } @@ -1643,7 +1781,6 @@ void slot_attach(struct slot *s) { struct dev *d = s->dev; - unsigned int slot_nch, dev_nch; long long pos; int startpos; @@ -1665,7 +1802,6 @@ slot_attach(struct slot *s) s->delta = startpos + pos / (int)d->round; s->delta_rem = pos % d->round; - s->pstate = SLOT_RUN; #ifdef DEBUG if (log_level >= 2) { slot_log(s); @@ -1691,91 +1827,10 @@ slot_attach(struct slot *s) #endif s->next = d->slot_list; d->slot_list = s; - s->skip = 0; 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); 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) return; - if (s->tstate == MMC_OFF) + if (!s->opt->mmc) { slot_attach(s); - else { - s->tstate = MMC_START; + s->pstate = SLOT_RUN; + } else dev_sync_attach(s->dev); - } } /* @@ -1806,59 +1860,43 @@ slot_ready(struct slot *s) void slot_start(struct slot *s) { - unsigned int bufsz; #ifdef DEBUG - struct dev *d = s->dev; - - if (s->pstate != SLOT_INIT) { slot_log(s); log_puts(": slot_start: wrong state\n"); panic(); } -#endif - bufsz = s->appbufsz; if (s->mode & MODE_PLAY) { -#ifdef DEBUG if (log_level >= 3) { slot_log(s); log_puts(": playing "); aparams_log(&s->par); log_puts(" -> "); - aparams_log(&d->par); + aparams_log(&s->dev->par); 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) { -#ifdef DEBUG if (log_level >= 3) { slot_log(s); log_puts(": recording "); aparams_log(&s->par); log_puts(" <- "); - aparams_log(&d->par); + aparams_log(&s->dev->par); log_puts("\n"); + } } #endif - s->sub.bpf = s->par.bps * - (s->sub.slot_cmax - s->sub.slot_cmin + 1); - abuf_init(&s->sub.buf, bufsz * s->sub.bpf); + slot_allocbufs(s); + + 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); -#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 + s->skip = 0; + if (s->mode & MODE_PLAY) { s->pstate = SLOT_START; } else { @@ -1891,19 +1929,8 @@ slot_detach(struct slot *s) #endif } *ps = s->next; - if (s->mode & MODE_RECMASK) { - 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); + if (s->mode & MODE_PLAY) dev_mix_adjvol(s->dev); - } } /* @@ -1920,37 +1947,37 @@ slot_stop(struct slot *s) } #endif if (s->pstate == SLOT_START) { - if (s->mode & MODE_PLAY) { - s->pstate = SLOT_READY; - slot_ready(s); - } else - s->pstate = SLOT_INIT; + /* + * If in rec-only mode, we're already in the READY or + * RUN states. We're here because the play buffer was + * not full enough, try to start so it's drained. + */ + s->pstate = SLOT_READY; + slot_ready(s); } - if (s->mode & MODE_RECMASK) - abuf_done(&s->sub.buf); - if (s->pstate == SLOT_READY) { + + if (s->pstate == SLOT_RUN) { + 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 if (log_level >= 3) { slot_log(s); log_puts(": not drained (blocked by mmc)\n"); } #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 diff --git a/sndiod/dev.h b/sndiod/dev.h index 2581434..3ccd695 100644 --- a/sndiod/dev.h +++ b/sndiod/dev.h @@ -44,16 +44,15 @@ struct slot { struct slotops *ops; /* client callbacks */ struct slot *next; /* next on the play list */ struct dev *dev; /* device this belongs to */ + struct opt *opt; /* config used */ void *arg; /* user data for callbacks */ struct aparams par; /* socket side params */ struct { int weight; /* dynamic range */ - int maxweight; /* max dynamic range allowed */ unsigned int vol; /* volume within the vol */ struct abuf buf; /* socket side buffer */ int bpf; /* byte per frame */ - int slot_cmin, slot_cmax; /* slot source chans */ - int dev_cmin, dev_cmax; /* device destination chans */ + int nch; /* number of play chans */ struct cmap cmap; /* channel mapper state */ struct resamp resamp; /* resampler state */ struct conv dec; /* format decoder params */ @@ -65,8 +64,7 @@ struct slot { struct abuf buf; /* socket side buffer */ int prime; /* initial cycles to skip */ int bpf; /* byte per frame */ - int slot_cmin, slot_cmax; /* slot destination chans */ - int dev_cmin, dev_cmax; /* device source chans */ + int nch; /* number of rec chans */ struct cmap cmap; /* channel mapper state */ struct resamp resamp; /* buffer for resampling */ struct conv enc; /* buffer for encoding */ @@ -76,7 +74,6 @@ struct slot { } sub; int xrun; /* underrun policy */ int skip; /* cycles to skip (for xrun) */ - int dup; /* mono-to-stereo and alike */ #define SLOT_BUFSZ(s) \ ((s)->appbufsz + (s)->dev->bufsz / (s)->dev->round * (s)->round) int appbufsz; /* slot-side buffer size */ @@ -97,7 +94,18 @@ struct slot { unsigned int unit; /* instance of name */ unsigned int serial; /* global unique number */ 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 *next; struct slot *slot_list; /* audio streams attached */ + struct opt *opt_list; struct midi *midi; /* @@ -217,7 +226,6 @@ struct dev { /* * MIDI machine control (MMC) */ -#define MMC_OFF 0 /* ignore MMC messages */ #define MMC_STOP 1 /* stopped, can't start */ #define MMC_START 2 /* attempting to start */ #define MMC_RUN 3 /* started */ @@ -268,7 +276,8 @@ void dev_midi_vol(struct dev *, struct slot *); * sio_open(3) like interface for clients */ 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_setvol(struct slot *, unsigned int); void slot_start(struct slot *); diff --git a/sndiod/opt.c b/sndiod/opt.c index bf25d12..53554d8 100644 --- a/sndiod/opt.c +++ b/sndiod/opt.c @@ -20,13 +20,11 @@ #include "opt.h" #include "utils.h" -struct opt *opt_list = NULL; - /* * create a new audio sub-device "configuration" */ 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 maxweight, int mmc, int dup, unsigned int mode) { @@ -34,7 +32,9 @@ opt_new(char *name, struct dev *dev, unsigned int len; char c; - if (opt_byname(name, dev->num)) { + if (opt_byname(d, name)) { + dev_log(d); + log_puts("."); log_puts(name); log_puts(": already defined\n"); return NULL; @@ -66,12 +66,11 @@ opt_new(char *name, struct dev *dev, o->mmc = mmc; o->dup = dup; o->mode = mode; - o->dev = dev; memcpy(o->name, name, len + 1); - o->next = opt_list; - opt_list = o; + o->next = d->opt_list; + d->opt_list = o; if (log_level >= 2) { - dev_log(o->dev); + dev_log(d); log_puts("."); log_puts(o->name); log_puts(":"); @@ -107,13 +106,11 @@ opt_new(char *name, struct dev *dev, } struct opt * -opt_byname(char *name, unsigned int num) +opt_byname(struct dev *d, char *name) { struct opt *o; - for (o = opt_list; o != NULL; o = o->next) { - if (o->dev->num != num) - continue; + for (o = d->opt_list; o != NULL; o = o->next) { if (strcmp(name, o->name) == 0) return o; } @@ -121,11 +118,11 @@ opt_byname(char *name, unsigned int num) } void -opt_del(struct opt *o) +opt_del(struct dev *d, struct opt *o) { struct opt **po; - for (po = &opt_list; *po != o; po = &(*po)->next) { + for (po = &d->opt_list; *po != o; po = &(*po)->next) { #ifdef DEBUG if (*po == NULL) { log_puts("opt_del: not on list\n"); diff --git a/sndiod/opt.h b/sndiod/opt.h index 4380f7a..b4ae622 100644 --- a/sndiod/opt.h +++ b/sndiod/opt.h @@ -19,24 +19,9 @@ struct dev; -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 */ - 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, +struct opt *opt_new(struct dev *, char *, int, int, int, int, int, int, int, unsigned int); -void opt_del(struct opt *); -struct opt *opt_byname(char *, unsigned int); +void opt_del(struct dev *, struct opt *); +struct opt *opt_byname(struct dev *, char *); #endif /* !defined(OPT_H) */ diff --git a/sndiod/sndiod.c b/sndiod/sndiod.c index 8158966..c6acc7c 100644 --- a/sndiod/sndiod.c +++ b/sndiod/sndiod.c @@ -325,7 +325,7 @@ mkopt(char *path, struct dev *d, { 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); if (o == NULL) return NULL; @@ -466,7 +466,7 @@ main(int argc, char **argv) if (dev_list == NULL) mkdev(DEFAULT_DEV, &par, 0, bufsz, round, rate, hold, autovol); for (d = dev_list; d != NULL; d = d->next) { - if (opt_byname("default", d->num)) + if (opt_byname(d, "default")) continue; if (mkopt("default", d, pmin, pmax, rmin, rmax, mode, vol, mmc, dup) == NULL) @@ -534,8 +534,6 @@ main(int argc, char **argv) ; /* nothing */ midi_done(); - while (opt_list != NULL) - opt_del(opt_list); while (dev_list) dev_del(dev_list); while (port_list) diff --git a/sndiod/sock.c b/sndiod/sock.c index 864760b..09c6cc3 100644 --- a/sndiod/sock.c +++ b/sndiod/sock.c @@ -285,7 +285,6 @@ sock_new(int fd) f = xmalloc(sizeof(struct sock)); f->pstate = SOCK_AUTH; - f->opt = NULL; f->slot = NULL; f->port = NULL; f->midi = NULL; @@ -646,21 +645,18 @@ sock_setpar(struct sock *f) rchan = 1; else if (rchan > NCHAN_MAX) rchan = NCHAN_MAX; - s->sub.slot_cmin = f->opt->rmin; - s->sub.slot_cmax = f->opt->rmin + rchan - 1; - s->sub.dev_cmin = f->opt->rmin; - s->sub.dev_cmax = f->opt->rmax; + s->sub.nch = rchan; #ifdef DEBUG if (log_level >= 3) { sock_log(f); log_puts(": recording channels "); - log_putu(s->sub.dev_cmin); + log_putu(s->opt->rmin); log_puts(":"); - log_putu(s->sub.dev_cmax); + log_putu(s->opt->rmax); log_puts(" -> "); - log_putu(s->sub.slot_cmin); + log_putu(s->opt->rmin); log_puts(":"); - log_putu(s->sub.slot_cmax); + log_putu(s->opt->rmin + s->sub.nch - 1); log_puts("\n"); } #endif @@ -670,21 +666,18 @@ sock_setpar(struct sock *f) pchan = 1; else if (pchan > NCHAN_MAX) pchan = NCHAN_MAX; - s->mix.slot_cmin = f->opt->pmin; - s->mix.slot_cmax = f->opt->pmin + pchan - 1; - s->mix.dev_cmin = f->opt->pmin; - s->mix.dev_cmax = f->opt->pmax; + s->mix.nch = pchan; #ifdef DEBUG if (log_level >= 3) { sock_log(f); log_puts(": playback channels "); - log_putu(s->mix.slot_cmin); + log_putu(s->opt->pmin); log_puts(":"); - log_putu(s->mix.slot_cmax); + log_putu(s->opt->pmin + s->mix.nch - 1); log_puts(" -> "); - log_putu(s->mix.dev_cmin); + log_putu(s->opt->pmin); log_puts(":"); - log_putu(s->mix.dev_cmax); + log_putu(s->opt->pmax); log_puts("\n"); } #endif @@ -733,7 +726,7 @@ sock_setpar(struct sock *f) return 0; } s->xrun = p->xrun; - if (f->opt->mmc && s->xrun == XRUN_IGNORE) + if (s->opt->mmc && s->xrun == XRUN_IGNORE) s->xrun = XRUN_SYNC; #ifdef DEBUG if (log_level >= 3) { @@ -790,9 +783,9 @@ int sock_hello(struct sock *f) { struct amsg_hello *p = &f->rmsg.u.hello; - struct slot *s; struct port *c; struct dev *d; + struct opt *opt; unsigned int mode; mode = ntohs(p->mode); @@ -889,54 +882,16 @@ sock_hello(struct sock *f) f->ctlsyncpending = 0; return 1; } - f->opt = opt_byname(p->opt, p->devnum); - if (f->opt == NULL) + d = dev_bynum(p->devnum); + if (d == NULL) return 0; -#ifdef DEBUG - if (log_level >= 3) { - 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"); - } + opt = opt_byname(d, p->opt); + if (opt == NULL) return 0; - } - s = slot_new(f->opt->dev, p->who, &sock_slotops, f, mode); - if (s == NULL) + f->slot = slot_new(d, opt, p->who, &sock_slotops, f, mode); + if (f->slot == NULL) return 0; 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; } @@ -1089,15 +1044,15 @@ sock_execmsg(struct sock *f) aparams_log(&s->par); if (s->mode & MODE_PLAY) { log_puts(", play "); - log_puti(s->mix.slot_cmin); + log_puti(s->opt->pmin); log_puts(":"); - log_puti(s->mix.slot_cmax); + log_puti(s->opt->pmin + s->mix.nch - 1); } if (s->mode & MODE_RECMASK) { log_puts(", rec "); - log_puti(s->sub.slot_cmin); + log_puti(s->opt->rmin); log_puts(":"); - log_puti(s->sub.slot_cmax); + log_puti(s->opt->rmin + s->sub.nch - 1); } log_puts(", "); 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.le = s->par.le; m->u.par.msb = s->par.msb; - if (s->mode & MODE_PLAY) { - m->u.par.pchan = htons(s->mix.slot_cmax - - s->mix.slot_cmin + 1); - } - if (s->mode & MODE_RECMASK) { - m->u.par.rchan = htons(s->sub.slot_cmax - - s->sub.slot_cmin + 1); - } + if (s->mode & MODE_PLAY) + m->u.par.pchan = htons(s->mix.nch); + if (s->mode & MODE_RECMASK) + m->u.par.rchan = htons(s->sub.nch); m->u.par.rate = htonl(s->rate); m->u.par.appbufsz = htonl(s->appbufsz); m->u.par.bufsz = htonl(SLOT_BUFSZ(s)); diff --git a/sndiod/sock.h b/sndiod/sock.h index 892cc49..9e46929 100644 --- a/sndiod/sock.h +++ b/sndiod/sock.h @@ -19,7 +19,6 @@ #include "amsg.h" -struct opt; struct file; struct slot; struct midi; @@ -56,7 +55,6 @@ struct sock { unsigned int walign; /* align written data to this */ unsigned int ralign; /* read data is aligned to this */ int lastvol; /* last volume */ - struct opt *opt; /* "subdevice" definition */ struct slot *slot; /* audio device slot number */ struct midi *midi; /* midi endpoint */ struct port *port; /* midi port */