diff --git a/xvolkeys/Makefile.in b/xvolkeys/Makefile.in index 5b69be2..3e977f5 100644 --- a/xvolkeys/Makefile.in +++ b/xvolkeys/Makefile.in @@ -49,4 +49,4 @@ xvolkeys: ${OBJS} .c.o: ${CC} ${CFLAGS} ${INCLUDE} ${DEFS} -c $< -xvolkeys.o: xvolkeys.c sysex.h +xvolkeys.o: xvolkeys.c diff --git a/xvolkeys/sysex.h b/xvolkeys/sysex.h deleted file mode 100644 index 4366ee5..0000000 --- a/xvolkeys/sysex.h +++ /dev/null @@ -1,125 +0,0 @@ -/* $OpenBSD$ */ -/* - * Copyright (c) 2011 Alexandre Ratchov - * - * 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 - -/* - * 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_CONTROL 0x04 -#define SYSEX_MASTER 0x01 -#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 - -/* - * sepcial "any" midi device number - */ -#define SYSEX_DEV_ANY 0x7f - -/* - * aucat-specific messages, in the "edu" namespace - */ -#define SYSEX_AUCAT 0x23 /* aucat-specific */ -#define SYSEX_AUCAT_SLOTDESC 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_master { - uint8_t fine; - uint8_t coarse; - uint8_t end; - } master; - 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_slotdesc { - 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; - } slotdesc; - struct sysex_dumpreq { - uint8_t end; - } dumpreq; - struct sysex_dumpend { - uint8_t end; - } dumpend; - } u; -}; - -#endif /* !defined(AUCAT_SYSEX_H) */ diff --git a/xvolkeys/xvolkeys.c b/xvolkeys/xvolkeys.c index 0dc9a85..1347849 100644 --- a/xvolkeys/xvolkeys.c +++ b/xvolkeys/xvolkeys.c @@ -23,7 +23,6 @@ #include #include #include -#include "sysex.h" /* * X keysyms to increment / decrement volume: + and - @@ -36,46 +35,21 @@ */ #define MODMASK (Mod1Mask | ControlMask) -/* - * max MIDI message length we accept - */ -#define MIDI_MSGMAX (sizeof(struct sysex)) - -/* - * max MIDI volume - */ -#define MIDI_MAXVOL 127 - -int midi_connect(void); -void midi_disconnect(void); -void midi_setvol(int); -void midi_sysex(unsigned char *, unsigned); -void midi_parse(unsigned char *, unsigned); +int mixer_connect(void); +void mixer_disconnect(void); +void mixer_setvol(int); +void mixer_sysex(unsigned char *, unsigned); +void mixer_parse(unsigned char *, unsigned); void grab_keys(void); void ungrab_keys(void); void usage(void); -/* - * midi parser state - */ -char *port; +char *devname; struct pollfd pfds[16]; -struct mio_hdl *hdl; -unsigned int midx; -unsigned char mev[MIDI_MSGMAX]; - -int master = MIDI_MAXVOL; +struct siomix_hdl *hdl; +int master_addr, master_val = SIOMIX_INTMAX; int verbose; -unsigned char dumpreq[] = { - SYSEX_START, - SYSEX_TYPE_EDU, - 0, - SYSEX_AUCAT, - SYSEX_AUCAT_DUMPREQ, - SYSEX_END -}; - /* * X bits */ @@ -83,20 +57,87 @@ Display *dpy; KeyCode inc_code, dec_code; KeySym *inc_map, *dec_map; +/* + * send master volume message and to the server + */ +void +mixer_setvol(int vol) +{ + if (vol > SIOMIX_INTMAX) + vol = SIOMIX_INTMAX; + if (vol < 0) + vol = 0; + if (!mixer_connect()) + return; + if (master_val != vol) { + master_val = vol; + if (hdl && master_addr != -1) { + if (verbose) { + fprintf(stderr, "%s: setting volume to %d\n", + devname, vol); + } + siomix_setctl(hdl, master_addr, master_val); + mixer_disconnect(); + } + } +} + +/* + * new control + */ +void +mixer_ondesc(void *unused, struct siomix_desc *desc, int val) +{ + unsigned c; + + if (desc == NULL) + return; + if (master_addr != -1) + return; + if (strcmp(desc->chan0.str, "master0") == 0 && + strcmp(desc->grp, "softvol") == 0) { + master_addr = desc->addr; + master_val = val; + if (verbose) + fprintf(stderr, "%s: master at addr %u, value = %u\n", + devname, master_addr, master_val); + } +} + +/* + * control value changed + */ +void +mixer_onctl(void *unused, unsigned int addr, unsigned int val) +{ + if (addr == master_addr) { + if (verbose) + fprintf(stderr, "master changed %u -> %u\n", master_val, val); + master_val = val; + } +} + /* * connect to sndiod */ int -midi_connect(void) +mixer_connect(void) { if (hdl != NULL) return 1; - hdl = mio_open(port, MIO_IN | MIO_OUT, 0); + hdl = siomix_open(devname, SIOMIX_READ | SIOMIX_WRITE, 0); if (hdl == NULL) { if (verbose) - fprintf(stderr, "%s: couldn't open MIDI port\n", port); + fprintf(stderr, "%s: couldn't open mixer device\n", + devname); return 0; } + master_addr = -1; + siomix_ondesc(hdl, mixer_ondesc, NULL); + siomix_onctl(hdl, mixer_onctl, NULL); + if (master_addr) + fprintf(stderr, "%s: warning, couldn't find master control\n", + devname); return 1; } @@ -104,101 +145,16 @@ midi_connect(void) * if there's an error, close connection to sndiod */ void -midi_disconnect(void) +mixer_disconnect(void) { - if (!mio_eof(hdl)) + if (!siomix_eof(hdl)) return; if (verbose) - fprintf(stderr, "%s: MIDI port disconnected\n", port); - mio_close(hdl); + fprintf(stderr, "%s: mixer device disconnected\n", devname); + siomix_close(hdl); hdl = NULL; } -/* - * send master volume message and to the server - */ -void -midi_setvol(int vol) -{ - struct sysex msg; - - if (vol > MIDI_MAXVOL) - vol = MIDI_MAXVOL; - if (vol < 0) - vol = 0; - if (verbose) - fprintf(stderr, "%s: setting volume to %d\n", port, vol); - if (!midi_connect()) - return; - if (master != vol) { - master = vol; - msg.start = SYSEX_START; - msg.type = SYSEX_TYPE_RT; - msg.dev = SYSEX_DEV_ANY; - msg.id0 = SYSEX_CONTROL; - msg.id1 = SYSEX_MASTER; - msg.u.master.fine = 0; - msg.u.master.coarse = vol; - msg.u.master.end = SYSEX_END; - if (hdl) { - mio_write(hdl, &msg, SYSEX_SIZE(master)); - midi_disconnect(); - } - } -} - -/* - * decode midi sysex message - */ -void -midi_sysex(unsigned char *msg, unsigned len) -{ - if (len == 8 && - msg[1] == SYSEX_TYPE_RT && - msg[3] == SYSEX_CONTROL && - msg[4] == SYSEX_MASTER) { - if (master != msg[6]) { - master = msg[6]; - if (verbose) { - fprintf(stderr, "%s: volume is %d\n", - port, master); - } - } - } -} - -/* - * decode midi bytes - */ -void -midi_parse(unsigned char *mbuf, unsigned len) -{ - unsigned c; - - for (; len > 0; len--) { - c = *mbuf++; - if (c >= 0xf8) { - /* ignore */ - } else if (c == SYSEX_END) { - if (mev[0] == SYSEX_START) { - mev[midx++] = c; - midi_sysex(mev, midx); - } - mev[0] = 0; - } else if (c == SYSEX_START) { - mev[0] = c; - midx = 1; - } else if (c >= 0x80) { - mev[0] = 0; - } else if (mev[0]) { - if (midx < MIDI_MSGMAX - 1) { - mev[midx++] = c; - } else - mev[0] = 0; - } - } -} - /* * register hot-keys in X */ @@ -262,15 +218,13 @@ ungrab_keys(void) void usage(void) { - fprintf(stderr, "usage: xvolkeys [-Dv] [-q port]\n"); + fprintf(stderr, "usage: xvolkeys [-Dv] [-f device]\n"); exit(1); } int main(int argc, char **argv) { -#define MIDIBUFSZ 0x100 - unsigned char msg[MIDIBUFSZ]; unsigned int scr; XEvent xev; int c, nfds, n; @@ -279,10 +233,10 @@ main(int argc, char **argv) /* * parse command line options */ - port = "snd/0"; + devname = SIOMIX_DEVANY; verbose = 0; background = 0; - while ((c = getopt(argc, argv, "Dq:v")) != -1) { + while ((c = getopt(argc, argv, "Df:q:v")) != -1) { switch (c) { case 'D': background = 1; @@ -290,8 +244,10 @@ main(int argc, char **argv) case 'v': verbose++; break; - case 'q': - port = optarg; + + case 'q': /* compat */ + case 'f': + devname = optarg; break; default: usage(); @@ -312,15 +268,7 @@ main(int argc, char **argv) for (scr = 0; scr != ScreenCount(dpy); scr++) XSelectInput(dpy, RootWindow(dpy, scr), KeyPress); - (void)midi_connect(); - - /* - * request initial volume - */ - if (hdl) { - mio_write(hdl, dumpreq, sizeof(dumpreq)); - midi_disconnect(); - } + (void)mixer_connect(); grab_keys(); @@ -347,24 +295,23 @@ main(int argc, char **argv) continue; if (xev.xkey.keycode == inc_code && inc_map[xev.xkey.state & ShiftMask] == KEY_INC) { - midi_setvol(master + 9); + mixer_setvol(master_val + 9); } else if (xev.xkey.keycode == dec_code && dec_map[xev.xkey.state & ShiftMask] == KEY_DEC) { - midi_setvol(master - 9); + mixer_setvol(master_val - 9); } } - nfds = (hdl != NULL) ? mio_pollfd(hdl, pfds, POLLIN) : 0; + nfds = (hdl != NULL) ? siomix_pollfd(hdl, pfds, 0) : 0; pfds[nfds].fd = ConnectionNumber(dpy); pfds[nfds].events = POLLIN; while (poll(pfds, nfds + 1, -1) < 0 && errno == EINTR) ; /* nothing */ if (hdl) { - revents = mio_revents(hdl, pfds); + revents = siomix_revents(hdl, pfds); if (revents & POLLHUP) - midi_disconnect(); + mixer_disconnect(); else if (revents & POLLIN) { - n = mio_read(hdl, msg, MIDIBUFSZ); - midi_parse(msg, n); + /* what */ } } } @@ -372,6 +319,6 @@ main(int argc, char **argv) XFree(dec_map); XCloseDisplay(dpy); if (hdl) - mio_close(hdl); + siomix_close(hdl); return 0; }