version 1.26, 2011/06/03 10:05:27 |
version 1.27, 2011/10/12 07:20:04 |
|
|
pipe_revents |
pipe_revents |
}; |
}; |
|
|
|
struct wav *wav_list = NULL; |
|
|
int rwav_in(struct aproc *, struct abuf *); |
int rwav_in(struct aproc *, struct abuf *); |
int rwav_out(struct aproc *, struct abuf *); |
int rwav_out(struct aproc *, struct abuf *); |
void rwav_eof(struct aproc *, struct abuf *); |
void rwav_eof(struct aproc *, struct abuf *); |
|
|
void |
void |
wav_dbg(struct wav *f) |
wav_dbg(struct wav *f) |
{ |
{ |
static char *pstates[] = { "ini", "sta", "rdy", "run", "fai" }; |
static char *pstates[] = { "cfg", "ini", "sta", "rdy", "run", "mid" }; |
struct aproc *midi = f->dev ? f->dev->midi : NULL; |
struct aproc *midi = f->dev ? f->dev->midi : NULL; |
|
|
dbg_puts("wav("); |
dbg_puts("wav("); |
|
|
void |
void |
wav_close(struct file *file) |
wav_close(struct file *file) |
{ |
{ |
struct wav *f = (struct wav *)file; |
struct wav *f = (struct wav *)file, **pf; |
|
|
if (f->mode & MODE_RECMASK) { |
if (f->mode & MODE_RECMASK) { |
pipe_trunc(&f->pipe.file, f->endpos); |
pipe_trunc(&f->pipe.file, f->endpos); |
|
|
} |
} |
} |
} |
pipe_close(file); |
pipe_close(file); |
if (f->dev) { |
if (f->pstate != WAV_CFG) |
dev_unref(f->dev); |
dev_unref(f->dev); |
f->dev = NULL; |
for (pf = &wav_list; *pf != f; pf = &(*pf)->next) { |
|
#ifdef DEBUG |
|
if (*pf == NULL) { |
|
dbg_puts("wav_close: not on list\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
} |
} |
|
*pf = f->next; |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
|
|
/* |
/* |
|
* allocate buffers, so client can start filling write-end. |
|
*/ |
|
void |
|
wav_midiattach(struct wav *f) |
|
{ |
|
struct abuf *rbuf = NULL, *wbuf = NULL; |
|
|
|
if (f->mode & MODE_MIDIOUT) { |
|
rbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setout(f->pipe.file.rproc, rbuf); |
|
} |
|
if (f->mode & MODE_MIDIIN) { |
|
wbuf = abuf_new(MIDI_BUFSZ, &aparams_none); |
|
aproc_setin(f->pipe.file.wproc, wbuf); |
|
} |
|
f->pstate = WAV_MIDI; |
|
dev_midiattach(f->dev, rbuf, wbuf); |
|
} |
|
|
|
/* |
* allocate the play (rec) abuf structure; if this is a |
* allocate the play (rec) abuf structure; if this is a |
* file to record, then attach it to the device |
* file to record, then attach it to the device |
* |
* |
|
|
/* PASSTHROUGH */ |
/* PASSTHROUGH */ |
case WAV_RUN: |
case WAV_RUN: |
wav_freebuf(f); |
wav_freebuf(f); |
f->pstate = WAV_INIT; |
|
/* PASSTHROUGH */ |
/* PASSTHROUGH */ |
case WAV_INIT: |
case WAV_INIT: |
case WAV_FAILED: |
|
/* nothing yet */ |
/* nothing yet */ |
break; |
break; |
|
case WAV_MIDI: |
|
dbg_puts("wav_reset: in midi mode\n"); |
|
dbg_panic(); |
} |
} |
} |
} |
|
|
|
|
wav_exit(struct wav *f) |
wav_exit(struct wav *f) |
{ |
{ |
/* XXX: call file_close() ? */ |
/* XXX: call file_close() ? */ |
if (f->mode & MODE_PLAY) { |
if (f->mode & (MODE_PLAY | MODE_MIDIOUT)) { |
aproc_del(f->pipe.file.rproc); |
aproc_del(f->pipe.file.rproc); |
} else if (f->mode & MODE_RECMASK) { |
} else if (f->mode & (MODE_RECMASK | MODE_MIDIIN)) { |
aproc_del(f->pipe.file.wproc); |
aproc_del(f->pipe.file.wproc); |
} |
} |
} |
} |
|
|
/* |
/* |
|
* allocate the device |
|
*/ |
|
int |
|
wav_init(struct wav *f) |
|
{ |
|
if (!dev_ref(f->dev)) { |
|
wav_exit(f); |
|
return 0; |
|
} |
|
if (!f->mmc) |
|
f->dev->autostart = 1; |
|
if (f->mode & MODE_MIDIMASK) { |
|
wav_midiattach(f); |
|
return 1; |
|
} |
|
f->slot = ctl_slotnew(f->dev->midi, "wav", &ctl_wavops, f, 1); |
|
f->pstate = WAV_INIT; |
|
if ((f->mode & f->dev->mode) != f->mode) { |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
wav_dbg(f); |
|
dbg_puts(": "); |
|
dbg_puts(": operation not supported by device\n"); |
|
} |
|
#endif |
|
wav_exit(f); |
|
return 0; |
|
} |
|
wav_allocbuf(f); |
|
return 1; |
|
} |
|
|
|
/* |
* seek to f->mmcpos and prepare to start, close |
* seek to f->mmcpos and prepare to start, close |
* the file on error. |
* the file on error. |
*/ |
*/ |
|
|
* don't go beyond the end-of-file, if so |
* don't go beyond the end-of-file, if so |
* put it in INIT state so it dosn't start |
* put it in INIT state so it dosn't start |
*/ |
*/ |
if (f->mmcpos > f->endpos) { |
if (f->mmcpos > f->endpos && !(f->mode & MODE_RECMASK)) { |
wav_reset(f); |
wav_reset(f); |
f->pstate = WAV_FAILED; |
|
/* |
/* |
* don't make other stream wait for us |
* don't make other stream wait for us |
*/ |
*/ |
|
|
wav_exit(f); |
wav_exit(f); |
return 0; |
return 0; |
} |
} |
|
if (f->mode & MODE_RECMASK) |
|
f->endpos = f->mmcpos; |
if (f->hdr == HDR_WAV) |
if (f->hdr == HDR_WAV) |
f->wbytes = WAV_DATAMAX - f->mmcpos; |
f->wbytes = WAV_DATAMAX - f->mmcpos; |
f->rbytes = f->endpos - f->mmcpos; |
f->rbytes = f->endpos - f->mmcpos; |
|
|
if (ctl_slotstart(f->dev->midi, f->slot)) |
if (ctl_slotstart(f->dev->midi, f->slot)) |
(void)wav_attach(f, 0); |
(void)wav_attach(f, 0); |
break; |
break; |
#ifdef DEBUG |
|
case WAV_RUN: |
case WAV_RUN: |
break; |
break; |
|
case WAV_MIDI: |
|
return 1; |
|
#ifdef DEBUG |
default: |
default: |
wav_dbg(f); |
wav_dbg(f); |
dbg_puts(": bad state\n"); |
dbg_puts(": bad state\n"); |
|
|
struct wav *f = (struct wav *)arg; |
struct wav *f = (struct wav *)arg; |
|
|
switch (f->pstate) { |
switch (f->pstate) { |
case WAV_FAILED: |
case WAV_INIT: |
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
wav_dbg(f); |
wav_dbg(f); |
|
|
return; |
return; |
case WAV_READY: |
case WAV_READY: |
if (f->mode & MODE_RECMASK) |
if (f->mode & MODE_RECMASK) |
f->endpos = f->startpos; |
f->endpos = f->mmcpos + f->startpos; |
(void)wav_attach(f, 0); |
(void)wav_attach(f, 0); |
break; |
break; |
#ifdef DEBUG |
#ifdef DEBUG |
|
|
if (debug_level >= 2) { |
if (debug_level >= 2) { |
wav_dbg(f); |
wav_dbg(f); |
dbg_puts(": stopping"); |
dbg_puts(": stopping"); |
if (f->pstate != WAV_FAILED && (f->mode & MODE_RECMASK)) { |
if (f->pstate != WAV_INIT && (f->mode & MODE_RECMASK)) { |
dbg_puts(", "); |
dbg_puts(", "); |
dbg_putu(f->endpos); |
dbg_putu(f->endpos); |
dbg_puts(" bytes recorded"); |
dbg_puts(" bytes recorded"); |
|
|
/* |
/* |
* determine the header by the file name |
* determine the header by the file name |
*/ |
*/ |
unsigned |
int |
wav_autohdr(char *name, unsigned hdr) |
wav_autohdr(char *name, struct dev *dev, unsigned *hdr, unsigned *mode) |
{ |
{ |
size_t len; |
char *ext; |
|
|
if (hdr != HDR_AUTO) |
if (dev->reqmode & MODE_THRU) |
return hdr; |
*mode &= MODE_MIDIMASK; |
if (name == NULL) |
if (*hdr == HDR_AUTO) { |
return HDR_RAW; |
ext = strrchr(name, '.'); |
len = strlen(name); |
if (ext != NULL) { |
if (len >= 4 && strcasecmp(name + len - 4, ".wav") == 0) |
ext++; |
return HDR_WAV; |
if (strcasecmp(ext, "wav") == 0) { |
else |
*hdr = HDR_WAV; |
return HDR_RAW; |
*mode &= ~MODE_MIDIMASK; |
|
} else if (strcasecmp(ext, "syx") == 0) { |
|
*hdr = HDR_WAV; |
|
*mode &= ~MODE_AUDIOMASK; |
|
} |
|
} else |
|
*hdr = HDR_RAW; |
|
} |
|
if (*mode & MODE_AUDIOMASK) |
|
*mode &= ~MODE_MIDIMASK; |
|
if (*mode == 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
dbg_puts(name); |
|
dbg_puts(": requested mode not supported\n"); |
|
} |
|
#endif |
|
return 0; |
|
} |
|
return 1; |
} |
} |
|
|
/* |
/* |
* create a file reader in the ``INIT'' state |
* create a file reader in the ``INIT'' state |
*/ |
*/ |
struct wav * |
struct wav * |
wav_new_in(struct fileops *ops, |
wav_new_in(struct fileops *ops, struct dev *dev, |
struct dev *dev, unsigned mode, char *name, unsigned hdr, |
unsigned mode, char *name, unsigned hdr, |
struct aparams *par, unsigned xrun, unsigned volctl, int tr, int join) |
struct aparams *par, unsigned xrun, unsigned volctl, int mmc, int join) |
{ |
{ |
int fd; |
int fd; |
struct wav *f; |
struct wav *f; |
|
|
hdr = wav_autohdr(name, hdr); |
if (!wav_autohdr(name, dev, &hdr, &mode)) |
if (name != NULL) { |
return NULL; |
|
if (strcmp(name, "-") == 0) { |
|
fd = STDIN_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
perror(name); |
|
} else { |
fd = open(name, O_RDONLY | O_NONBLOCK, 0666); |
fd = open(name, O_RDONLY | O_NONBLOCK, 0666); |
if (fd < 0) { |
if (fd < 0) { |
perror(name); |
perror(name); |
return NULL; |
return NULL; |
} |
} |
} else { |
|
name = "stdin"; |
|
fd = STDIN_FILENO; |
|
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
|
perror(name); |
|
} |
} |
f = (struct wav *)pipe_new(ops, fd, name); |
f = (struct wav *)pipe_new(ops, fd, name); |
if (f == NULL) { |
if (f == NULL) { |
close(fd); |
close(fd); |
return NULL; |
return NULL; |
} |
} |
if (!dev_ref(dev)) { |
f->pstate = WAV_CFG; |
close(fd); |
|
return NULL; |
|
} |
|
if (!(dev->mode & MODE_PLAY)) { |
|
#ifdef DEBUG |
|
dbg_puts(name); |
|
dbg_puts(": device can't play\n"); |
|
#endif |
|
close(fd); |
|
dev_unref(dev); |
|
return NULL; |
|
} |
|
f->dev = dev; |
|
if (hdr == HDR_WAV) { |
if (hdr == HDR_WAV) { |
if (!wav_readhdr(f->pipe.fd, par, &f->startpos, &f->rbytes, &f->map)) { |
if (!wav_readhdr(f->pipe.fd, par, |
|
&f->startpos, &f->rbytes, &f->map)) { |
file_del((struct file *)f); |
file_del((struct file *)f); |
return NULL; |
return NULL; |
} |
} |
|
|
f->rbytes = -1; |
f->rbytes = -1; |
f->map = NULL; |
f->map = NULL; |
} |
} |
f->pstate = WAV_INIT; |
f->dev = dev; |
f->mmc = tr; |
f->mmc = mmc; |
f->join = join; |
f->join = join; |
f->mode = mode; |
f->mode = mode; |
f->hpar = *par; |
f->hpar = *par; |
f->hdr = hdr; |
f->hdr = hdr; |
f->xrun = xrun; |
f->xrun = xrun; |
f->maxweight = MIDI_TO_ADATA(volctl); |
f->maxweight = MIDI_TO_ADATA(volctl); |
f->slot = ctl_slotnew(f->dev->midi, "play", &ctl_wavops, f, 1); |
f->slot = -1; |
rwav_new((struct file *)f); |
rwav_new((struct file *)f); |
wav_allocbuf(f); |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
dbg_puts(name); |
dbg_puts(name); |
dbg_puts(": playing "); |
dbg_puts(":"); |
dbg_putu(f->startpos); |
if (f->mode & MODE_PLAY) { |
dbg_puts(".."); |
dbg_puts(" playing "); |
dbg_putu(f->endpos); |
aparams_dbg(par); |
dbg_puts(": playing "); |
dbg_puts(" "); |
aparams_dbg(par); |
dbg_putu(f->startpos); |
if (f->mmc) |
dbg_puts(".."); |
dbg_puts(", mmc"); |
dbg_putu(f->endpos); |
|
if (f->mmc) |
|
dbg_puts(", mmc"); |
|
} |
|
if (f->mode & MODE_MIDIOUT) |
|
dbg_puts(" midi/out"); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
|
f->next = wav_list; |
|
wav_list = f; |
return f; |
return f; |
} |
} |
|
|
|
|
* create a file writer in the ``INIT'' state |
* create a file writer in the ``INIT'' state |
*/ |
*/ |
struct wav * |
struct wav * |
wav_new_out(struct fileops *ops, |
wav_new_out(struct fileops *ops, struct dev *dev, |
struct dev *dev, unsigned mode, char *name, unsigned hdr, |
unsigned mode, char *name, unsigned hdr, |
struct aparams *par, unsigned xrun, int tr, int join) |
struct aparams *par, unsigned xrun, int mmc, int join) |
{ |
{ |
int fd; |
int fd; |
struct wav *f; |
struct wav *f; |
|
|
hdr = wav_autohdr(name, hdr); |
if (!wav_autohdr(name, dev, &hdr, &mode)) |
if (name == NULL) { |
return NULL; |
name = "stdout"; |
if (strcmp(name, "-") == 0) { |
fd = STDOUT_FILENO; |
fd = STDOUT_FILENO; |
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
if (fcntl(fd, F_SETFL, O_NONBLOCK) < 0) |
perror(name); |
perror(name); |
|
|
close(fd); |
close(fd); |
return NULL; |
return NULL; |
} |
} |
if (!dev_ref(dev)) { |
f->pstate = WAV_CFG; |
close(fd); |
|
return NULL; |
|
} |
|
if (!(dev->mode & MODE_RECMASK)) { |
|
#ifdef DEBUG |
|
dbg_puts(name); |
|
dbg_puts(": device can't record\n"); |
|
#endif |
|
close(fd); |
|
dev_unref(dev); |
|
return NULL; |
|
} |
|
f->dev = dev; |
|
if (hdr == HDR_WAV) { |
if (hdr == HDR_WAV) { |
par->le = 1; |
par->le = 1; |
par->sig = (par->bits <= 8) ? 0 : 1; |
par->sig = (par->bits <= 8) ? 0 : 1; |
|
|
f->wbytes = -1; |
f->wbytes = -1; |
f->startpos = f->endpos = 0; |
f->startpos = f->endpos = 0; |
} |
} |
f->pstate = WAV_INIT; |
f->dev = dev; |
f->mmc = tr; |
f->mmc = mmc; |
f->join = join; |
f->join = join; |
f->mode = mode; |
f->mode = mode; |
f->hpar = *par; |
f->hpar = *par; |
f->hdr = hdr; |
f->hdr = hdr; |
f->xrun = xrun; |
f->xrun = xrun; |
f->slot = ctl_slotnew(f->dev->midi, "rec", &ctl_wavops, f, 1); |
|
wwav_new((struct file *)f); |
wwav_new((struct file *)f); |
wav_allocbuf(f); |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
dbg_puts(name); |
dbg_puts(name); |
dbg_puts(": recording "); |
dbg_puts(":"); |
aparams_dbg(par); |
if (f->mode & MODE_RECMASK) { |
|
dbg_puts(" recording "); |
|
aparams_dbg(par); |
|
if (f->mmc) |
|
dbg_puts(", mmc"); |
|
} |
|
if (f->mode & MODE_MIDIIN) |
|
dbg_puts(" midi/in"); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
|
f->next = wav_list; |
|
wav_list = f; |
return f; |
return f; |
} |
} |
|
|
|
|
f->wproc = p; |
f->wproc = p; |
return p; |
return p; |
} |
} |
|
|