version 1.56, 2010/05/08 15:35:45 |
version 1.57, 2010/06/04 06:15:28 |
|
|
* |
* |
* From the main loop, the device is used as follows: |
* From the main loop, the device is used as follows: |
* |
* |
* 1. create the device using dev_init_xxx() |
* 1. create the device using dev_new_xxx() |
* 2. call dev_run() in the event loop |
* 2. call dev_run() in the event loop |
* 3. destroy the device using dev_done() |
* 3. destroy the device using dev_del() |
* 4. continue running the event loop to drain |
* 4. continue running the event loop to drain |
* |
* |
* The device is used as follows from aproc context: |
* The device is used as follows from aproc context: |
|
|
#include "dbg.h" |
#include "dbg.h" |
#endif |
#endif |
|
|
/* |
int dev_open(struct dev *); |
* state of the device |
void dev_close(struct dev *); |
*/ |
void dev_start(struct dev *); |
#define DEV_CLOSED 0 /* closed */ |
void dev_stop(struct dev *); |
#define DEV_INIT 1 /* stopped */ |
void dev_clear(struct dev *); |
#define DEV_START 2 /* ready to start */ |
void dev_prime(struct dev *); |
#define DEV_RUN 3 /* started */ |
|
|
|
/* |
struct dev *dev_list = NULL; |
* desired parameters |
|
*/ |
|
unsigned dev_reqmode; /* mode */ |
|
struct aparams dev_reqipar, dev_reqopar; /* parameters */ |
|
unsigned dev_reqbufsz; /* buffer size */ |
|
unsigned dev_reqround; /* block size */ |
|
unsigned dev_reqprime; /* prime play buffer? */ |
|
|
|
/* |
/* |
* actual parameters and runtime state |
|
*/ |
|
char *dev_path; /* sio path */ |
|
unsigned dev_refcnt = 0; /* number of openers */ |
|
unsigned dev_pstate; /* on of DEV_xxx */ |
|
unsigned dev_mode; /* bitmap of MODE_xxx */ |
|
unsigned dev_bufsz, dev_round, dev_rate; |
|
struct aparams dev_ipar, dev_opar; |
|
struct aproc *dev_mix, *dev_sub, *dev_rec, *dev_play, *dev_submon, *dev_mon; |
|
struct aproc *dev_midi; |
|
|
|
void dev_start(void); |
|
void dev_stop(void); |
|
void dev_clear(void); |
|
void dev_prime(void); |
|
|
|
/* |
|
* Create a sndio device |
* Create a sndio device |
*/ |
*/ |
void |
struct dev * |
dev_init_sio(char *path, unsigned mode, |
dev_new_sio(char *path, |
struct aparams *dipar, struct aparams *dopar, |
unsigned mode, struct aparams *dipar, struct aparams *dopar, |
unsigned bufsz, unsigned round) |
unsigned bufsz, unsigned round, unsigned hold, unsigned prime) |
{ |
{ |
dev_path = path; |
struct dev *d; |
dev_reqmode = mode; |
|
|
d = malloc(sizeof(struct dev)); |
|
if (d == NULL) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
|
d->path = path; |
|
d->reqmode = mode; |
if (mode & MODE_PLAY) |
if (mode & MODE_PLAY) |
dev_reqopar = *dopar; |
d->reqopar = *dopar; |
if (mode & MODE_RECMASK) |
if (mode & MODE_RECMASK) |
dev_reqipar = *dipar; |
d->reqipar = *dipar; |
dev_reqbufsz = bufsz; |
d->reqbufsz = bufsz; |
dev_reqround = round; |
d->reqround = round; |
dev_pstate = DEV_CLOSED; |
d->prime = prime; |
|
d->hold = hold; |
|
d->pstate = DEV_CLOSED; |
|
d->next = dev_list; |
|
dev_list = d; |
|
if (d->hold && !dev_open(d)) { |
|
dev_del(d); |
|
return NULL; |
|
} |
|
return d; |
} |
} |
|
|
/* |
/* |
* Create a loopback synchronous device |
* Create a loopback synchronous device |
*/ |
*/ |
void |
struct dev * |
dev_init_loop(struct aparams *dipar, struct aparams *dopar, unsigned bufsz) |
dev_new_loop(struct aparams *dipar, struct aparams *dopar, unsigned bufsz) |
{ |
{ |
struct aparams par; |
struct aparams par; |
unsigned cmin, cmax, rate; |
unsigned cmin, cmax, rate; |
|
struct dev *d; |
|
|
|
d = malloc(sizeof(struct dev)); |
|
if (d == NULL) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin; |
cmin = (dipar->cmin < dopar->cmin) ? dipar->cmin : dopar->cmin; |
cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax; |
cmax = (dipar->cmax > dopar->cmax) ? dipar->cmax : dopar->cmax; |
rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate; |
rate = (dipar->rate > dopar->rate) ? dipar->rate : dopar->rate; |
aparams_init(&par, cmin, cmax, rate); |
aparams_init(&par, cmin, cmax, rate); |
dev_reqipar = par; |
d->reqipar = par; |
dev_reqopar = par; |
d->reqopar = par; |
dev_rate = rate; |
d->rate = rate; |
dev_reqround = (bufsz + 1) / 2; |
d->reqround = (bufsz + 1) / 2; |
dev_reqbufsz = dev_reqround * 2; |
d->reqbufsz = d->reqround * 2; |
dev_reqmode = MODE_PLAY | MODE_REC | MODE_LOOP; |
d->reqmode = MODE_PLAY | MODE_REC | MODE_LOOP; |
dev_pstate = DEV_CLOSED; |
d->pstate = DEV_CLOSED; |
|
d->hold = 0; |
|
d->prime = 0; |
|
d->next = dev_list; |
|
dev_list = d; |
|
return d; |
} |
} |
|
|
/* |
/* |
* Create a MIDI thru box device |
* Create a MIDI thru box device |
*/ |
*/ |
void |
struct dev * |
dev_init_thru(void) |
dev_new_thru(void) |
{ |
{ |
dev_reqmode = 0; |
struct dev *d; |
dev_pstate = DEV_CLOSED; |
|
|
d = malloc(sizeof(struct dev)); |
|
if (d == NULL) { |
|
perror("malloc"); |
|
exit(1); |
|
} |
|
d->reqmode = 0; |
|
d->pstate = DEV_CLOSED; |
|
d->hold = 0; |
|
d->prime = 0; |
|
d->next = dev_list; |
|
dev_list = d; |
|
return d; |
} |
} |
|
|
/* |
/* |
|
|
* monitor, midi control, and any necessary conversions. |
* monitor, midi control, and any necessary conversions. |
*/ |
*/ |
int |
int |
dev_open(void) |
dev_open(struct dev *d) |
{ |
{ |
struct file *f; |
struct file *f; |
struct aparams par; |
struct aparams par; |
|
|
struct abuf *buf; |
struct abuf *buf; |
unsigned siomode; |
unsigned siomode; |
|
|
dev_mode = dev_reqmode; |
d->mode = d->reqmode; |
dev_round = dev_reqround; |
d->round = d->reqround; |
dev_bufsz = dev_reqbufsz; |
d->bufsz = d->reqbufsz; |
dev_ipar = dev_reqipar; |
d->ipar = d->reqipar; |
dev_opar = dev_reqopar; |
d->opar = d->reqopar; |
dev_rec = NULL; |
d->rec = NULL; |
dev_play = NULL; |
d->play = NULL; |
dev_mon = NULL; |
d->mon = NULL; |
dev_submon = NULL; |
d->submon = NULL; |
dev_rate = 0; |
d->rate = 0; |
|
|
/* |
/* |
* If needed, open the device (ie create dev_rec and dev_play) |
* If needed, open the device (ie create dev_rec and dev_play) |
*/ |
*/ |
if ((dev_mode & (MODE_PLAY | MODE_REC)) && !(dev_mode & MODE_LOOP)) { |
if ((d->mode & (MODE_PLAY | MODE_REC)) && !(d->mode & MODE_LOOP)) { |
siomode = dev_mode & (MODE_PLAY | MODE_REC); |
siomode = d->mode & (MODE_PLAY | MODE_REC); |
f = (struct file *)siofile_new(&siofile_ops, |
f = (struct file *)siofile_new(&siofile_ops, |
dev_path, |
d->path, |
&siomode, |
&siomode, |
&dev_ipar, |
&d->ipar, |
&dev_opar, |
&d->opar, |
&dev_bufsz, |
&d->bufsz, |
&dev_round); |
&d->round); |
if (f == NULL) { |
if (f == NULL) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
dbg_puts(dev_path ? dev_path : "default"); |
dbg_puts(d->path ? d->path : "default"); |
dbg_puts(": failed to open audio device\n"); |
dbg_puts(": failed to open audio device\n"); |
} |
} |
#endif |
#endif |
return 0; |
return 0; |
} |
} |
if (!(siomode & MODE_PLAY)) |
if (!(siomode & MODE_PLAY)) |
dev_mode &= ~(MODE_PLAY | MODE_MON); |
d->mode &= ~(MODE_PLAY | MODE_MON); |
if (!(siomode & MODE_REC)) |
if (!(siomode & MODE_REC)) |
dev_mode &= ~MODE_REC; |
d->mode &= ~MODE_REC; |
if ((dev_mode & (MODE_PLAY | MODE_REC)) == 0) { |
if ((d->mode & (MODE_PLAY | MODE_REC)) == 0) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) { |
if (debug_level >= 1) { |
dbg_puts(dev_path ? dev_path : "default"); |
dbg_puts(d->path ? d->path : "default"); |
dbg_puts(": mode not supported by device\n"); |
dbg_puts(": mode not supported by device\n"); |
} |
} |
#endif |
#endif |
return 0; |
return 0; |
} |
} |
dev_rate = dev_mode & MODE_REC ? dev_ipar.rate : dev_opar.rate; |
d->rate = d->mode & MODE_REC ? d->ipar.rate : d->opar.rate; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
if (dev_mode & MODE_REC) { |
if (d->mode & MODE_REC) { |
dbg_puts("hw recording "); |
dbg_puts("hw recording "); |
aparams_dbg(&dev_ipar); |
aparams_dbg(&d->ipar); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
if (dev_mode & MODE_PLAY) { |
if (d->mode & MODE_PLAY) { |
dbg_puts("hw playing "); |
dbg_puts("hw playing "); |
aparams_dbg(&dev_opar); |
aparams_dbg(&d->opar); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
} |
} |
#endif |
#endif |
if (dev_mode & MODE_REC) { |
if (d->mode & MODE_REC) { |
dev_rec = rsio_new(f); |
d->rec = rsio_new(f); |
dev_rec->refs++; |
d->rec->refs++; |
} |
} |
if (dev_mode & MODE_PLAY) { |
if (d->mode & MODE_PLAY) { |
dev_play = wsio_new(f); |
d->play = wsio_new(f); |
dev_play->refs++; |
d->play->refs++; |
} |
} |
} |
} |
|
|
|
|
* Create the midi control end, or a simple thru box |
* Create the midi control end, or a simple thru box |
* if there's no device |
* if there's no device |
*/ |
*/ |
dev_midi = (dev_mode == 0) ? thru_new("thru") : ctl_new("ctl"); |
d->midi = (d->mode == 0) ? thru_new("thru") : ctl_new("ctl", d); |
dev_midi->refs++; |
d->midi->refs++; |
|
|
/* |
/* |
* Create mixer, demuxer and monitor |
* Create mixer, demuxer and monitor |
*/ |
*/ |
if (dev_mode & MODE_PLAY) { |
if (d->mode & MODE_PLAY) { |
dev_mix = mix_new("play", dev_bufsz, dev_round); |
d->mix = mix_new("play", d->bufsz, d->round); |
dev_mix->refs++; |
d->mix->refs++; |
dev_mix->u.mix.ctl = dev_midi; |
d->mix->u.mix.ctl = d->midi; |
} |
} |
if (dev_mode & MODE_REC) { |
if (d->mode & MODE_REC) { |
dev_sub = sub_new("rec", dev_bufsz, dev_round); |
d->sub = sub_new("rec", d->bufsz, d->round); |
dev_sub->refs++; |
d->sub->refs++; |
/* |
/* |
* If not playing, use the record end as clock source |
* If not playing, use the record end as clock source |
*/ |
*/ |
if (!(dev_mode & MODE_PLAY)) |
if (!(d->mode & MODE_PLAY)) |
dev_sub->u.sub.ctl = dev_midi; |
d->sub->u.sub.ctl = d->midi; |
} |
} |
if (dev_mode & MODE_LOOP) { |
if (d->mode & MODE_LOOP) { |
/* |
/* |
* connect mixer out to demuxer in |
* connect mixer out to demuxer in |
*/ |
*/ |
buf = abuf_new(dev_bufsz, &dev_opar); |
buf = abuf_new(d->bufsz, &d->opar); |
aproc_setout(dev_mix, buf); |
aproc_setout(d->mix, buf); |
aproc_setin(dev_sub, buf); |
aproc_setin(d->sub, buf); |
|
|
dev_mix->flags |= APROC_QUIT; |
d->mix->flags |= APROC_QUIT; |
dev_sub->flags |= APROC_QUIT; |
d->sub->flags |= APROC_QUIT; |
dev_rate = dev_opar.rate; |
d->rate = d->opar.rate; |
} |
} |
if (dev_rec) { |
if (d->rec) { |
aparams_init(&par, dev_ipar.cmin, dev_ipar.cmax, dev_rate); |
aparams_init(&par, d->ipar.cmin, d->ipar.cmax, d->rate); |
|
|
/* |
/* |
* Create device <-> demuxer buffer |
* Create device <-> demuxer buffer |
*/ |
*/ |
buf = abuf_new(dev_bufsz, &dev_ipar); |
buf = abuf_new(d->bufsz, &d->ipar); |
aproc_setout(dev_rec, buf); |
aproc_setout(d->rec, buf); |
|
|
/* |
/* |
* Insert a converter, if needed. |
* Insert a converter, if needed. |
*/ |
*/ |
if (!aparams_eqenc(&dev_ipar, &par)) { |
if (!aparams_eqenc(&d->ipar, &par)) { |
conv = dec_new("rec", &dev_ipar); |
conv = dec_new("rec", &d->ipar); |
aproc_setin(conv, buf); |
aproc_setin(conv, buf); |
buf = abuf_new(dev_round, &par); |
buf = abuf_new(d->round, &par); |
aproc_setout(conv, buf); |
aproc_setout(conv, buf); |
} |
} |
dev_ipar = par; |
d->ipar = par; |
aproc_setin(dev_sub, buf); |
aproc_setin(d->sub, buf); |
} |
} |
if (dev_play) { |
if (d->play) { |
aparams_init(&par, dev_opar.cmin, dev_opar.cmax, dev_rate); |
aparams_init(&par, d->opar.cmin, d->opar.cmax, d->rate); |
|
|
/* |
/* |
* Create device <-> mixer buffer |
* Create device <-> mixer buffer |
*/ |
*/ |
buf = abuf_new(dev_bufsz, &dev_opar); |
buf = abuf_new(d->bufsz, &d->opar); |
aproc_setin(dev_play, buf); |
aproc_setin(d->play, buf); |
|
|
/* |
/* |
* Append a converter, if needed. |
* Append a converter, if needed. |
*/ |
*/ |
if (!aparams_eqenc(&par, &dev_opar)) { |
if (!aparams_eqenc(&par, &d->opar)) { |
conv = enc_new("play", &dev_opar); |
conv = enc_new("play", &d->opar); |
aproc_setout(conv, buf); |
aproc_setout(conv, buf); |
buf = abuf_new(dev_round, &par); |
buf = abuf_new(d->round, &par); |
aproc_setin(conv, buf); |
aproc_setin(conv, buf); |
} |
} |
dev_opar = par; |
d->opar = par; |
aproc_setout(dev_mix, buf); |
aproc_setout(d->mix, buf); |
} |
} |
if (dev_mode & MODE_MON) { |
if (d->mode & MODE_MON) { |
dev_mon = mon_new("mon", dev_bufsz); |
d->mon = mon_new("mon", d->bufsz); |
dev_mon->refs++; |
d->mon->refs++; |
buf = abuf_new(dev_bufsz, &dev_opar); |
buf = abuf_new(d->bufsz, &d->opar); |
aproc_setout(dev_mon, buf); |
aproc_setout(d->mon, buf); |
|
|
/* |
/* |
* Append a "sub" to which clients will connect. |
* Append a "sub" to which clients will connect. |
*/ |
*/ |
dev_submon = sub_new("mon", dev_bufsz, dev_round); |
d->submon = sub_new("mon", d->bufsz, d->round); |
dev_submon->refs++; |
d->submon->refs++; |
aproc_setin(dev_submon, buf); |
aproc_setin(d->submon, buf); |
|
|
/* |
/* |
* Attach to the mixer |
* Attach to the mixer |
*/ |
*/ |
dev_mix->u.mix.mon = dev_mon; |
d->mix->u.mix.mon = d->mon; |
dev_mon->refs++; |
d->mon->refs++; |
} |
} |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
if (dev_mode & (MODE_PLAY | MODE_RECMASK)) { |
if (d->mode & (MODE_PLAY | MODE_RECMASK)) { |
dbg_puts("device block size is "); |
dbg_puts("device block size is "); |
dbg_putu(dev_round); |
dbg_putu(d->round); |
dbg_puts(" frames, using "); |
dbg_puts(" frames, using "); |
dbg_putu(dev_bufsz / dev_round); |
dbg_putu(d->bufsz / d->round); |
dbg_puts(" blocks\n"); |
dbg_puts(" blocks\n"); |
} |
} |
} |
} |
#endif |
#endif |
dev_pstate = DEV_INIT; |
d->pstate = DEV_INIT; |
if (dev_reqprime) |
if (d->prime) |
dev_prime(); |
dev_prime(d); |
return 1; |
return 1; |
} |
} |
|
|
|
|
* once both play chain and record chain are gone. |
* once both play chain and record chain are gone. |
*/ |
*/ |
void |
void |
dev_close(void) |
dev_close(struct dev *d) |
{ |
{ |
struct file *f; |
struct file *f; |
|
|
|
|
* if the device is starting, ensure it actually starts |
* if the device is starting, ensure it actually starts |
* so buffers are drained, else clear any buffers |
* so buffers are drained, else clear any buffers |
*/ |
*/ |
switch (dev_pstate) { |
switch (d->pstate) { |
case DEV_START: |
case DEV_START: |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("draining device\n"); |
dbg_puts("draining device\n"); |
#endif |
#endif |
dev_start(); |
dev_start(d); |
break; |
break; |
case DEV_INIT: |
case DEV_INIT: |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("flushing device\n"); |
dbg_puts("flushing device\n"); |
#endif |
#endif |
dev_clear(); |
dev_clear(d); |
break; |
break; |
} |
} |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
dbg_puts("closing device\n"); |
dbg_puts("closing device\n"); |
#endif |
#endif |
|
|
if (dev_mix) { |
if (d->mix) { |
/* |
/* |
* Put the mixer in ``autoquit'' state and generate |
* Put the mixer in ``autoquit'' state and generate |
* EOF on all inputs connected it. Once buffers are |
* EOF on all inputs connected it. Once buffers are |
|
|
* reorder the file_list, we have to restart the loop |
* reorder the file_list, we have to restart the loop |
* after each call to file_eof(). |
* after each call to file_eof(). |
*/ |
*/ |
if (APROC_OK(dev_mix)) |
if (APROC_OK(d->mix)) |
mix_quit(dev_mix); |
mix_quit(d->mix); |
|
|
/* |
/* |
* XXX: handle this in mix_done() |
* XXX: handle this in mix_done() |
*/ |
*/ |
if (APROC_OK(dev_mix->u.mix.mon)) { |
if (APROC_OK(d->mix->u.mix.mon)) { |
dev_mix->u.mix.mon->refs--; |
d->mix->u.mix.mon->refs--; |
aproc_del(dev_mix->u.mix.mon); |
aproc_del(d->mix->u.mix.mon); |
dev_mix->u.mix.mon = NULL; |
d->mix->u.mix.mon = NULL; |
} |
} |
restart_mix: |
restart_mix: |
LIST_FOREACH(f, &file_list, entry) { |
LIST_FOREACH(f, &file_list, entry) { |
if (f->rproc != NULL && |
if (f->rproc != NULL && |
aproc_depend(dev_mix, f->rproc)) { |
aproc_depend(d->mix, f->rproc)) { |
file_eof(f); |
file_eof(f); |
goto restart_mix; |
goto restart_mix; |
} |
} |
} |
} |
} else if (dev_sub || dev_submon) { |
} else if (d->sub || d->submon) { |
/* |
/* |
* Same as above, but since there's no mixer, |
* Same as above, but since there's no mixer, |
* we generate EOF on the record-end of the |
* we generate EOF on the record-end of the |
|
|
restart_sub: |
restart_sub: |
LIST_FOREACH(f, &file_list, entry) { |
LIST_FOREACH(f, &file_list, entry) { |
if (f->rproc != NULL && |
if (f->rproc != NULL && |
(aproc_depend(dev_sub, f->rproc) || |
(aproc_depend(d->sub, f->rproc) || |
aproc_depend(dev_submon, f->rproc))) { |
aproc_depend(d->submon, f->rproc))) { |
file_eof(f); |
file_eof(f); |
goto restart_sub; |
goto restart_sub; |
} |
} |
} |
} |
} |
} |
if (dev_midi) { |
if (d->midi) { |
dev_midi->flags |= APROC_QUIT; |
d->midi->flags |= APROC_QUIT; |
if (LIST_EMPTY(&dev_midi->ins)) |
if (LIST_EMPTY(&d->midi->ins)) |
aproc_del(dev_midi); |
aproc_del(d->midi); |
restart_midi: |
restart_midi: |
LIST_FOREACH(f, &file_list, entry) { |
LIST_FOREACH(f, &file_list, entry) { |
if (f->rproc && |
if (f->rproc && |
aproc_depend(dev_midi, f->rproc)) { |
aproc_depend(d->midi, f->rproc)) { |
file_eof(f); |
file_eof(f); |
goto restart_midi; |
goto restart_midi; |
} |
} |
} |
} |
} |
} |
if (dev_mix) { |
if (d->mix) { |
if (--dev_mix->refs == 0 && (dev_mix->flags & APROC_ZOMB)) |
if (--d->mix->refs == 0 && (d->mix->flags & APROC_ZOMB)) |
aproc_del(dev_mix); |
aproc_del(d->mix); |
dev_mix = NULL; |
d->mix = NULL; |
} |
} |
if (dev_play) { |
if (d->play) { |
if (--dev_play->refs == 0 && (dev_play->flags & APROC_ZOMB)) |
if (--d->play->refs == 0 && (d->play->flags & APROC_ZOMB)) |
aproc_del(dev_play); |
aproc_del(d->play); |
dev_play = NULL; |
d->play = NULL; |
} |
} |
if (dev_sub) { |
if (d->sub) { |
if (--dev_sub->refs == 0 && (dev_sub->flags & APROC_ZOMB)) |
if (--d->sub->refs == 0 && (d->sub->flags & APROC_ZOMB)) |
aproc_del(dev_sub); |
aproc_del(d->sub); |
dev_sub = NULL; |
d->sub = NULL; |
} |
} |
if (dev_rec) { |
if (d->rec) { |
if (--dev_rec->refs == 0 && (dev_rec->flags & APROC_ZOMB)) |
if (--d->rec->refs == 0 && (d->rec->flags & APROC_ZOMB)) |
aproc_del(dev_rec); |
aproc_del(d->rec); |
dev_rec = NULL; |
d->rec = NULL; |
} |
} |
if (dev_submon) { |
if (d->submon) { |
if (--dev_submon->refs == 0 && (dev_submon->flags & APROC_ZOMB)) |
if (--d->submon->refs == 0 && (d->submon->flags & APROC_ZOMB)) |
aproc_del(dev_submon); |
aproc_del(d->submon); |
dev_submon = NULL; |
d->submon = NULL; |
} |
} |
if (dev_mon) { |
if (d->mon) { |
if (--dev_mon->refs == 0 && (dev_mon->flags & APROC_ZOMB)) |
if (--d->mon->refs == 0 && (d->mon->flags & APROC_ZOMB)) |
aproc_del(dev_mon); |
aproc_del(d->mon); |
dev_mon = NULL; |
d->mon = NULL; |
} |
} |
if (dev_midi) { |
if (d->midi) { |
if (--dev_midi->refs == 0 && (dev_midi->flags & APROC_ZOMB)) |
if (--d->midi->refs == 0 && (d->midi->flags & APROC_ZOMB)) |
aproc_del(dev_midi); |
aproc_del(d->midi); |
dev_midi = NULL; |
d->midi = NULL; |
} |
} |
dev_pstate = DEV_CLOSED; |
d->pstate = DEV_CLOSED; |
} |
} |
|
|
/* |
/* |
* Free the device |
* Free the device |
*/ |
*/ |
void |
void |
dev_done(void) |
dev_del(struct dev *d) |
{ |
{ |
if (dev_pstate != DEV_CLOSED) |
struct dev **p; |
dev_close(); |
|
|
if (d->pstate != DEV_CLOSED) |
|
dev_close(d); |
|
for (p = &dev_list; *p != d; p = &(*p)->next) { |
|
#ifdef DEBUG |
|
if (*p == NULL) { |
|
dbg_puts("device to delete not on the list\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
|
} |
|
*p = d->next; |
|
free(d); |
} |
} |
|
|
/* |
/* |
* Open a MIDI device and connect it to the thru box |
* Open a MIDI device and connect it to the thru box |
*/ |
*/ |
int |
int |
dev_thruadd(char *name, int in, int out) |
dev_thruadd(struct dev *d, char *name, int in, int out) |
{ |
{ |
struct file *f; |
struct file *f; |
struct abuf *rbuf = NULL, *wbuf = NULL; |
struct abuf *rbuf = NULL, *wbuf = NULL; |
struct aproc *rproc, *wproc; |
struct aproc *rproc, *wproc; |
|
|
if (!dev_ref()) |
if (!dev_ref(d)) |
return 0; |
return 0; |
f = (struct file *)miofile_new(&miofile_ops, name, in, out); |
f = (struct file *)miofile_new(&miofile_ops, name, in, out); |
if (f == NULL) |
if (f == NULL) |
|
|
wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
aproc_setin(wproc, wbuf); |
aproc_setin(wproc, wbuf); |
} |
} |
dev_midiattach(rbuf, wbuf); |
dev_midiattach(d, rbuf, wbuf); |
return 1; |
return 1; |
} |
} |
|
|
|
|
* Attach a bi-directional MIDI stream to the MIDI device |
* Attach a bi-directional MIDI stream to the MIDI device |
*/ |
*/ |
void |
void |
dev_midiattach(struct abuf *ibuf, struct abuf *obuf) |
dev_midiattach(struct dev *d, struct abuf *ibuf, struct abuf *obuf) |
{ |
{ |
if (ibuf) |
if (ibuf) |
aproc_setin(dev_midi, ibuf); |
aproc_setin(d->midi, ibuf); |
if (obuf) { |
if (obuf) { |
aproc_setout(dev_midi, obuf); |
aproc_setout(d->midi, obuf); |
if (ibuf) { |
if (ibuf) { |
ibuf->duplex = obuf; |
ibuf->duplex = obuf; |
obuf->duplex = ibuf; |
obuf->duplex = ibuf; |
|
|
} |
} |
|
|
unsigned |
unsigned |
dev_roundof(unsigned newrate) |
dev_roundof(struct dev *d, unsigned newrate) |
{ |
{ |
return (dev_round * newrate + dev_rate / 2) / dev_rate; |
return (d->round * newrate + d->rate / 2) / d->rate; |
} |
} |
|
|
/* |
/* |
* Start the (paused) device. By default it's paused. |
* Start the (paused) device. By default it's paused. |
*/ |
*/ |
void |
void |
dev_start(void) |
dev_start(struct dev *d) |
{ |
{ |
struct file *f; |
struct file *f; |
|
|
|
|
if (debug_level >= 2) |
if (debug_level >= 2) |
dbg_puts("starting device\n"); |
dbg_puts("starting device\n"); |
#endif |
#endif |
dev_pstate = DEV_RUN; |
d->pstate = DEV_RUN; |
if (dev_mode & MODE_LOOP) |
if (d->mode & MODE_LOOP) |
return; |
return; |
if (APROC_OK(dev_mix)) |
if (APROC_OK(d->mix)) |
dev_mix->flags |= APROC_DROP; |
d->mix->flags |= APROC_DROP; |
if (APROC_OK(dev_sub)) |
if (APROC_OK(d->sub)) |
dev_sub->flags |= APROC_DROP; |
d->sub->flags |= APROC_DROP; |
if (APROC_OK(dev_submon)) |
if (APROC_OK(d->submon)) |
dev_submon->flags |= APROC_DROP; |
d->submon->flags |= APROC_DROP; |
if (APROC_OK(dev_play) && dev_play->u.io.file) { |
if (APROC_OK(d->play) && d->play->u.io.file) { |
f = dev_play->u.io.file; |
f = d->play->u.io.file; |
f->ops->start(f); |
f->ops->start(f); |
} else if (APROC_OK(dev_rec) && dev_rec->u.io.file) { |
} else if (APROC_OK(d->rec) && d->rec->u.io.file) { |
f = dev_rec->u.io.file; |
f = d->rec->u.io.file; |
f->ops->start(f); |
f->ops->start(f); |
} |
} |
} |
} |
|
|
* so it shouldn't be called from aproc methods |
* so it shouldn't be called from aproc methods |
*/ |
*/ |
void |
void |
dev_stop(void) |
dev_stop(struct dev *d) |
{ |
{ |
struct file *f; |
struct file *f; |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) |
if (debug_level >= 2) |
dbg_puts("stopping stopped\n"); |
dbg_puts("device stopped\n"); |
#endif |
#endif |
dev_pstate = DEV_INIT; |
d->pstate = DEV_INIT; |
if (dev_mode & MODE_LOOP) |
if (d->mode & MODE_LOOP) |
return; |
return; |
if (APROC_OK(dev_play) && dev_play->u.io.file) { |
if (APROC_OK(d->play) && d->play->u.io.file) { |
f = dev_play->u.io.file; |
f = d->play->u.io.file; |
f->ops->stop(f); |
f->ops->stop(f); |
} else if (APROC_OK(dev_rec) && dev_rec->u.io.file) { |
} else if (APROC_OK(d->rec) && d->rec->u.io.file) { |
f = dev_rec->u.io.file; |
f = d->rec->u.io.file; |
f->ops->stop(f); |
f->ops->stop(f); |
} |
} |
if (APROC_OK(dev_mix)) |
if (APROC_OK(d->mix)) |
dev_mix->flags &= ~APROC_DROP; |
d->mix->flags &= ~APROC_DROP; |
if (APROC_OK(dev_sub)) |
if (APROC_OK(d->sub)) |
dev_sub->flags &= ~APROC_DROP; |
d->sub->flags &= ~APROC_DROP; |
if (APROC_OK(dev_submon)) |
if (APROC_OK(d->submon)) |
dev_submon->flags &= ~APROC_DROP; |
d->submon->flags &= ~APROC_DROP; |
} |
} |
|
|
int |
int |
dev_ref(void) |
dev_ref(struct dev *d) |
{ |
{ |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("device requested\n"); |
dbg_puts("device requested\n"); |
#endif |
#endif |
if (dev_pstate == DEV_CLOSED && !dev_open()) |
if (d->pstate == DEV_CLOSED && !dev_open(d)) { |
|
if (d->hold) |
|
dev_del(d); |
return 0; |
return 0; |
dev_refcnt++; |
} |
|
d->refcnt++; |
return 1; |
return 1; |
} |
} |
|
|
void |
void |
dev_unref(void) |
dev_unref(struct dev *d) |
{ |
{ |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("device released\n"); |
dbg_puts("device released\n"); |
#endif |
#endif |
dev_refcnt--; |
d->refcnt--; |
if (dev_refcnt == 0 && dev_pstate == DEV_INIT) |
if (d->refcnt == 0 && d->pstate == DEV_INIT && !d->hold) |
dev_close(); |
dev_close(d); |
} |
} |
|
|
/* |
/* |
|
|
* on fatal error |
* on fatal error |
*/ |
*/ |
int |
int |
dev_run(void) |
dev_run(struct dev *d) |
{ |
{ |
if (dev_pstate == DEV_CLOSED) |
if (d->pstate == DEV_CLOSED) |
return 1; |
return 1; |
/* |
/* |
* check if device isn't gone |
* check if device isn't gone |
*/ |
*/ |
if (((dev_mode & MODE_PLAY) && !APROC_OK(dev_mix)) || |
if (((d->mode & MODE_PLAY) && !APROC_OK(d->mix)) || |
((dev_mode & MODE_REC) && !APROC_OK(dev_sub)) || |
((d->mode & MODE_REC) && !APROC_OK(d->sub)) || |
((dev_mode & MODE_MON) && !APROC_OK(dev_submon))) { |
((d->mode & MODE_MON) && !APROC_OK(d->submon))) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 1) |
if (debug_level >= 1) |
dbg_puts("device disappeared\n"); |
dbg_puts("device disappeared\n"); |
#endif |
#endif |
dev_close(); |
if (d->hold) { |
return 0; |
dev_del(d); |
|
return 0; |
|
} |
|
dev_close(d); |
|
return 1; |
} |
} |
switch (dev_pstate) { |
switch (d->pstate) { |
case DEV_INIT: |
case DEV_INIT: |
/* nothing */ |
/* nothing */ |
break; |
break; |
case DEV_START: |
case DEV_START: |
dev_start(); |
dev_start(d); |
/* PASSTHROUGH */ |
/* PASSTHROUGH */ |
case DEV_RUN: |
case DEV_RUN: |
/* |
/* |
* if the device is not used, then stop it |
* if the device is not used, then stop it |
*/ |
*/ |
if ((!APROC_OK(dev_mix) || |
if ((!APROC_OK(d->mix) || |
dev_mix->u.mix.idle > 2 * dev_bufsz) && |
d->mix->u.mix.idle > 2 * d->bufsz) && |
(!APROC_OK(dev_sub) || |
(!APROC_OK(d->sub) || |
dev_sub->u.sub.idle > 2 * dev_bufsz) && |
d->sub->u.sub.idle > 2 * d->bufsz) && |
(!APROC_OK(dev_submon) || |
(!APROC_OK(d->submon) || |
dev_submon->u.sub.idle > 2 * dev_bufsz) && |
d->submon->u.sub.idle > 2 * d->bufsz) && |
(!APROC_OK(dev_midi) || |
(!APROC_OK(d->midi) || |
dev_midi->u.ctl.tstate != CTL_RUN)) { |
d->midi->u.ctl.tstate != CTL_RUN)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("device idle, suspending\n"); |
dbg_puts("device idle, suspending\n"); |
#endif |
#endif |
dev_stop(); |
dev_stop(d); |
if (dev_refcnt == 0) |
if (d->refcnt == 0 && !d->hold) |
dev_close(); |
dev_close(d); |
else { |
else { |
dev_clear(); |
dev_clear(d); |
if (dev_reqprime) |
if (d->prime) |
dev_prime(); |
dev_prime(d); |
} |
} |
} |
} |
break; |
break; |
|
|
* This routine can be called from aproc context. |
* This routine can be called from aproc context. |
*/ |
*/ |
void |
void |
dev_wakeup(void) |
dev_wakeup(struct dev *d) |
{ |
{ |
if (dev_pstate == DEV_INIT) |
if (d->pstate == DEV_INIT) |
dev_pstate = DEV_START; |
d->pstate = DEV_START; |
} |
} |
|
|
/* |
/* |
* Find the end points connected to the mix/sub. |
* Find the end points connected to the mix/sub. |
*/ |
*/ |
int |
int |
dev_getep(unsigned mode, struct abuf **sibuf, struct abuf **sobuf) |
dev_getep(struct dev *d, |
|
unsigned mode, struct abuf **sibuf, struct abuf **sobuf) |
{ |
{ |
struct abuf *ibuf, *obuf; |
struct abuf *ibuf, *obuf; |
|
|
if (mode & MODE_PLAY) { |
if (mode & MODE_PLAY) { |
if (!APROC_OK(dev_mix)) |
if (!APROC_OK(d->mix)) |
return 0; |
return 0; |
ibuf = *sibuf; |
ibuf = *sibuf; |
for (;;) { |
for (;;) { |
|
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
if (ibuf->rproc == dev_mix) |
if (ibuf->rproc == d->mix) |
break; |
break; |
ibuf = LIST_FIRST(&ibuf->rproc->outs); |
ibuf = LIST_FIRST(&ibuf->rproc->outs); |
} |
} |
*sibuf = ibuf; |
*sibuf = ibuf; |
} |
} |
if (mode & MODE_REC) { |
if (mode & MODE_REC) { |
if (!APROC_OK(dev_sub)) |
if (!APROC_OK(d->sub)) |
return 0; |
return 0; |
obuf = *sobuf; |
obuf = *sobuf; |
for (;;) { |
for (;;) { |
|
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
if (obuf->wproc == dev_sub) |
if (obuf->wproc == d->sub) |
break; |
break; |
obuf = LIST_FIRST(&obuf->wproc->ins); |
obuf = LIST_FIRST(&obuf->wproc->ins); |
} |
} |
*sobuf = obuf; |
*sobuf = obuf; |
} |
} |
if (mode & MODE_MON) { |
if (mode & MODE_MON) { |
if (!APROC_OK(dev_submon)) |
if (!APROC_OK(d->submon)) |
return 0; |
return 0; |
obuf = *sobuf; |
obuf = *sobuf; |
for (;;) { |
for (;;) { |
|
|
#endif |
#endif |
return 0; |
return 0; |
} |
} |
if (obuf->wproc == dev_submon) |
if (obuf->wproc == d->submon) |
break; |
break; |
obuf = LIST_FIRST(&obuf->wproc->ins); |
obuf = LIST_FIRST(&obuf->wproc->ins); |
} |
} |
|
|
* them underruns/overruns). |
* them underruns/overruns). |
*/ |
*/ |
void |
void |
dev_sync(unsigned mode, struct abuf *ibuf, struct abuf *obuf) |
dev_sync(struct dev *d, unsigned mode, struct abuf *ibuf, struct abuf *obuf) |
{ |
{ |
int delta, offs; |
int delta, offs; |
struct abuf *mbuf; |
struct abuf *mbuf = NULL; |
|
|
if (!dev_getep(mode, &ibuf, &obuf)) |
if (!dev_getep(d, mode, &ibuf, &obuf)) |
return; |
return; |
/* |
/* |
* Calculate delta, the number of frames the play chain is ahead |
* Calculate delta, the number of frames the play chain is ahead |
|
|
*/ |
*/ |
offs = 0; |
offs = 0; |
delta = 0; |
delta = 0; |
if (APROC_OK(dev_mix)) { |
if (APROC_OK(d->mix)) { |
mbuf = LIST_FIRST(&dev_mix->outs); |
mbuf = LIST_FIRST(&d->mix->outs); |
offs += mbuf->w.mix.todo; |
offs += mbuf->w.mix.todo; |
delta += dev_mix->u.mix.lat; |
delta += d->mix->u.mix.lat; |
} |
} |
if (APROC_OK(dev_sub)) |
if (APROC_OK(d->sub)) |
delta += dev_sub->u.sub.lat; |
delta += d->sub->u.sub.lat; |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
dbg_puts("syncing device"); |
dbg_puts("syncing device"); |
if (APROC_OK(dev_mix)) { |
if (APROC_OK(d->mix)) { |
dbg_puts(", "); |
dbg_puts(", "); |
aproc_dbg(dev_mix); |
aproc_dbg(d->mix); |
dbg_puts(": todo = "); |
dbg_puts(": todo = "); |
dbg_putu(mbuf->w.mix.todo); |
dbg_putu(mbuf->w.mix.todo); |
dbg_puts(": lat = "); |
dbg_puts(": lat = "); |
dbg_putu(dev_mix->u.mix.lat); |
dbg_putu(d->mix->u.mix.lat); |
} |
} |
if (APROC_OK(dev_sub)) { |
if (APROC_OK(d->sub)) { |
dbg_puts(", "); |
dbg_puts(", "); |
aproc_dbg(dev_sub); |
aproc_dbg(d->sub); |
dbg_puts(": lat = "); |
dbg_puts(": lat = "); |
dbg_putu(dev_sub->u.sub.lat); |
dbg_putu(d->sub->u.sub.lat); |
} |
} |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
|
|
* a stream would have if dev_attach() is called on it. |
* a stream would have if dev_attach() is called on it. |
*/ |
*/ |
int |
int |
dev_getpos(void) |
dev_getpos(struct dev *d) |
{ |
{ |
struct abuf *mbuf = NULL; |
struct abuf *mbuf = NULL; |
|
|
if (APROC_OK(dev_mix)) { |
if (APROC_OK(d->mix)) { |
mbuf = LIST_FIRST(&dev_mix->outs); |
mbuf = LIST_FIRST(&d->mix->outs); |
return -(mbuf->w.mix.todo + dev_mix->u.mix.lat); |
return -(mbuf->w.mix.todo + d->mix->u.mix.lat); |
} else |
} else |
return 0; |
return 0; |
} |
} |
|
|
* and rec. |
* and rec. |
*/ |
*/ |
void |
void |
dev_attach(char *name, unsigned mode, |
dev_attach(struct dev *d, char *name, unsigned mode, |
struct abuf *ibuf, struct aparams *sipar, unsigned inch, |
struct abuf *ibuf, struct aparams *sipar, unsigned inch, |
struct abuf *obuf, struct aparams *sopar, unsigned onch, |
struct abuf *obuf, struct aparams *sopar, unsigned onch, |
unsigned xrun, int vol) |
unsigned xrun, int vol) |
|
|
unsigned round, nblk, nch; |
unsigned round, nblk, nch; |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if ((!APROC_OK(dev_mix) && (mode & MODE_PLAY)) || |
if ((!APROC_OK(d->mix) && (mode & MODE_PLAY)) || |
(!APROC_OK(dev_sub) && (mode & MODE_REC)) || |
(!APROC_OK(d->sub) && (mode & MODE_REC)) || |
(!APROC_OK(dev_submon) && (mode & MODE_MON))) { |
(!APROC_OK(d->submon) && (mode & MODE_MON))) { |
dbg_puts("mode beyond device mode, not attaching\n"); |
dbg_puts("mode beyond device mode, not attaching\n"); |
return; |
return; |
} |
} |
#endif |
#endif |
if (mode & MODE_PLAY) { |
if (mode & MODE_PLAY) { |
ipar = *sipar; |
ipar = *sipar; |
pbuf = LIST_FIRST(&dev_mix->outs); |
pbuf = LIST_FIRST(&d->mix->outs); |
nblk = (dev_bufsz / dev_round + 3) / 4; |
nblk = (d->bufsz / d->round + 3) / 4; |
round = dev_roundof(ipar.rate); |
round = dev_roundof(d, ipar.rate); |
nch = ipar.cmax - ipar.cmin + 1; |
nch = ipar.cmax - ipar.cmin + 1; |
if (!aparams_eqenc(&ipar, &dev_opar)) { |
if (!aparams_eqenc(&ipar, &d->opar)) { |
conv = dec_new(name, &ipar); |
conv = dec_new(name, &ipar); |
ipar.bps = dev_opar.bps; |
ipar.bps = d->opar.bps; |
ipar.bits = dev_opar.bits; |
ipar.bits = d->opar.bits; |
ipar.sig = dev_opar.sig; |
ipar.sig = d->opar.sig; |
ipar.le = dev_opar.le; |
ipar.le = d->opar.le; |
ipar.msb = dev_opar.msb; |
ipar.msb = d->opar.msb; |
aproc_setin(conv, ibuf); |
aproc_setin(conv, ibuf); |
ibuf = abuf_new(nblk * round, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
|
|
ibuf = abuf_new(nblk * round, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
} |
} |
if (!aparams_eqrate(&ipar, &dev_opar)) { |
if (!aparams_eqrate(&ipar, &d->opar)) { |
conv = resamp_new(name, round, dev_round); |
conv = resamp_new(name, round, d->round); |
ipar.rate = dev_opar.rate; |
ipar.rate = d->opar.rate; |
round = dev_round; |
round = d->round; |
aproc_setin(conv, ibuf); |
aproc_setin(conv, ibuf); |
ibuf = abuf_new(nblk * round, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
|
|
ibuf = abuf_new(nblk * round, &ipar); |
ibuf = abuf_new(nblk * round, &ipar); |
aproc_setout(conv, ibuf); |
aproc_setout(conv, ibuf); |
} |
} |
aproc_setin(dev_mix, ibuf); |
aproc_setin(d->mix, ibuf); |
ibuf->r.mix.xrun = xrun; |
ibuf->r.mix.xrun = xrun; |
ibuf->r.mix.maxweight = vol; |
ibuf->r.mix.maxweight = vol; |
mix_setmaster(dev_mix); |
mix_setmaster(d->mix); |
} |
} |
if (mode & MODE_REC) { |
if (mode & MODE_REC) { |
opar = *sopar; |
opar = *sopar; |
rbuf = LIST_FIRST(&dev_sub->ins); |
rbuf = LIST_FIRST(&d->sub->ins); |
round = dev_roundof(opar.rate); |
round = dev_roundof(d, opar.rate); |
nblk = (dev_bufsz / dev_round + 3) / 4; |
nblk = (d->bufsz / d->round + 3) / 4; |
nch = opar.cmax - opar.cmin + 1; |
nch = opar.cmax - opar.cmin + 1; |
if (!aparams_eqenc(&opar, &dev_ipar)) { |
if (!aparams_eqenc(&opar, &d->ipar)) { |
conv = enc_new(name, &opar); |
conv = enc_new(name, &opar); |
opar.bps = dev_ipar.bps; |
opar.bps = d->ipar.bps; |
opar.bits = dev_ipar.bits; |
opar.bits = d->ipar.bits; |
opar.sig = dev_ipar.sig; |
opar.sig = d->ipar.sig; |
opar.le = dev_ipar.le; |
opar.le = d->ipar.le; |
opar.msb = dev_ipar.msb; |
opar.msb = d->ipar.msb; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
|
|
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
if (!aparams_eqrate(&opar, &dev_ipar)) { |
if (!aparams_eqrate(&opar, &d->ipar)) { |
conv = resamp_new(name, dev_round, round); |
conv = resamp_new(name, d->round, round); |
opar.rate = dev_ipar.rate; |
opar.rate = d->ipar.rate; |
round = dev_round; |
round = d->round; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
|
|
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
aproc_setout(dev_sub, obuf); |
aproc_setout(d->sub, obuf); |
obuf->w.sub.xrun = xrun; |
obuf->w.sub.xrun = xrun; |
} |
} |
if (mode & MODE_MON) { |
if (mode & MODE_MON) { |
opar = *sopar; |
opar = *sopar; |
rbuf = LIST_FIRST(&dev_submon->ins); |
rbuf = LIST_FIRST(&d->submon->ins); |
round = dev_roundof(opar.rate); |
round = dev_roundof(d, opar.rate); |
nblk = (dev_bufsz / dev_round + 3) / 4; |
nblk = (d->bufsz / d->round + 3) / 4; |
nch = opar.cmax - opar.cmin + 1; |
nch = opar.cmax - opar.cmin + 1; |
if (!aparams_eqenc(&opar, &dev_opar)) { |
if (!aparams_eqenc(&opar, &d->opar)) { |
conv = enc_new(name, &opar); |
conv = enc_new(name, &opar); |
opar.bps = dev_opar.bps; |
opar.bps = d->opar.bps; |
opar.bits = dev_opar.bits; |
opar.bits = d->opar.bits; |
opar.sig = dev_opar.sig; |
opar.sig = d->opar.sig; |
opar.le = dev_opar.le; |
opar.le = d->opar.le; |
opar.msb = dev_opar.msb; |
opar.msb = d->opar.msb; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
|
|
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
if (!aparams_eqrate(&opar, &dev_opar)) { |
if (!aparams_eqrate(&opar, &d->opar)) { |
conv = resamp_new(name, dev_round, round); |
conv = resamp_new(name, d->round, round); |
opar.rate = dev_opar.rate; |
opar.rate = d->opar.rate; |
round = dev_round; |
round = d->round; |
aproc_setout(conv, obuf); |
aproc_setout(conv, obuf); |
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
|
|
obuf = abuf_new(nblk * round, &opar); |
obuf = abuf_new(nblk * round, &opar); |
aproc_setin(conv, obuf); |
aproc_setin(conv, obuf); |
} |
} |
aproc_setout(dev_submon, obuf); |
aproc_setout(d->submon, obuf); |
obuf->w.sub.xrun = xrun; |
obuf->w.sub.xrun = xrun; |
} |
} |
|
|
|
|
ibuf->duplex = obuf; |
ibuf->duplex = obuf; |
obuf->duplex = ibuf; |
obuf->duplex = ibuf; |
} |
} |
dev_sync(mode, ibuf, obuf); |
dev_sync(d, mode, ibuf, obuf); |
} |
} |
|
|
/* |
/* |
* Change the playback volume of the given stream. |
* Change the playback volume of the given stream. |
*/ |
*/ |
void |
void |
dev_setvol(struct abuf *ibuf, int vol) |
dev_setvol(struct dev *d, struct abuf *ibuf, int vol) |
{ |
{ |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) { |
if (debug_level >= 3) { |
|
|
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
if (!dev_getep(MODE_PLAY, &ibuf, NULL)) { |
if (!dev_getep(d, MODE_PLAY, &ibuf, NULL)) { |
return; |
return; |
} |
} |
ibuf->r.mix.vol = vol; |
ibuf->r.mix.vol = vol; |
|
|
* is started, playback and record start in sync. |
* is started, playback and record start in sync. |
*/ |
*/ |
void |
void |
dev_clear(void) |
dev_clear(struct dev *d) |
{ |
{ |
struct abuf *buf; |
struct abuf *buf; |
|
|
if (APROC_OK(dev_mix)) { |
if (APROC_OK(d->mix)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (!LIST_EMPTY(&dev_mix->ins)) { |
if (!LIST_EMPTY(&d->mix->ins)) { |
dbg_puts("play end not idle, can't clear device\n"); |
dbg_puts("play end not idle, can't clear device\n"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
#endif |
#endif |
buf = LIST_FIRST(&dev_mix->outs); |
buf = LIST_FIRST(&d->mix->outs); |
while (buf) { |
while (buf) { |
abuf_clear(buf); |
abuf_clear(buf); |
buf = LIST_FIRST(&buf->rproc->outs); |
buf = LIST_FIRST(&buf->rproc->outs); |
} |
} |
mix_clear(dev_mix); |
mix_clear(d->mix); |
} |
} |
if (APROC_OK(dev_sub)) { |
if (APROC_OK(d->sub)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (!LIST_EMPTY(&dev_sub->outs)) { |
if (!LIST_EMPTY(&d->sub->outs)) { |
dbg_puts("record end not idle, can't clear device\n"); |
dbg_puts("record end not idle, can't clear device\n"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
#endif |
#endif |
buf = LIST_FIRST(&dev_sub->ins); |
buf = LIST_FIRST(&d->sub->ins); |
while (buf) { |
while (buf) { |
abuf_clear(buf); |
abuf_clear(buf); |
buf = LIST_FIRST(&buf->wproc->ins); |
buf = LIST_FIRST(&buf->wproc->ins); |
} |
} |
sub_clear(dev_sub); |
sub_clear(d->sub); |
} |
} |
if (APROC_OK(dev_submon)) { |
if (APROC_OK(d->submon)) { |
#ifdef DEBUG |
#ifdef DEBUG |
dbg_puts("clearing monitor\n"); |
dbg_puts("clearing monitor\n"); |
if (!LIST_EMPTY(&dev_submon->outs)) { |
if (!LIST_EMPTY(&d->submon->outs)) { |
dbg_puts("monitoring end not idle, can't clear device\n"); |
dbg_puts("monitoring end not idle, can't clear device\n"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
#endif |
#endif |
buf = LIST_FIRST(&dev_submon->ins); |
buf = LIST_FIRST(&d->submon->ins); |
while (buf) { |
while (buf) { |
abuf_clear(buf); |
abuf_clear(buf); |
buf = LIST_FIRST(&buf->wproc->ins); |
buf = LIST_FIRST(&buf->wproc->ins); |
} |
} |
sub_clear(dev_submon); |
sub_clear(d->submon); |
mon_clear(dev_mon); |
mon_clear(d->mon); |
} |
} |
} |
} |
|
|
|
|
* samples to drop |
* samples to drop |
*/ |
*/ |
void |
void |
dev_prime(void) |
dev_prime(struct dev *d) |
{ |
{ |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 3) |
if (debug_level >= 3) |
dbg_puts("priming device\n"); |
dbg_puts("priming device\n"); |
#endif |
#endif |
if (APROC_OK(dev_mix)) { |
if (APROC_OK(d->mix)) { |
#ifdef DEBUG |
#ifdef DEBUG |
if (!LIST_EMPTY(&dev_mix->ins)) { |
if (!LIST_EMPTY(&d->mix->ins)) { |
dbg_puts("play end not idle, can't prime device\n"); |
dbg_puts("play end not idle, can't prime device\n"); |
dbg_panic(); |
dbg_panic(); |
} |
} |
#endif |
#endif |
mix_prime(dev_mix); |
mix_prime(d->mix); |
} |
} |
} |
} |