mirror of https://github.com/ericonr/sndio.git
use flow control instead of throtteling
This commit is contained in:
parent
2b55c6e659
commit
fffd1b2ad5
|
@ -31,7 +31,7 @@ extern unsigned int log_level;
|
|||
/*
|
||||
* MIDI buffer size
|
||||
*/
|
||||
#define MIDI_BUFSZ 125 /* 1 second at 31.25kbit/s */
|
||||
#define MIDI_BUFSZ 15 /* 1 second at 31.25kbit/s */
|
||||
|
||||
/*
|
||||
* units used for MTC clock.
|
||||
|
|
22
sndiod/dev.c
22
sndiod/dev.c
|
@ -50,6 +50,7 @@ void zomb_exit(void *);
|
|||
|
||||
void dev_midi_imsg(void *, unsigned char *, int);
|
||||
void dev_midi_omsg(void *, unsigned char *, int);
|
||||
void dev_midi_fill(void *, int);
|
||||
void dev_midi_exit(void *);
|
||||
|
||||
struct midiops dev_midiops = {
|
||||
|
@ -465,6 +466,18 @@ dev_midi_omsg(void *arg, unsigned char *msg, int len)
|
|||
}
|
||||
}
|
||||
|
||||
void
|
||||
dev_midi_fill(void *arg, int count)
|
||||
{
|
||||
struct dev *d = arg;
|
||||
|
||||
#ifdef DEBUG
|
||||
dev_log(d);
|
||||
log_puts(": can't receive fill input\n");
|
||||
panic();
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
dev_midi_exit(void *arg)
|
||||
{
|
||||
|
@ -663,7 +676,7 @@ dev_mix_cycle(struct dev *d)
|
|||
*ps = s->next;
|
||||
continue;
|
||||
}
|
||||
if (s->mix.buf.used < s->round * s->mix.bpf &&
|
||||
if (s->mix.buf.used < s->round * s->mix.bpf &&
|
||||
!(s->pstate == SLOT_STOP)) {
|
||||
if (s->xrun == XRUN_IGNORE) {
|
||||
if (s->mode & MODE_RECMASK)
|
||||
|
@ -976,6 +989,13 @@ dev_new(char *path, struct aparams *par,
|
|||
}
|
||||
d = xmalloc(sizeof(struct dev), "dev");
|
||||
d->num = dev_sndnum++;
|
||||
/*
|
||||
* XXX
|
||||
* we don't use the input buffer, since we don't receive
|
||||
* raw midi data, so no need to allocate a input ibuf.
|
||||
* Possibly set imsg & fill callbacks to NULL and use this
|
||||
* to in midi_new() to check if buffers need to be allocated
|
||||
*/
|
||||
d->midi = midi_new(&dev_midiops, d, MODE_MIDIIN | MODE_MIDIOUT);
|
||||
midi_tag(d->midi, d->num);
|
||||
d->path = path;
|
||||
|
|
|
@ -697,7 +697,7 @@ sqrtone(int ctx, adata_t *out, int period, int vol, int todo)
|
|||
ctx = period / 2;
|
||||
}
|
||||
ctx--;
|
||||
*(out++) = vol;
|
||||
*(out++) += vol;
|
||||
}
|
||||
return ctx;
|
||||
}
|
||||
|
|
150
sndiod/midi.c
150
sndiod/midi.c
|
@ -44,11 +44,13 @@
|
|||
int port_open(struct port *);
|
||||
void port_imsg(void *, unsigned char *, int);
|
||||
void port_omsg(void *, unsigned char *, int);
|
||||
void port_fill(void *, int);
|
||||
void port_exit(void *);
|
||||
|
||||
struct midiops port_midiops = {
|
||||
port_imsg,
|
||||
port_omsg,
|
||||
port_fill,
|
||||
port_exit
|
||||
};
|
||||
|
||||
|
@ -83,11 +85,6 @@ midi_ontimo(void *arg)
|
|||
struct midi *ep;
|
||||
|
||||
for (i = MIDI_NEP, ep = midi_ep; i > 0; i--, ep++) {
|
||||
ep->tickets = MIDI_XFER;
|
||||
if (ep->ibuf.used > 0) {
|
||||
while (midi_in(ep))
|
||||
; /* nothing */
|
||||
}
|
||||
}
|
||||
timo_add(&midi_timo, MIDI_TIMO);
|
||||
}
|
||||
|
@ -125,7 +122,6 @@ midi_new(struct midiops *ops, void *arg, int mode)
|
|||
ep->st = 0;
|
||||
ep->txmask = 0;
|
||||
ep->rxmask = 1 << i;
|
||||
ep->tickets = MIDI_XFER;
|
||||
ep->mode = mode;
|
||||
/*
|
||||
* client output is our input (ibuf) and our output (obuf) goes
|
||||
|
@ -236,30 +232,55 @@ midi_send(struct midi *iep, unsigned char *msg, int size)
|
|||
}
|
||||
}
|
||||
|
||||
|
||||
void
|
||||
midi_fill(struct midi *oep)
|
||||
{
|
||||
int i, count;
|
||||
struct midi *iep;
|
||||
|
||||
for (i = 0; i < MIDI_NEP ; i++) {
|
||||
if ((oep->rxmask & (1 << i)) == 0)
|
||||
continue;
|
||||
iep = midi_ep + i;
|
||||
count = midi_in(iep);
|
||||
if (count)
|
||||
iep->ops->fill(iep->arg, count);
|
||||
}
|
||||
}
|
||||
|
||||
int
|
||||
midi_in(struct midi *ep)
|
||||
midi_in(struct midi *iep)
|
||||
{
|
||||
unsigned char c, *idata;
|
||||
int i, icount;
|
||||
int i, icount, maxavail, avail;
|
||||
struct midi *oep;
|
||||
|
||||
if (ep->ibuf.used == 0)
|
||||
return 0;
|
||||
if (ep->tickets == 0) {
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
midi_log(ep);
|
||||
log_puts(": out of tickets, blocking\n");
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
/*
|
||||
* calculate the max message size we can process
|
||||
*/
|
||||
maxavail = MIDI_BUFSZ;
|
||||
for (i = 0; i < MIDI_NEP ; i++) {
|
||||
if ((iep->txmask & (1 << i)) == 0)
|
||||
continue;
|
||||
oep = midi_ep + i;
|
||||
avail = oep->obuf.len - oep->obuf.used;
|
||||
if (maxavail > avail)
|
||||
maxavail = avail;
|
||||
}
|
||||
idata = abuf_rgetblk(&ep->ibuf, &icount);
|
||||
//if (icount > ep->tickets)
|
||||
// icount = ep->tickets;
|
||||
//ep->tickets -= icount;
|
||||
|
||||
/*
|
||||
* in the works case output message is twice the
|
||||
* input message (2-byte messages with running status)
|
||||
*/
|
||||
maxavail /= 2;
|
||||
|
||||
idata = abuf_rgetblk(&iep->ibuf, &icount);
|
||||
if (icount > maxavail)
|
||||
icount = maxavail;
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
midi_log(ep);
|
||||
midi_log(iep);
|
||||
log_puts(": in:");
|
||||
for (i = 0; i < icount; i++) {
|
||||
log_puts(" ");
|
||||
|
@ -272,42 +293,42 @@ midi_in(struct midi *ep)
|
|||
c = *idata++;
|
||||
if (c >= 0xf8) {
|
||||
if (c != MIDI_ACK)
|
||||
ep->ops->imsg(ep->arg, &c, 1);
|
||||
iep->ops->imsg(iep->arg, &c, 1);
|
||||
} else if (c == SYSEX_END) {
|
||||
if (ep->st == SYSEX_START) {
|
||||
ep->msg[ep->idx++] = c;
|
||||
ep->ops->imsg(ep->arg, ep->msg, ep->idx);
|
||||
if (iep->st == SYSEX_START) {
|
||||
iep->msg[iep->idx++] = c;
|
||||
iep->ops->imsg(iep->arg, iep->msg, iep->idx);
|
||||
}
|
||||
ep->st = 0;
|
||||
ep->idx = 0;
|
||||
iep->st = 0;
|
||||
iep->idx = 0;
|
||||
} else if (c >= 0xf0) {
|
||||
ep->msg[0] = c;
|
||||
ep->len = common_len[c & 7];
|
||||
ep->st = c;
|
||||
ep->idx = 1;
|
||||
iep->msg[0] = c;
|
||||
iep->len = common_len[c & 7];
|
||||
iep->st = c;
|
||||
iep->idx = 1;
|
||||
} else if (c >= 0x80) {
|
||||
ep->msg[0] = c;
|
||||
ep->len = voice_len[(c >> 4) & 7];
|
||||
ep->st = c;
|
||||
ep->idx = 1;
|
||||
} else if (ep->st) {
|
||||
if (ep->idx == 0 && ep->st != SYSEX_START)
|
||||
ep->msg[ep->idx++] = ep->st;
|
||||
ep->msg[ep->idx++] = c;
|
||||
if (ep->idx == ep->len) {
|
||||
ep->ops->imsg(ep->arg, ep->msg, ep->idx);
|
||||
if (ep->st >= 0xf0)
|
||||
ep->st = 0;
|
||||
ep->idx = 0;
|
||||
} else if (ep->idx == MIDI_MSGMAX) {
|
||||
iep->msg[0] = c;
|
||||
iep->len = voice_len[(c >> 4) & 7];
|
||||
iep->st = c;
|
||||
iep->idx = 1;
|
||||
} else if (iep->st) {
|
||||
if (iep->idx == 0 && iep->st != SYSEX_START)
|
||||
iep->msg[iep->idx++] = iep->st;
|
||||
iep->msg[iep->idx++] = c;
|
||||
if (iep->idx == iep->len) {
|
||||
iep->ops->imsg(iep->arg, iep->msg, iep->idx);
|
||||
if (iep->st >= 0xf0)
|
||||
iep->st = 0;
|
||||
iep->idx = 0;
|
||||
} else if (iep->idx == MIDI_MSGMAX) {
|
||||
/* sysex continued */
|
||||
ep->ops->imsg(ep->arg, ep->msg, ep->idx);
|
||||
ep->idx = 0;
|
||||
iep->ops->imsg(iep->arg, iep->msg, iep->idx);
|
||||
iep->idx = 0;
|
||||
}
|
||||
}
|
||||
}
|
||||
abuf_rdiscard(&ep->ibuf, icount);
|
||||
return 1;
|
||||
abuf_rdiscard(&iep->ibuf, icount);
|
||||
return icount;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -319,7 +340,7 @@ midi_out(struct midi *oep, unsigned char *idata, int icount)
|
|||
while (icount > 0) {
|
||||
if (oep->obuf.used == oep->obuf.len) {
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 3) {
|
||||
if (log_level >= 2) {
|
||||
midi_log(oep);
|
||||
log_puts(": overrun, discarding ");
|
||||
log_putu(oep->obuf.used);
|
||||
|
@ -385,6 +406,12 @@ port_omsg(void *arg, unsigned char *msg, int size)
|
|||
midi_out(p->midi, msg, size);
|
||||
}
|
||||
|
||||
void
|
||||
port_fill(void *arg, int count)
|
||||
{
|
||||
/* no flow control */
|
||||
}
|
||||
|
||||
void
|
||||
port_exit(void *arg)
|
||||
{
|
||||
|
@ -423,6 +450,7 @@ port_del(struct port *c)
|
|||
|
||||
if (c->state != PORT_CFG)
|
||||
port_close(c);
|
||||
midi_del(c->midi);
|
||||
for (p = &port_list; *p != c; p = &(*p)->next) {
|
||||
#ifdef DEBUG
|
||||
if (*p == NULL) {
|
||||
|
@ -435,9 +463,18 @@ port_del(struct port *c)
|
|||
xfree(c);
|
||||
}
|
||||
|
||||
/*
|
||||
* Open a MIDI device and connect it to the thru box
|
||||
*/
|
||||
struct port *
|
||||
port_bynum(int num)
|
||||
{
|
||||
struct port *p;
|
||||
|
||||
for (p = port_list; p != NULL; p = p->next) {
|
||||
if (num-- == 0)
|
||||
return p;
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
int
|
||||
port_open(struct port *c)
|
||||
{
|
||||
|
@ -480,5 +517,6 @@ void
|
|||
port_done(struct port *c)
|
||||
{
|
||||
/* XXX: drain */
|
||||
port_close(c);
|
||||
if (c->state != PORT_CFG)
|
||||
port_close(c);
|
||||
}
|
||||
|
|
|
@ -56,6 +56,7 @@ struct midiops
|
|||
{
|
||||
void (*imsg)(void *, unsigned char *, int);
|
||||
void (*omsg)(void *, unsigned char *, int);
|
||||
void (*fill)(void *, int);
|
||||
void (*exit)(void *);
|
||||
};
|
||||
|
||||
|
@ -70,7 +71,6 @@ struct midi {
|
|||
unsigned int used; /* bytes used in ``msg'' */
|
||||
unsigned int idx; /* current ``msg'' size */
|
||||
unsigned int len; /* expected ``msg'' length */
|
||||
unsigned int tickets; /* input throttling */
|
||||
unsigned int txmask; /* list of ep we send to */
|
||||
unsigned int rxmask; /* single ep we accept data for */
|
||||
struct abuf ibuf; /* input buffer */
|
||||
|
@ -105,10 +105,12 @@ void midi_log(struct midi *);
|
|||
int midi_in(struct midi *);
|
||||
void midi_out(struct midi *, unsigned char *, int);
|
||||
void midi_send(struct midi *, unsigned char *, int);
|
||||
void midi_fill(struct midi *);
|
||||
void midi_tag(struct midi *, unsigned int);
|
||||
void midi_untag(struct midi *, unsigned int);
|
||||
|
||||
struct port *port_new(char *, unsigned int);
|
||||
struct port *port_bynum(int);
|
||||
void port_del(struct port *);
|
||||
int port_init(struct port *);
|
||||
void port_done(struct port *);
|
||||
|
|
|
@ -124,6 +124,7 @@ port_mio_out(void *arg)
|
|||
abuf_rdiscard(&ep->obuf, n);
|
||||
if (n < count)
|
||||
break;
|
||||
midi_fill(ep);
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -65,6 +65,7 @@ void sock_slot_mmcstop(void *);
|
|||
void sock_slot_mmcloc(void *, unsigned int);
|
||||
void sock_midi_imsg(void *, unsigned char *, int);
|
||||
void sock_midi_omsg(void *, unsigned char *, int);
|
||||
void sock_midi_fill(void *, int);
|
||||
void sock_exit(void *);
|
||||
|
||||
struct fileops sock_fileops = {
|
||||
|
@ -91,6 +92,7 @@ struct slotops sock_slotops = {
|
|||
struct midiops sock_midiops = {
|
||||
sock_midi_imsg,
|
||||
sock_midi_omsg,
|
||||
sock_midi_fill,
|
||||
sock_exit
|
||||
};
|
||||
|
||||
|
@ -272,6 +274,16 @@ sock_midi_omsg(void *arg, unsigned char *msg, int size)
|
|||
;
|
||||
}
|
||||
|
||||
void
|
||||
sock_midi_fill(void *arg, int count)
|
||||
{
|
||||
struct sock *f = arg;
|
||||
|
||||
f->fillpending += count;
|
||||
while (sock_write(f))
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* Initialise socket in the SOCK_HELLO state with default
|
||||
* parameters.
|
||||
|
@ -540,9 +552,11 @@ sock_rdata(struct sock *f)
|
|||
if (f->slot)
|
||||
slot_write(f->slot);
|
||||
if (f->midi) {
|
||||
count = f->midi->ibuf.used;
|
||||
while (midi_in(f->midi))
|
||||
; /* nothing */
|
||||
f->fillpending += f->midi->ibuf.len - f->midi->ibuf.used;
|
||||
count -= f->midi->ibuf.used;
|
||||
f->fillpending += count;
|
||||
}
|
||||
return 1;
|
||||
}
|
||||
|
@ -597,6 +611,8 @@ sock_wdata(struct sock *f)
|
|||
}
|
||||
if (f->slot)
|
||||
slot_read(f->slot);
|
||||
if (f->midi)
|
||||
midi_fill(f->midi);
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
sock_log(f);
|
||||
|
@ -814,6 +830,7 @@ sock_hello(struct sock *f)
|
|||
{
|
||||
struct amsg_hello *p = &f->rmsg.u.hello;
|
||||
struct slot *s;
|
||||
struct port *c;
|
||||
struct dev *d;
|
||||
unsigned int mode;
|
||||
|
||||
|
@ -872,6 +889,14 @@ sock_hello(struct sock *f)
|
|||
midi_tag(f->midi, p->devnum);
|
||||
} else if (p->devnum < 32) {
|
||||
midi_tag(f->midi, p->devnum);
|
||||
} else if (p->devnum < 48) {
|
||||
c = port_bynum(p->devnum - 32);
|
||||
if (c == NULL)
|
||||
return 0;
|
||||
if (mode & MODE_MIDIOUT)
|
||||
f->midi->txmask |= c->midi->rxmask;
|
||||
if (mode & MODE_MIDIIN)
|
||||
c->midi->txmask |= f->midi->rxmask;
|
||||
} else
|
||||
return 0;
|
||||
if (mode & MODE_MIDIOUT)
|
||||
|
@ -1339,14 +1364,6 @@ sock_buildmsg(struct sock *f)
|
|||
}
|
||||
|
||||
if (f->fillpending > 0) {
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
sock_log(f);
|
||||
log_puts(": building FLOWCTL message, count = ");
|
||||
log_puti(f->fillpending);
|
||||
log_puts("\n");
|
||||
}
|
||||
#endif
|
||||
AMSG_INIT(&f->wmsg);
|
||||
f->wmsg.cmd = htonl(AMSG_FLOWCTL);
|
||||
f->wmsg.u.ts.delta = htonl(f->fillpending);
|
||||
|
@ -1354,6 +1371,16 @@ sock_buildmsg(struct sock *f)
|
|||
if (f->slot)
|
||||
size *= f->slot->mix.bpf;
|
||||
f->rmax += size;
|
||||
#ifdef DEBUG
|
||||
if (log_level >= 4) {
|
||||
sock_log(f);
|
||||
log_puts(": building FLOWCTL message, count = ");
|
||||
log_puti(f->fillpending);
|
||||
log_puts(", rmax -> ");
|
||||
log_puti(f->rmax);
|
||||
log_puts("\n");
|
||||
}
|
||||
#endif
|
||||
f->wtodo = sizeof(struct amsg);
|
||||
f->wstate = SOCK_WMSG;
|
||||
f->fillpending = 0;
|
||||
|
|
Loading…
Reference in New Issue