mirror of https://github.com/ericonr/sndio.git
add a sysex.h header with all sysex messages and
expose new dumpreq, dumpend and mixinfo
This commit is contained in:
parent
1b9b1c16b8
commit
c4c6839064
|
@ -73,7 +73,7 @@ headers.o: headers.c aparams.h conf.h wav.h pipe.h file.h \
|
|||
listen.o: listen.c conf.h listen.h aparams.h file.h sock.h \
|
||||
../libsndio/amsg.h pipe.h ../bsd-compat/bsd-compat.h
|
||||
midi.o: midi.c abuf.h aproc.h aparams.h file.h conf.h dev.h \
|
||||
midi.h dbg.h ../bsd-compat/bsd-compat.h
|
||||
midi.h sysex.h dbg.h ../bsd-compat/bsd-compat.h
|
||||
miofile.o: miofile.c conf.h file.h miofile.h dbg.h
|
||||
opt.o: opt.c dev.h aparams.h conf.h opt.h dbg.h
|
||||
pipe.o: pipe.c conf.h pipe.h file.h dbg.h
|
||||
|
|
233
aucat/midi.c
233
aucat/midi.c
|
@ -32,6 +32,7 @@
|
|||
#include "conf.h"
|
||||
#include "dev.h"
|
||||
#include "midi.h"
|
||||
#include "sysex.h"
|
||||
#ifdef DEBUG
|
||||
#include "dbg.h"
|
||||
#endif
|
||||
|
@ -385,6 +386,47 @@ ctl_slotdbg(struct aproc *p, int slot)
|
|||
}
|
||||
#endif
|
||||
|
||||
/*
|
||||
* 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
|
||||
if (debug_level >= 4) {
|
||||
abuf_dbg(obuf);
|
||||
dbg_puts(": stored ");
|
||||
dbg_putu(ocount);
|
||||
dbg_puts(" bytes\n");
|
||||
}
|
||||
#endif
|
||||
memcpy(odata, idata, ocount);
|
||||
abuf_wcommit(obuf, ocount);
|
||||
itodo -= ocount;
|
||||
idata += ocount;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* broadcast a message to all output buffers on the behalf of ibuf.
|
||||
* ie. don't sent back the message to the sender
|
||||
|
@ -392,44 +434,13 @@ ctl_slotdbg(struct aproc *p, int slot)
|
|||
void
|
||||
ctl_sendmsg(struct aproc *p, struct abuf *ibuf, unsigned char *msg, unsigned len)
|
||||
{
|
||||
unsigned ocount, itodo;
|
||||
unsigned char *odata, *idata;
|
||||
struct abuf *i, *inext;
|
||||
|
||||
for (i = LIST_FIRST(&p->outs); i != NULL; i = inext) {
|
||||
inext = LIST_NEXT(i, oent);
|
||||
if (i->duplex && i->duplex == ibuf)
|
||||
continue;
|
||||
itodo = len;
|
||||
idata = msg;
|
||||
while (itodo > 0) {
|
||||
if (!ABUF_WOK(i)) {
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 3) {
|
||||
abuf_dbg(i);
|
||||
dbg_puts(": overrun, discarding ");
|
||||
dbg_putu(i->used);
|
||||
dbg_puts(" bytes\n");
|
||||
}
|
||||
#endif
|
||||
abuf_rdiscard(i, i->used);
|
||||
}
|
||||
odata = abuf_wgetblk(i, &ocount, 0);
|
||||
if (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);
|
||||
abuf_wcommit(i, ocount);
|
||||
itodo -= ocount;
|
||||
idata += ocount;
|
||||
}
|
||||
ctl_copymsg(i, msg, len);
|
||||
(void)abuf_flush(i);
|
||||
}
|
||||
}
|
||||
|
@ -527,6 +538,61 @@ ctl_full(struct aproc *p)
|
|||
ctl_sendmsg(p, NULL, buf, 10);
|
||||
}
|
||||
|
||||
void
|
||||
ctl_msg_info(struct aproc *p, int slot, char *msg)
|
||||
{
|
||||
struct ctl_slot *s;
|
||||
struct sysex *x = (struct sysex *)msg;
|
||||
|
||||
s = p->u.ctl.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.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 char msg[sizeof(struct sysex)];
|
||||
struct ctl_slot *s;
|
||||
|
||||
for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) {
|
||||
ctl_msg_info(p, i, msg);
|
||||
ctl_copymsg(obuf, msg, SYSEX_SIZE(mixinfo));
|
||||
ctl_msg_vol(p, i, msg);
|
||||
ctl_copymsg(obuf, msg, 3);
|
||||
}
|
||||
msg[0] = SYSEX_START;
|
||||
msg[1] = SYSEX_TYPE_EDU;
|
||||
msg[2] = 0;
|
||||
msg[3] = SYSEX_AUCAT;
|
||||
msg[4] = SYSEX_AUCAT_DUMPEND;
|
||||
msg[5] = SYSEX_END;
|
||||
ctl_copymsg(obuf, msg, 6);
|
||||
dbg_puts("end dump\n");
|
||||
abuf_flush(obuf);
|
||||
}
|
||||
|
||||
/*
|
||||
* find the best matching free slot index (ie midi channel).
|
||||
* return -1, if there are no free slots anymore
|
||||
|
@ -724,6 +790,7 @@ ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr)
|
|||
{
|
||||
int idx;
|
||||
struct ctl_slot *s;
|
||||
unsigned char msg[sizeof(struct sysex)];
|
||||
|
||||
if (!APROC_OK(p)) {
|
||||
#ifdef DEBUG
|
||||
|
@ -743,7 +810,10 @@ ctl_slotnew(struct aproc *p, char *who, struct ctl_ops *ops, void *arg, int tr)
|
|||
s->arg = arg;
|
||||
s->tstate = tr ? CTL_STOP : CTL_OFF;
|
||||
s->ops->vol(s->arg, s->vol);
|
||||
ctl_slotvol(p, idx, s->vol);
|
||||
ctl_msg_info(p, idx, msg);
|
||||
ctl_sendmsg(p, NULL, msg, SYSEX_SIZE(mixinfo));
|
||||
ctl_msg_vol(p, idx, msg);
|
||||
ctl_sendmsg(p, NULL, msg, 3);
|
||||
return idx;
|
||||
}
|
||||
|
||||
|
@ -820,9 +890,7 @@ ctl_slotvol(struct aproc *p, int slot, unsigned vol)
|
|||
}
|
||||
#endif
|
||||
p->u.ctl.slot[slot].vol = vol;
|
||||
msg[0] = MIDI_CTL | slot;
|
||||
msg[1] = MIDI_CTLVOL;
|
||||
msg[2] = vol;
|
||||
ctl_msg_vol(p, slot, msg);
|
||||
ctl_sendmsg(p, NULL, msg, 3);
|
||||
}
|
||||
|
||||
|
@ -991,7 +1059,8 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
|||
{
|
||||
unsigned chan;
|
||||
struct ctl_slot *slot;
|
||||
unsigned fps;
|
||||
struct sysex *x;
|
||||
unsigned fps, len;
|
||||
#ifdef DEBUG
|
||||
unsigned i;
|
||||
|
||||
|
@ -1006,7 +1075,7 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
|||
}
|
||||
#endif
|
||||
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;
|
||||
if (chan >= CTL_NSLOT)
|
||||
return;
|
||||
|
@ -1017,13 +1086,20 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
|||
slot->ops->vol(slot->arg, slot->vol);
|
||||
ctl_sendmsg(p, ibuf, ibuf->r.midi.msg, ibuf->r.midi.len);
|
||||
}
|
||||
if (ibuf->r.midi.idx == 6 &&
|
||||
ibuf->r.midi.msg[0] == 0xf0 &&
|
||||
ibuf->r.midi.msg[1] == 0x7f && /* type is realtime */
|
||||
ibuf->r.midi.msg[3] == 0x06 && /* subtype is mmc */
|
||||
ibuf->r.midi.msg[5] == 0xf7) { /* subtype is mmc */
|
||||
switch (ibuf->r.midi.msg[4]) {
|
||||
case 0x01: /* mmc stop */
|
||||
x = (struct sysex *)ibuf->r.midi.msg;
|
||||
len = ibuf->r.midi.idx;
|
||||
if (x->start != SYSEX_START)
|
||||
return;
|
||||
if (len < SYSEX_SIZE(empty))
|
||||
return;
|
||||
switch (x->type) {
|
||||
case SYSEX_TYPE_RT:
|
||||
if (x->id0 != SYSEX_MMC)
|
||||
return;
|
||||
switch (x->id1) {
|
||||
case SYSEX_MMC_STOP:
|
||||
if (len != SYSEX_SIZE(stop))
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 3) {
|
||||
abuf_dbg(ibuf);
|
||||
|
@ -1032,7 +1108,9 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
|||
#endif
|
||||
ctl_stop(p);
|
||||
break;
|
||||
case 0x02: /* mmc start */
|
||||
case SYSEX_MMC_START:
|
||||
if (len != SYSEX_SIZE(start))
|
||||
return;
|
||||
#ifdef DEBUG
|
||||
if (debug_level >= 3) {
|
||||
abuf_dbg(ibuf);
|
||||
|
@ -1041,36 +1119,43 @@ ctl_ev(struct aproc *p, struct abuf *ibuf)
|
|||
#endif
|
||||
ctl_start(p);
|
||||
break;
|
||||
case SYSEX_MMC_LOC:
|
||||
if (len != SYSEX_SIZE(loc) ||
|
||||
x->u.loc.len != SYSEX_MMC_LOC_LEN ||
|
||||
x->u.loc.cmd != SYSEX_MMC_LOC_CMD)
|
||||
return;
|
||||
switch (x->u.loc.hr >> 5) {
|
||||
case MTC_FPS_24:
|
||||
fps = 24;
|
||||
break;
|
||||
case MTC_FPS_25:
|
||||
fps = 25;
|
||||
break;
|
||||
case MTC_FPS_30:
|
||||
fps = 30;
|
||||
break;
|
||||
default:
|
||||
p->u.ctl.origin = 0;
|
||||
return;
|
||||
}
|
||||
ctl_loc(p,
|
||||
(x->u.loc.hr & 0x1f) * 3600 * MTC_SEC +
|
||||
x->u.loc.min * 60 * MTC_SEC +
|
||||
x->u.loc.sec * MTC_SEC +
|
||||
x->u.loc.fr * (MTC_SEC / fps) +
|
||||
x->u.loc.cent * (MTC_SEC / 100 / fps));
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ibuf->r.midi.idx == 13 &&
|
||||
ibuf->r.midi.msg[0] == 0xf0 &&
|
||||
ibuf->r.midi.msg[1] == 0x7f &&
|
||||
ibuf->r.midi.msg[3] == 0x06 &&
|
||||
ibuf->r.midi.msg[4] == 0x44 &&
|
||||
ibuf->r.midi.msg[5] == 0x06 &&
|
||||
ibuf->r.midi.msg[6] == 0x01 &&
|
||||
ibuf->r.midi.msg[12] == 0xf7) {
|
||||
switch (ibuf->r.midi.msg[7] >> 5) {
|
||||
case MTC_FPS_24:
|
||||
fps = 24;
|
||||
break;
|
||||
case MTC_FPS_25:
|
||||
fps = 25;
|
||||
break;
|
||||
case MTC_FPS_30:
|
||||
fps = 30;
|
||||
break;
|
||||
default:
|
||||
p->u.ctl.origin = 0;
|
||||
break;
|
||||
case SYSEX_TYPE_EDU:
|
||||
if (x->id0 != SYSEX_AUCAT || x->id1 != SYSEX_AUCAT_DUMPREQ)
|
||||
return;
|
||||
}
|
||||
ctl_loc(p,
|
||||
(ibuf->r.midi.msg[7] & 0x1f) * 3600 * MTC_SEC +
|
||||
ibuf->r.midi.msg[8] * 60 * MTC_SEC +
|
||||
ibuf->r.midi.msg[9] * MTC_SEC +
|
||||
ibuf->r.midi.msg[10] * (MTC_SEC / fps) +
|
||||
ibuf->r.midi.msg[11] * (MTC_SEC / 100 / fps));
|
||||
if (len != SYSEX_SIZE(dumpreq))
|
||||
return;
|
||||
dbg_puts("dump request\n");
|
||||
if (ibuf->duplex)
|
||||
ctl_dump(p, ibuf->duplex);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -0,0 +1,113 @@
|
|||
/* $OpenBSD$ */
|
||||
/*
|
||||
* Copyright (c) 2011 Alexandre Ratchov <alex@caoua.org>
|
||||
*
|
||||
* Permission to use, copy, modify, and distribute this software for any
|
||||
* purpose with or without fee is hereby granted, provided that the above
|
||||
* copyright notice and this permission notice appear in all copies.
|
||||
*
|
||||
* THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
|
||||
* WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
|
||||
* MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
|
||||
* ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
|
||||
* WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
|
||||
* ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
|
||||
* OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
|
||||
*/
|
||||
#ifndef AUCAT_SYSEX_H
|
||||
#define AUCAT_SYSEX_H
|
||||
|
||||
#include <stdint.h>
|
||||
|
||||
/*
|
||||
* start and end markers
|
||||
*/
|
||||
#define SYSEX_START 0xf0
|
||||
#define SYSEX_END 0xf7
|
||||
|
||||
/*
|
||||
* type/vendor namespace IDs we use
|
||||
*/
|
||||
#define SYSEX_TYPE_RT 0x7f /* real-time universal */
|
||||
#define SYSEX_TYPE_EDU 0x7d /* non-comercial */
|
||||
|
||||
/*
|
||||
* realtime messages in the "universal real-time" namespace
|
||||
*/
|
||||
#define SYSEX_MTC 0x01 /* mtc messages */
|
||||
#define SYSEX_MTC_FULL 0x01 /* mtc full frame message */
|
||||
#define SYSEX_MMC 0x06
|
||||
#define SYSEX_MMC_STOP 0x01
|
||||
#define SYSEX_MMC_START 0x02
|
||||
#define SYSEX_MMC_LOC 0x44
|
||||
#define SYSEX_MMC_LOC_LEN 0x06
|
||||
#define SYSEX_MMC_LOC_CMD 0x01
|
||||
|
||||
/*
|
||||
* aucat-specific messages, in the "edu" namespace
|
||||
*/
|
||||
#define SYSEX_AUCAT 0x23 /* aucat-specific */
|
||||
#define SYSEX_AUCAT_MIXINFO 0x01 /* mixer info */
|
||||
#define SYSEX_AUCAT_DUMPREQ 0x02 /* dump request */
|
||||
#define SYSEX_AUCAT_DUMPEND 0x03 /* end of dump */
|
||||
|
||||
/*
|
||||
* minimum size of sysex message we accept
|
||||
*/
|
||||
#define SYSEX_SIZE(m) (5 + sizeof(struct sysex_ ## m))
|
||||
|
||||
/*
|
||||
* all possible system exclusive messages we support. For aucat-specific
|
||||
* messages we use the same header as real-time messages to simplify the
|
||||
* message parser
|
||||
*/
|
||||
struct sysex {
|
||||
uint8_t start;
|
||||
uint8_t type; /* type or vendor id */
|
||||
uint8_t dev; /* device or product id */
|
||||
uint8_t id0; /* message id */
|
||||
uint8_t id1; /* sub-id */
|
||||
union sysex_all {
|
||||
struct sysex_empty {
|
||||
uint8_t end;
|
||||
} empty;
|
||||
struct sysex_start {
|
||||
uint8_t end;
|
||||
} start;
|
||||
struct sysex_stop {
|
||||
uint8_t end;
|
||||
} stop;
|
||||
struct sysex_loc {
|
||||
uint8_t len;
|
||||
uint8_t cmd;
|
||||
uint8_t hr;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t fr;
|
||||
uint8_t cent;
|
||||
uint8_t end;
|
||||
} loc;
|
||||
struct sysex_full {
|
||||
uint8_t hr;
|
||||
uint8_t min;
|
||||
uint8_t sec;
|
||||
uint8_t fr;
|
||||
uint8_t end;
|
||||
} full;
|
||||
struct sysex_mixinfo {
|
||||
uint8_t chan; /* channel */
|
||||
uint8_t vol; /* current volume */
|
||||
#define SYSEX_NAMELEN 10 /* \0 included */
|
||||
uint8_t name[SYSEX_NAMELEN]; /* stream name */
|
||||
uint8_t end;
|
||||
} mixinfo;
|
||||
struct sysex_dumpreq {
|
||||
uint8_t end;
|
||||
} dumpreq;
|
||||
struct sysex_dumpend {
|
||||
uint8_t end;
|
||||
} dumpend;
|
||||
} u;
|
||||
};
|
||||
|
||||
#endif /* !defined(AUCAT_SYSEX_H) */
|
Loading…
Reference in New Issue