use flow control instead of throtteling

This commit is contained in:
Alexandre Ratchov 2012-11-04 23:07:45 +01:00
parent 2b55c6e659
commit fffd1b2ad5
7 changed files with 157 additions and 69 deletions

View File

@ -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.

View File

@ -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;

View File

@ -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;
}

View File

@ -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);
}

View File

@ -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 *);

View File

@ -124,6 +124,7 @@ port_mio_out(void *arg)
abuf_rdiscard(&ep->obuf, n);
if (n < count)
break;
midi_fill(ep);
}
}

View File

@ -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;