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

Reply via email to