version 1.13, 2009/11/03 21:31:37 |
version 1.14, 2010/01/10 21:47:41 |
|
|
#include "conf.h" |
#include "conf.h" |
#include "dev.h" |
#include "dev.h" |
#include "midi.h" |
#include "midi.h" |
|
#ifdef DEBUG |
|
#include "dbg.h" |
|
#endif |
|
|
/* |
/* |
* input data rate is XFER / TIMO (in bytes per microsecond), |
* input data rate is XFER / TIMO (in bytes per microsecond), |
|
|
|
|
itodo = ibuf->r.midi.used; |
itodo = ibuf->r.midi.used; |
idata = ibuf->r.midi.msg; |
idata = ibuf->r.midi.msg; |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": flushing "); |
|
dbg_putu(itodo); |
|
dbg_puts(" byte message\n"); |
|
} |
|
#endif |
while (itodo > 0) { |
while (itodo > 0) { |
if (!ABUF_WOK(obuf)) { |
if (!ABUF_WOK(obuf)) { |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": overrun, discarding "); |
|
dbg_putu(obuf->used); |
|
dbg_puts(" bytes\n"); |
|
} |
|
#endif |
abuf_rdiscard(obuf, obuf->used); |
abuf_rdiscard(obuf, obuf->used); |
if (p->u.thru.owner == ibuf) |
if (p->u.thru.owner == ibuf) |
p->u.thru.owner = NULL; |
p->u.thru.owner = NULL; |
|
|
unsigned ocount; |
unsigned ocount; |
unsigned char *odata; |
unsigned char *odata; |
|
|
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": "); |
|
dbg_putu(c); |
|
dbg_puts(": flushing realtime message\n"); |
|
} |
|
#endif |
if (!ABUF_WOK(obuf)) { |
if (!ABUF_WOK(obuf)) { |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
aproc_dbg(p); |
|
dbg_puts(": overrun, discarding "); |
|
dbg_putu(obuf->used); |
|
dbg_puts(" bytes\n"); |
|
} |
|
#endif |
abuf_rdiscard(obuf, obuf->used); |
abuf_rdiscard(obuf, obuf->used); |
if (p->u.thru.owner == ibuf) |
if (p->u.thru.owner == ibuf) |
p->u.thru.owner = NULL; |
p->u.thru.owner = NULL; |
|
|
if (!ABUF_ROK(ibuf)) |
if (!ABUF_ROK(ibuf)) |
return 0; |
return 0; |
if (ibuf->tickets == 0) { |
if (ibuf->tickets == 0) { |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
abuf_dbg(ibuf); |
|
dbg_puts(": out of tickets, blocking\n"); |
|
} |
|
#endif |
return 0; |
return 0; |
} |
} |
todo = ibuf->used; |
todo = ibuf->used; |
|
|
return p; |
return p; |
} |
} |
|
|
|
#ifdef DEBUG |
|
void |
|
ctl_slotdbg(struct aproc *p, int slot) |
|
{ |
|
struct ctl_slot *s; |
|
|
|
aproc_dbg(p); |
|
if (slot < 0) { |
|
dbg_puts("/none"); |
|
} else { |
|
s = p->u.ctl.slot + slot; |
|
dbg_puts(s->name); |
|
dbg_putu(s->unit); |
|
dbg_puts("="); |
|
dbg_putu(s->vol); |
|
dbg_puts("/"); |
|
switch (s->tstate) { |
|
case CTL_OFF: |
|
dbg_puts("off"); |
|
break; |
|
case CTL_RUN: |
|
dbg_puts("run"); |
|
break; |
|
case CTL_START: |
|
dbg_puts("sta"); |
|
break; |
|
case CTL_STOP: |
|
dbg_puts("stp"); |
|
break; |
|
default: |
|
dbg_puts("unk"); |
|
break; |
|
} |
|
} |
|
} |
|
#endif |
|
|
/* |
/* |
* broadcast a message to all output buffers on the behalf of ibuf. |
* broadcast a message to all output buffers on the behalf of ibuf. |
* ie. don't sent back the message to the sender |
* ie. don't sent back the message to the sender |
|
|
idata = msg; |
idata = msg; |
while (itodo > 0) { |
while (itodo > 0) { |
if (!ABUF_WOK(i)) { |
if (!ABUF_WOK(i)) { |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
abuf_dbg(i); |
|
dbg_puts(": overrun, discarding "); |
|
dbg_putu(i->used); |
|
dbg_puts(" bytes\n"); |
|
} |
|
#endif |
abuf_rdiscard(i, i->used); |
abuf_rdiscard(i, i->used); |
} |
} |
odata = abuf_wgetblk(i, &ocount, 0); |
odata = abuf_wgetblk(i, &ocount, 0); |
if (ocount > itodo) |
if (ocount > itodo) |
ocount = itodo; |
ocount = itodo; |
|
#ifdef DEBUG |
|
if (debug_level >= 4) { |
|
abuf_dbg(i); |
|
dbg_puts(": stored "); |
|
dbg_putu(ocount); |
|
dbg_puts(" bytes\n"); |
|
} |
|
#endif |
memcpy(odata, idata, ocount); |
memcpy(odata, idata, ocount); |
abuf_wcommit(i, ocount); |
abuf_wcommit(i, ocount); |
itodo -= ocount; |
itodo -= ocount; |
|
|
if ((umap & (1 << unit)) == 0) |
if ((umap & (1 << unit)) == 0) |
break; |
break; |
} |
} |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": new control name is "); |
|
dbg_puts(name); |
|
dbg_putu(unit); |
|
dbg_puts("\n"); |
|
} |
|
#endif |
/* |
/* |
* find a free controller slot with the same name/unit |
* find a free controller slot with the same name/unit |
*/ |
*/ |
|
|
if (slot->ops == NULL && |
if (slot->ops == NULL && |
strcmp(slot->name, name) == 0 && |
strcmp(slot->name, name) == 0 && |
slot->unit == unit) { |
slot->unit == unit) { |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": found slot "); |
|
dbg_putu(i); |
|
dbg_puts("\n"); |
|
} |
|
#endif |
return i; |
return i; |
} |
} |
} |
} |
|
|
slot->serial = p->u.ctl.serial++; |
slot->serial = p->u.ctl.serial++; |
slot->unit = unit; |
slot->unit = unit; |
slot->vol = MIDI_MAXCTL; |
slot->vol = MIDI_MAXCTL; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
aproc_dbg(p); |
|
dbg_puts(": overwritten slot "); |
|
dbg_putu(bestidx); |
|
dbg_puts("\n"); |
|
} |
|
#endif |
return bestidx; |
return bestidx; |
} |
} |
|
|
|
|
struct ctl_slot *s; |
struct ctl_slot *s; |
|
|
if (p->u.ctl.tstate != CTL_START) { |
if (p->u.ctl.tstate != CTL_START) { |
|
#ifdef DEBUG |
|
aproc_dbg(p); |
|
dbg_puts(": not in starting state\n"); |
|
#endif |
return 0; |
return 0; |
} |
} |
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++) { |
if (!s->ops || i == caller) |
if (!s->ops || i == caller) |
continue; |
continue; |
if (s->tstate != CTL_OFF && s->tstate != CTL_START) { |
if (s->tstate != CTL_OFF && s->tstate != CTL_START) { |
|
#ifdef DEBUG |
|
ctl_slotdbg(p, i); |
|
dbg_puts(": not ready to start, start delayed\n"); |
|
#endif |
return 0; |
return 0; |
} |
} |
} |
} |
|
|
if (!s->ops || i == caller) |
if (!s->ops || i == caller) |
continue; |
continue; |
if (s->tstate == CTL_START) { |
if (s->tstate == CTL_START) { |
|
#ifdef DEBUG |
|
ctl_slotdbg(p, i); |
|
dbg_puts(": started\n"); |
|
#endif |
s->tstate = CTL_RUN; |
s->tstate = CTL_RUN; |
s->ops->start(s->arg); |
s->ops->start(s->arg); |
} |
} |
|
|
p->u.ctl.fps_id = MTC_FPS_24; |
p->u.ctl.fps_id = MTC_FPS_24; |
p->u.ctl.fps = 24; |
p->u.ctl.fps = 24; |
} |
} |
|
#ifdef DEBUG |
|
ctl_slotdbg(p, caller); |
|
dbg_puts(": started server at "); |
|
dbg_puti(p->u.ctl.delta); |
|
dbg_puts(", "); |
|
dbg_puti(p->u.ctl.fps); |
|
dbg_puts(" mtc fps\n"); |
|
#endif |
ctl_full(p); |
ctl_full(p); |
return 1; |
return 1; |
} |
} |
|
|
|
|
if (p == NULL) |
if (p == NULL) |
return; |
return; |
|
#ifdef DEBUG |
|
if (debug_level >= 3) { |
|
ctl_slotdbg(p, slot); |
|
dbg_puts(": changing volume to "); |
|
dbg_putu(vol); |
|
dbg_puts("\n"); |
|
} |
|
#endif |
p->u.ctl.slot[slot].vol = 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; |
|
|
unsigned chan; |
unsigned chan; |
struct ctl_slot *slot; |
struct ctl_slot *slot; |
unsigned fps; |
unsigned fps; |
|
#ifdef DEBUG |
|
unsigned i; |
|
|
|
if (debug_level >= 3) { |
|
abuf_dbg(ibuf); |
|
dbg_puts(": got event:"); |
|
for (i = 0; i < ibuf->r.midi.idx; i++) { |
|
dbg_puts(" "); |
|
dbg_putx(ibuf->r.midi.msg[i]); |
|
} |
|
dbg_puts("\n"); |
|
} |
|
#endif |
if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL && |
if ((ibuf->r.midi.msg[0] & MIDI_CMDMASK) == MIDI_CTL && |
ibuf->r.midi.msg[1] == MIDI_CTLVOL) { |
ibuf->r.midi.msg[1] == MIDI_CTLVOL) { |
chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK; |
chan = ibuf->r.midi.msg[0] & MIDI_CHANMASK; |
|
|
ibuf->r.midi.msg[5] == 0xf7) { /* subtype is mmc */ |
ibuf->r.midi.msg[5] == 0xf7) { /* subtype is mmc */ |
switch (ibuf->r.midi.msg[4]) { |
switch (ibuf->r.midi.msg[4]) { |
case 0x01: /* mmc stop */ |
case 0x01: /* mmc stop */ |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
abuf_dbg(ibuf); |
|
dbg_puts(": mmc stop\n"); |
|
} |
|
#endif |
if (p->u.ctl.tstate == CTL_RUN || |
if (p->u.ctl.tstate == CTL_RUN || |
p->u.ctl.tstate == CTL_START) |
p->u.ctl.tstate == CTL_START) |
p->u.ctl.tstate = CTL_STOP; |
p->u.ctl.tstate = CTL_STOP; |
|
#ifdef DEBUG |
|
else { |
|
if (debug_level >= 1) { |
|
aproc_dbg(p); |
|
dbg_puts(": ignored mmc stop\n"); |
|
} |
|
} |
|
#endif |
break; |
break; |
case 0x02: /* mmc start */ |
case 0x02: /* mmc start */ |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
abuf_dbg(ibuf); |
|
dbg_puts(": mmc start\n"); |
|
} |
|
#endif |
if (p->u.ctl.tstate == CTL_STOP) { |
if (p->u.ctl.tstate == CTL_STOP) { |
p->u.ctl.tstate = CTL_START; |
p->u.ctl.tstate = CTL_START; |
(void)ctl_trystart(p, -1); |
(void)ctl_trystart(p, -1); |
|
#ifdef DEBUG |
|
} else { |
|
if (debug_level >= 1) { |
|
abuf_dbg(ibuf); |
|
dbg_puts(": ignoring mmc start\n"); |
|
} |
|
#endif |
} |
} |
break; |
break; |
} |
} |
|
|
ibuf->r.midi.msg[9] * MTC_SEC + |
ibuf->r.midi.msg[9] * MTC_SEC + |
ibuf->r.midi.msg[10] * (MTC_SEC / fps) + |
ibuf->r.midi.msg[10] * (MTC_SEC / fps) + |
ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps); |
ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps); |
|
#ifdef DEBUG |
|
if (debug_level >= 1) { |
|
aproc_dbg(p); |
|
dbg_puts(": relocated to "); |
|
dbg_putu(p->u.ctl.origin); |
|
dbg_puts("\n"); |
|
} |
|
#endif |
} |
} |
} |
} |
|
|
|
|
void |
void |
ctl_done(struct aproc *p) |
ctl_done(struct aproc *p) |
{ |
{ |
|
#ifdef DEBUG |
|
unsigned i; |
|
struct ctl_slot *s; |
|
|
|
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { |
|
/* |
|
* XXX: shouldn't we abord() here ? |
|
*/ |
|
if (s->ops != NULL) { |
|
ctl_slotdbg(p, i); |
|
dbg_puts(": still in use\n"); |
|
} |
|
} |
|
#endif |
} |
} |
|
|
struct aproc_ops ctl_ops = { |
struct aproc_ops ctl_ops = { |