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;
}
/*