version 1.14, 2010/04/03 17:59:17 |
version 1.15, 2010/04/06 20:07:01 |
|
|
#include "aproc.h" |
#include "aproc.h" |
#include "conf.h" |
#include "conf.h" |
#include "dev.h" |
#include "dev.h" |
|
#include "midi.h" |
#include "wav.h" |
#include "wav.h" |
|
#include "opt.h" |
#ifdef DEBUG |
#ifdef DEBUG |
#include "dbg.h" |
#include "dbg.h" |
#endif |
#endif |
|
|
void rwav_eof(struct aproc *, struct abuf *); |
void rwav_eof(struct aproc *, struct abuf *); |
void rwav_hup(struct aproc *, struct abuf *); |
void rwav_hup(struct aproc *, struct abuf *); |
void rwav_done(struct aproc *); |
void rwav_done(struct aproc *); |
|
struct aproc *rwav_new(struct file *); |
|
|
int wwav_in(struct aproc *, struct abuf *); |
int wwav_in(struct aproc *, struct abuf *); |
int wwav_out(struct aproc *, struct abuf *); |
int wwav_out(struct aproc *, struct abuf *); |
void wwav_eof(struct aproc *, struct abuf *); |
void wwav_eof(struct aproc *, struct abuf *); |
void wwav_hup(struct aproc *, struct abuf *); |
void wwav_hup(struct aproc *, struct abuf *); |
void wwav_done(struct aproc *); |
void wwav_done(struct aproc *); |
|
struct aproc *wwav_new(struct file *); |
|
|
|
void wav_setvol(void *, unsigned); |
|
void wav_startreq(void *); |
|
void wav_stopreq(void *); |
|
void wav_locreq(void *, unsigned); |
|
|
|
struct ctl_ops ctl_wavops = { |
|
wav_setvol, |
|
wav_startreq, |
|
wav_stopreq, |
|
wav_locreq |
|
}; |
|
|
struct aproc_ops rwav_ops = { |
struct aproc_ops rwav_ops = { |
"rwav", |
"rwav", |
rwav_in, |
rwav_in, |
rwav_out, |
rwav_out, |
rwav_eof, |
rfile_eof, |
rwav_hup, |
rfile_hup, |
NULL, /* newin */ |
NULL, /* newin */ |
NULL, /* newout */ |
NULL, /* newout */ |
NULL, /* ipos */ |
NULL, /* ipos */ |
|
|
"wwav", |
"wwav", |
wwav_in, |
wwav_in, |
wwav_out, |
wwav_out, |
wwav_eof, |
wfile_eof, |
wwav_hup, |
wfile_hup, |
NULL, /* newin */ |
NULL, /* newin */ |
NULL, /* newout */ |
NULL, /* newout */ |
NULL, /* ipos */ |
NULL, /* ipos */ |
|
|
wwav_done |
wwav_done |
}; |
}; |
|
|
struct aproc * |
#ifdef DEBUG |
rwav_new(struct file *f) |
/* |
|
* print the given wav structure |
|
*/ |
|
void |
|
wav_dbg(struct wav *f) |
{ |
{ |
struct aproc *p; |
static char *pstates[] = { "ini", "sta", "rdy", "run", "fai" }; |
|
|
p = aproc_new(&rwav_ops, f->name); |
dbg_puts("wav("); |
p->u.io.file = f; |
if (f->slot >= 0 && APROC_OK(dev_midi)) { |
f->rproc = p; |
dbg_puts(dev_midi->u.ctl.slot[f->slot].name); |
return p; |
dbg_putu(dev_midi->u.ctl.slot[f->slot].unit); |
|
} else |
|
dbg_puts(f->pipe.file.name); |
|
dbg_puts(")/"); |
|
dbg_puts(pstates[f->pstate]); |
} |
} |
|
#endif |
|
|
int |
/* |
rwav_in(struct aproc *p, struct abuf *ibuf_dummy) |
* convert ``count'' samples using the given char->short map |
|
*/ |
|
void |
|
wav_conv(unsigned char *data, unsigned count, short *map) |
{ |
{ |
struct abuf *obuf = LIST_FIRST(&p->obuflist); |
unsigned i; |
struct file *f = p->u.io.file; |
unsigned char *iptr; |
unsigned char *data; |
short *optr; |
unsigned count; |
|
|
|
if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) |
iptr = data + count; |
return 0; |
optr = (short *)data + count; |
data = abuf_wgetblk(obuf, &count, 0); |
for (i = count; i > 0; i--) { |
count = file_read(f, data, count); |
--optr; |
if (count == 0) |
--iptr; |
return 0; |
*optr = map[*iptr]; |
abuf_wcommit(obuf, count); |
} |
if (!abuf_flush(obuf)) |
|
return 0; |
|
return 1; |
|
} |
} |
|
|
int |
/* |
rwav_out(struct aproc *p, struct abuf *obuf) |
* read method of the file structure |
|
*/ |
|
unsigned |
|
wav_read(struct file *file, unsigned char *data, unsigned count) |
{ |
{ |
struct file *f = p->u.io.file; |
struct wav *f = (struct wav *)file; |
unsigned char *data; |
unsigned n; |
unsigned count; |
|
|
|
if (f->state & FILE_RINUSE) |
if (f->map) |
|
count /= sizeof(short); |
|
if (f->rbytes >= 0 && count > f->rbytes) { |
|
count = f->rbytes; /* file->rbytes fits in count */ |
|
if (count == 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
wav_dbg(f); |
|
dbg_puts(": read complete\n"); |
|
} |
|
#endif |
|
if (!f->tr) |
|
file_eof(&f->pipe.file); |
|
return 0; |
|
} |
|
} |
|
n = pipe_read(file, data, count); |
|
if (n == 0) |
return 0; |
return 0; |
if (ABUF_FULL(obuf) || !(f->state & FILE_ROK)) |
if (f->rbytes >= 0) |
return 0; |
f->rbytes -= n; |
data = abuf_wgetblk(obuf, &count, 0); |
if (f->map) { |
count = file_read(f, data, count); |
wav_conv(data, n, f->map); |
if (count == 0) |
n *= sizeof(short); |
return 0; |
} |
abuf_wcommit(obuf, count); |
return n; |
return 1; |
|
} |
} |
|
|
void |
/* |
rwav_done(struct aproc *p) |
* write method of the file structure |
|
*/ |
|
unsigned |
|
wav_write(struct file *file, unsigned char *data, unsigned count) |
{ |
{ |
struct file *f = p->u.io.file; |
struct wav *f = (struct wav *)file; |
struct abuf *obuf; |
unsigned n; |
|
|
if (f == NULL) |
if (f->wbytes >= 0 && count > f->wbytes) { |
return; |
count = f->wbytes; /* wbytes fits in count */ |
/* |
if (count == 0) { |
* all buffers must be detached before deleting f->wproc, |
#ifdef DEBUG |
* because otherwise it could trigger this code again |
if (debug_level >= 3) { |
*/ |
wav_dbg(f); |
obuf = LIST_FIRST(&p->obuflist); |
dbg_puts(": write complete\n"); |
if (obuf) |
} |
abuf_eof(obuf); |
#endif |
if (f->wproc) { |
file_hup(&f->pipe.file); |
f->rproc = NULL; |
return 0; |
aproc_del(f->wproc); |
} |
} else |
} |
file_del(f); |
n = pipe_write(file, data, count); |
p->u.io.file = NULL; |
if (f->wbytes >= 0) |
|
f->wbytes -= n; |
|
f->endpos += n; |
|
return n; |
} |
} |
|
|
|
/* |
|
* close method of the file structure |
|
*/ |
void |
void |
rwav_eof(struct aproc *p, struct abuf *ibuf_dummy) |
wav_close(struct file *file) |
{ |
{ |
aproc_del(p); |
struct wav *f = (struct wav *)file; |
|
|
|
if (f->mode & MODE_RECMASK) { |
|
pipe_trunc(&f->pipe.file, f->endpos); |
|
if (f->hdr == HDR_WAV) { |
|
wav_writehdr(f->pipe.fd, |
|
&f->hpar, |
|
&f->startpos, |
|
f->endpos - f->startpos); |
|
} |
|
} |
|
pipe_close(file); |
} |
} |
|
|
|
/* |
|
* attach play (rec) abuf structure to the device and |
|
* switch to the ``RUN'' state; the play abug must not be empty |
|
*/ |
|
int |
|
wav_attach(struct wav *f, int force) |
|
{ |
|
struct abuf *rbuf = NULL, *wbuf = NULL; |
|
|
|
if (f->mode & MODE_PLAY) |
|
rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist); |
|
if (f->mode & MODE_RECMASK) |
|
wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist); |
|
f->pstate = WAV_RUN; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
wav_dbg(f); |
|
dbg_puts(": attaching\n"); |
|
} |
|
#endif |
|
dev_attach(f->pipe.file.name, f->mode, |
|
rbuf, &f->hpar, wbuf, &f->hpar, f->xrun, f->maxweight); |
|
if (f->mode & MODE_PLAY) |
|
dev_setvol(rbuf, MIDI_TO_ADATA(f->vol)); |
|
return 1; |
|
} |
|
|
|
/* |
|
* allocate the play (rec) abuf structure; if this is a |
|
* file to record, then attach it to the device |
|
* |
|
* XXX: buffer size should be larger than dev_bufsz, because |
|
* in non-server mode we don't prime play buffers with |
|
* silence |
|
*/ |
void |
void |
rwav_hup(struct aproc *p, struct abuf *obuf) |
wav_allocbuf(struct wav *f) |
{ |
{ |
aproc_del(p); |
struct abuf *buf; |
|
unsigned nfr; |
|
|
|
f->pstate = WAV_START; |
|
if (f->mode & MODE_PLAY) { |
|
nfr = 2 * dev_bufsz * f->hpar.rate / dev_rate; |
|
buf = abuf_new(nfr, &f->hpar); |
|
aproc_setout(f->pipe.file.rproc, buf); |
|
abuf_fill(buf); |
|
if (!ABUF_WOK(buf) || (f->pipe.file.state & FILE_EOF)) |
|
f->pstate = WAV_READY; |
|
} |
|
if (f->mode & MODE_RECMASK) { |
|
nfr = 2 * dev_bufsz * f->hpar.rate / dev_rate; |
|
buf = abuf_new(nfr, &f->hpar); |
|
aproc_setin(f->pipe.file.wproc, buf); |
|
f->pstate = WAV_READY; |
|
} |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
wav_dbg(f); |
|
dbg_puts(": allocating buffers\n"); |
|
} |
|
#endif |
|
if (f->pstate == WAV_READY && ctl_slotstart(dev_midi, f->slot)) |
|
(void)wav_attach(f, 0); |
} |
} |
|
|
struct aproc * |
/* |
wwav_new(struct file *f) |
* free abuf structure and switch to the ``INIT'' state |
|
*/ |
|
void |
|
wav_freebuf(struct wav *f) |
{ |
{ |
struct aproc *p; |
struct abuf *rbuf = NULL, *wbuf = NULL; |
|
|
p = aproc_new(&wwav_ops, f->name); |
if (f->mode & MODE_PLAY) |
p->u.io.file = f; |
rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist); |
f->wproc = p; |
if (f->mode & MODE_RECMASK) |
return p; |
wbuf = LIST_FIRST(&f->pipe.file.wproc->ibuflist); |
|
f->pstate = WAV_INIT; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
wav_dbg(f); |
|
dbg_puts(": freeing buffers\n"); |
|
} |
|
#endif |
|
if (rbuf || wbuf) |
|
ctl_slotstop(dev_midi, f->slot); |
|
if (rbuf) |
|
abuf_eof(rbuf); |
|
if (wbuf) |
|
abuf_hup(wbuf); |
} |
} |
|
|
|
/* |
|
* switch to the ``INIT'' state performing |
|
* necessary actions to reach it |
|
*/ |
void |
void |
wwav_done(struct aproc *p) |
wav_reset(struct wav *f) |
{ |
{ |
struct file *f = p->u.io.file; |
switch (f->pstate) { |
struct abuf *ibuf; |
case WAV_START: |
|
case WAV_READY: |
|
if (ctl_slotstart(dev_midi, f->slot)) |
|
(void)wav_attach(f, 1); |
|
/* PASSTHROUGH */ |
|
case WAV_RUN: |
|
wav_freebuf(f); |
|
f->pstate = WAV_INIT; |
|
/* PASSTHROUGH */ |
|
case WAV_INIT: |
|
case WAV_FAILED: |
|
/* nothing yet */ |
|
break; |
|
} |
|
} |
|
|
if (f == NULL) |
/* |
return; |
* terminate the wav reader/writer |
|
*/ |
|
void |
|
wav_exit(struct wav *f) |
|
{ |
|
if (f->mode & MODE_PLAY) { |
|
aproc_del(f->pipe.file.rproc); |
|
} else if (f->mode & MODE_RECMASK) { |
|
aproc_del(f->pipe.file.wproc); |
|
} |
|
} |
|
|
|
/* |
|
* seek to f->mmcpos and prepare to start, close |
|
* the file on error. |
|
*/ |
|
int |
|
wav_seekmmc(struct wav *f) |
|
{ |
/* |
/* |
* all buffers must be detached before deleting f->rproc, |
* don't go beyond the end-of-file, if so |
* because otherwise it could trigger this code again |
* put it in INIT state so it dosn't start |
*/ |
*/ |
ibuf = LIST_FIRST(&p->ibuflist); |
if (f->mmcpos > f->endpos) { |
if (ibuf) |
wav_reset(f); |
abuf_hup(ibuf); |
f->pstate = WAV_FAILED; |
if (f->rproc) { |
/* |
f->wproc = NULL; |
* don't make other stream wait for us |
aproc_del(f->rproc); |
*/ |
} else |
if (f->slot >= 0) |
file_del(f); |
ctl_slotstart(dev_midi, f->slot); |
p->u.io.file = NULL; |
return 0; |
|
} |
|
if (!pipe_seek(&f->pipe.file, f->mmcpos)) { |
|
wav_exit(f); |
|
return 0; |
|
} |
|
if (f->hdr == HDR_WAV) |
|
f->wbytes = WAV_DATAMAX - f->mmcpos; |
|
f->rbytes = f->endpos - f->mmcpos; |
|
wav_reset(f); |
|
wav_allocbuf(f); |
|
return 1; |
} |
} |
|
|
|
/* |
|
* read samples from the file and possibly start it |
|
*/ |
int |
int |
wwav_in(struct aproc *p, struct abuf *ibuf) |
wav_rdata(struct wav *f) |
{ |
{ |
struct file *f = p->u.io.file; |
struct aproc *p; |
unsigned char *data; |
struct abuf *obuf; |
unsigned count; |
|
|
|
if (f->state & FILE_WINUSE) |
p = f->pipe.file.rproc; |
|
obuf = LIST_FIRST(&p->obuflist); |
|
if (obuf == NULL) |
return 0; |
return 0; |
if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) |
if (!ABUF_WOK(obuf) || !(f->pipe.file.state & FILE_ROK)) |
return 0; |
return 0; |
data = abuf_rgetblk(ibuf, &count, 0); |
if (!rfile_do(p, obuf->len, NULL)) |
count = file_write(f, data, count); |
|
if (count == 0) |
|
return 0; |
return 0; |
abuf_rdiscard(ibuf, count); |
switch (f->pstate) { |
|
case WAV_START: |
|
if (!ABUF_WOK(obuf) || (f->pipe.file.state & FILE_EOF)) |
|
f->pstate = WAV_READY; |
|
/* PASSTHROUGH */ |
|
case WAV_READY: |
|
if (ctl_slotstart(dev_midi, f->slot)) |
|
(void)wav_attach(f, 0); |
|
break; |
|
#ifdef DEBUG |
|
case WAV_RUN: |
|
break; |
|
default: |
|
wav_dbg(f); |
|
dbg_puts(": bad state\n"); |
|
dbg_panic(); |
|
#endif |
|
} |
|
if (f->rbytes == 0 && f->tr) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
wav_dbg(f); |
|
dbg_puts(": trying to restart\n"); |
|
} |
|
#endif |
|
if (!wav_seekmmc(f)) |
|
return 0; |
|
} |
return 1; |
return 1; |
} |
} |
|
|
int |
int |
wwav_out(struct aproc *p, struct abuf *obuf_dummy) |
wav_wdata(struct wav *f) |
{ |
{ |
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
struct aproc *p; |
struct file *f = p->u.io.file; |
struct abuf *ibuf; |
unsigned char *data; |
|
unsigned count; |
|
|
|
if (!abuf_fill(ibuf)) |
if (!(f->pipe.file.state & FILE_WOK)) |
return 0; |
return 0; |
if (ABUF_EMPTY(ibuf) || !(f->state & FILE_WOK)) |
p = f->pipe.file.wproc; |
|
ibuf = LIST_FIRST(&p->ibuflist); |
|
if (ibuf == NULL) |
return 0; |
return 0; |
data = abuf_rgetblk(ibuf, &count, 0); |
if (!ABUF_ROK(ibuf)) |
if (count == 0) { |
|
/* XXX: this can't happen, right ? */ |
|
return 0; |
return 0; |
} |
if (!wfile_do(p, ibuf->len, NULL)) |
count = file_write(f, data, count); |
|
if (count == 0) |
|
return 0; |
return 0; |
abuf_rdiscard(ibuf, count); |
|
return 1; |
return 1; |
} |
} |
|
|
|
/* |
|
* callback to set the volume, invoked by the MIDI control code |
|
*/ |
void |
void |
wwav_eof(struct aproc *p, struct abuf *ibuf) |
wav_setvol(void *arg, unsigned vol) |
{ |
{ |
aproc_del(p); |
struct wav *f = (struct wav *)arg; |
|
struct abuf *rbuf; |
|
|
|
f->vol = vol; |
|
if ((f->mode & MODE_PLAY) && f->pstate == WAV_RUN) { |
|
rbuf = LIST_FIRST(&f->pipe.file.rproc->obuflist); |
|
dev_setvol(rbuf, MIDI_TO_ADATA(vol)); |
|
} |
} |
} |
|
|
|
/* |
|
* callback to start the stream, invoked by the MIDI control code |
|
*/ |
void |
void |
wwav_hup(struct aproc *p, struct abuf *obuf_dummy) |
wav_startreq(void *arg) |
{ |
{ |
aproc_del(p); |
struct wav *f = (struct wav *)arg; |
|
|
|
switch (f->pstate) { |
|
case WAV_FAILED: |
|
#ifdef DEBUG |
|
if (debug_level >= 2) { |
|
wav_dbg(f); |
|
dbg_puts(": skipped (failed to seek)\n"); |
|
} |
|
#endif |
|
return; |
|
case WAV_READY: |
|
if (f->mode & MODE_RECMASK) |
|
f->endpos = f->startpos; |
|
(void)wav_attach(f, 0); |
|
break; |
|
#ifdef DEBUG |
|
default: |
|
wav_dbg(f); |
|
dbg_puts(": not in READY state\n"); |
|
dbg_panic(); |
|
break; |
|
#endif |
|
} |
} |
} |
|
|
|
/* |
|
* callback to stop the stream, invoked by the MIDI control code |
|
*/ |
|
void |
|
wav_stopreq(void *arg) |
|
{ |
|
struct wav *f = (struct wav *)arg; |
|
|
|
#ifdef DEBUG |
|
if (debug_level >= 2) { |
|
wav_dbg(f); |
|
dbg_puts(": stopping"); |
|
if (f->pstate != WAV_FAILED && (f->mode & MODE_RECMASK)) { |
|
dbg_puts(", "); |
|
dbg_putu(f->endpos); |
|
dbg_puts(" bytes recorded"); |
|
} |
|
dbg_puts("\n"); |
|
} |
|
#endif |
|
if (!f->tr) { |
|
wav_exit(f); |
|
return; |
|
} |
|
(void)wav_seekmmc(f); |
|
} |
|
|
|
/* |
|
* callback to relocate the stream, invoked by the MIDI control code |
|
* on a stopped stream |
|
*/ |
|
void |
|
wav_locreq(void *arg, unsigned mmc) |
|
{ |
|
struct wav *f = (struct wav *)arg; |
|
|
|
#ifdef DEBUG |
|
if (f->pstate == WAV_RUN) { |
|
wav_dbg(f); |
|
dbg_puts(": in RUN state\n"); |
|
dbg_panic(); |
|
} |
|
#endif |
|
f->mmcpos = f->startpos + |
|
((off_t)mmc * f->hpar.rate / MTC_SEC) * aparams_bpf(&f->hpar); |
|
(void)wav_seekmmc(f); |
|
} |
|
|
|
/* |
|
* create a file reader in the ``INIT'' state |
|
*/ |
struct wav * |
struct wav * |
wav_new_in(struct fileops *ops, char *name, unsigned hdr, |
wav_new_in(struct fileops *ops, unsigned mode, char *name, unsigned hdr, |
struct aparams *par, unsigned xrun, unsigned volctl) |
struct aparams *par, unsigned xrun, unsigned volctl, int tr) |
{ |
{ |
int fd; |
int fd; |
struct wav *f; |
struct wav *f; |
struct aproc *p; |
|
struct abuf *buf; |
|
unsigned nfr; |
|
|
|
if (name != NULL) { |
if (name != NULL) { |
fd = open(name, O_RDONLY | O_NONBLOCK, 0666); |
fd = open(name, O_RDONLY | O_NONBLOCK, 0666); |
|
|
if (f == NULL) |
if (f == NULL) |
return NULL; |
return NULL; |
if (hdr == HDR_WAV) { |
if (hdr == HDR_WAV) { |
if (!wav_readhdr(f->pipe.fd, par, &f->rbytes, &f->map)) { |
if (!wav_readhdr(f->pipe.fd, par, &f->startpos, &f->rbytes, &f->map)) { |
file_del((struct file *)f); |
file_del((struct file *)f); |
return NULL; |
return NULL; |
} |
} |
f->hpar = *par; |
f->endpos = f->startpos + f->rbytes; |
} else { |
} else { |
f->rbytes = -1; |
f->startpos = 0; |
|
f->endpos = pipe_endpos(&f->pipe.file); |
|
if (f->endpos > 0) { |
|
if (!pipe_seek(&f->pipe.file, 0)) { |
|
file_del((struct file *)f); |
|
return NULL; |
|
} |
|
f->rbytes = f->endpos; |
|
} else |
|
f->rbytes = -1; |
f->map = NULL; |
f->map = NULL; |
} |
} |
|
f->tr = tr; |
|
f->mode = mode; |
|
f->hpar = *par; |
f->hdr = 0; |
f->hdr = 0; |
nfr = dev_bufsz * par->rate / dev_rate; |
f->xrun = xrun; |
buf = abuf_new(nfr, par); |
f->maxweight = MIDI_TO_ADATA(volctl); |
p = rwav_new((struct file *)f); |
f->slot = ctl_slotnew(dev_midi, "play", &ctl_wavops, f, 1); |
aproc_setout(p, buf); |
rwav_new((struct file *)f); |
abuf_fill(buf); /* XXX: move this in dev_attach() ? */ |
wav_allocbuf(f); |
dev_attach(name, buf, par, xrun, NULL, NULL, 0, ADATA_UNIT); |
|
dev_setvol(buf, MIDI_TO_ADATA(volctl)); |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
dbg_puts(name); |
dbg_puts(name); |
dbg_puts(": playing "); |
dbg_puts(": playing "); |
|
dbg_putu(f->startpos); |
|
dbg_puts(".."); |
|
dbg_putu(f->endpos); |
|
dbg_puts(": playing "); |
aparams_dbg(par); |
aparams_dbg(par); |
|
if (f->tr) |
|
dbg_puts(", mmc"); |
dbg_puts("\n"); |
dbg_puts("\n"); |
} |
} |
#endif |
#endif |
return f; |
return f; |
} |
} |
|
|
|
/* |
|
* create a file writer in the ``INIT'' state |
|
*/ |
struct wav * |
struct wav * |
wav_new_out(struct fileops *ops, char *name, unsigned hdr, |
wav_new_out(struct fileops *ops, unsigned mode, char *name, unsigned hdr, |
struct aparams *par, unsigned xrun) |
struct aparams *par, unsigned xrun, int tr) |
{ |
{ |
int fd; |
int fd; |
struct wav *f; |
struct wav *f; |
struct aproc *p; |
|
struct abuf *buf; |
|
unsigned nfr; |
|
|
|
if (name == NULL) { |
if (name == NULL) { |
name = "stdout"; |
name = "stdout"; |
|
|
par->le = 1; |
par->le = 1; |
par->sig = (par->bits <= 8) ? 0 : 1; |
par->sig = (par->bits <= 8) ? 0 : 1; |
par->bps = (par->bits + 7) / 8; |
par->bps = (par->bits + 7) / 8; |
if (!wav_writehdr(f->pipe.fd, par)) { |
if (!wav_writehdr(f->pipe.fd, par, &f->startpos, 0)) { |
file_del((struct file *)f); |
file_del((struct file *)f); |
return NULL; |
return NULL; |
} |
} |
f->hpar = *par; |
|
f->wbytes = WAV_DATAMAX; |
f->wbytes = WAV_DATAMAX; |
} else |
f->endpos = f->startpos; |
|
} else { |
f->wbytes = -1; |
f->wbytes = -1; |
|
f->startpos = f->endpos = 0; |
|
} |
|
f->tr = tr; |
|
f->mode = mode; |
|
f->hpar = *par; |
f->hdr = hdr; |
f->hdr = hdr; |
nfr = dev_bufsz * par->rate / dev_rate; |
f->xrun = xrun; |
p = wwav_new((struct file *)f); |
f->slot = ctl_slotnew(dev_midi, "rec", &ctl_wavops, f, 1); |
buf = abuf_new(nfr, par); |
wwav_new((struct file *)f); |
aproc_setin(p, buf); |
wav_allocbuf(f); |
dev_attach(name, NULL, NULL, 0, buf, par, xrun, 0); |
|
#ifdef DEBUG |
#ifdef DEBUG |
if (debug_level >= 2) { |
if (debug_level >= 2) { |
dbg_puts(name); |
dbg_puts(name); |
|
|
} |
} |
|
|
void |
void |
wav_conv(unsigned char *data, unsigned count, short *map) |
rwav_done(struct aproc *p) |
{ |
{ |
unsigned i; |
struct wav *f = (struct wav *)p->u.io.file; |
unsigned char *iptr; |
|
short *optr; |
|
|
|
iptr = data + count; |
if (f->slot >= 0) |
optr = (short *)data + count; |
ctl_slotdel(dev_midi, f->slot); |
for (i = count; i > 0; i--) { |
f->slot = -1; |
--optr; |
rfile_done(p); |
--iptr; |
} |
*optr = map[*iptr]; |
|
|
int |
|
rwav_in(struct aproc *p, struct abuf *ibuf_dummy) |
|
{ |
|
struct wav *f = (struct wav *)p->u.io.file; |
|
struct abuf *obuf; |
|
|
|
if (!wav_rdata(f)) |
|
return 0; |
|
obuf = LIST_FIRST(&p->obuflist); |
|
if (obuf && f->pstate >= WAV_RUN) { |
|
if (!abuf_flush(obuf)) |
|
return 0; |
} |
} |
|
return 1; |
} |
} |
|
|
unsigned |
int |
wav_read(struct file *file, unsigned char *data, unsigned count) |
rwav_out(struct aproc *p, struct abuf *obuf) |
{ |
{ |
struct wav *f = (struct wav *)file; |
struct wav *f = (struct wav *)p->u.io.file; |
unsigned n; |
|
|
|
if (f->map) |
if (f->pipe.file.state & FILE_RINUSE) |
count /= sizeof(short); |
return 0; |
if (f->rbytes >= 0 && count > f->rbytes) { |
for (;;) { |
count = f->rbytes; /* file->rbytes fits in count */ |
if (!wav_rdata(f)) |
if (count == 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
file_dbg(&f->pipe.file); |
|
dbg_puts(": read complete\n"); |
|
} |
|
#endif |
|
file_eof(&f->pipe.file); |
|
return 0; |
return 0; |
} |
|
} |
} |
n = pipe_read(file, data, count); |
return 1; |
if (n == 0) |
} |
|
|
|
struct aproc * |
|
rwav_new(struct file *f) |
|
{ |
|
struct aproc *p; |
|
|
|
p = aproc_new(&rwav_ops, f->name); |
|
p->u.io.file = f; |
|
p->u.io.partial = 0;; |
|
f->rproc = p; |
|
return p; |
|
} |
|
|
|
void |
|
wwav_done(struct aproc *p) |
|
{ |
|
struct wav *f = (struct wav *)p->u.io.file; |
|
|
|
if (f->slot >= 0) |
|
ctl_slotdel(dev_midi, f->slot); |
|
f->slot = -1; |
|
wfile_done(p); |
|
} |
|
|
|
int |
|
wwav_in(struct aproc *p, struct abuf *ibuf) |
|
{ |
|
struct wav *f = (struct wav *)p->u.io.file; |
|
|
|
if (f->pipe.file.state & FILE_WINUSE) |
return 0; |
return 0; |
if (f->rbytes >= 0) |
for (;;) { |
f->rbytes -= n; |
if (!wav_wdata(f)) |
if (f->map) { |
return 0; |
wav_conv(data, n, f->map); |
|
n *= sizeof(short); |
|
} |
} |
return n; |
return 1; |
} |
} |
|
|
unsigned |
int |
wav_write(struct file *file, unsigned char *data, unsigned count) |
wwav_out(struct aproc *p, struct abuf *obuf_dummy) |
{ |
{ |
struct wav *f = (struct wav *)file; |
struct abuf *ibuf = LIST_FIRST(&p->ibuflist); |
unsigned n; |
struct wav *f = (struct wav *)p->u.io.file; |
|
|
if (f->wbytes >= 0 && count > f->wbytes) { |
if (ibuf && f->pstate == WAV_RUN) { |
count = f->wbytes; /* wbytes fits in count */ |
if (!abuf_fill(ibuf)) |
if (count == 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
file_dbg(&f->pipe.file); |
|
dbg_puts(": write complete\n"); |
|
} |
|
#endif |
|
file_hup(&f->pipe.file); |
|
return 0; |
return 0; |
} |
|
} |
} |
n = pipe_write(file, data, count); |
if (!wav_wdata(f)) |
if (f->wbytes >= 0) |
return 0; |
f->wbytes -= n; |
return 1; |
return n; |
|
} |
} |
|
|
void |
struct aproc * |
wav_close(struct file *file) |
wwav_new(struct file *f) |
{ |
{ |
struct wav *f = (struct wav *)file; |
struct aproc *p; |
|
|
if (f->hdr == HDR_WAV) |
p = aproc_new(&wwav_ops, f->name); |
wav_writehdr(f->pipe.fd, &f->hpar); |
p->u.io.file = f; |
pipe_close(file); |
p->u.io.partial = 0;; |
|
f->wproc = p; |
|
return p; |
} |
} |
|
|