version 1.1, 2012/11/23 07:03:28 |
version 1.2, 2012/11/30 20:30:24 |
|
|
unsigned int midi_portnum = 0; |
unsigned int midi_portnum = 0; |
|
|
struct midithru { |
struct midithru { |
unsigned txmask; |
unsigned int txmask, rxmask; |
#define MIDITHRU_NMAX 32 |
#define MIDITHRU_NMAX 32 |
} midithru[MIDITHRU_NMAX]; |
} midithru[MIDITHRU_NMAX]; |
|
|
|
|
ep->idx = 0; |
ep->idx = 0; |
ep->st = 0; |
ep->st = 0; |
ep->txmask = 0; |
ep->txmask = 0; |
ep->rxmask = 1 << i; |
ep->self = 1 << i; |
|
ep->tickets = 0; |
ep->mode = mode; |
ep->mode = mode; |
|
|
/* |
/* |
* client output is our input (ibuf) and our output (obuf) goes |
* the output buffer is the client intput |
* to client input |
|
*/ |
*/ |
if (ep->mode & MODE_MIDIOUT) { |
if (ep->mode & MODE_MIDIIN) |
abuf_init(&ep->ibuf, MIDI_BUFSZ); |
|
} |
|
if (ep->mode & MODE_MIDIIN) { |
|
abuf_init(&ep->obuf, MIDI_BUFSZ); |
abuf_init(&ep->obuf, MIDI_BUFSZ); |
} |
midi_tickets(ep); |
return ep; |
return ep; |
} |
} |
|
|
|
|
midi_del(struct midi *ep) |
midi_del(struct midi *ep) |
{ |
{ |
int i; |
int i; |
|
struct midi *peer; |
|
|
for (i = 0; i < MIDI_NEP; i++) |
ep->txmask = 0; |
midi_ep[i].txmask &= ~ep->rxmask; |
for (i = 0; i < MIDI_NEP; i++) { |
for (i = 0; i < MIDITHRU_NMAX; i++) |
peer = midi_ep + i; |
midithru[i].txmask &= ~ep->rxmask; |
if (peer->txmask & ep->self) { |
|
peer->txmask &= ~ep->self; |
/* XXX: drain output */ |
midi_tickets(peer); |
ep->ops = NULL; |
} |
if (ep->mode & MODE_MIDIOUT) { |
|
abuf_done(&ep->ibuf); |
|
} |
} |
|
for (i = 0; i < MIDITHRU_NMAX; i++) { |
|
midithru[i].txmask &= ~ep->self; |
|
midithru[i].rxmask &= ~ep->self; |
|
} |
|
ep->ops = NULL; |
if (ep->mode & MODE_MIDIIN) { |
if (ep->mode & MODE_MIDIIN) { |
abuf_done(&ep->obuf); |
abuf_done(&ep->obuf); |
} |
} |
} |
} |
|
|
/* |
/* |
* add the midi endpoint in the ``tag'' midi thru box |
* connect two midi endpoints |
*/ |
*/ |
void |
void |
midi_tag(struct midi *ep, unsigned int tag) |
midi_link(struct midi *ep, struct midi *peer) |
{ |
{ |
int i; |
if (ep->mode & MODE_MIDIOUT) { |
struct midi *m; |
ep->txmask |= peer->self; |
unsigned members; |
midi_tickets(ep); |
|
|
members = midithru[tag].txmask; |
|
midithru[tag].txmask |= ep->rxmask; |
|
|
|
for (i = 0, m = midi_ep; i < MIDI_NEP; i++, m++) { |
|
if (!(members & (1 << i))) |
|
continue; |
|
if (ep->mode & MODE_MIDIOUT) |
|
ep->txmask |= m->rxmask; |
|
if (ep->mode & MODE_MIDIIN) |
|
m->txmask |= ep->rxmask; |
|
} |
} |
|
if (ep->mode & MODE_MIDIIN) { |
|
#ifdef DEBUG |
|
if (ep->obuf.used > 0) { |
|
midi_log(ep); |
|
log_puts(": linked with non-empty buffer\n"); |
|
panic(); |
|
} |
|
#endif |
|
/* ep has empry buffer, so no need to call midi_tickets() */ |
|
peer->txmask |= ep->self; |
|
} |
} |
} |
|
|
/* |
/* |
* remove the midi endpoint from the ``tag'' midi thru box |
* add the midi endpoint in the ``tag'' midi thru box |
*/ |
*/ |
void |
void |
midi_untag(struct midi *ep, unsigned int tag) |
midi_tag(struct midi *ep, unsigned int tag) |
{ |
{ |
|
struct midi *peer; |
|
struct midithru *t = midithru + tag; |
int i; |
int i; |
struct midi *m; |
|
unsigned members; |
|
|
|
members = midithru[tag].txmask; |
if (ep->mode & MODE_MIDIOUT) { |
midithru[tag].txmask &= ~ep->rxmask; |
ep->txmask |= t->txmask; |
|
midi_tickets(ep); |
for (i = 0, m = midi_ep;; i++, m++) { |
|
if (!(members & (1 << i))) |
|
continue; |
|
ep->txmask &= ~m->rxmask; |
|
m->txmask &= ~ep->rxmask; |
|
} |
} |
|
if (ep->mode & MODE_MIDIIN) { |
|
#ifdef DEBUG |
|
if (ep->obuf.used > 0) { |
|
midi_log(ep); |
|
log_puts(": tagged with non-empty buffer\n"); |
|
panic(); |
|
} |
|
#endif |
|
for (i = 0; i < MIDI_NEP; i++) { |
|
if (!(t->rxmask & (1 << i))) |
|
continue; |
|
peer = midi_ep + i; |
|
peer->txmask |= ep->self; |
|
} |
|
} |
|
if (ep->mode & MODE_MIDIOUT) |
|
t->rxmask |= ep->self; |
|
if (ep->mode & MODE_MIDIIN) |
|
t->txmask |= ep->self; |
} |
} |
|
|
/* |
/* |
|
|
} |
} |
|
|
|
|
|
/* |
|
* determine if we have gained more input tickets, and if so call the |
|
* fill() call-back to notify the i/o layer that it can send more data |
|
*/ |
void |
void |
midi_fill(struct midi *oep) |
midi_tickets(struct midi *iep) |
{ |
{ |
int i, count; |
int i, tickets, avail, maxavail; |
struct midi *iep; |
struct midi *oep; |
|
|
|
maxavail = MIDI_BUFSZ; |
for (i = 0; i < MIDI_NEP ; i++) { |
for (i = 0; i < MIDI_NEP ; i++) { |
if ((oep->rxmask & (1 << i)) == 0) |
if ((iep->txmask & (1 << i)) == 0) |
continue; |
continue; |
|
oep = midi_ep + i; |
|
avail = oep->obuf.len - oep->obuf.used; |
|
if (maxavail > avail) |
|
maxavail = avail; |
|
} |
|
|
|
/* |
|
* in the worst case output message is twice the |
|
* input message (2-byte messages with running status) |
|
*/ |
|
tickets = maxavail / 2 - iep->tickets; |
|
if (tickets > 0) { |
|
iep->tickets += tickets; |
|
iep->ops->fill(iep->arg, tickets); |
|
} |
|
} |
|
|
|
/* |
|
* recalculate tickets of endpoints sending data to this one |
|
*/ |
|
void |
|
midi_fill(struct midi *oep) |
|
{ |
|
int i; |
|
struct midi *iep; |
|
|
|
for (i = 0; i < MIDI_NEP; i++) { |
iep = midi_ep + i; |
iep = midi_ep + i; |
count = midi_in(iep); |
if (iep->txmask & oep->self) |
if (count) |
midi_tickets(iep); |
iep->ops->fill(iep->arg, count); |
|
} |
} |
} |
} |
|
|
/* |
/* |
* parse the give data chunk, and calling imsg() for each message |
* parse then give data chunk, and calling imsg() for each message |
*/ |
*/ |
void |
void |
midi_parse(struct midi *iep, unsigned char *idata, int icount) |
midi_in(struct midi *iep, unsigned char *idata, int icount) |
{ |
{ |
int i; |
int i; |
unsigned char c; |
unsigned char c; |
|
|
} |
} |
} |
} |
} |
} |
|
iep->tickets -= icount; |
|
if (iep->tickets < 0) |
|
iep->tickets = 0; |
} |
} |
|
|
/* |
/* |
* process input data stored in ep->ibuf |
|
*/ |
|
int |
|
midi_in(struct midi *iep) |
|
{ |
|
unsigned char *idata; |
|
int i, icount, maxavail, avail, idone; |
|
struct midi *oep; |
|
|
|
/* |
|
* 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; |
|
} |
|
|
|
/* |
|
* in the works case output message is twice the |
|
* input message (2-byte messages with running status) |
|
*/ |
|
maxavail /= 2; |
|
idone = 0; |
|
for (;;) { |
|
idata = abuf_rgetblk(&iep->ibuf, &icount); |
|
if (icount > maxavail) |
|
icount = maxavail; |
|
if (icount == 0) |
|
break; |
|
maxavail -= icount; |
|
#ifdef DEBUG |
|
if (log_level >= 4) { |
|
midi_log(iep); |
|
log_puts(": in:"); |
|
for (i = 0; i < icount; i++) { |
|
log_puts(" "); |
|
log_putx(idata[i]); |
|
} |
|
log_puts("\n"); |
|
} |
|
#endif |
|
midi_parse(iep, idata, icount); |
|
abuf_rdiscard(&iep->ibuf, icount); |
|
idone += icount; |
|
} |
|
return idone; |
|
} |
|
|
|
/* |
|
* store the given message in the output buffer |
* store the given message in the output buffer |
*/ |
*/ |
void |
void |
|
|
#ifdef DEBUG |
#ifdef DEBUG |
if (log_level >= 2) { |
if (log_level >= 2) { |
midi_log(oep); |
midi_log(oep); |
log_puts(": overrun, discarding "); |
log_puts(": too slow, discarding "); |
log_putu(oep->obuf.used); |
log_putu(oep->obuf.used); |
log_puts(" bytes\n"); |
log_puts(" bytes\n"); |
} |
} |