=================================================================== RCS file: /cvsrepo/anoncvs/cvs/src/usr.bin/aucat/Attic/midi.c,v retrieving revision 1.2 retrieving revision 1.3 diff -u -r1.2 -r1.3 --- src/usr.bin/aucat/Attic/midi.c 2009/08/19 05:54:15 1.2 +++ src/usr.bin/aucat/Attic/midi.c 2009/08/21 16:48:03 1.3 @@ -1,4 +1,4 @@ -/* $OpenBSD: midi.c,v 1.2 2009/08/19 05:54:15 ratchov Exp $ */ +/* $OpenBSD: midi.c,v 1.3 2009/08/21 16:48:03 ratchov Exp $ */ /* * Copyright (c) 2008 Alexandre Ratchov * @@ -29,9 +29,10 @@ #include #include -#include "conf.h" #include "abuf.h" #include "aproc.h" +#include "conf.h" +#include "dev.h" #include "midi.h" /* @@ -41,6 +42,32 @@ #define MIDITHRU_XFER 340 #define MIDITHRU_TIMO 100000 +/* + * masks to extract command and channel of status byte + */ +#define MIDI_CMDMASK 0xf0 +#define MIDI_CHANMASK 0x0f + +/* + * MIDI status bytes of voice messages + */ +#define MIDI_NOFF 0x80 /* note off */ +#define MIDI_NON 0x90 /* note on */ +#define MIDI_KAT 0xa0 /* key after touch */ +#define MIDI_CTL 0xb0 /* controller */ +#define MIDI_PC 0xc0 /* program change */ +#define MIDI_CAT 0xd0 /* channel after touch */ +#define MIDI_BEND 0xe0 /* pitch bend */ + +/* + * MIDI controller numbers + */ +#define MIDI_CTLVOL 7 /* volume */ +#define MIDI_CTLPAN 11 /* pan */ + +/* + * length of voice and common messages (status byte included) + */ unsigned voice_len[] = { 3, 3, 3, 3, 2, 2, 3 }; unsigned common_len[] = { 0, 2, 3, 2, 0, 0, 1, 1 }; @@ -263,6 +290,216 @@ p->u.thru.owner = NULL; timo_set(&p->u.thru.timo, thru_cb, p); timo_add(&p->u.thru.timo, MIDITHRU_TIMO); + return p; +} + +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->obuflist); i != NULL; i = inext) { + inext = LIST_NEXT(i, oent); + if (i->duplex == ibuf) + continue; + itodo = len; + idata = msg; + while (itodo > 0) { + if (!ABUF_WOK(i)) { + DPRINTFN(2, "ctl_sendmsg: lost %u\n", i->used); + abuf_rdiscard(i, i->used); + } + odata = abuf_wgetblk(i, &ocount, 0); + if (ocount > itodo) + ocount = itodo; + DPRINTFN(2, "ctl_sendmsg: xfer %u\n", ocount); + memcpy(odata, idata, ocount); + abuf_wcommit(i, ocount); + itodo -= ocount; + idata += ocount; + } + (void)abuf_flush(i); + } +} + +int +ctl_slotnew(struct aproc *p, char *name, struct aproc *owner) +{ + char *s; + int index, i; + struct ctl_slot *slot; + + DPRINTF("ctl_newslot: called by %s \"%s\"\n", owner->name, name); + for (index = 0, slot = p->u.ctl.slot; ; index++, slot++) { + if (index == CTL_NSLOT) + return -1; + if (slot->owner == NULL) + break; + } + for (i = 0, s = name; ; s++) { + if (i == CTL_NAMEMAX - 1 || *s == '\0') { + break; + } else if (*s >= 'A' && *s <= 'Z') { + slot->name[i++] = *s + 'a' - 'A'; + } else if (*s >= 'a' || *s <= 'z') + slot->name[i++] = *s; + } + if (i == 0) + strlcpy(slot->name, "noname", CTL_NAMEMAX); + else + slot->name[i] = '\0'; + slot->owner = owner; + slot->unit = index; + DPRINTFN(1, "ctl_newslot: %s%u\n", slot->name, slot->unit); + return index; +} + +void +ctl_slotdel(struct aproc *p, int index) +{ + p->u.ctl.slot[index].owner = NULL; +} + +void +ctl_slotvol(struct aproc *p, int slot, unsigned vol) +{ + unsigned char msg[3]; + + DPRINTFN(1, "ctl_slotvol: [%u] -> %u\n", slot, vol); + msg[0] = MIDI_CTL | slot; + msg[1] = MIDI_CTLVOL; + msg[2] = vol; + ctl_sendmsg(p, NULL, msg, 3); +} + +void +ctl_ev(struct aproc *p, struct abuf *ibuf) +{ + unsigned i; + unsigned chan; + struct aproc *owner; + +#ifdef DEBUG + if (debug_level > 0) { + fprintf(stderr, "ctl_ev:"); + for (i = 0; i < ibuf->mlen; i++) + fprintf(stderr, " %02x", ibuf->mdata[i]); + fprintf(stderr, "\n"); + } +#endif + if ((ibuf->mdata[0] & MIDI_CMDMASK) == MIDI_CTL && + ibuf->mdata[1] == MIDI_CTLVOL) { + chan = ibuf->mdata[0] & MIDI_CHANMASK; + if (chan >= CTL_NSLOT) + return; + owner = p->u.ctl.slot[chan].owner; + if (owner == NULL || LIST_EMPTY(&owner->obuflist)) + return; + dev_setvol( + LIST_FIRST(&owner->obuflist), + MIDI_TO_ADATA(ibuf->mdata[2])); + ctl_sendmsg(p, ibuf, ibuf->mdata, ibuf->mlen); + } +} + +int +ctl_in(struct aproc *p, struct abuf *ibuf) +{ + unsigned char *idata; + unsigned c, i, icount; + + if (!ABUF_ROK(ibuf)) + return 0; + idata = abuf_rgetblk(ibuf, &icount, 0); + for (i = 0; i < icount; i++) { + c = *idata++; + if (c >= 0xf0) { + /* clock and common events not used yet */ + } else if (c >= 0x80) { + ibuf->mdata[0] = c; + ibuf->mlen = voice_len[(c >> 4) & 7]; + ibuf->mstatus = c; + ibuf->mindex = 1; + } else if (ibuf->mstatus) { + if (ibuf->mindex == 0) + ibuf->mdata[ibuf->mindex++] = ibuf->mstatus; + ibuf->mdata[ibuf->mindex++] = c; + if (ibuf->mindex == ibuf->mlen) { + ctl_ev(p, ibuf); + ibuf->mindex = 0; + } + } + } + abuf_rdiscard(ibuf, icount); + return 1; +} + +int +ctl_out(struct aproc *p, struct abuf *obuf) +{ + return 0; +} + +void +ctl_eof(struct aproc *p, struct abuf *ibuf) +{ + DPRINTF("ctl_eof: %s: eof\n", p->name); +} + +void +ctl_hup(struct aproc *p, struct abuf *obuf) +{ + DPRINTF("ctl_hup: %s: detached\n", p->name); +} + +void +ctl_newin(struct aproc *p, struct abuf *ibuf) +{ + ibuf->mused = 0; + ibuf->mlen = 0; + ibuf->mindex = 0; + ibuf->mstatus = 0; +} + +void +ctl_done(struct aproc *p) +{ + unsigned i; + struct ctl_slot *s; + + for (i = 0, s = p->u.ctl.slot; i < CTL_NSLOT; i++, s++) { + if (s->owner) + DPRINTF("ctl_done: %s%u not freed\n", s->name, s->unit); + } +} + +struct aproc_ops ctl_ops = { + "ctl", + ctl_in, + ctl_out, + ctl_eof, + ctl_hup, + ctl_newin, + NULL, /* newout */ + NULL, /* ipos */ + NULL, /* opos */ + ctl_done +}; + +struct aproc * +ctl_new(char *name) +{ + struct aproc *p; + unsigned i; + + p = aproc_new(&ctl_ops, name); + for (i = 0; i < CTL_NSLOT; i++) { + p->u.ctl.slot[i].unit = i; + p->u.ctl.slot[i].owner = NULL; + strlcpy(p->u.ctl.slot[i].name, "unknown", CTL_NAMEMAX); + } return p; }