/* midi status */
struct snd_midi_event {
- size_t qlen; /* queue length */
- size_t read; /* chars read */
- int type; /* current event type */
+ size_t qlen; /* queue length */
+ size_t read; /* chars read */
+ int type; /* current event type */
unsigned char lastcmd;
unsigned char nostat;
+ unsigned char xreg_hit;
size_t bufsize;
unsigned char *buf; /* input buffer */
};
/* 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 */
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);
};
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 count, 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[] = {
{SND_SEQ_EVENT_CONTROL14, extra_decode_ctrl14},
- /*{SND_SEQ_EVENT_NONREGPARAM, extra_decode_nrpn},*/
- /*{SND_SEQ_EVENT_REGPARAM, extra_decode_rpn},*/
+ {SND_SEQ_EVENT_NONREGPARAM, extra_decode_xrpn},
+ {SND_SEQ_EVENT_REGPARAM, extra_decode_xrpn},
};
#ifndef DOC_HIDDEN
*/
int snd_midi_event_encode_byte(snd_midi_event_t *dev, int c, snd_seq_event_t *ev)
{
- int rc = 0;
+ int tmp = 0;
c &= 0xff;
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;
+ return 0;
+ }
+ 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;
}
}
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 */
+ return 0;
+ }
+ if (dev->type == ST_XREG_PARM) {
+ tmp = get_xreg_hit_bit(dev->buf[1]);
+ if (tmp == 0 || (tmp & dev->xreg_hit)) {
+ reset_encode(dev);
+ dev->type = ST_CONTROLLER;
+ dev->read = 1;
+ return 0;
+ }
+ dev->xreg_hit |= tmp;
+ if (dev->xreg_hit == 0x0f) { /* finished */
+ xreg_event(dev, ev);
+ return 1;
+ }
+ dev->qlen = 2; /* we need more bytes */
+ return 0;
+ }
+ /* 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) {
+ return 1;
+ } else if (dev->type == ST_SYSEX) {
if (c == MIDI_CMD_COMMON_SYSEX_END ||
dev->read >= dev->bufsize) {
ev->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK;
dev->read = 0; /* continue to parse */
else
reset_encode(dev); /* all parsed */
- rc = 1;
+ return 1;
}
}
- return rc;
+ return 0;
}
/* encode note event */
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) ?
+ SND_SEQ_EVENT_NONREGPARAM : SND_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;
+ }
+ }
+}
+
/**
* \brief Decode sequencer event to MIDI byte stream
* \param dev MIDI event parser
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;
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;
}
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 == SND_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;
}