mirror of https://github.com/ericonr/sndio.git
reuse midi-control code to implement midi thru boxes and remove
the old midithru implementation; less code, less bugs. As a side effect, midi output doesn't implement running status "compression" any more
This commit is contained in:
parent
a3955999b1
commit
37f7cba0f8
|
@ -169,11 +169,9 @@ struct aproc {
|
||||||
int bnext; /* to reach the next byte */
|
int bnext; /* to reach the next byte */
|
||||||
int snext; /* to reach the next sample */
|
int snext; /* to reach the next sample */
|
||||||
} conv;
|
} conv;
|
||||||
struct {
|
|
||||||
struct timo timo; /* timout for throtteling */
|
|
||||||
} thru;
|
|
||||||
struct {
|
struct {
|
||||||
struct dev *dev; /* controlled device */
|
struct dev *dev; /* controlled device */
|
||||||
|
struct timo timo; /* timout for throtteling */
|
||||||
unsigned fps; /* MTC frames per second */
|
unsigned fps; /* MTC frames per second */
|
||||||
#define MTC_FPS_24 0
|
#define MTC_FPS_24 0
|
||||||
#define MTC_FPS_25 1
|
#define MTC_FPS_25 1
|
||||||
|
@ -185,7 +183,7 @@ struct aproc {
|
||||||
unsigned fr; /* MTC frames */
|
unsigned fr; /* MTC frames */
|
||||||
unsigned qfr; /* MTC quarter frames */
|
unsigned qfr; /* MTC quarter frames */
|
||||||
int delta; /* rel. to the last MTC tick */
|
int delta; /* rel. to the last MTC tick */
|
||||||
} ctl;
|
} midi;
|
||||||
} u;
|
} u;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -532,7 +532,7 @@ main(int argc, char **argv)
|
||||||
mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
|
mkdev("loopback", MODE_LOOP, bufsz, round, 1, autovol);
|
||||||
break;
|
break;
|
||||||
case 'M':
|
case 'M':
|
||||||
mkdev("midithru", MODE_THRU, 0, 0, 1, 0);
|
mkdev("midithru", MODE_THRU, 0, 0, hold, 0);
|
||||||
break;
|
break;
|
||||||
case 'l':
|
case 'l':
|
||||||
background = 1;
|
background = 1;
|
||||||
|
@ -609,7 +609,7 @@ main(int argc, char **argv)
|
||||||
dnext = d->next;
|
dnext = d->next;
|
||||||
if (!dev_run(d))
|
if (!dev_run(d))
|
||||||
goto fatal;
|
goto fatal;
|
||||||
if (!dev_idle(d))
|
if (d->refcnt > 0)
|
||||||
active = 1;
|
active = 1;
|
||||||
}
|
}
|
||||||
if (dev_list == NULL)
|
if (dev_list == NULL)
|
||||||
|
|
56
aucat/dev.c
56
aucat/dev.c
|
@ -141,6 +141,7 @@ dev_new(char *path, unsigned mode,
|
||||||
d->hold = hold;
|
d->hold = hold;
|
||||||
d->autovol = autovol;
|
d->autovol = autovol;
|
||||||
d->autostart = 0;
|
d->autostart = 0;
|
||||||
|
d->refcnt = 0;
|
||||||
d->pstate = DEV_CLOSED;
|
d->pstate = DEV_CLOSED;
|
||||||
d->serial = 0;
|
d->serial = 0;
|
||||||
for (i = 0; i < CTL_NSLOT; i++) {
|
for (i = 0; i < CTL_NSLOT; i++) {
|
||||||
|
@ -395,8 +396,7 @@ dev_open(struct dev *d)
|
||||||
* if there's no device
|
* if there's no device
|
||||||
*/
|
*/
|
||||||
if (d->mode & MODE_MIDIMASK) {
|
if (d->mode & MODE_MIDIMASK) {
|
||||||
d->midi = (d->mode & MODE_THRU) ?
|
d->midi = midi_new("midi", (d->mode & MODE_THRU) ? NULL : d);
|
||||||
thru_new("thru") : ctl_new("ctl", d);
|
|
||||||
d->midi->refs++;
|
d->midi->refs++;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1450,8 +1450,9 @@ dev_slotnew(struct dev *d, char *who, struct ctl_ops *ops, void *arg, int mmc)
|
||||||
s->ops->vol(s->arg, s->vol);
|
s->ops->vol(s->arg, s->vol);
|
||||||
|
|
||||||
if (APROC_OK(d->midi)) {
|
if (APROC_OK(d->midi)) {
|
||||||
ctl_slot(d->midi, slot);
|
midi_send_slot(d->midi, slot);
|
||||||
ctl_vol(d->midi, slot, s->vol);
|
midi_send_vol(d->midi, slot, s->vol);
|
||||||
|
midi_flush(d->midi);
|
||||||
} else {
|
} else {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (debug_level >= 2) {
|
if (debug_level >= 2) {
|
||||||
|
@ -1495,38 +1496,10 @@ dev_slotvol(struct dev *d, int slot, unsigned vol)
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
d->slot[slot].vol = vol;
|
d->slot[slot].vol = vol;
|
||||||
if (APROC_OK(d->midi))
|
if (APROC_OK(d->midi)) {
|
||||||
ctl_vol(d->midi, slot, vol);
|
midi_send_vol(d->midi, slot, vol);
|
||||||
}
|
midi_flush(d->midi);
|
||||||
|
|
||||||
|
|
||||||
/*
|
|
||||||
* check if there are controlled streams
|
|
||||||
*/
|
|
||||||
int
|
|
||||||
dev_idle(struct dev *d)
|
|
||||||
{
|
|
||||||
unsigned i;
|
|
||||||
struct ctl_slot *s;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX: this conditions breaks -aoff for thru boxes
|
|
||||||
*/
|
|
||||||
if (d->mode & MODE_THRU)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
if (d->pstate != DEV_CLOSED)
|
|
||||||
return 0;
|
|
||||||
|
|
||||||
/*
|
|
||||||
* XXX: if the device is closed, we're sure there are no
|
|
||||||
* slots in use, so the following test is useless
|
|
||||||
*/
|
|
||||||
for (i = 0, s = d->slot; i < CTL_NSLOT; i++, s++) {
|
|
||||||
if (s->ops)
|
|
||||||
return 0;
|
|
||||||
}
|
}
|
||||||
return 1;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1578,8 +1551,11 @@ dev_try(struct dev *d, int slot)
|
||||||
if (slot >= 0)
|
if (slot >= 0)
|
||||||
d->slot[slot].tstate = CTL_RUN;
|
d->slot[slot].tstate = CTL_RUN;
|
||||||
d->tstate = CTL_RUN;
|
d->tstate = CTL_RUN;
|
||||||
if (APROC_OK(d->midi))
|
if (APROC_OK(d->midi)) {
|
||||||
ctl_full(d->midi, d->origin, d->rate, d->round, dev_getpos(d));
|
midi_send_full(d->midi,
|
||||||
|
d->origin, d->rate, d->round, dev_getpos(d));
|
||||||
|
midi_flush(d->midi);
|
||||||
|
}
|
||||||
dev_wakeup(d);
|
dev_wakeup(d);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
@ -1726,6 +1702,8 @@ dev_onmove(void *arg, int delta)
|
||||||
*/
|
*/
|
||||||
if (d->tstate != CTL_RUN)
|
if (d->tstate != CTL_RUN)
|
||||||
return;
|
return;
|
||||||
if (APROC_OK(d->midi))
|
if (APROC_OK(d->midi)) {
|
||||||
ctl_qfr(d->midi, d->rate, delta);
|
midi_send_qfr(d->midi, d->rate, delta);
|
||||||
|
midi_flush(d->midi);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -32,7 +32,6 @@ struct dev {
|
||||||
struct aparams reqipar, reqopar; /* parameters */
|
struct aparams reqipar, reqopar; /* parameters */
|
||||||
unsigned reqbufsz; /* buffer size */
|
unsigned reqbufsz; /* buffer size */
|
||||||
unsigned reqround; /* block size */
|
unsigned reqround; /* block size */
|
||||||
unsigned reqrate; /* sample rate */
|
|
||||||
unsigned hold; /* hold the device open ? */
|
unsigned hold; /* hold the device open ? */
|
||||||
unsigned autovol; /* auto adjust playvol ? */
|
unsigned autovol; /* auto adjust playvol ? */
|
||||||
unsigned autostart; /* don't wait for MMC start */
|
unsigned autostart; /* don't wait for MMC start */
|
||||||
|
@ -120,6 +119,5 @@ void dev_slotstop(struct dev *, int);
|
||||||
void dev_mmcstart(struct dev *);
|
void dev_mmcstart(struct dev *);
|
||||||
void dev_mmcstop(struct dev *);
|
void dev_mmcstop(struct dev *);
|
||||||
void dev_loc(struct dev *, unsigned);
|
void dev_loc(struct dev *, unsigned);
|
||||||
int dev_idle(struct dev *);
|
|
||||||
|
|
||||||
#endif /* !define(DEV_H) */
|
#endif /* !define(DEV_H) */
|
||||||
|
|
695
aucat/midi.c
695
aucat/midi.c
|
@ -19,9 +19,6 @@
|
||||||
*
|
*
|
||||||
* use shadow variables (to save NRPNs, LSB of controller)
|
* use shadow variables (to save NRPNs, LSB of controller)
|
||||||
* in the midi merger
|
* in the midi merger
|
||||||
*
|
|
||||||
* make output and input identical when only one
|
|
||||||
* input is used (fix running status)
|
|
||||||
*/
|
*/
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <stdlib.h>
|
#include <stdlib.h>
|
||||||
|
@ -76,25 +73,71 @@ 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->r.midi.msg to obuf
|
* 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_flush(struct abuf *ibuf, struct abuf *obuf)
|
midi_cb(void *addr)
|
||||||
{
|
{
|
||||||
unsigned ocount, itodo;
|
struct aproc *p = (struct aproc *)addr;
|
||||||
unsigned char *odata, *idata;
|
struct abuf *i, *inext;
|
||||||
|
unsigned tickets;
|
||||||
|
|
||||||
itodo = ibuf->r.midi.used;
|
timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
|
||||||
idata = ibuf->r.midi.msg;
|
|
||||||
#ifdef DEBUG
|
for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
|
||||||
if (debug_level >= 4) {
|
inext = LIST_NEXT(i, ient);
|
||||||
abuf_dbg(obuf);
|
tickets = i->tickets;
|
||||||
dbg_puts(": flushing ");
|
i->tickets = MIDITHRU_XFER;
|
||||||
dbg_putu(itodo);
|
if (tickets == 0)
|
||||||
dbg_puts(" byte message\n");
|
abuf_run(i);
|
||||||
}
|
}
|
||||||
#endif
|
}
|
||||||
while (itodo > 0) {
|
|
||||||
|
void
|
||||||
|
midi_msg_info(struct aproc *p, int slot, char *msg)
|
||||||
|
{
|
||||||
|
struct ctl_slot *s;
|
||||||
|
struct sysex *x = (struct sysex *)msg;
|
||||||
|
|
||||||
|
s = p->u.midi.dev->slot + slot;
|
||||||
|
memset(x, 0, sizeof(struct sysex));
|
||||||
|
x->start = SYSEX_START;
|
||||||
|
x->type = SYSEX_TYPE_EDU;
|
||||||
|
x->id0 = SYSEX_AUCAT;
|
||||||
|
x->id1 = SYSEX_AUCAT_MIXINFO;
|
||||||
|
if (*s->name != '\0') {
|
||||||
|
snprintf(x->u.mixinfo.name,
|
||||||
|
SYSEX_NAMELEN, "%s%u", s->name, s->unit);
|
||||||
|
}
|
||||||
|
x->u.mixinfo.chan = slot;
|
||||||
|
x->u.mixinfo.end = SYSEX_END;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
midi_msg_vol(struct aproc *p, int slot, char *msg)
|
||||||
|
{
|
||||||
|
struct ctl_slot *s;
|
||||||
|
|
||||||
|
s = p->u.midi.dev->slot + slot;
|
||||||
|
msg[0] = MIDI_CTL | slot;
|
||||||
|
msg[1] = MIDI_CTLVOL;
|
||||||
|
msg[2] = s->vol;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* send a message to the given output
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
midi_copy(struct abuf *ibuf, struct abuf *obuf, unsigned char *msg, unsigned len)
|
||||||
|
{
|
||||||
|
unsigned ocount;
|
||||||
|
unsigned char *odata;
|
||||||
|
|
||||||
|
if (msg[0] == SYSEX_START)
|
||||||
|
obuf->w.midi.owner = ibuf;
|
||||||
|
while (len > 0) {
|
||||||
if (!ABUF_WOK(obuf)) {
|
if (!ABUF_WOK(obuf)) {
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (debug_level >= 3) {
|
if (debug_level >= 3) {
|
||||||
|
@ -110,277 +153,8 @@ thru_flush(struct abuf *ibuf, struct abuf *obuf)
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
odata = abuf_wgetblk(obuf, &ocount, 0);
|
odata = abuf_wgetblk(obuf, &ocount, 0);
|
||||||
if (ocount > itodo)
|
if (ocount > len)
|
||||||
ocount = itodo;
|
ocount = len;
|
||||||
memcpy(odata, idata, ocount);
|
|
||||||
abuf_wcommit(obuf, ocount);
|
|
||||||
itodo -= ocount;
|
|
||||||
idata += ocount;
|
|
||||||
}
|
|
||||||
ibuf->r.midi.used = 0;
|
|
||||||
obuf->w.midi.owner = ibuf;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send the real-time message (one byte) to obuf, similar to thru_flush()
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
thru_rt(struct abuf *ibuf, struct abuf *obuf, unsigned c)
|
|
||||||
{
|
|
||||||
unsigned ocount;
|
|
||||||
unsigned char *odata;
|
|
||||||
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (debug_level >= 4) {
|
|
||||||
abuf_dbg(obuf);
|
|
||||||
dbg_puts(": ");
|
|
||||||
dbg_putx(c);
|
|
||||||
dbg_puts(": flushing realtime message\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
if (c == MIDI_ACK)
|
|
||||||
return;
|
|
||||||
if (!ABUF_WOK(obuf)) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (debug_level >= 3) {
|
|
||||||
abuf_dbg(obuf);
|
|
||||||
dbg_puts(": overrun, discarding ");
|
|
||||||
dbg_putu(obuf->used);
|
|
||||||
dbg_puts(" bytes\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
abuf_rdiscard(obuf, obuf->used);
|
|
||||||
if (obuf->w.midi.owner == ibuf)
|
|
||||||
obuf->w.midi.owner = NULL;
|
|
||||||
}
|
|
||||||
odata = abuf_wgetblk(obuf, &ocount, 0);
|
|
||||||
odata[0] = c;
|
|
||||||
abuf_wcommit(obuf, 1);
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* parse ibuf contents and store each message into obuf,
|
|
||||||
* use at most ``todo'' bytes (for throttling)
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
thru_bcopy(struct abuf *ibuf, struct abuf *obuf, unsigned todo)
|
|
||||||
{
|
|
||||||
unsigned char *idata;
|
|
||||||
unsigned c, icount, ioffs;
|
|
||||||
|
|
||||||
idata = NULL;
|
|
||||||
icount = ioffs = 0;
|
|
||||||
for (;;) {
|
|
||||||
if (icount == 0) {
|
|
||||||
if (todo == 0)
|
|
||||||
break;
|
|
||||||
idata = abuf_rgetblk(ibuf, &icount, ioffs);
|
|
||||||
if (icount > todo)
|
|
||||||
icount = todo;
|
|
||||||
if (icount == 0)
|
|
||||||
break;
|
|
||||||
todo -= icount;
|
|
||||||
ioffs += icount;
|
|
||||||
}
|
|
||||||
c = *idata++;
|
|
||||||
icount--;
|
|
||||||
if (c < 0x80) {
|
|
||||||
if (ibuf->r.midi.idx == 0 && ibuf->r.midi.st) {
|
|
||||||
ibuf->r.midi.msg[ibuf->r.midi.used++] = ibuf->r.midi.st;
|
|
||||||
ibuf->r.midi.idx++;
|
|
||||||
}
|
|
||||||
ibuf->r.midi.msg[ibuf->r.midi.used++] = c;
|
|
||||||
ibuf->r.midi.idx++;
|
|
||||||
if (ibuf->r.midi.idx == ibuf->r.midi.len) {
|
|
||||||
thru_flush(ibuf, obuf);
|
|
||||||
if (ibuf->r.midi.st >= 0xf0)
|
|
||||||
ibuf->r.midi.st = 0;
|
|
||||||
ibuf->r.midi.idx = 0;
|
|
||||||
}
|
|
||||||
if (ibuf->r.midi.used == MIDI_MSGMAX) {
|
|
||||||
if (ibuf->r.midi.used == ibuf->r.midi.idx ||
|
|
||||||
obuf->w.midi.owner == ibuf)
|
|
||||||
thru_flush(ibuf, obuf);
|
|
||||||
else
|
|
||||||
ibuf->r.midi.used = 0;
|
|
||||||
}
|
|
||||||
} else if (c < 0xf8) {
|
|
||||||
if (ibuf->r.midi.used == ibuf->r.midi.idx ||
|
|
||||||
obuf->w.midi.owner == ibuf) {
|
|
||||||
thru_flush(ibuf, obuf);
|
|
||||||
} else
|
|
||||||
ibuf->r.midi.used = 0;
|
|
||||||
ibuf->r.midi.msg[0] = c;
|
|
||||||
ibuf->r.midi.used = 1;
|
|
||||||
ibuf->r.midi.len = (c >= 0xf0) ?
|
|
||||||
common_len[c & 7] :
|
|
||||||
voice_len[(c >> 4) & 7];
|
|
||||||
if (ibuf->r.midi.len == 1) {
|
|
||||||
thru_flush(ibuf, obuf);
|
|
||||||
ibuf->r.midi.idx = 0;
|
|
||||||
ibuf->r.midi.st = 0;
|
|
||||||
ibuf->r.midi.len = 0;
|
|
||||||
} else {
|
|
||||||
ibuf->r.midi.st = c;
|
|
||||||
ibuf->r.midi.idx = 1;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
thru_rt(ibuf, obuf, c);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
thru_in(struct aproc *p, struct abuf *ibuf)
|
|
||||||
{
|
|
||||||
struct abuf *i, *inext;
|
|
||||||
unsigned todo;
|
|
||||||
|
|
||||||
if (!ABUF_ROK(ibuf))
|
|
||||||
return 0;
|
|
||||||
if (ibuf->tickets == 0) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (debug_level >= 4) {
|
|
||||||
abuf_dbg(ibuf);
|
|
||||||
dbg_puts(": out of tickets, blocking\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
todo = ibuf->used;
|
|
||||||
if (todo > ibuf->tickets)
|
|
||||||
todo = ibuf->tickets;
|
|
||||||
ibuf->tickets -= todo;
|
|
||||||
for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
|
|
||||||
inext = LIST_NEXT(i, oent);
|
|
||||||
if (ibuf->duplex == i)
|
|
||||||
continue;
|
|
||||||
thru_bcopy(ibuf, i, todo);
|
|
||||||
(void)abuf_flush(i);
|
|
||||||
}
|
|
||||||
abuf_rdiscard(ibuf, todo);
|
|
||||||
return 1;
|
|
||||||
}
|
|
||||||
|
|
||||||
int
|
|
||||||
thru_out(struct aproc *p, struct abuf *obuf)
|
|
||||||
{
|
|
||||||
return 0;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
thru_eof(struct aproc *p, struct abuf *ibuf)
|
|
||||||
{
|
|
||||||
if (!(p->flags & APROC_QUIT))
|
|
||||||
return;
|
|
||||||
if (LIST_EMPTY(&p->ins))
|
|
||||||
aproc_del(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
thru_hup(struct aproc *p, struct abuf *obuf)
|
|
||||||
{
|
|
||||||
if (!(p->flags & APROC_QUIT))
|
|
||||||
return;
|
|
||||||
if (LIST_EMPTY(&p->ins))
|
|
||||||
aproc_del(p);
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
thru_newin(struct aproc *p, struct abuf *ibuf)
|
|
||||||
{
|
|
||||||
ibuf->r.midi.used = 0;
|
|
||||||
ibuf->r.midi.len = 0;
|
|
||||||
ibuf->r.midi.idx = 0;
|
|
||||||
ibuf->r.midi.st = 0;
|
|
||||||
ibuf->tickets = MIDITHRU_XFER;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
thru_newout(struct aproc *p, struct abuf *obuf)
|
|
||||||
{
|
|
||||||
obuf->w.midi.owner = NULL;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
thru_done(struct aproc *p)
|
|
||||||
{
|
|
||||||
timo_del(&p->u.thru.timo);
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aproc_ops thru_ops = {
|
|
||||||
"thru",
|
|
||||||
thru_in,
|
|
||||||
thru_out,
|
|
||||||
thru_eof,
|
|
||||||
thru_hup,
|
|
||||||
thru_newin,
|
|
||||||
thru_newout,
|
|
||||||
NULL, /* ipos */
|
|
||||||
NULL, /* opos */
|
|
||||||
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
|
|
||||||
thru_cb(void *addr)
|
|
||||||
{
|
|
||||||
struct aproc *p = (struct aproc *)addr;
|
|
||||||
struct abuf *i, *inext;
|
|
||||||
unsigned tickets;
|
|
||||||
|
|
||||||
timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
|
|
||||||
|
|
||||||
for (i = LIST_FIRST(&p->ins); i != NULL; i = inext) {
|
|
||||||
inext = LIST_NEXT(i, ient);
|
|
||||||
tickets = i->tickets;
|
|
||||||
i->tickets = MIDITHRU_XFER;
|
|
||||||
if (tickets == 0)
|
|
||||||
abuf_run(i);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
struct aproc *
|
|
||||||
thru_new(char *name)
|
|
||||||
{
|
|
||||||
struct aproc *p;
|
|
||||||
|
|
||||||
p = aproc_new(&thru_ops, name);
|
|
||||||
timo_set(&p->u.thru.timo, thru_cb, p);
|
|
||||||
timo_add(&p->u.thru.timo, MIDITHRU_TIMO);
|
|
||||||
return p;
|
|
||||||
}
|
|
||||||
|
|
||||||
/*
|
|
||||||
* send a message to the given output
|
|
||||||
*/
|
|
||||||
void
|
|
||||||
ctl_copymsg(struct abuf *obuf, unsigned char *msg, unsigned len)
|
|
||||||
{
|
|
||||||
unsigned ocount, itodo;
|
|
||||||
unsigned char *odata, *idata;
|
|
||||||
|
|
||||||
itodo = len;
|
|
||||||
idata = msg;
|
|
||||||
while (itodo > 0) {
|
|
||||||
if (!ABUF_WOK(obuf)) {
|
|
||||||
#ifdef DEBUG
|
|
||||||
if (debug_level >= 3) {
|
|
||||||
abuf_dbg(obuf);
|
|
||||||
dbg_puts(": overrun, discarding ");
|
|
||||||
dbg_putu(obuf->used);
|
|
||||||
dbg_puts(" bytes\n");
|
|
||||||
}
|
|
||||||
#endif
|
|
||||||
abuf_rdiscard(obuf, obuf->used);
|
|
||||||
}
|
|
||||||
odata = abuf_wgetblk(obuf, &ocount, 0);
|
|
||||||
if (ocount > itodo)
|
|
||||||
ocount = itodo;
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (debug_level >= 4) {
|
if (debug_level >= 4) {
|
||||||
abuf_dbg(obuf);
|
abuf_dbg(obuf);
|
||||||
|
@ -389,10 +163,27 @@ ctl_copymsg(struct abuf *obuf, unsigned char *msg, unsigned len)
|
||||||
dbg_puts(" bytes\n");
|
dbg_puts(" bytes\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
memcpy(odata, idata, ocount);
|
memcpy(odata, msg, ocount);
|
||||||
abuf_wcommit(obuf, ocount);
|
abuf_wcommit(obuf, ocount);
|
||||||
itodo -= ocount;
|
len -= ocount;
|
||||||
idata += ocount;
|
msg += ocount;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* flush all buffers. Since most of the MIDI traffic is broadcasted to
|
||||||
|
* all outputs, the flush is delayed to avoid flushing all outputs for
|
||||||
|
* each message.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
midi_flush(struct aproc *p)
|
||||||
|
{
|
||||||
|
struct abuf *i, *inext;
|
||||||
|
|
||||||
|
for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
|
||||||
|
inext = LIST_NEXT(i, oent);
|
||||||
|
if (ABUF_ROK(i))
|
||||||
|
(void)abuf_flush(i);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -401,7 +192,7 @@ ctl_copymsg(struct abuf *obuf, unsigned char *msg, unsigned len)
|
||||||
* ie. don't sent back the message to the sender
|
* 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)
|
midi_send(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
|
||||||
{
|
{
|
||||||
struct abuf *i, *inext;
|
struct abuf *i, *inext;
|
||||||
|
|
||||||
|
@ -409,8 +200,7 @@ ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len
|
||||||
inext = LIST_NEXT(i, oent);
|
inext = LIST_NEXT(i, oent);
|
||||||
if (i->duplex && i->duplex == ibuf)
|
if (i->duplex && i->duplex == ibuf)
|
||||||
continue;
|
continue;
|
||||||
ctl_copymsg(i, msg, len);
|
midi_copy(ibuf, i, msg, len);
|
||||||
(void)abuf_flush(i);
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -418,77 +208,69 @@ ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len
|
||||||
* send a quarter frame MTC message
|
* send a quarter frame MTC message
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ctl_qfr(struct aproc *p, unsigned rate, int delta)
|
midi_send_qfr(struct aproc *p, unsigned rate, int delta)
|
||||||
{
|
{
|
||||||
unsigned char buf[2];
|
unsigned char buf[2];
|
||||||
unsigned data;
|
unsigned data;
|
||||||
int qfrlen;
|
int qfrlen;
|
||||||
|
|
||||||
p->u.ctl.delta += delta * MTC_SEC;
|
p->u.midi.delta += delta * MTC_SEC;
|
||||||
|
qfrlen = rate * (MTC_SEC / (4 * p->u.midi.fps));
|
||||||
/*
|
while (p->u.midi.delta >= qfrlen) {
|
||||||
* don't send ticks during the count-down
|
switch (p->u.midi.qfr) {
|
||||||
* XXX: test not useful, given while() condition
|
|
||||||
*/
|
|
||||||
if (p->u.ctl.delta < 0)
|
|
||||||
return;
|
|
||||||
|
|
||||||
qfrlen = rate * (MTC_SEC / (4 * p->u.ctl.fps));
|
|
||||||
while (p->u.ctl.delta >= qfrlen) {
|
|
||||||
switch (p->u.ctl.qfr) {
|
|
||||||
case 0:
|
case 0:
|
||||||
data = p->u.ctl.fr & 0xf;
|
data = p->u.midi.fr & 0xf;
|
||||||
break;
|
break;
|
||||||
case 1:
|
case 1:
|
||||||
data = p->u.ctl.fr >> 4;
|
data = p->u.midi.fr >> 4;
|
||||||
break;
|
break;
|
||||||
case 2:
|
case 2:
|
||||||
data = p->u.ctl.sec & 0xf;
|
data = p->u.midi.sec & 0xf;
|
||||||
break;
|
break;
|
||||||
case 3:
|
case 3:
|
||||||
data = p->u.ctl.sec >> 4;
|
data = p->u.midi.sec >> 4;
|
||||||
break;
|
break;
|
||||||
case 4:
|
case 4:
|
||||||
data = p->u.ctl.min & 0xf;
|
data = p->u.midi.min & 0xf;
|
||||||
break;
|
break;
|
||||||
case 5:
|
case 5:
|
||||||
data = p->u.ctl.min >> 4;
|
data = p->u.midi.min >> 4;
|
||||||
break;
|
break;
|
||||||
case 6:
|
case 6:
|
||||||
data = p->u.ctl.hr & 0xf;
|
data = p->u.midi.hr & 0xf;
|
||||||
break;
|
break;
|
||||||
case 7:
|
case 7:
|
||||||
data = (p->u.ctl.hr >> 4) | (p->u.ctl.fps_id << 1);
|
data = (p->u.midi.hr >> 4) | (p->u.midi.fps_id << 1);
|
||||||
/*
|
/*
|
||||||
* tick messages are sent 2 frames ahead
|
* tick messages are sent 2 frames ahead
|
||||||
*/
|
*/
|
||||||
p->u.ctl.fr += 2;
|
p->u.midi.fr += 2;
|
||||||
if (p->u.ctl.fr < p->u.ctl.fps)
|
if (p->u.midi.fr < p->u.midi.fps)
|
||||||
break;
|
break;
|
||||||
p->u.ctl.fr -= p->u.ctl.fps;
|
p->u.midi.fr -= p->u.midi.fps;
|
||||||
p->u.ctl.sec++;
|
p->u.midi.sec++;
|
||||||
if (p->u.ctl.sec < 60)
|
if (p->u.midi.sec < 60)
|
||||||
break;
|
break;
|
||||||
p->u.ctl.sec = 0;
|
p->u.midi.sec = 0;
|
||||||
p->u.ctl.min++;
|
p->u.midi.min++;
|
||||||
if (p->u.ctl.min < 60)
|
if (p->u.midi.min < 60)
|
||||||
break;
|
break;
|
||||||
p->u.ctl.min = 0;
|
p->u.midi.min = 0;
|
||||||
p->u.ctl.hr++;
|
p->u.midi.hr++;
|
||||||
if (p->u.ctl.hr < 24)
|
if (p->u.midi.hr < 24)
|
||||||
break;
|
break;
|
||||||
p->u.ctl.hr = 0;
|
p->u.midi.hr = 0;
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* NOTREACHED */
|
/* NOTREACHED */
|
||||||
data = 0;
|
data = 0;
|
||||||
}
|
}
|
||||||
buf[0] = 0xf1;
|
buf[0] = 0xf1;
|
||||||
buf[1] = (p->u.ctl.qfr << 4) | data;
|
buf[1] = (p->u.midi.qfr << 4) | data;
|
||||||
p->u.ctl.qfr++;
|
p->u.midi.qfr++;
|
||||||
p->u.ctl.qfr &= 7;
|
p->u.midi.qfr &= 7;
|
||||||
ctl_sendmsg(p, NULL, buf, 2);
|
midi_send(p, NULL, buf, 2);
|
||||||
p->u.ctl.delta -= qfrlen;
|
p->u.midi.delta -= qfrlen;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -496,95 +278,64 @@ ctl_qfr(struct aproc *p, unsigned rate, int delta)
|
||||||
* send a full frame MTC message
|
* send a full frame MTC message
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ctl_full(struct aproc *p, unsigned origin, unsigned rate, unsigned round, unsigned pos)
|
midi_send_full(struct aproc *p, unsigned origin, unsigned rate, unsigned round, unsigned pos)
|
||||||
{
|
{
|
||||||
unsigned char buf[10];
|
unsigned char buf[10];
|
||||||
unsigned fps;
|
unsigned fps;
|
||||||
|
|
||||||
p->u.ctl.delta = MTC_SEC * pos;
|
p->u.midi.delta = MTC_SEC * pos;
|
||||||
if (rate % (30 * 4 * round) == 0) {
|
if (rate % (30 * 4 * round) == 0) {
|
||||||
p->u.ctl.fps_id = MTC_FPS_30;
|
p->u.midi.fps_id = MTC_FPS_30;
|
||||||
p->u.ctl.fps = 30;
|
p->u.midi.fps = 30;
|
||||||
} else if (rate % (25 * 4 * round) == 0) {
|
} else if (rate % (25 * 4 * round) == 0) {
|
||||||
p->u.ctl.fps_id = MTC_FPS_25;
|
p->u.midi.fps_id = MTC_FPS_25;
|
||||||
p->u.ctl.fps = 25;
|
p->u.midi.fps = 25;
|
||||||
} else {
|
} else {
|
||||||
p->u.ctl.fps_id = MTC_FPS_24;
|
p->u.midi.fps_id = MTC_FPS_24;
|
||||||
p->u.ctl.fps = 24;
|
p->u.midi.fps = 24;
|
||||||
}
|
}
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
if (debug_level >= 3) {
|
if (debug_level >= 3) {
|
||||||
aproc_dbg(p);
|
aproc_dbg(p);
|
||||||
dbg_puts(": mtc full frame at ");
|
dbg_puts(": mtc full frame at ");
|
||||||
dbg_puti(p->u.ctl.delta);
|
dbg_puti(p->u.midi.delta);
|
||||||
dbg_puts(", ");
|
dbg_puts(", ");
|
||||||
dbg_puti(p->u.ctl.fps);
|
dbg_puti(p->u.midi.fps);
|
||||||
dbg_puts(" fps\n");
|
dbg_puts(" fps\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
fps = p->u.ctl.fps;
|
fps = p->u.midi.fps;
|
||||||
p->u.ctl.hr = (origin / (3600 * MTC_SEC)) % 24;
|
p->u.midi.hr = (origin / (3600 * MTC_SEC)) % 24;
|
||||||
p->u.ctl.min = (origin / (60 * MTC_SEC)) % 60;
|
p->u.midi.min = (origin / (60 * MTC_SEC)) % 60;
|
||||||
p->u.ctl.sec = (origin / MTC_SEC) % 60;
|
p->u.midi.sec = (origin / MTC_SEC) % 60;
|
||||||
p->u.ctl.fr = (origin / (MTC_SEC / fps)) % fps;
|
p->u.midi.fr = (origin / (MTC_SEC / fps)) % fps;
|
||||||
|
|
||||||
buf[0] = 0xf0;
|
buf[0] = 0xf0;
|
||||||
buf[1] = 0x7f;
|
buf[1] = 0x7f;
|
||||||
buf[2] = 0x7f;
|
buf[2] = 0x7f;
|
||||||
buf[3] = 0x01;
|
buf[3] = 0x01;
|
||||||
buf[4] = 0x01;
|
buf[4] = 0x01;
|
||||||
buf[5] = p->u.ctl.hr | (p->u.ctl.fps_id << 5);
|
buf[5] = p->u.midi.hr | (p->u.midi.fps_id << 5);
|
||||||
buf[6] = p->u.ctl.min;
|
buf[6] = p->u.midi.min;
|
||||||
buf[7] = p->u.ctl.sec;
|
buf[7] = p->u.midi.sec;
|
||||||
buf[8] = p->u.ctl.fr;
|
buf[8] = p->u.midi.fr;
|
||||||
buf[9] = 0xf7;
|
buf[9] = 0xf7;
|
||||||
p->u.ctl.qfr = 0;
|
p->u.midi.qfr = 0;
|
||||||
ctl_sendmsg(p, NULL, buf, 10);
|
midi_send(p, NULL, buf, 10);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ctl_msg_info(struct aproc *p, int slot, char *msg)
|
midi_copy_dump(struct aproc *p, struct abuf *obuf)
|
||||||
{
|
|
||||||
struct ctl_slot *s;
|
|
||||||
struct sysex *x = (struct sysex *)msg;
|
|
||||||
|
|
||||||
s = p->u.ctl.dev->slot + slot;
|
|
||||||
memset(x, 0, sizeof(struct sysex));
|
|
||||||
x->start = SYSEX_START;
|
|
||||||
x->type = SYSEX_TYPE_EDU;
|
|
||||||
x->id0 = SYSEX_AUCAT;
|
|
||||||
x->id1 = SYSEX_AUCAT_MIXINFO;
|
|
||||||
if (*s->name != '\0') {
|
|
||||||
snprintf(x->u.mixinfo.name,
|
|
||||||
SYSEX_NAMELEN, "%s%u", s->name, s->unit);
|
|
||||||
}
|
|
||||||
x->u.mixinfo.chan = slot;
|
|
||||||
x->u.mixinfo.end = SYSEX_END;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ctl_msg_vol(struct aproc *p, int slot, char *msg)
|
|
||||||
{
|
|
||||||
struct ctl_slot *s;
|
|
||||||
|
|
||||||
s = p->u.ctl.dev->slot + slot;
|
|
||||||
msg[0] = MIDI_CTL | slot;
|
|
||||||
msg[1] = MIDI_CTLVOL;
|
|
||||||
msg[2] = s->vol;
|
|
||||||
}
|
|
||||||
|
|
||||||
void
|
|
||||||
ctl_dump(struct aproc *p, struct abuf *obuf)
|
|
||||||
{
|
{
|
||||||
unsigned i;
|
unsigned i;
|
||||||
unsigned char msg[sizeof(struct sysex)];
|
unsigned char msg[sizeof(struct sysex)];
|
||||||
struct ctl_slot *s;
|
struct ctl_slot *s;
|
||||||
|
|
||||||
for (i = 0, s = p->u.ctl.dev->slot; i < CTL_NSLOT; i++, s++) {
|
for (i = 0, s = p->u.midi.dev->slot; i < CTL_NSLOT; i++, s++) {
|
||||||
ctl_msg_info(p, i, msg);
|
midi_msg_info(p, i, msg);
|
||||||
ctl_copymsg(obuf, msg, SYSEX_SIZE(mixinfo));
|
midi_copy(NULL, obuf, msg, SYSEX_SIZE(mixinfo));
|
||||||
ctl_msg_vol(p, i, msg);
|
midi_msg_vol(p, i, msg);
|
||||||
ctl_copymsg(obuf, msg, 3);
|
midi_copy(NULL, obuf, msg, 3);
|
||||||
}
|
}
|
||||||
msg[0] = SYSEX_START;
|
msg[0] = SYSEX_START;
|
||||||
msg[1] = SYSEX_TYPE_EDU;
|
msg[1] = SYSEX_TYPE_EDU;
|
||||||
|
@ -592,8 +343,7 @@ ctl_dump(struct aproc *p, struct abuf *obuf)
|
||||||
msg[3] = SYSEX_AUCAT;
|
msg[3] = SYSEX_AUCAT;
|
||||||
msg[4] = SYSEX_AUCAT_DUMPEND;
|
msg[4] = SYSEX_AUCAT_DUMPEND;
|
||||||
msg[5] = SYSEX_END;
|
msg[5] = SYSEX_END;
|
||||||
ctl_copymsg(obuf, msg, 6);
|
midi_copy(NULL, obuf, msg, 6);
|
||||||
abuf_flush(obuf);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -602,39 +352,37 @@ ctl_dump(struct aproc *p, struct abuf *obuf)
|
||||||
* call-back.
|
* call-back.
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ctl_vol(struct aproc *p, int slot, unsigned vol)
|
midi_send_vol(struct aproc *p, int slot, unsigned vol)
|
||||||
{
|
{
|
||||||
unsigned char msg[3];
|
unsigned char msg[3];
|
||||||
|
|
||||||
ctl_msg_vol(p, slot, msg);
|
midi_msg_vol(p, slot, msg);
|
||||||
ctl_sendmsg(p, NULL, msg, 3);
|
midi_send(p, NULL, msg, 3);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ctl_slot(struct aproc *p, int slot)
|
midi_send_slot(struct aproc *p, int slot)
|
||||||
{
|
{
|
||||||
unsigned char msg[sizeof(struct sysex)];
|
unsigned char msg[sizeof(struct sysex)];
|
||||||
|
|
||||||
ctl_msg_info(p, slot, msg);
|
midi_msg_info(p, slot, msg);
|
||||||
ctl_sendmsg(p, NULL, msg, SYSEX_SIZE(mixinfo));
|
midi_send(p, NULL, msg, SYSEX_SIZE(mixinfo));
|
||||||
}
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* handle a MIDI event received from ibuf
|
* handle a MIDI voice event received from ibuf
|
||||||
*/
|
*/
|
||||||
void
|
void
|
||||||
ctl_ev(struct aproc *p, struct abuf *ibuf)
|
midi_onvoice(struct aproc *p, struct abuf *ibuf)
|
||||||
{
|
{
|
||||||
unsigned chan;
|
|
||||||
struct ctl_slot *slot;
|
struct ctl_slot *slot;
|
||||||
struct sysex *x;
|
unsigned chan;
|
||||||
unsigned fps, len;
|
|
||||||
#ifdef DEBUG
|
#ifdef DEBUG
|
||||||
unsigned i;
|
unsigned i;
|
||||||
|
|
||||||
if (debug_level >= 3) {
|
if (debug_level >= 3) {
|
||||||
abuf_dbg(ibuf);
|
abuf_dbg(ibuf);
|
||||||
dbg_puts(": got event:");
|
dbg_puts(": got voice event:");
|
||||||
for (i = 0; i < ibuf->r.midi.idx; i++) {
|
for (i = 0; i < ibuf->r.midi.idx; i++) {
|
||||||
dbg_puts(" ");
|
dbg_puts(" ");
|
||||||
dbg_putx(ibuf->r.midi.msg[i]);
|
dbg_putx(ibuf->r.midi.msg[i]);
|
||||||
|
@ -647,13 +395,35 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
||||||
chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
|
chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK;
|
||||||
if (chan >= CTL_NSLOT)
|
if (chan >= CTL_NSLOT)
|
||||||
return;
|
return;
|
||||||
slot = p->u.ctl.dev->slot + chan;
|
slot = p->u.midi.dev->slot + chan;
|
||||||
slot->vol = ibuf->r.midi.msg[2];
|
slot->vol = ibuf->r.midi.msg[2];
|
||||||
if (slot->ops == NULL)
|
if (slot->ops == NULL)
|
||||||
return;
|
return;
|
||||||
slot->ops->vol(slot->arg, slot->vol);
|
slot->ops->vol(slot->arg, slot->vol);
|
||||||
ctl_sendmsg(p, ibuf, ibuf->r.midi.msg, ibuf->r.midi.len);
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* handle a MIDI sysex received from ibuf
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
midi_onsysex(struct aproc *p, struct abuf *ibuf)
|
||||||
|
{
|
||||||
|
struct sysex *x;
|
||||||
|
unsigned fps, len;
|
||||||
|
#ifdef DEBUG
|
||||||
|
unsigned i;
|
||||||
|
|
||||||
|
if (debug_level >= 3) {
|
||||||
|
abuf_dbg(ibuf);
|
||||||
|
dbg_puts(": got sysex:");
|
||||||
|
for (i = 0; i < ibuf->r.midi.idx; i++) {
|
||||||
|
dbg_puts(" ");
|
||||||
|
dbg_putx(ibuf->r.midi.msg[i]);
|
||||||
|
}
|
||||||
|
dbg_puts("\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
x = (struct sysex *)ibuf->r.midi.msg;
|
x = (struct sysex *)ibuf->r.midi.msg;
|
||||||
len = ibuf->r.midi.idx;
|
len = ibuf->r.midi.idx;
|
||||||
if (x->start != SYSEX_START)
|
if (x->start != SYSEX_START)
|
||||||
|
@ -674,7 +444,7 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
||||||
dbg_puts(": mmc stop\n");
|
dbg_puts(": mmc stop\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dev_mmcstop(p->u.ctl.dev);
|
dev_mmcstop(p->u.midi.dev);
|
||||||
break;
|
break;
|
||||||
case SYSEX_MMC_START:
|
case SYSEX_MMC_START:
|
||||||
if (len != SYSEX_SIZE(start))
|
if (len != SYSEX_SIZE(start))
|
||||||
|
@ -685,7 +455,7 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
||||||
dbg_puts(": mmc start\n");
|
dbg_puts(": mmc start\n");
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
dev_mmcstart(p->u.ctl.dev);
|
dev_mmcstart(p->u.midi.dev);
|
||||||
break;
|
break;
|
||||||
case SYSEX_MMC_LOC:
|
case SYSEX_MMC_LOC:
|
||||||
if (len != SYSEX_SIZE(loc) ||
|
if (len != SYSEX_SIZE(loc) ||
|
||||||
|
@ -706,7 +476,7 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
||||||
/* XXX: should dev_mmcstop() here */
|
/* XXX: should dev_mmcstop() here */
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
dev_loc(p->u.ctl.dev,
|
dev_loc(p->u.midi.dev,
|
||||||
(x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
|
(x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
|
||||||
x->u.loc.min * 60 * MTC_SEC +
|
x->u.loc.min * 60 * MTC_SEC +
|
||||||
x->u.loc.sec * MTC_SEC +
|
x->u.loc.sec * MTC_SEC +
|
||||||
|
@ -721,31 +491,49 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
||||||
if (len != SYSEX_SIZE(dumpreq))
|
if (len != SYSEX_SIZE(dumpreq))
|
||||||
return;
|
return;
|
||||||
if (ibuf->duplex)
|
if (ibuf->duplex)
|
||||||
ctl_dump(p, ibuf->duplex);
|
midi_copy_dump(p, ibuf->duplex);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ctl_in(struct aproc *p, struct abuf *ibuf)
|
midi_in(struct aproc *p, struct abuf *ibuf)
|
||||||
{
|
{
|
||||||
unsigned char *idata;
|
unsigned char c, *idata;
|
||||||
unsigned c, i, icount;
|
unsigned i, icount;
|
||||||
|
|
||||||
if (!ABUF_ROK(ibuf))
|
if (!ABUF_ROK(ibuf))
|
||||||
return 0;
|
return 0;
|
||||||
|
if (ibuf->tickets == 0) {
|
||||||
|
#ifdef DEBUG
|
||||||
|
if (debug_level >= 4) {
|
||||||
|
abuf_dbg(ibuf);
|
||||||
|
dbg_puts(": out of tickets, blocking\n");
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
idata = abuf_rgetblk(ibuf, &icount, 0);
|
idata = abuf_rgetblk(ibuf, &icount, 0);
|
||||||
|
if (icount > ibuf->tickets)
|
||||||
|
icount = ibuf->tickets;
|
||||||
|
ibuf->tickets -= icount;
|
||||||
for (i = 0; i < icount; i++) {
|
for (i = 0; i < icount; i++) {
|
||||||
c = *idata++;
|
c = *idata++;
|
||||||
if (c >= 0xf8) {
|
if (c >= 0xf8) {
|
||||||
/* clock events not used yet */
|
if (!p->u.midi.dev && c != MIDI_ACK)
|
||||||
} else if (c >= 0xf0) {
|
midi_send(p, ibuf, &c, 1);
|
||||||
if (ibuf->r.midi.st == 0xf0 && c == 0xf7 &&
|
} else if (c == SYSEX_END) {
|
||||||
ibuf->r.midi.idx < MIDI_MSGMAX) {
|
if (ibuf->r.midi.st == SYSEX_START) {
|
||||||
ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
|
ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
|
||||||
ctl_ev(p, ibuf);
|
if (!p->u.midi.dev) {
|
||||||
continue;
|
midi_send(p, ibuf,
|
||||||
|
ibuf->r.midi.msg, ibuf->r.midi.idx);
|
||||||
|
} else
|
||||||
|
midi_onsysex(p, ibuf);
|
||||||
}
|
}
|
||||||
|
ibuf->r.midi.st = 0;
|
||||||
|
ibuf->r.midi.idx = 0;
|
||||||
|
} else if (c >= 0xf0) {
|
||||||
ibuf->r.midi.msg[0] = c;
|
ibuf->r.midi.msg[0] = c;
|
||||||
ibuf->r.midi.len = common_len[c & 7];
|
ibuf->r.midi.len = common_len[c & 7];
|
||||||
ibuf->r.midi.st = c;
|
ibuf->r.midi.st = c;
|
||||||
|
@ -756,69 +544,98 @@ ctl_in(struct aproc *p, struct abuf *ibuf)
|
||||||
ibuf->r.midi.st = c;
|
ibuf->r.midi.st = c;
|
||||||
ibuf->r.midi.idx = 1;
|
ibuf->r.midi.idx = 1;
|
||||||
} else if (ibuf->r.midi.st) {
|
} else if (ibuf->r.midi.st) {
|
||||||
if (ibuf->r.midi.idx == MIDI_MSGMAX)
|
if (ibuf->r.midi.idx == 0 &&
|
||||||
continue;
|
ibuf->r.midi.st != SYSEX_START) {
|
||||||
if (ibuf->r.midi.idx == 0)
|
ibuf->r.midi.msg[ibuf->r.midi.idx++] =
|
||||||
ibuf->r.midi.msg[ibuf->r.midi.idx++] = ibuf->r.midi.st;
|
ibuf->r.midi.st;
|
||||||
|
}
|
||||||
ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
|
ibuf->r.midi.msg[ibuf->r.midi.idx++] = c;
|
||||||
if (ibuf->r.midi.idx == ibuf->r.midi.len) {
|
if (ibuf->r.midi.idx == ibuf->r.midi.len) {
|
||||||
ctl_ev(p, ibuf);
|
if (!p->u.midi.dev) {
|
||||||
|
midi_send(p, ibuf,
|
||||||
|
ibuf->r.midi.msg, ibuf->r.midi.idx);
|
||||||
|
} else
|
||||||
|
midi_onvoice(p, ibuf);
|
||||||
|
if (ibuf->r.midi.st >= 0xf0)
|
||||||
|
ibuf->r.midi.st = 0;
|
||||||
|
ibuf->r.midi.idx = 0;
|
||||||
|
} else if (ibuf->r.midi.idx == MIDI_MSGMAX) {
|
||||||
|
if (!p->u.midi.dev) {
|
||||||
|
midi_send(p, ibuf,
|
||||||
|
ibuf->r.midi.msg, ibuf->r.midi.idx);
|
||||||
|
}
|
||||||
ibuf->r.midi.idx = 0;
|
ibuf->r.midi.idx = 0;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
/*
|
||||||
|
* XXX: if the sysex is received byte by byte, partial messages
|
||||||
|
* won't be sent until the end byte is received. On the other
|
||||||
|
* hand we can't flush it here, since we would loose messages
|
||||||
|
* we parse
|
||||||
|
*/
|
||||||
abuf_rdiscard(ibuf, icount);
|
abuf_rdiscard(ibuf, icount);
|
||||||
|
midi_flush(p);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
int
|
int
|
||||||
ctl_out(struct aproc *p, struct abuf *obuf)
|
midi_out(struct aproc *p, struct abuf *obuf)
|
||||||
{
|
{
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ctl_eof(struct aproc *p, struct abuf *ibuf)
|
midi_eof(struct aproc *p, struct abuf *ibuf)
|
||||||
{
|
{
|
||||||
if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
|
if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
|
||||||
aproc_del(p);
|
aproc_del(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ctl_hup(struct aproc *p, struct abuf *obuf)
|
midi_hup(struct aproc *p, struct abuf *obuf)
|
||||||
{
|
{
|
||||||
if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
|
if ((p->flags & APROC_QUIT) && LIST_EMPTY(&p->ins))
|
||||||
aproc_del(p);
|
aproc_del(p);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
ctl_newin(struct aproc *p, struct abuf *ibuf)
|
midi_newin(struct aproc *p, struct abuf *ibuf)
|
||||||
{
|
{
|
||||||
ibuf->r.midi.used = 0;
|
ibuf->r.midi.used = 0;
|
||||||
ibuf->r.midi.len = 0;
|
ibuf->r.midi.len = 0;
|
||||||
ibuf->r.midi.idx = 0;
|
ibuf->r.midi.idx = 0;
|
||||||
ibuf->r.midi.st = 0;
|
ibuf->r.midi.st = 0;
|
||||||
|
ibuf->tickets = MIDITHRU_XFER;
|
||||||
}
|
}
|
||||||
|
|
||||||
struct aproc_ops ctl_ops = {
|
void
|
||||||
"ctl",
|
midi_done(struct aproc *p)
|
||||||
ctl_in,
|
{
|
||||||
ctl_out,
|
timo_del(&p->u.midi.timo);
|
||||||
ctl_eof,
|
}
|
||||||
ctl_hup,
|
|
||||||
ctl_newin,
|
struct aproc_ops midi_ops = {
|
||||||
|
"midi",
|
||||||
|
midi_in,
|
||||||
|
midi_out,
|
||||||
|
midi_eof,
|
||||||
|
midi_hup,
|
||||||
|
midi_newin,
|
||||||
NULL, /* newout */
|
NULL, /* newout */
|
||||||
NULL, /* ipos */
|
NULL, /* ipos */
|
||||||
NULL, /* opos */
|
NULL, /* opos */
|
||||||
NULL,
|
midi_done,
|
||||||
};
|
};
|
||||||
|
|
||||||
struct aproc *
|
struct aproc *
|
||||||
ctl_new(char *name, struct dev *dev)
|
midi_new(char *name, struct dev *dev)
|
||||||
{
|
{
|
||||||
struct aproc *p;
|
struct aproc *p;
|
||||||
|
|
||||||
p = aproc_new(&ctl_ops, name);
|
p = aproc_new(&midi_ops, name);
|
||||||
p->u.ctl.dev = dev;
|
timo_set(&p->u.midi.timo, midi_cb, p);
|
||||||
|
timo_add(&p->u.midi.timo, MIDITHRU_TIMO);
|
||||||
|
p->u.midi.dev = dev;
|
||||||
return p;
|
return p;
|
||||||
}
|
}
|
||||||
|
|
14
aucat/midi.h
14
aucat/midi.h
|
@ -19,13 +19,13 @@
|
||||||
|
|
||||||
struct dev;
|
struct dev;
|
||||||
|
|
||||||
struct aproc *thru_new(char *);
|
struct aproc *midi_new(char *, struct dev *);
|
||||||
struct aproc *ctl_new(char *, struct dev *);
|
|
||||||
|
|
||||||
void ctl_ontick(struct aproc *, int);
|
void midi_ontick(struct aproc *, int);
|
||||||
void ctl_slot(struct aproc *, int);
|
void midi_send_slot(struct aproc *, int);
|
||||||
void ctl_vol(struct aproc *, int, unsigned);
|
void midi_send_vol(struct aproc *, int, unsigned);
|
||||||
void ctl_full(struct aproc *, unsigned, unsigned, unsigned, unsigned);
|
void midi_send_full(struct aproc *, unsigned, unsigned, unsigned, unsigned);
|
||||||
void ctl_qfr(struct aproc *, unsigned, int);
|
void midi_send_qfr(struct aproc *, unsigned, int);
|
||||||
|
void midi_flush(struct aproc *);
|
||||||
|
|
||||||
#endif /* !defined(MIDI_H) */
|
#endif /* !defined(MIDI_H) */
|
||||||
|
|
Loading…
Reference in New Issue