On Mon, 16 Jun 2003, Joern Nettingsmeier wrote: > Jaroslav Kysela wrote: > > On Mon, 16 Jun 2003, Jaroslav Kysela wrote: > > > > > >>>thanks for the clarification. i'd be glad to help, but i doubt i could > >>>meet the coding standards of alsa-lib. at least i could help test it. > >>>do you or anyone of the alsa core developers have plans to tackle this > >>>some time soon ? i'd love to be able to use my controller box for the > >>>LinuxTag presentations in mid-July. > >> > >>I am working on it right now, but it requires to add new states to > >>sequencer event encoder... > > > > > > Initial code is in CVS. It is not tested, but hopefully, without any major > > bugs. It seems that we have also missing encoding of CONTROL14 events. > > > > Jaroslav > > shit. anon cvs seems to be lagging behind. do you happen to have a patch > ? otherwise it will probably be another day before i can test it...
Attached. ----- Jaroslav Kysela <[EMAIL PROTECTED]> Linux Kernel Sound Maintainer ALSA Project, SuSE Labs
Index: seq_midi_event.h =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/include/seq_midi_event.h,v retrieving revision 1.4 retrieving revision 1.5 diff -u -r1.4 -r1.5 --- seq_midi_event.h 19 Apr 2002 17:29:59 -0000 1.4 +++ seq_midi_event.h 16 Jun 2003 11:19:12 -0000 1.5 @@ -30,13 +30,14 @@ /* midi status */ struct snd_midi_event_t { - int qlen; /* queue length */ - int read; /* chars read */ - int type; /* current event type */ + int qlen; /* queue length */ + int read; /* chars read */ + int type; /* current event type */ unsigned char lastcmd; unsigned char nostat; + unsigned char xreg_hit; int bufsize; - unsigned char *buf; /* input buffer */ + unsigned char *buf; /* input buffer */ spinlock_t lock; }; Index: seq_midi_event.c =================================================================== RCS file: /cvsroot/alsa/alsa-kernel/core/seq/seq_midi_event.c,v retrieving revision 1.10 retrieving revision 1.11 diff -u -r1.10 -r1.11 --- seq_midi_event.c 31 Jan 2003 15:19:34 -0000 1.10 +++ seq_midi_event.c 16 Jun 2003 11:19:12 -0000 1.11 @@ -36,9 +36,11 @@ /* from 0 to 7 are normal commands (note off, on, etc.) */ #define ST_NOTEOFF 0 #define ST_NOTEON 1 +#define ST_CONTROLLER 3 #define ST_SPECIAL 8 #define ST_SYSEX ST_SPECIAL /* from 8 to 15 are events for 0xf0-0xf7 */ +#define ST_XREG_PARM 16 /* status event types */ @@ -54,6 +56,8 @@ static void two_param_ctrl_event(snd_midi_event_t *dev, snd_seq_event_t *ev); static void one_param_event(snd_midi_event_t *dev, snd_seq_event_t *ev); static void songpos_event(snd_midi_event_t *dev, snd_seq_event_t *ev); +static unsigned char get_xreg_hit_bit(unsigned char c); +static void xreg_event(snd_midi_event_t *dev, snd_seq_event_t *ev); static void note_decode(snd_seq_event_t *ev, unsigned char *buf); static void one_param_decode(snd_seq_event_t *ev, unsigned char *buf); static void pitchbend_decode(snd_seq_event_t *ev, unsigned char *buf); @@ -98,14 +102,15 @@ }; static int extra_decode_ctrl14(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev); +static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev); static struct extra_event_list_t { int event; int (*decode)(snd_midi_event_t *dev, unsigned char *buf, int len, snd_seq_event_t *ev); } extra_event[] = { {SNDRV_SEQ_EVENT_CONTROL14, extra_decode_ctrl14}, - /*{SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_nrpn},*/ - /*{SNDRV_SEQ_EVENT_REGPARAM, extra_decode_rpn},*/ + {SNDRV_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn}, + {SNDRV_SEQ_EVENT_REGPARAM, extra_decode_xrpn}, }; /* @@ -253,11 +258,20 @@ spin_lock_irqsave(&dev->lock, flags); if (dev->qlen > 0) { /* rest of command */ + if (c & 0x80) { /* error? state inside data? */ + if (dev->type == ST_XREG_PARM) { + if (c != dev->buf[0]) + goto __new_command; + goto __end; + } + goto __new_command; + } dev->buf[dev->read++] = c; if (dev->type != ST_SYSEX) dev->qlen--; } else { /* new command */ + __new_command: dev->read = 1; if (c & 0x80) { dev->buf[0] = c; @@ -273,13 +287,42 @@ } } if (dev->qlen == 0) { + /* handle xrpn special case here */ + if (dev->type == ST_CONTROLLER && + dev->buf[1] >= MIDI_CTL_NONREG_PARM_NUM_LSB && + dev->buf[1] <= MIDI_CTL_REGIST_PARM_NUM_MSB) { + dev->type = ST_XREG_PARM; + dev->xreg_hit = get_xreg_hit_bit(dev->buf[1]); + dev->qlen = 2; /* we need more bytes */ + goto __end; + } + if (dev->type == ST_XREG_PARM) { + rc = get_xreg_hit_bit(dev->buf[1]); + if (rc == 0 || (rc & dev->xreg_hit)) { + reset_encode(dev); + dev->type = ST_CONTROLLER; + dev->read = 1; + rc = 0; + goto __end; + } + dev->xreg_hit |= rc; + if (dev->xreg_hit == 0x0f) { /* finished */ + xreg_event(dev, ev); + rc = 1; + goto __end; + } + dev->qlen = 2; /* we need more bytes */ + rc = 0; + goto __end; + } + /* handle standard midi events */ ev->type = status_event[dev->type].event; ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; ev->flags |= SNDRV_SEQ_EVENT_LENGTH_FIXED; if (status_event[dev->type].encode) /* set data values */ status_event[dev->type].encode(dev, ev); rc = 1; - } else if (dev->type == ST_SYSEX) { + } else if (dev->type == ST_SYSEX) { if (c == MIDI_CMD_COMMON_SYSEX_END || dev->read >= dev->bufsize) { ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; @@ -295,6 +338,7 @@ } } + __end: spin_unlock_irqrestore(&dev->lock, flags); return rc; } @@ -341,6 +385,44 @@ ev->data.control.value = (int)dev->buf[2] * 128 + (int)dev->buf[1]; } +static unsigned char get_xreg_hit_bit(unsigned char c) +{ + switch (c) { + case MIDI_CTL_NONREG_PARM_NUM_MSB: + case MIDI_CTL_REGIST_PARM_NUM_MSB: + return 1; + case MIDI_CTL_NONREG_PARM_NUM_LSB: + case MIDI_CTL_REGIST_PARM_NUM_LSB: + return 2; + case MIDI_CTL_MSB_DATA_ENTRY: + return 4; + case MIDI_CTL_LSB_DATA_ENTRY: + return 8; + default: + return 0; + } +} + +/* encode xreg event */ +static void xreg_event(snd_midi_event_t *dev, snd_seq_event_t *ev) +{ + int i; + + ev->type = (dev->buf[1] == MIDI_CTL_NONREG_PARM_NUM_MSB || + dev->buf[1] == MIDI_CTL_NONREG_PARM_NUM_LSB) ? + SNDRV_SEQ_EVENT_NONREGPARAM : SNDRV_SEQ_EVENT_REGPARAM; + ev->data.control.param = 0; + ev->data.control.value = 0; + for (i = 1; i < 9; i += 2) { + switch (get_xreg_hit_bit(dev->buf[i])) { + case 1: ev->data.control.param |= dev->buf[i+1] << 7; break; + case 2: ev->data.control.param |= dev->buf[i+1]; break; + case 4: ev->data.control.value |= dev->buf[i+1] << 7; break; + case 8: ev->data.control.value |= dev->buf[i+1]; break; + } + } +} + /* * decode from a sequencer event to midi bytes * return the size of decoded midi events @@ -441,12 +523,12 @@ unsigned char cmd; int idx = 0; + cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); if (ev->data.control.param < 32) { if (count < 4) return -ENOMEM; if (dev->nostat && count < 6) return -ENOMEM; - cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); if (cmd != dev->lastcmd || dev->nostat) { if (count < 5) return -ENOMEM; @@ -458,11 +540,9 @@ buf[idx++] = cmd; buf[idx++] = ev->data.control.param + 32; buf[idx++] = ev->data.control.value & 0x7f; - return idx; } else { if (count < 2) return -ENOMEM; - cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); if (cmd != dev->lastcmd || dev->nostat) { if (count < 3) return -ENOMEM; @@ -470,8 +550,48 @@ } buf[idx++] = ev->data.control.param & 0x7f; buf[idx++] = ev->data.control.value & 0x7f; - return idx; } + return idx; +} + +/* decode reg/nonreg param */ +static int extra_decode_xrpn(snd_midi_event_t *dev, unsigned char *buf, int count, snd_seq_event_t *ev) +{ + unsigned char cmd; + char *cbytes; + static char cbytes_nrpn[4] = { MIDI_CTL_NONREG_PARM_NUM_MSB, + MIDI_CTL_NONREG_PARM_NUM_LSB, + MIDI_CTL_MSB_DATA_ENTRY, + MIDI_CTL_LSB_DATA_ENTRY }; + static char cbytes_rpn[4] = { MIDI_CTL_REGIST_PARM_NUM_MSB, + MIDI_CTL_REGIST_PARM_NUM_LSB, + MIDI_CTL_MSB_DATA_ENTRY, + MIDI_CTL_LSB_DATA_ENTRY }; + unsigned char bytes[4]; + int idx = 0, i; + + if (count < 8) + return -ENOMEM; + if (dev->nostat && count < 12) + return -ENOMEM; + cmd = MIDI_CMD_CONTROL|(ev->data.control.channel & 0x0f); + bytes[0] = ev->data.control.param & 0x007f; + bytes[1] = (ev->data.control.param & 0x3f80) >> 7; + bytes[2] = ev->data.control.value & 0x007f; + bytes[3] = (ev->data.control.value & 0x3f80) >> 7; + if (cmd != dev->lastcmd && !dev->nostat) { + if (count < 9) + return -ENOMEM; + buf[idx++] = dev->lastcmd = cmd; + } + cbytes = ev->type == SNDRV_SEQ_EVENT_NONREGPARAM ? cbytes_nrpn : cbytes_rpn; + for (i = 0; i < 4; i++) { + if (dev->nostat) + buf[idx++] = dev->lastcmd = cmd; + buf[idx++] = cbytes[i]; + buf[idx++] = bytes[i]; + } + return idx; } /*