version 1.6, 2009/08/26 08:28:21 |
version 1.7, 2009/08/27 06:31:13 |
|
|
/* |
/* |
* TODO |
* TODO |
* |
* |
* use abuf->duplex to implement bidirectionnal sockets |
* use shadow variables (to save NRPNs, LSB of controller) |
* that don't receive what they send |
* in the midi merger |
* |
* |
* use shadow variables in the midi merger |
|
* |
|
* make output and input identical when only one |
* make output and input identical when only one |
* input is used (fix running status) |
* input is used (fix running status) |
*/ |
*/ |
|
|
unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; |
unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; |
unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; |
unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; |
|
|
|
/* |
|
* send the message stored in of ibuf->mdata to obuf |
|
*/ |
void |
void |
thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) |
thru_flush(struct aproc *p, struct abuf *ibuf, struct abuf *obuf) |
{ |
{ |
|
|
p->u.thru.owner = ibuf; |
p->u.thru.owner = ibuf; |
} |
} |
|
|
|
/* |
|
* send the real-time message (one byte) to obuf, similar to thrui_flush() |
|
*/ |
void |
void |
thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c) |
thru_rt(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned c) |
{ |
{ |
|
|
abuf_wcommit(obuf, 1); |
abuf_wcommit(obuf, 1); |
} |
} |
|
|
|
/* |
|
* parse ibuf contents and store each message into obuf, |
|
* use at most ``todo'' bytes (for throttling) |
|
*/ |
void |
void |
thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo) |
thru_bcopy(struct aproc *p, struct abuf *ibuf, struct abuf *obuf, unsigned todo) |
{ |
{ |
|
|
thru_done |
thru_done |
}; |
}; |
|
|
|
/* |
|
* call-back invoked periodically to implement throttling at each invocation |
|
* gain more ``tickets'' for processing. If one of the buffer was blocked by |
|
* the throttelling mechanism, then run it |
|
*/ |
void |
void |
thru_cb(void *addr) |
thru_cb(void *addr) |
{ |
{ |
|
|
return p; |
return p; |
} |
} |
|
|
|
/* |
|
* broadcast a message to all output buffers on the behalf of ibuf. |
|
* ie. don't sent back the message to the sender |
|
*/ |
void |
void |
ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len) |
ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len) |
{ |
{ |
|
|
} |
} |
} |
} |
|
|
|
/* |
|
* allocate a new slot (ie midi channel), register the given call-back |
|
* to be called volume is changed by MIDI. The call-back is invoked at |
|
* initialization to restore the saved volume. |
|
*/ |
int |
int |
ctl_slotnew(struct aproc *p, char *who, void (*cb)(void *, unsigned), void *arg) |
ctl_slotnew(struct aproc *p, char *who, void (*cb)(void *, unsigned), void *arg) |
{ |
{ |
|
|
if (slot->cb == NULL && |
if (slot->cb == NULL && |
strcmp(slot->name, name) == 0 && |
strcmp(slot->name, name) == 0 && |
slot->unit == unit) { |
slot->unit == unit) { |
|
DPRINTFN(1, "ctl_newslot: reusing %u\n", i); |
slot->cb = cb; |
slot->cb = cb; |
slot->arg = arg; |
slot->arg = arg; |
DPRINTFN(1, "ctl_newslot: reusing %u\n", i); |
slot->cb(slot->arg, slot->vol); |
|
ctl_slotvol(p, i, slot->vol); |
return i; |
return i; |
} |
} |
} |
} |
|
|
strlcpy(slot->name, name, CTL_NAMEMAX); |
strlcpy(slot->name, name, CTL_NAMEMAX); |
slot->serial = p->u.ctl.serial++; |
slot->serial = p->u.ctl.serial++; |
slot->unit = unit; |
slot->unit = unit; |
|
slot->vol = MIDI_MAXCTL; |
|
DPRINTFN(1, "ctl_newslot: %u overwritten)\n", bestidx); |
slot->cb = cb; |
slot->cb = cb; |
slot->arg = arg; |
slot->arg = arg; |
DPRINTFN(1, "ctl_newslot: %u overwritten)\n", bestidx); |
slot->cb(slot->arg, slot->vol); |
|
ctl_slotvol(p, bestidx, slot->vol); |
return bestidx; |
return bestidx; |
} |
} |
|
|
|
/* |
|
* release the given slot |
|
*/ |
void |
void |
ctl_slotdel(struct aproc *p, int index) |
ctl_slotdel(struct aproc *p, int index) |
{ |
{ |
p->u.ctl.slot[index].cb = NULL; |
p->u.ctl.slot[index].cb = NULL; |
} |
} |
|
|
|
/* |
|
* notifty the mixer that volume changed, called by whom allocad the slot using |
|
* ctl_slotnew(). Note: it doesn't make sens to call this from within the |
|
* call-back. |
|
*/ |
void |
void |
ctl_slotvol(struct aproc *p, int slot, unsigned vol) |
ctl_slotvol(struct aproc *p, int slot, unsigned vol) |
{ |
{ |
unsigned char msg[3]; |
unsigned char msg[3]; |
|
|
DPRINTFN(1, "ctl_slotvol: [%u] -> %u\n", slot, vol); |
DPRINTFN(1, "ctl_slotvol: [%u] -> %u\n", slot, vol); |
|
p->u.ctl.slot[slot].vol = vol; |
msg[0] = MIDI_CTL | slot; |
msg[0] = MIDI_CTL | slot; |
msg[1] = MIDI_CTLVOL; |
msg[1] = MIDI_CTLVOL; |
msg[2] = vol; |
msg[2] = vol; |
ctl_sendmsg(p, NULL, msg, 3); |
ctl_sendmsg(p, NULL, msg, 3); |
} |
} |
|
|
|
/* |
|
* handle a MIDI event received from ibuf |
|
*/ |
void |
void |
ctl_ev(struct aproc *p, struct abuf *ibuf) |
ctl_ev(struct aproc *p, struct abuf *ibuf) |
{ |
{ |
|
|
slot = p->u.ctl.slot + chan; |
slot = p->u.ctl.slot + chan; |
if (slot->cb == NULL) |
if (slot->cb == NULL) |
return; |
return; |
slot->cb(slot->arg, ibuf->mdata[2]); |
slot->vol = ibuf->mdata[2]; |
|
slot->cb(slot->arg, slot->vol); |
ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen); |
ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen); |
} |
} |
} |
} |
|
|
struct ctl_slot *s; |
struct ctl_slot *s; |
|
|
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { |
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { |
|
/* |
|
* XXX: shouldn't we abord() here ? |
|
*/ |
if (s->cb != NULL) |
if (s->cb != NULL) |
DPRINTF("ctl_done: %s%u in use\n", s->name, s->unit); |
DPRINTF("ctl_done: %s%u in use\n", s->name, s->unit); |
} |
} |
|
|
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { |
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { |
p->u.ctl.slot[i].unit = i; |
p->u.ctl.slot[i].unit = i; |
p->u.ctl.slot[i].cb = NULL; |
p->u.ctl.slot[i].cb = NULL; |
|
p->u.ctl.slot[i].vol = MIDI_MAXCTL; |
p->u.ctl.slot[i].serial = p->u.ctl.serial++; |
p->u.ctl.slot[i].serial = p->u.ctl.serial++; |
strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX); |
strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX); |
} |
} |