1e9e02819STakashi Iwai // SPDX-License-Identifier: GPL-2.0-or-later 2e9e02819STakashi Iwai /* 3e9e02819STakashi Iwai * ALSA sequencer event conversion between UMP and legacy clients 4e9e02819STakashi Iwai */ 5e9e02819STakashi Iwai 6e9e02819STakashi Iwai #include <linux/init.h> 7e9e02819STakashi Iwai #include <linux/errno.h> 8e9e02819STakashi Iwai #include <linux/string.h> 9e9e02819STakashi Iwai #include <sound/core.h> 10e9e02819STakashi Iwai #include <sound/ump.h> 11e9e02819STakashi Iwai #include <sound/ump_msg.h> 12e9e02819STakashi Iwai #include "seq_ump_convert.h" 13e9e02819STakashi Iwai 14e9e02819STakashi Iwai /* 15e9e02819STakashi Iwai * Upgrade / downgrade value bits 16e9e02819STakashi Iwai */ 17e9e02819STakashi Iwai static u8 downscale_32_to_7bit(u32 src) 18e9e02819STakashi Iwai { 19e9e02819STakashi Iwai return src >> 25; 20e9e02819STakashi Iwai } 21e9e02819STakashi Iwai 22e9e02819STakashi Iwai static u16 downscale_32_to_14bit(u32 src) 23e9e02819STakashi Iwai { 24e9e02819STakashi Iwai return src >> 18; 25e9e02819STakashi Iwai } 26e9e02819STakashi Iwai 27e9e02819STakashi Iwai static u8 downscale_16_to_7bit(u16 src) 28e9e02819STakashi Iwai { 29e9e02819STakashi Iwai return src >> 9; 30e9e02819STakashi Iwai } 31e9e02819STakashi Iwai 32e9e02819STakashi Iwai static u16 upscale_7_to_16bit(u8 src) 33e9e02819STakashi Iwai { 34e9e02819STakashi Iwai u16 val, repeat; 35e9e02819STakashi Iwai 36e9e02819STakashi Iwai val = (u16)src << 9; 37e9e02819STakashi Iwai if (src <= 0x40) 38e9e02819STakashi Iwai return val; 39e9e02819STakashi Iwai repeat = src & 0x3f; 40e9e02819STakashi Iwai return val | (repeat << 3) | (repeat >> 3); 41e9e02819STakashi Iwai } 42e9e02819STakashi Iwai 43e9e02819STakashi Iwai static u32 upscale_7_to_32bit(u8 src) 44e9e02819STakashi Iwai { 45e9e02819STakashi Iwai u32 val, repeat; 46e9e02819STakashi Iwai 47e9e02819STakashi Iwai val = src << 25; 48e9e02819STakashi Iwai if (src <= 0x40) 49e9e02819STakashi Iwai return val; 50e9e02819STakashi Iwai repeat = src & 0x3f; 51e9e02819STakashi Iwai return val | (repeat << 19) | (repeat << 13) | 52e9e02819STakashi Iwai (repeat << 7) | (repeat << 1) | (repeat >> 5); 53e9e02819STakashi Iwai } 54e9e02819STakashi Iwai 55e9e02819STakashi Iwai static u32 upscale_14_to_32bit(u16 src) 56e9e02819STakashi Iwai { 57e9e02819STakashi Iwai u32 val, repeat; 58e9e02819STakashi Iwai 59e9e02819STakashi Iwai val = src << 18; 60e9e02819STakashi Iwai if (src <= 0x2000) 61e9e02819STakashi Iwai return val; 62e9e02819STakashi Iwai repeat = src & 0x1fff; 63e9e02819STakashi Iwai return val | (repeat << 5) | (repeat >> 8); 64e9e02819STakashi Iwai } 65e9e02819STakashi Iwai 66e9e02819STakashi Iwai static unsigned char get_ump_group(struct snd_seq_client_port *port) 67e9e02819STakashi Iwai { 68e9e02819STakashi Iwai return port->ump_group ? (port->ump_group - 1) : 0; 69e9e02819STakashi Iwai } 70e9e02819STakashi Iwai 71e9e02819STakashi Iwai /* create a UMP header */ 72e9e02819STakashi Iwai #define make_raw_ump(port, type) \ 73e9e02819STakashi Iwai ump_compose(type, get_ump_group(port), 0, 0) 74e9e02819STakashi Iwai 75e9e02819STakashi Iwai /* 76e9e02819STakashi Iwai * UMP -> MIDI1 sequencer event 77e9e02819STakashi Iwai */ 78e9e02819STakashi Iwai 79e9e02819STakashi Iwai /* MIDI 1.0 CVM */ 80e9e02819STakashi Iwai 81e9e02819STakashi Iwai /* encode note event */ 82e9e02819STakashi Iwai static void ump_midi1_to_note_ev(const union snd_ump_midi1_msg *val, 83e9e02819STakashi Iwai struct snd_seq_event *ev) 84e9e02819STakashi Iwai { 85e9e02819STakashi Iwai ev->data.note.channel = val->note.channel; 86e9e02819STakashi Iwai ev->data.note.note = val->note.note; 87e9e02819STakashi Iwai ev->data.note.velocity = val->note.velocity; 88e9e02819STakashi Iwai } 89e9e02819STakashi Iwai 90e9e02819STakashi Iwai /* encode one parameter controls */ 91e9e02819STakashi Iwai static void ump_midi1_to_ctrl_ev(const union snd_ump_midi1_msg *val, 92e9e02819STakashi Iwai struct snd_seq_event *ev) 93e9e02819STakashi Iwai { 94e9e02819STakashi Iwai ev->data.control.channel = val->caf.channel; 95e9e02819STakashi Iwai ev->data.control.value = val->caf.data; 96e9e02819STakashi Iwai } 97e9e02819STakashi Iwai 98e9e02819STakashi Iwai /* encode pitch wheel change */ 99e9e02819STakashi Iwai static void ump_midi1_to_pitchbend_ev(const union snd_ump_midi1_msg *val, 100e9e02819STakashi Iwai struct snd_seq_event *ev) 101e9e02819STakashi Iwai { 102e9e02819STakashi Iwai ev->data.control.channel = val->pb.channel; 103e9e02819STakashi Iwai ev->data.control.value = (val->pb.data_msb << 7) | val->pb.data_lsb; 104e9e02819STakashi Iwai ev->data.control.value -= 8192; 105e9e02819STakashi Iwai } 106e9e02819STakashi Iwai 107e9e02819STakashi Iwai /* encode midi control change */ 108e9e02819STakashi Iwai static void ump_midi1_to_cc_ev(const union snd_ump_midi1_msg *val, 109e9e02819STakashi Iwai struct snd_seq_event *ev) 110e9e02819STakashi Iwai { 111e9e02819STakashi Iwai ev->data.control.channel = val->cc.channel; 112e9e02819STakashi Iwai ev->data.control.param = val->cc.index; 113e9e02819STakashi Iwai ev->data.control.value = val->cc.data; 114e9e02819STakashi Iwai } 115e9e02819STakashi Iwai 116e9e02819STakashi Iwai /* Encoding MIDI 1.0 UMP packet */ 117e9e02819STakashi Iwai struct seq_ump_midi1_to_ev { 118e9e02819STakashi Iwai int seq_type; 119e9e02819STakashi Iwai void (*encode)(const union snd_ump_midi1_msg *val, struct snd_seq_event *ev); 120e9e02819STakashi Iwai }; 121e9e02819STakashi Iwai 122e9e02819STakashi Iwai /* Encoders for MIDI1 status 0x80-0xe0 */ 123e9e02819STakashi Iwai static struct seq_ump_midi1_to_ev midi1_msg_encoders[] = { 124e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi1_to_note_ev}, /* 0x80 */ 125e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NOTEON, ump_midi1_to_note_ev}, /* 0x90 */ 126e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi1_to_note_ev}, /* 0xa0 */ 127e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi1_to_cc_ev}, /* 0xb0 */ 128e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi1_to_ctrl_ev}, /* 0xc0 */ 129e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi1_to_ctrl_ev}, /* 0xd0 */ 130e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi1_to_pitchbend_ev}, /* 0xe0 */ 131e9e02819STakashi Iwai }; 132e9e02819STakashi Iwai 133e9e02819STakashi Iwai static int cvt_ump_midi1_to_event(const union snd_ump_midi1_msg *val, 134e9e02819STakashi Iwai struct snd_seq_event *ev) 135e9e02819STakashi Iwai { 136e9e02819STakashi Iwai unsigned char status = val->note.status; 137e9e02819STakashi Iwai 138e9e02819STakashi Iwai if (status < 0x8 || status > 0xe) 139e9e02819STakashi Iwai return 0; /* invalid - skip */ 140e9e02819STakashi Iwai status -= 8; 141e9e02819STakashi Iwai ev->type = midi1_msg_encoders[status].seq_type; 142e9e02819STakashi Iwai ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; 143e9e02819STakashi Iwai midi1_msg_encoders[status].encode(val, ev); 144e9e02819STakashi Iwai return 1; 145e9e02819STakashi Iwai } 146e9e02819STakashi Iwai 147e9e02819STakashi Iwai /* MIDI System message */ 148e9e02819STakashi Iwai 149e9e02819STakashi Iwai /* encode one parameter value*/ 150e9e02819STakashi Iwai static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg *val, 151e9e02819STakashi Iwai struct snd_seq_event *ev) 152e9e02819STakashi Iwai { 153e9e02819STakashi Iwai ev->data.control.value = val->system.parm1; 154e9e02819STakashi Iwai } 155e9e02819STakashi Iwai 156e9e02819STakashi Iwai /* encode song position */ 157e9e02819STakashi Iwai static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg *val, 158e9e02819STakashi Iwai struct snd_seq_event *ev) 159e9e02819STakashi Iwai { 160e9e02819STakashi Iwai ev->data.control.value = (val->system.parm1 << 7) | val->system.parm2; 161e9e02819STakashi Iwai } 162e9e02819STakashi Iwai 163e9e02819STakashi Iwai /* Encoders for 0xf0 - 0xff */ 164e9e02819STakashi Iwai static struct seq_ump_midi1_to_ev system_msg_encoders[] = { 165e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */ 166e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_QFRAME, ump_system_to_one_param_ev}, /* 0xf1 */ 167e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_SONGPOS, ump_system_to_songpos_ev}, /* 0xf2 */ 168e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_SONGSEL, ump_system_to_one_param_ev}, /* 0xf3 */ 169e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf4 */ 170e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf5 */ 171e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_TUNE_REQUEST, NULL}, /* 0xf6 */ 172e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf7 */ 173e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CLOCK, NULL}, /* 0xf8 */ 174e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf9 */ 175e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_START, NULL}, /* 0xfa */ 176e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CONTINUE, NULL}, /* 0xfb */ 177e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_STOP, NULL}, /* 0xfc */ 178e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xfd */ 179e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_SENSING, NULL}, /* 0xfe */ 180e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_RESET, NULL}, /* 0xff */ 181e9e02819STakashi Iwai }; 182e9e02819STakashi Iwai 183e9e02819STakashi Iwai static int cvt_ump_system_to_event(const union snd_ump_midi1_msg *val, 184e9e02819STakashi Iwai struct snd_seq_event *ev) 185e9e02819STakashi Iwai { 186e9e02819STakashi Iwai unsigned char status = val->system.status; 187e9e02819STakashi Iwai 188e9e02819STakashi Iwai if ((status & 0xf0) != UMP_MIDI1_MSG_REALTIME) 189e9e02819STakashi Iwai return 0; /* invalid status - skip */ 190e9e02819STakashi Iwai status &= 0x0f; 191e9e02819STakashi Iwai ev->type = system_msg_encoders[status].seq_type; 192e9e02819STakashi Iwai ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; 193e9e02819STakashi Iwai if (ev->type == SNDRV_SEQ_EVENT_NONE) 194e9e02819STakashi Iwai return 0; 195e9e02819STakashi Iwai if (system_msg_encoders[status].encode) 196e9e02819STakashi Iwai system_msg_encoders[status].encode(val, ev); 197e9e02819STakashi Iwai return 1; 198e9e02819STakashi Iwai } 199e9e02819STakashi Iwai 200e9e02819STakashi Iwai /* MIDI 2.0 CVM */ 201e9e02819STakashi Iwai 202e9e02819STakashi Iwai /* encode note event */ 203e9e02819STakashi Iwai static int ump_midi2_to_note_ev(const union snd_ump_midi2_msg *val, 204e9e02819STakashi Iwai struct snd_seq_event *ev) 205e9e02819STakashi Iwai { 206e9e02819STakashi Iwai ev->data.note.channel = val->note.channel; 207e9e02819STakashi Iwai ev->data.note.note = val->note.note; 208e9e02819STakashi Iwai ev->data.note.velocity = downscale_16_to_7bit(val->note.velocity); 209e9e02819STakashi Iwai /* correct note-on velocity 0 to 1; 210e9e02819STakashi Iwai * it's no longer equivalent as not-off for MIDI 2.0 211e9e02819STakashi Iwai */ 212e9e02819STakashi Iwai if (ev->type == SNDRV_SEQ_EVENT_NOTEON && 213e9e02819STakashi Iwai !ev->data.note.velocity) 214e9e02819STakashi Iwai ev->data.note.velocity = 1; 215e9e02819STakashi Iwai return 1; 216e9e02819STakashi Iwai } 217e9e02819STakashi Iwai 218e9e02819STakashi Iwai /* encode pitch wheel change */ 219e9e02819STakashi Iwai static int ump_midi2_to_pitchbend_ev(const union snd_ump_midi2_msg *val, 220e9e02819STakashi Iwai struct snd_seq_event *ev) 221e9e02819STakashi Iwai { 222e9e02819STakashi Iwai ev->data.control.channel = val->pb.channel; 223e9e02819STakashi Iwai ev->data.control.value = downscale_32_to_14bit(val->pb.data); 224e9e02819STakashi Iwai ev->data.control.value -= 8192; 225e9e02819STakashi Iwai return 1; 226e9e02819STakashi Iwai } 227e9e02819STakashi Iwai 228e9e02819STakashi Iwai /* encode midi control change */ 229e9e02819STakashi Iwai static int ump_midi2_to_cc_ev(const union snd_ump_midi2_msg *val, 230e9e02819STakashi Iwai struct snd_seq_event *ev) 231e9e02819STakashi Iwai { 232e9e02819STakashi Iwai ev->data.control.channel = val->cc.channel; 233e9e02819STakashi Iwai ev->data.control.param = val->cc.index; 234e9e02819STakashi Iwai ev->data.control.value = downscale_32_to_7bit(val->cc.data); 235e9e02819STakashi Iwai return 1; 236e9e02819STakashi Iwai } 237e9e02819STakashi Iwai 238e9e02819STakashi Iwai /* encode midi program change */ 239e9e02819STakashi Iwai static int ump_midi2_to_pgm_ev(const union snd_ump_midi2_msg *val, 240e9e02819STakashi Iwai struct snd_seq_event *ev) 241e9e02819STakashi Iwai { 242e9e02819STakashi Iwai int size = 1; 243e9e02819STakashi Iwai 244e9e02819STakashi Iwai ev->data.control.channel = val->pg.channel; 245e9e02819STakashi Iwai if (val->pg.bank_valid) { 246e9e02819STakashi Iwai ev->type = SNDRV_SEQ_EVENT_CONTROL14; 247e9e02819STakashi Iwai ev->data.control.param = UMP_CC_BANK_SELECT; 248e9e02819STakashi Iwai ev->data.control.value = (val->pg.bank_msb << 7) | val->pg.bank_lsb; 249e9e02819STakashi Iwai ev[1] = ev[0]; 250e9e02819STakashi Iwai ev++; 251e9e02819STakashi Iwai ev->type = SNDRV_SEQ_EVENT_PGMCHANGE; 252e9e02819STakashi Iwai size = 2; 253e9e02819STakashi Iwai } 254e9e02819STakashi Iwai ev->data.control.value = val->pg.program; 255e9e02819STakashi Iwai return size; 256e9e02819STakashi Iwai } 257e9e02819STakashi Iwai 258e9e02819STakashi Iwai /* encode one parameter controls */ 259e9e02819STakashi Iwai static int ump_midi2_to_ctrl_ev(const union snd_ump_midi2_msg *val, 260e9e02819STakashi Iwai struct snd_seq_event *ev) 261e9e02819STakashi Iwai { 262e9e02819STakashi Iwai ev->data.control.channel = val->caf.channel; 263e9e02819STakashi Iwai ev->data.control.value = downscale_32_to_7bit(val->caf.data); 264e9e02819STakashi Iwai return 1; 265e9e02819STakashi Iwai } 266e9e02819STakashi Iwai 267e9e02819STakashi Iwai /* encode RPN/NRPN */ 268e9e02819STakashi Iwai static int ump_midi2_to_rpn_ev(const union snd_ump_midi2_msg *val, 269e9e02819STakashi Iwai struct snd_seq_event *ev) 270e9e02819STakashi Iwai { 271e9e02819STakashi Iwai ev->data.control.channel = val->rpn.channel; 272e9e02819STakashi Iwai ev->data.control.param = (val->rpn.bank << 7) | val->rpn.index; 273e9e02819STakashi Iwai ev->data.control.value = downscale_32_to_14bit(val->rpn.data); 274e9e02819STakashi Iwai return 1; 275e9e02819STakashi Iwai } 276e9e02819STakashi Iwai 277e9e02819STakashi Iwai /* Encoding MIDI 2.0 UMP Packet */ 278e9e02819STakashi Iwai struct seq_ump_midi2_to_ev { 279e9e02819STakashi Iwai int seq_type; 280e9e02819STakashi Iwai int (*encode)(const union snd_ump_midi2_msg *val, struct snd_seq_event *ev); 281e9e02819STakashi Iwai }; 282e9e02819STakashi Iwai 283e9e02819STakashi Iwai /* Encoders for MIDI2 status 0x00-0xf0 */ 284e9e02819STakashi Iwai static struct seq_ump_midi2_to_ev midi2_msg_encoders[] = { 285e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x00 */ 286e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x10 */ 287e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_REGPARAM, ump_midi2_to_rpn_ev}, /* 0x20 */ 288e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONREGPARAM, ump_midi2_to_rpn_ev}, /* 0x30 */ 289e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x40 */ 290e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x50 */ 291e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x60 */ 292e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0x70 */ 293e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NOTEOFF, ump_midi2_to_note_ev}, /* 0x80 */ 294e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NOTEON, ump_midi2_to_note_ev}, /* 0x90 */ 295e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_KEYPRESS, ump_midi2_to_note_ev}, /* 0xa0 */ 296e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CONTROLLER, ump_midi2_to_cc_ev}, /* 0xb0 */ 297e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_PGMCHANGE, ump_midi2_to_pgm_ev}, /* 0xc0 */ 298e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_CHANPRESS, ump_midi2_to_ctrl_ev}, /* 0xd0 */ 299e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_PITCHBEND, ump_midi2_to_pitchbend_ev}, /* 0xe0 */ 300e9e02819STakashi Iwai {SNDRV_SEQ_EVENT_NONE, NULL}, /* 0xf0 */ 301e9e02819STakashi Iwai }; 302e9e02819STakashi Iwai 303e9e02819STakashi Iwai static int cvt_ump_midi2_to_event(const union snd_ump_midi2_msg *val, 304e9e02819STakashi Iwai struct snd_seq_event *ev) 305e9e02819STakashi Iwai { 306e9e02819STakashi Iwai unsigned char status = val->note.status; 307e9e02819STakashi Iwai 308e9e02819STakashi Iwai ev->type = midi2_msg_encoders[status].seq_type; 309e9e02819STakashi Iwai if (ev->type == SNDRV_SEQ_EVENT_NONE) 310e9e02819STakashi Iwai return 0; /* skip */ 311e9e02819STakashi Iwai ev->flags = SNDRV_SEQ_EVENT_LENGTH_FIXED; 312e9e02819STakashi Iwai return midi2_msg_encoders[status].encode(val, ev); 313e9e02819STakashi Iwai } 314e9e02819STakashi Iwai 315e9e02819STakashi Iwai /* parse and compose for a sysex var-length event */ 316e9e02819STakashi Iwai static int cvt_ump_sysex7_to_event(const u32 *data, unsigned char *buf, 317e9e02819STakashi Iwai struct snd_seq_event *ev) 318e9e02819STakashi Iwai { 319e9e02819STakashi Iwai unsigned char status; 320e9e02819STakashi Iwai unsigned char bytes; 321e9e02819STakashi Iwai u32 val; 322e9e02819STakashi Iwai int size = 0; 323e9e02819STakashi Iwai 324e9e02819STakashi Iwai val = data[0]; 325e9e02819STakashi Iwai status = ump_sysex_message_status(val); 326e9e02819STakashi Iwai bytes = ump_sysex_message_length(val); 327e9e02819STakashi Iwai if (bytes > 6) 328e9e02819STakashi Iwai return 0; // skip 329e9e02819STakashi Iwai 330e9e02819STakashi Iwai if (status == UMP_SYSEX_STATUS_SINGLE || 331e9e02819STakashi Iwai status == UMP_SYSEX_STATUS_START) { 332e9e02819STakashi Iwai buf[0] = UMP_MIDI1_MSG_SYSEX_START; 333e9e02819STakashi Iwai size = 1; 334e9e02819STakashi Iwai } 335e9e02819STakashi Iwai 336e9e02819STakashi Iwai if (bytes > 0) 337e9e02819STakashi Iwai buf[size++] = (val >> 8) & 0x7f; 338e9e02819STakashi Iwai if (bytes > 1) 339e9e02819STakashi Iwai buf[size++] = val & 0x7f; 340e9e02819STakashi Iwai val = data[1]; 341e9e02819STakashi Iwai if (bytes > 2) 342e9e02819STakashi Iwai buf[size++] = (val >> 24) & 0x7f; 343e9e02819STakashi Iwai if (bytes > 3) 344e9e02819STakashi Iwai buf[size++] = (val >> 16) & 0x7f; 345e9e02819STakashi Iwai if (bytes > 4) 346e9e02819STakashi Iwai buf[size++] = (val >> 8) & 0x7f; 347e9e02819STakashi Iwai if (bytes > 5) 348e9e02819STakashi Iwai buf[size++] = val & 0x7f; 349e9e02819STakashi Iwai 350e9e02819STakashi Iwai if (status == UMP_SYSEX_STATUS_SINGLE || 351e9e02819STakashi Iwai status == UMP_SYSEX_STATUS_END) 352e9e02819STakashi Iwai buf[size++] = UMP_MIDI1_MSG_SYSEX_END; 353e9e02819STakashi Iwai 354e9e02819STakashi Iwai ev->type = SNDRV_SEQ_EVENT_SYSEX; 355e9e02819STakashi Iwai ev->flags = SNDRV_SEQ_EVENT_LENGTH_VARIABLE; 356e9e02819STakashi Iwai ev->data.ext.len = size; 357e9e02819STakashi Iwai ev->data.ext.ptr = buf; 358e9e02819STakashi Iwai return 1; 359e9e02819STakashi Iwai } 360e9e02819STakashi Iwai 361e9e02819STakashi Iwai /* convert UMP packet from MIDI 1.0 to MIDI 2.0 and deliver it */ 362e9e02819STakashi Iwai static int cvt_ump_midi1_to_midi2(struct snd_seq_client *dest, 363e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 364e9e02819STakashi Iwai struct snd_seq_event *__event, 365e9e02819STakashi Iwai int atomic, int hop) 366e9e02819STakashi Iwai { 367e9e02819STakashi Iwai struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event; 368e9e02819STakashi Iwai struct snd_seq_ump_event ev_cvt; 369e9e02819STakashi Iwai const union snd_ump_midi1_msg *midi1 = (const union snd_ump_midi1_msg *)event->ump; 370e9e02819STakashi Iwai union snd_ump_midi2_msg *midi2 = (union snd_ump_midi2_msg *)ev_cvt.ump; 371e9e02819STakashi Iwai 372e9e02819STakashi Iwai ev_cvt = *event; 373e9e02819STakashi Iwai memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump)); 374e9e02819STakashi Iwai 375e9e02819STakashi Iwai midi2->note.type = UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE; 376e9e02819STakashi Iwai midi2->note.group = midi1->note.group; 377e9e02819STakashi Iwai midi2->note.status = midi1->note.status; 378e9e02819STakashi Iwai midi2->note.channel = midi1->note.channel; 379e9e02819STakashi Iwai switch (midi1->note.status) { 380e9e02819STakashi Iwai case UMP_MSG_STATUS_NOTE_ON: 381e9e02819STakashi Iwai case UMP_MSG_STATUS_NOTE_OFF: 382e9e02819STakashi Iwai midi2->note.note = midi1->note.note; 383e9e02819STakashi Iwai midi2->note.velocity = upscale_7_to_16bit(midi1->note.velocity); 384e9e02819STakashi Iwai break; 385e9e02819STakashi Iwai case UMP_MSG_STATUS_POLY_PRESSURE: 386e9e02819STakashi Iwai midi2->paf.note = midi1->paf.note; 387e9e02819STakashi Iwai midi2->paf.data = upscale_7_to_32bit(midi1->paf.data); 388e9e02819STakashi Iwai break; 389e9e02819STakashi Iwai case UMP_MSG_STATUS_CC: 390e9e02819STakashi Iwai midi2->cc.index = midi1->cc.index; 391e9e02819STakashi Iwai midi2->cc.data = upscale_7_to_32bit(midi1->cc.data); 392e9e02819STakashi Iwai break; 393e9e02819STakashi Iwai case UMP_MSG_STATUS_PROGRAM: 394e9e02819STakashi Iwai midi2->pg.program = midi1->pg.program; 395e9e02819STakashi Iwai break; 396e9e02819STakashi Iwai case UMP_MSG_STATUS_CHANNEL_PRESSURE: 397e9e02819STakashi Iwai midi2->caf.data = upscale_7_to_32bit(midi1->caf.data); 398e9e02819STakashi Iwai break; 399e9e02819STakashi Iwai case UMP_MSG_STATUS_PITCH_BEND: 400e9e02819STakashi Iwai midi2->pb.data = upscale_14_to_32bit((midi1->pb.data_msb << 7) | 401e9e02819STakashi Iwai midi1->pb.data_lsb); 402e9e02819STakashi Iwai break; 403e9e02819STakashi Iwai default: 404e9e02819STakashi Iwai return 0; 405e9e02819STakashi Iwai } 406e9e02819STakashi Iwai 407e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 408e9e02819STakashi Iwai (struct snd_seq_event *)&ev_cvt, 409e9e02819STakashi Iwai atomic, hop); 410e9e02819STakashi Iwai } 411e9e02819STakashi Iwai 412e9e02819STakashi Iwai /* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */ 413e9e02819STakashi Iwai static int cvt_ump_midi2_to_midi1(struct snd_seq_client *dest, 414e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 415e9e02819STakashi Iwai struct snd_seq_event *__event, 416e9e02819STakashi Iwai int atomic, int hop) 417e9e02819STakashi Iwai { 418e9e02819STakashi Iwai struct snd_seq_ump_event *event = (struct snd_seq_ump_event *)__event; 419e9e02819STakashi Iwai struct snd_seq_ump_event ev_cvt; 420e9e02819STakashi Iwai union snd_ump_midi1_msg *midi1 = (union snd_ump_midi1_msg *)ev_cvt.ump; 421e9e02819STakashi Iwai const union snd_ump_midi2_msg *midi2 = (const union snd_ump_midi2_msg *)event->ump; 422e9e02819STakashi Iwai u16 v; 423e9e02819STakashi Iwai 424e9e02819STakashi Iwai ev_cvt = *event; 425e9e02819STakashi Iwai memset(&ev_cvt.ump, 0, sizeof(ev_cvt.ump)); 426e9e02819STakashi Iwai 427e9e02819STakashi Iwai midi1->note.type = UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE; 428e9e02819STakashi Iwai midi1->note.group = midi2->note.group; 429e9e02819STakashi Iwai midi1->note.status = midi2->note.status; 430e9e02819STakashi Iwai midi1->note.channel = midi2->note.channel; 431e9e02819STakashi Iwai switch (midi2->note.status << 4) { 432e9e02819STakashi Iwai case UMP_MSG_STATUS_NOTE_ON: 433e9e02819STakashi Iwai case UMP_MSG_STATUS_NOTE_OFF: 434e9e02819STakashi Iwai midi1->note.note = midi2->note.note; 435e9e02819STakashi Iwai midi1->note.velocity = downscale_16_to_7bit(midi2->note.velocity); 436e9e02819STakashi Iwai break; 437e9e02819STakashi Iwai case UMP_MSG_STATUS_POLY_PRESSURE: 438e9e02819STakashi Iwai midi1->paf.note = midi2->paf.note; 439e9e02819STakashi Iwai midi1->paf.data = downscale_32_to_7bit(midi2->paf.data); 440e9e02819STakashi Iwai break; 441e9e02819STakashi Iwai case UMP_MSG_STATUS_CC: 442e9e02819STakashi Iwai midi1->cc.index = midi2->cc.index; 443e9e02819STakashi Iwai midi1->cc.data = downscale_32_to_7bit(midi2->cc.data); 444e9e02819STakashi Iwai break; 445e9e02819STakashi Iwai case UMP_MSG_STATUS_PROGRAM: 446e9e02819STakashi Iwai midi1->pg.program = midi2->pg.program; 447e9e02819STakashi Iwai break; 448e9e02819STakashi Iwai case UMP_MSG_STATUS_CHANNEL_PRESSURE: 449e9e02819STakashi Iwai midi1->caf.data = downscale_32_to_7bit(midi2->caf.data); 450e9e02819STakashi Iwai break; 451e9e02819STakashi Iwai case UMP_MSG_STATUS_PITCH_BEND: 452e9e02819STakashi Iwai v = downscale_32_to_14bit(midi2->pb.data); 453e9e02819STakashi Iwai midi1->pb.data_msb = v >> 7; 454e9e02819STakashi Iwai midi1->pb.data_lsb = v & 0x7f; 455e9e02819STakashi Iwai break; 456e9e02819STakashi Iwai default: 457e9e02819STakashi Iwai return 0; 458e9e02819STakashi Iwai } 459e9e02819STakashi Iwai 460e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 461e9e02819STakashi Iwai (struct snd_seq_event *)&ev_cvt, 462e9e02819STakashi Iwai atomic, hop); 463e9e02819STakashi Iwai } 464e9e02819STakashi Iwai 465e9e02819STakashi Iwai /* convert UMP to a legacy ALSA seq event and deliver it */ 466e9e02819STakashi Iwai static int cvt_ump_to_any(struct snd_seq_client *dest, 467e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 468e9e02819STakashi Iwai struct snd_seq_event *event, 469e9e02819STakashi Iwai unsigned char type, 470e9e02819STakashi Iwai int atomic, int hop) 471e9e02819STakashi Iwai { 472e9e02819STakashi Iwai struct snd_seq_event ev_cvt[2]; /* up to two events */ 473e9e02819STakashi Iwai struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event; 474e9e02819STakashi Iwai /* use the second event as a temp buffer for saving stack usage */ 475e9e02819STakashi Iwai unsigned char *sysex_buf = (unsigned char *)(ev_cvt + 1); 476e9e02819STakashi Iwai unsigned char flags = event->flags & ~SNDRV_SEQ_EVENT_UMP; 477e9e02819STakashi Iwai int i, len, err; 478e9e02819STakashi Iwai 479e9e02819STakashi Iwai ev_cvt[0] = ev_cvt[1] = *event; 480e9e02819STakashi Iwai ev_cvt[0].flags = flags; 481e9e02819STakashi Iwai ev_cvt[1].flags = flags; 482e9e02819STakashi Iwai switch (type) { 483e9e02819STakashi Iwai case UMP_MSG_TYPE_SYSTEM: 484e9e02819STakashi Iwai len = cvt_ump_system_to_event((union snd_ump_midi1_msg *)ump_ev->ump, 485e9e02819STakashi Iwai ev_cvt); 486e9e02819STakashi Iwai break; 487e9e02819STakashi Iwai case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE: 488e9e02819STakashi Iwai len = cvt_ump_midi1_to_event((union snd_ump_midi1_msg *)ump_ev->ump, 489e9e02819STakashi Iwai ev_cvt); 490e9e02819STakashi Iwai break; 491e9e02819STakashi Iwai case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE: 492e9e02819STakashi Iwai len = cvt_ump_midi2_to_event((union snd_ump_midi2_msg *)ump_ev->ump, 493e9e02819STakashi Iwai ev_cvt); 494e9e02819STakashi Iwai break; 495e9e02819STakashi Iwai case UMP_MSG_TYPE_DATA: 496e9e02819STakashi Iwai len = cvt_ump_sysex7_to_event(ump_ev->ump, sysex_buf, ev_cvt); 497e9e02819STakashi Iwai break; 498e9e02819STakashi Iwai default: 499e9e02819STakashi Iwai return 0; 500e9e02819STakashi Iwai } 501e9e02819STakashi Iwai 502e9e02819STakashi Iwai for (i = 0; i < len; i++) { 503e9e02819STakashi Iwai err = __snd_seq_deliver_single_event(dest, dest_port, 504e9e02819STakashi Iwai &ev_cvt[i], atomic, hop); 505e9e02819STakashi Iwai if (err < 0) 506e9e02819STakashi Iwai return err; 507e9e02819STakashi Iwai } 508e9e02819STakashi Iwai 509e9e02819STakashi Iwai return 0; 510e9e02819STakashi Iwai } 511e9e02819STakashi Iwai 512e9e02819STakashi Iwai /* Replace UMP group field with the destination and deliver */ 513e9e02819STakashi Iwai static int deliver_with_group_convert(struct snd_seq_client *dest, 514e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 515e9e02819STakashi Iwai struct snd_seq_ump_event *ump_ev, 516e9e02819STakashi Iwai int atomic, int hop) 517e9e02819STakashi Iwai { 518e9e02819STakashi Iwai struct snd_seq_ump_event ev = *ump_ev; 519e9e02819STakashi Iwai 520e9e02819STakashi Iwai /* rewrite the group to the destination port */ 521e9e02819STakashi Iwai ev.ump[0] &= ~(0xfU << 24); 522e9e02819STakashi Iwai /* fill with the new group; the dest_port->ump_group field is 1-based */ 523e9e02819STakashi Iwai ev.ump[0] |= ((dest_port->ump_group - 1) << 24); 524e9e02819STakashi Iwai 525e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 526e9e02819STakashi Iwai (struct snd_seq_event *)&ev, 527e9e02819STakashi Iwai atomic, hop); 528e9e02819STakashi Iwai } 529e9e02819STakashi Iwai 530*d2b70607STakashi Iwai /* apply the UMP event filter; return true to skip the event */ 531*d2b70607STakashi Iwai static bool ump_event_filtered(struct snd_seq_client *dest, 532*d2b70607STakashi Iwai const struct snd_seq_ump_event *ev) 533*d2b70607STakashi Iwai { 534*d2b70607STakashi Iwai unsigned char group; 535*d2b70607STakashi Iwai 536*d2b70607STakashi Iwai group = ump_message_group(ev->ump[0]); 537*d2b70607STakashi Iwai /* check the bitmap for 1-based group number */ 538*d2b70607STakashi Iwai return dest->group_filter & (1U << (group + 1)); 539*d2b70607STakashi Iwai } 540*d2b70607STakashi Iwai 541e9e02819STakashi Iwai /* Convert from UMP packet and deliver */ 542e9e02819STakashi Iwai int snd_seq_deliver_from_ump(struct snd_seq_client *source, 543e9e02819STakashi Iwai struct snd_seq_client *dest, 544e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 545e9e02819STakashi Iwai struct snd_seq_event *event, 546e9e02819STakashi Iwai int atomic, int hop) 547e9e02819STakashi Iwai { 548e9e02819STakashi Iwai struct snd_seq_ump_event *ump_ev = (struct snd_seq_ump_event *)event; 549e9e02819STakashi Iwai unsigned char type; 550e9e02819STakashi Iwai 551e9e02819STakashi Iwai if (snd_seq_ev_is_variable(event)) 552e9e02819STakashi Iwai return 0; // skip, no variable event for UMP, so far 553*d2b70607STakashi Iwai if (ump_event_filtered(dest, ump_ev)) 554*d2b70607STakashi Iwai return 0; // skip if group filter is set and matching 555e9e02819STakashi Iwai type = ump_message_type(ump_ev->ump[0]); 556e9e02819STakashi Iwai 557e9e02819STakashi Iwai if (snd_seq_client_is_ump(dest)) { 558e9e02819STakashi Iwai if (snd_seq_client_is_midi2(dest) && 559e9e02819STakashi Iwai type == UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE) 560e9e02819STakashi Iwai return cvt_ump_midi1_to_midi2(dest, dest_port, 561e9e02819STakashi Iwai event, atomic, hop); 562e9e02819STakashi Iwai else if (!snd_seq_client_is_midi2(dest) && 563e9e02819STakashi Iwai type == UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE) 564e9e02819STakashi Iwai return cvt_ump_midi2_to_midi1(dest, dest_port, 565e9e02819STakashi Iwai event, atomic, hop); 566e9e02819STakashi Iwai /* non-EP port and different group is set? */ 567e9e02819STakashi Iwai if (dest_port->ump_group && 568e9e02819STakashi Iwai ump_message_group(*ump_ev->ump) + 1 != dest_port->ump_group) 569e9e02819STakashi Iwai return deliver_with_group_convert(dest, dest_port, 570e9e02819STakashi Iwai ump_ev, atomic, hop); 571e9e02819STakashi Iwai /* copy as-is */ 572e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 573e9e02819STakashi Iwai event, atomic, hop); 574e9e02819STakashi Iwai } 575e9e02819STakashi Iwai 576e9e02819STakashi Iwai return cvt_ump_to_any(dest, dest_port, event, type, atomic, hop); 577e9e02819STakashi Iwai } 578e9e02819STakashi Iwai 579e9e02819STakashi Iwai /* 580e9e02819STakashi Iwai * MIDI1 sequencer event -> UMP conversion 581e9e02819STakashi Iwai */ 582e9e02819STakashi Iwai 583e9e02819STakashi Iwai /* Conversion to UMP MIDI 1.0 */ 584e9e02819STakashi Iwai 585e9e02819STakashi Iwai /* convert note on/off event to MIDI 1.0 UMP */ 586e9e02819STakashi Iwai static int note_ev_to_ump_midi1(const struct snd_seq_event *event, 587e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 588e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 589e9e02819STakashi Iwai unsigned char status) 590e9e02819STakashi Iwai { 591e9e02819STakashi Iwai if (!event->data.note.velocity) 592e9e02819STakashi Iwai status = UMP_MSG_STATUS_NOTE_OFF; 593e9e02819STakashi Iwai data->note.status = status; 594e9e02819STakashi Iwai data->note.channel = event->data.note.channel & 0x0f; 595e9e02819STakashi Iwai data->note.velocity = event->data.note.velocity & 0x7f; 596e9e02819STakashi Iwai data->note.note = event->data.note.note & 0x7f; 597e9e02819STakashi Iwai return 1; 598e9e02819STakashi Iwai } 599e9e02819STakashi Iwai 600e9e02819STakashi Iwai /* convert CC event to MIDI 1.0 UMP */ 601e9e02819STakashi Iwai static int cc_ev_to_ump_midi1(const struct snd_seq_event *event, 602e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 603e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 604e9e02819STakashi Iwai unsigned char status) 605e9e02819STakashi Iwai { 606e9e02819STakashi Iwai data->cc.status = status; 607e9e02819STakashi Iwai data->cc.channel = event->data.control.channel & 0x0f; 608e9e02819STakashi Iwai data->cc.index = event->data.control.param; 609e9e02819STakashi Iwai data->cc.data = event->data.control.value; 610e9e02819STakashi Iwai return 1; 611e9e02819STakashi Iwai } 612e9e02819STakashi Iwai 613e9e02819STakashi Iwai /* convert one-parameter control event to MIDI 1.0 UMP */ 614e9e02819STakashi Iwai static int ctrl_ev_to_ump_midi1(const struct snd_seq_event *event, 615e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 616e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 617e9e02819STakashi Iwai unsigned char status) 618e9e02819STakashi Iwai { 619e9e02819STakashi Iwai data->caf.status = status; 620e9e02819STakashi Iwai data->caf.channel = event->data.control.channel & 0x0f; 621e9e02819STakashi Iwai data->caf.data = event->data.control.value & 0x7f; 622e9e02819STakashi Iwai return 1; 623e9e02819STakashi Iwai } 624e9e02819STakashi Iwai 625e9e02819STakashi Iwai /* convert pitchbend event to MIDI 1.0 UMP */ 626e9e02819STakashi Iwai static int pitchbend_ev_to_ump_midi1(const struct snd_seq_event *event, 627e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 628e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 629e9e02819STakashi Iwai unsigned char status) 630e9e02819STakashi Iwai { 631e9e02819STakashi Iwai int val = event->data.control.value + 8192; 632e9e02819STakashi Iwai 633e9e02819STakashi Iwai val = clamp(val, 0, 0x3fff); 634e9e02819STakashi Iwai data->pb.status = status; 635e9e02819STakashi Iwai data->pb.channel = event->data.control.channel & 0x0f; 636e9e02819STakashi Iwai data->pb.data_msb = (val >> 7) & 0x7f; 637e9e02819STakashi Iwai data->pb.data_lsb = val & 0x7f; 638e9e02819STakashi Iwai return 1; 639e9e02819STakashi Iwai } 640e9e02819STakashi Iwai 641e9e02819STakashi Iwai /* convert 14bit control event to MIDI 1.0 UMP; split to two events */ 642e9e02819STakashi Iwai static int ctrl14_ev_to_ump_midi1(const struct snd_seq_event *event, 643e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 644e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 645e9e02819STakashi Iwai unsigned char status) 646e9e02819STakashi Iwai { 647e9e02819STakashi Iwai data->cc.status = UMP_MSG_STATUS_CC; 648e9e02819STakashi Iwai data->cc.channel = event->data.control.channel & 0x0f; 649e9e02819STakashi Iwai data->cc.index = event->data.control.param & 0x7f; 650e9e02819STakashi Iwai if (event->data.control.param < 0x20) { 651e9e02819STakashi Iwai data->cc.data = (event->data.control.value >> 7) & 0x7f; 652e9e02819STakashi Iwai data[1] = data[0]; 653e9e02819STakashi Iwai data[1].cc.index = event->data.control.param | 0x20; 654e9e02819STakashi Iwai data[1].cc.data = event->data.control.value & 0x7f; 655e9e02819STakashi Iwai return 2; 656e9e02819STakashi Iwai } 657e9e02819STakashi Iwai 658e9e02819STakashi Iwai data->cc.data = event->data.control.value & 0x7f; 659e9e02819STakashi Iwai return 1; 660e9e02819STakashi Iwai } 661e9e02819STakashi Iwai 662e9e02819STakashi Iwai /* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */ 663e9e02819STakashi Iwai static int rpn_ev_to_ump_midi1(const struct snd_seq_event *event, 664e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 665e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 666e9e02819STakashi Iwai unsigned char status) 667e9e02819STakashi Iwai { 668e9e02819STakashi Iwai bool is_rpn = (status == UMP_MSG_STATUS_RPN); 669e9e02819STakashi Iwai 670e9e02819STakashi Iwai data->cc.status = UMP_MSG_STATUS_CC; 671e9e02819STakashi Iwai data->cc.channel = event->data.control.channel & 0x0f; 672e9e02819STakashi Iwai data[1] = data[2] = data[3] = data[0]; 673e9e02819STakashi Iwai 674e9e02819STakashi Iwai data[0].cc.index = is_rpn ? UMP_CC_RPN_MSB : UMP_CC_NRPN_MSB; 675e9e02819STakashi Iwai data[0].cc.data = (event->data.control.param >> 7) & 0x7f; 676e9e02819STakashi Iwai data[1].cc.index = is_rpn ? UMP_CC_RPN_LSB : UMP_CC_NRPN_LSB; 677e9e02819STakashi Iwai data[1].cc.data = event->data.control.param & 0x7f; 678e9e02819STakashi Iwai data[2].cc.index = UMP_CC_DATA; 679e9e02819STakashi Iwai data[2].cc.data = (event->data.control.value >> 7) & 0x7f; 680e9e02819STakashi Iwai data[3].cc.index = UMP_CC_DATA_LSB; 681e9e02819STakashi Iwai data[3].cc.data = event->data.control.value & 0x7f; 682e9e02819STakashi Iwai return 4; 683e9e02819STakashi Iwai } 684e9e02819STakashi Iwai 685e9e02819STakashi Iwai /* convert system / RT message to UMP */ 686e9e02819STakashi Iwai static int system_ev_to_ump_midi1(const struct snd_seq_event *event, 687e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 688e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 689e9e02819STakashi Iwai unsigned char status) 690e9e02819STakashi Iwai { 691e9e02819STakashi Iwai data->system.status = status; 692e9e02819STakashi Iwai return 1; 693e9e02819STakashi Iwai } 694e9e02819STakashi Iwai 695e9e02819STakashi Iwai /* convert system / RT message with 1 parameter to UMP */ 696e9e02819STakashi Iwai static int system_1p_ev_to_ump_midi1(const struct snd_seq_event *event, 697e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 698e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 699e9e02819STakashi Iwai unsigned char status) 700e9e02819STakashi Iwai { 701e9e02819STakashi Iwai data->system.status = status; 702e9e02819STakashi Iwai data->system.parm1 = event->data.control.value & 0x7f; 703e9e02819STakashi Iwai return 1; 704e9e02819STakashi Iwai } 705e9e02819STakashi Iwai 706e9e02819STakashi Iwai /* convert system / RT message with two parameters to UMP */ 707e9e02819STakashi Iwai static int system_2p_ev_to_ump_midi1(const struct snd_seq_event *event, 708e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 709e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 710e9e02819STakashi Iwai unsigned char status) 711e9e02819STakashi Iwai { 712e9e02819STakashi Iwai data->system.status = status; 713e9e02819STakashi Iwai data->system.parm1 = (event->data.control.value >> 7) & 0x7f; 714e9e02819STakashi Iwai data->system.parm1 = event->data.control.value & 0x7f; 715e9e02819STakashi Iwai return 1; 716e9e02819STakashi Iwai } 717e9e02819STakashi Iwai 718e9e02819STakashi Iwai /* Conversion to UMP MIDI 2.0 */ 719e9e02819STakashi Iwai 720e9e02819STakashi Iwai /* convert note on/off event to MIDI 2.0 UMP */ 721e9e02819STakashi Iwai static int note_ev_to_ump_midi2(const struct snd_seq_event *event, 722e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 723e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 724e9e02819STakashi Iwai unsigned char status) 725e9e02819STakashi Iwai { 726e9e02819STakashi Iwai if (!event->data.note.velocity) 727e9e02819STakashi Iwai status = UMP_MSG_STATUS_NOTE_OFF; 728e9e02819STakashi Iwai data->note.status = status; 729e9e02819STakashi Iwai data->note.channel = event->data.note.channel & 0x0f; 730e9e02819STakashi Iwai data->note.note = event->data.note.note & 0x7f; 731e9e02819STakashi Iwai data->note.velocity = upscale_7_to_16bit(event->data.note.velocity & 0x7f); 732e9e02819STakashi Iwai return 1; 733e9e02819STakashi Iwai } 734e9e02819STakashi Iwai 735e9e02819STakashi Iwai /* convert PAF event to MIDI 2.0 UMP */ 736e9e02819STakashi Iwai static int paf_ev_to_ump_midi2(const struct snd_seq_event *event, 737e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 738e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 739e9e02819STakashi Iwai unsigned char status) 740e9e02819STakashi Iwai { 741e9e02819STakashi Iwai data->paf.status = status; 742e9e02819STakashi Iwai data->paf.channel = event->data.note.channel & 0x0f; 743e9e02819STakashi Iwai data->paf.note = event->data.note.note & 0x7f; 744e9e02819STakashi Iwai data->paf.data = upscale_7_to_32bit(event->data.note.velocity & 0x7f); 745e9e02819STakashi Iwai return 1; 746e9e02819STakashi Iwai } 747e9e02819STakashi Iwai 748e9e02819STakashi Iwai /* set up the MIDI2 RPN/NRPN packet data from the parsed info */ 749e9e02819STakashi Iwai static void fill_rpn(struct snd_seq_ump_midi2_bank *cc, 750e9e02819STakashi Iwai union snd_ump_midi2_msg *data) 751e9e02819STakashi Iwai { 752e9e02819STakashi Iwai if (cc->rpn_set) { 753e9e02819STakashi Iwai data->rpn.status = UMP_MSG_STATUS_RPN; 754e9e02819STakashi Iwai data->rpn.bank = cc->cc_rpn_msb; 755e9e02819STakashi Iwai data->rpn.index = cc->cc_rpn_lsb; 756e9e02819STakashi Iwai cc->rpn_set = 0; 757e9e02819STakashi Iwai cc->cc_rpn_msb = cc->cc_rpn_lsb = 0; 758e9e02819STakashi Iwai } else { 759e9e02819STakashi Iwai data->rpn.status = UMP_MSG_STATUS_NRPN; 760e9e02819STakashi Iwai data->rpn.bank = cc->cc_nrpn_msb; 761e9e02819STakashi Iwai data->rpn.index = cc->cc_nrpn_lsb; 762e9e02819STakashi Iwai cc->nrpn_set = 0; 763e9e02819STakashi Iwai cc->cc_nrpn_msb = cc->cc_nrpn_lsb = 0; 764e9e02819STakashi Iwai } 765e9e02819STakashi Iwai data->rpn.data = upscale_14_to_32bit((cc->cc_data_msb << 7) | 766e9e02819STakashi Iwai cc->cc_data_lsb); 767e9e02819STakashi Iwai cc->cc_data_msb = cc->cc_data_lsb = 0; 768e9e02819STakashi Iwai } 769e9e02819STakashi Iwai 770e9e02819STakashi Iwai /* convert CC event to MIDI 2.0 UMP */ 771e9e02819STakashi Iwai static int cc_ev_to_ump_midi2(const struct snd_seq_event *event, 772e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 773e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 774e9e02819STakashi Iwai unsigned char status) 775e9e02819STakashi Iwai { 776e9e02819STakashi Iwai unsigned char channel = event->data.control.channel & 0x0f; 777e9e02819STakashi Iwai unsigned char index = event->data.control.param & 0x7f; 778e9e02819STakashi Iwai unsigned char val = event->data.control.value & 0x7f; 779e9e02819STakashi Iwai struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; 780e9e02819STakashi Iwai 781e9e02819STakashi Iwai /* process special CC's (bank/rpn/nrpn) */ 782e9e02819STakashi Iwai switch (index) { 783e9e02819STakashi Iwai case UMP_CC_RPN_MSB: 784e9e02819STakashi Iwai cc->rpn_set = 1; 785e9e02819STakashi Iwai cc->cc_rpn_msb = val; 786e9e02819STakashi Iwai return 0; // skip 787e9e02819STakashi Iwai case UMP_CC_RPN_LSB: 788e9e02819STakashi Iwai cc->rpn_set = 1; 789e9e02819STakashi Iwai cc->cc_rpn_lsb = val; 790e9e02819STakashi Iwai return 0; // skip 791e9e02819STakashi Iwai case UMP_CC_NRPN_MSB: 792e9e02819STakashi Iwai cc->nrpn_set = 1; 793e9e02819STakashi Iwai cc->cc_nrpn_msb = val; 794e9e02819STakashi Iwai return 0; // skip 795e9e02819STakashi Iwai case UMP_CC_NRPN_LSB: 796e9e02819STakashi Iwai cc->nrpn_set = 1; 797e9e02819STakashi Iwai cc->cc_nrpn_lsb = val; 798e9e02819STakashi Iwai return 0; // skip 799e9e02819STakashi Iwai case UMP_CC_DATA: 800e9e02819STakashi Iwai cc->cc_data_msb = val; 801e9e02819STakashi Iwai return 0; // skip 802e9e02819STakashi Iwai case UMP_CC_BANK_SELECT: 803e9e02819STakashi Iwai cc->bank_set = 1; 804e9e02819STakashi Iwai cc->cc_bank_msb = val; 805e9e02819STakashi Iwai return 0; // skip 806e9e02819STakashi Iwai case UMP_CC_BANK_SELECT_LSB: 807e9e02819STakashi Iwai cc->bank_set = 1; 808e9e02819STakashi Iwai cc->cc_bank_lsb = val; 809e9e02819STakashi Iwai return 0; // skip 810e9e02819STakashi Iwai case UMP_CC_DATA_LSB: 811e9e02819STakashi Iwai cc->cc_data_lsb = val; 812e9e02819STakashi Iwai if (!(cc->rpn_set || cc->nrpn_set)) 813e9e02819STakashi Iwai return 0; // skip 814e9e02819STakashi Iwai fill_rpn(cc, data); 815e9e02819STakashi Iwai return 1; 816e9e02819STakashi Iwai } 817e9e02819STakashi Iwai 818e9e02819STakashi Iwai data->cc.status = status; 819e9e02819STakashi Iwai data->cc.channel = channel; 820e9e02819STakashi Iwai data->cc.index = index; 821e9e02819STakashi Iwai data->cc.data = upscale_7_to_32bit(event->data.control.value & 0x7f); 822e9e02819STakashi Iwai return 1; 823e9e02819STakashi Iwai } 824e9e02819STakashi Iwai 825e9e02819STakashi Iwai /* convert one-parameter control event to MIDI 2.0 UMP */ 826e9e02819STakashi Iwai static int ctrl_ev_to_ump_midi2(const struct snd_seq_event *event, 827e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 828e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 829e9e02819STakashi Iwai unsigned char status) 830e9e02819STakashi Iwai { 831e9e02819STakashi Iwai data->caf.status = status; 832e9e02819STakashi Iwai data->caf.channel = event->data.control.channel & 0x0f; 833e9e02819STakashi Iwai data->caf.data = upscale_7_to_32bit(event->data.control.value & 0x7f); 834e9e02819STakashi Iwai return 1; 835e9e02819STakashi Iwai } 836e9e02819STakashi Iwai 837e9e02819STakashi Iwai /* convert program change event to MIDI 2.0 UMP */ 838e9e02819STakashi Iwai static int pgm_ev_to_ump_midi2(const struct snd_seq_event *event, 839e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 840e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 841e9e02819STakashi Iwai unsigned char status) 842e9e02819STakashi Iwai { 843e9e02819STakashi Iwai unsigned char channel = event->data.control.channel & 0x0f; 844e9e02819STakashi Iwai struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; 845e9e02819STakashi Iwai 846e9e02819STakashi Iwai data->pg.status = status; 847e9e02819STakashi Iwai data->pg.channel = channel; 848e9e02819STakashi Iwai data->pg.program = event->data.control.value & 0x7f; 849e9e02819STakashi Iwai if (cc->bank_set) { 850e9e02819STakashi Iwai data->pg.bank_valid = 1; 851e9e02819STakashi Iwai data->pg.bank_msb = cc->cc_bank_msb; 852e9e02819STakashi Iwai data->pg.bank_lsb = cc->cc_bank_lsb; 853e9e02819STakashi Iwai cc->bank_set = 0; 854e9e02819STakashi Iwai cc->cc_bank_msb = cc->cc_bank_lsb = 0; 855e9e02819STakashi Iwai } 856e9e02819STakashi Iwai return 1; 857e9e02819STakashi Iwai } 858e9e02819STakashi Iwai 859e9e02819STakashi Iwai /* convert pitchbend event to MIDI 2.0 UMP */ 860e9e02819STakashi Iwai static int pitchbend_ev_to_ump_midi2(const struct snd_seq_event *event, 861e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 862e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 863e9e02819STakashi Iwai unsigned char status) 864e9e02819STakashi Iwai { 865e9e02819STakashi Iwai int val = event->data.control.value + 8192; 866e9e02819STakashi Iwai 867e9e02819STakashi Iwai val = clamp(val, 0, 0x3fff); 868e9e02819STakashi Iwai data->pb.status = status; 869e9e02819STakashi Iwai data->pb.channel = event->data.control.channel & 0x0f; 870e9e02819STakashi Iwai data->pb.data = upscale_14_to_32bit(val); 871e9e02819STakashi Iwai return 1; 872e9e02819STakashi Iwai } 873e9e02819STakashi Iwai 874e9e02819STakashi Iwai /* convert 14bit control event to MIDI 2.0 UMP; split to two events */ 875e9e02819STakashi Iwai static int ctrl14_ev_to_ump_midi2(const struct snd_seq_event *event, 876e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 877e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 878e9e02819STakashi Iwai unsigned char status) 879e9e02819STakashi Iwai { 880e9e02819STakashi Iwai unsigned char channel = event->data.control.channel & 0x0f; 881e9e02819STakashi Iwai unsigned char index = event->data.control.param & 0x7f; 882e9e02819STakashi Iwai struct snd_seq_ump_midi2_bank *cc = &dest_port->midi2_bank[channel]; 883e9e02819STakashi Iwai unsigned char msb, lsb; 884e9e02819STakashi Iwai 885e9e02819STakashi Iwai msb = (event->data.control.value >> 7) & 0x7f; 886e9e02819STakashi Iwai lsb = event->data.control.value & 0x7f; 887e9e02819STakashi Iwai /* process special CC's (bank/rpn/nrpn) */ 888e9e02819STakashi Iwai switch (index) { 889e9e02819STakashi Iwai case UMP_CC_BANK_SELECT: 890e9e02819STakashi Iwai cc->cc_bank_msb = msb; 891e9e02819STakashi Iwai fallthrough; 892e9e02819STakashi Iwai case UMP_CC_BANK_SELECT_LSB: 893e9e02819STakashi Iwai cc->bank_set = 1; 894e9e02819STakashi Iwai cc->cc_bank_lsb = lsb; 895e9e02819STakashi Iwai return 0; // skip 896e9e02819STakashi Iwai case UMP_CC_RPN_MSB: 897e9e02819STakashi Iwai cc->cc_rpn_msb = msb; 898e9e02819STakashi Iwai fallthrough; 899e9e02819STakashi Iwai case UMP_CC_RPN_LSB: 900e9e02819STakashi Iwai cc->rpn_set = 1; 901e9e02819STakashi Iwai cc->cc_rpn_lsb = lsb; 902e9e02819STakashi Iwai return 0; // skip 903e9e02819STakashi Iwai case UMP_CC_NRPN_MSB: 904e9e02819STakashi Iwai cc->cc_nrpn_msb = msb; 905e9e02819STakashi Iwai fallthrough; 906e9e02819STakashi Iwai case UMP_CC_NRPN_LSB: 907e9e02819STakashi Iwai cc->nrpn_set = 1; 908e9e02819STakashi Iwai cc->cc_nrpn_lsb = lsb; 909e9e02819STakashi Iwai return 0; // skip 910e9e02819STakashi Iwai case UMP_CC_DATA: 911e9e02819STakashi Iwai cc->cc_data_msb = msb; 912e9e02819STakashi Iwai fallthrough; 913e9e02819STakashi Iwai case UMP_CC_DATA_LSB: 914e9e02819STakashi Iwai cc->cc_data_lsb = lsb; 915e9e02819STakashi Iwai if (!(cc->rpn_set || cc->nrpn_set)) 916e9e02819STakashi Iwai return 0; // skip 917e9e02819STakashi Iwai fill_rpn(cc, data); 918e9e02819STakashi Iwai return 1; 919e9e02819STakashi Iwai } 920e9e02819STakashi Iwai 921e9e02819STakashi Iwai data->cc.status = UMP_MSG_STATUS_CC; 922e9e02819STakashi Iwai data->cc.channel = channel; 923e9e02819STakashi Iwai data->cc.index = index; 924e9e02819STakashi Iwai if (event->data.control.param < 0x20) { 925e9e02819STakashi Iwai data->cc.data = upscale_7_to_32bit(msb); 926e9e02819STakashi Iwai data[1] = data[0]; 927e9e02819STakashi Iwai data[1].cc.index = event->data.control.param | 0x20; 928e9e02819STakashi Iwai data[1].cc.data = upscale_7_to_32bit(lsb); 929e9e02819STakashi Iwai return 2; 930e9e02819STakashi Iwai } 931e9e02819STakashi Iwai 932e9e02819STakashi Iwai data->cc.data = upscale_7_to_32bit(lsb); 933e9e02819STakashi Iwai return 1; 934e9e02819STakashi Iwai } 935e9e02819STakashi Iwai 936e9e02819STakashi Iwai /* convert RPN/NRPN event to MIDI 2.0 UMP */ 937e9e02819STakashi Iwai static int rpn_ev_to_ump_midi2(const struct snd_seq_event *event, 938e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 939e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 940e9e02819STakashi Iwai unsigned char status) 941e9e02819STakashi Iwai { 942e9e02819STakashi Iwai data->rpn.status = status; 943e9e02819STakashi Iwai data->rpn.channel = event->data.control.channel; 944e9e02819STakashi Iwai data->rpn.bank = (event->data.control.param >> 7) & 0x7f; 945e9e02819STakashi Iwai data->rpn.index = event->data.control.param & 0x7f; 946e9e02819STakashi Iwai data->rpn.data = upscale_14_to_32bit(event->data.control.value & 0x3fff); 947e9e02819STakashi Iwai return 1; 948e9e02819STakashi Iwai } 949e9e02819STakashi Iwai 950e9e02819STakashi Iwai /* convert system / RT message to UMP */ 951e9e02819STakashi Iwai static int system_ev_to_ump_midi2(const struct snd_seq_event *event, 952e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 953e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 954e9e02819STakashi Iwai unsigned char status) 955e9e02819STakashi Iwai { 956e9e02819STakashi Iwai return system_ev_to_ump_midi1(event, dest_port, 957e9e02819STakashi Iwai (union snd_ump_midi1_msg *)data, 958e9e02819STakashi Iwai status); 959e9e02819STakashi Iwai } 960e9e02819STakashi Iwai 961e9e02819STakashi Iwai /* convert system / RT message with 1 parameter to UMP */ 962e9e02819STakashi Iwai static int system_1p_ev_to_ump_midi2(const struct snd_seq_event *event, 963e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 964e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 965e9e02819STakashi Iwai unsigned char status) 966e9e02819STakashi Iwai { 967e9e02819STakashi Iwai return system_1p_ev_to_ump_midi1(event, dest_port, 968e9e02819STakashi Iwai (union snd_ump_midi1_msg *)data, 969e9e02819STakashi Iwai status); 970e9e02819STakashi Iwai } 971e9e02819STakashi Iwai 972e9e02819STakashi Iwai /* convert system / RT message with two parameters to UMP */ 973e9e02819STakashi Iwai static int system_2p_ev_to_ump_midi2(const struct snd_seq_event *event, 974e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 975e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 976e9e02819STakashi Iwai unsigned char status) 977e9e02819STakashi Iwai { 978e9e02819STakashi Iwai return system_1p_ev_to_ump_midi1(event, dest_port, 979e9e02819STakashi Iwai (union snd_ump_midi1_msg *)data, 980e9e02819STakashi Iwai status); 981e9e02819STakashi Iwai } 982e9e02819STakashi Iwai 983e9e02819STakashi Iwai struct seq_ev_to_ump { 984e9e02819STakashi Iwai int seq_type; 985e9e02819STakashi Iwai unsigned char status; 986e9e02819STakashi Iwai int (*midi1_encode)(const struct snd_seq_event *event, 987e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 988e9e02819STakashi Iwai union snd_ump_midi1_msg *data, 989e9e02819STakashi Iwai unsigned char status); 990e9e02819STakashi Iwai int (*midi2_encode)(const struct snd_seq_event *event, 991e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 992e9e02819STakashi Iwai union snd_ump_midi2_msg *data, 993e9e02819STakashi Iwai unsigned char status); 994e9e02819STakashi Iwai }; 995e9e02819STakashi Iwai 996e9e02819STakashi Iwai static const struct seq_ev_to_ump seq_ev_ump_encoders[] = { 997e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_NOTEON, UMP_MSG_STATUS_NOTE_ON, 998e9e02819STakashi Iwai note_ev_to_ump_midi1, note_ev_to_ump_midi2 }, 999e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_NOTEOFF, UMP_MSG_STATUS_NOTE_OFF, 1000e9e02819STakashi Iwai note_ev_to_ump_midi1, note_ev_to_ump_midi2 }, 1001e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_KEYPRESS, UMP_MSG_STATUS_POLY_PRESSURE, 1002e9e02819STakashi Iwai note_ev_to_ump_midi1, paf_ev_to_ump_midi2 }, 1003e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_CONTROLLER, UMP_MSG_STATUS_CC, 1004e9e02819STakashi Iwai cc_ev_to_ump_midi1, cc_ev_to_ump_midi2 }, 1005e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_PGMCHANGE, UMP_MSG_STATUS_PROGRAM, 1006e9e02819STakashi Iwai ctrl_ev_to_ump_midi1, pgm_ev_to_ump_midi2 }, 1007e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_CHANPRESS, UMP_MSG_STATUS_CHANNEL_PRESSURE, 1008e9e02819STakashi Iwai ctrl_ev_to_ump_midi1, ctrl_ev_to_ump_midi2 }, 1009e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_PITCHBEND, UMP_MSG_STATUS_PITCH_BEND, 1010e9e02819STakashi Iwai pitchbend_ev_to_ump_midi1, pitchbend_ev_to_ump_midi2 }, 1011e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_CONTROL14, 0, 1012e9e02819STakashi Iwai ctrl14_ev_to_ump_midi1, ctrl14_ev_to_ump_midi2 }, 1013e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_NONREGPARAM, UMP_MSG_STATUS_NRPN, 1014e9e02819STakashi Iwai rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 }, 1015e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_REGPARAM, UMP_MSG_STATUS_RPN, 1016e9e02819STakashi Iwai rpn_ev_to_ump_midi1, rpn_ev_to_ump_midi2 }, 1017e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_QFRAME, UMP_SYSTEM_STATUS_MIDI_TIME_CODE, 1018e9e02819STakashi Iwai system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 }, 1019e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_SONGPOS, UMP_SYSTEM_STATUS_SONG_POSITION, 1020e9e02819STakashi Iwai system_2p_ev_to_ump_midi1, system_2p_ev_to_ump_midi2 }, 1021e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_SONGSEL, UMP_SYSTEM_STATUS_SONG_SELECT, 1022e9e02819STakashi Iwai system_1p_ev_to_ump_midi1, system_1p_ev_to_ump_midi2 }, 1023e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_TUNE_REQUEST, UMP_SYSTEM_STATUS_TUNE_REQUEST, 1024e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1025e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_CLOCK, UMP_SYSTEM_STATUS_TIMING_CLOCK, 1026e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1027e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_START, UMP_SYSTEM_STATUS_START, 1028e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1029e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_CONTINUE, UMP_SYSTEM_STATUS_CONTINUE, 1030e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1031e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_STOP, UMP_SYSTEM_STATUS_STOP, 1032e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1033e9e02819STakashi Iwai { SNDRV_SEQ_EVENT_SENSING, UMP_SYSTEM_STATUS_ACTIVE_SENSING, 1034e9e02819STakashi Iwai system_ev_to_ump_midi1, system_ev_to_ump_midi2 }, 1035e9e02819STakashi Iwai }; 1036e9e02819STakashi Iwai 1037e9e02819STakashi Iwai static const struct seq_ev_to_ump *find_ump_encoder(int type) 1038e9e02819STakashi Iwai { 1039e9e02819STakashi Iwai int i; 1040e9e02819STakashi Iwai 1041e9e02819STakashi Iwai for (i = 0; i < ARRAY_SIZE(seq_ev_ump_encoders); i++) 1042e9e02819STakashi Iwai if (seq_ev_ump_encoders[i].seq_type == type) 1043e9e02819STakashi Iwai return &seq_ev_ump_encoders[i]; 1044e9e02819STakashi Iwai 1045e9e02819STakashi Iwai return NULL; 1046e9e02819STakashi Iwai } 1047e9e02819STakashi Iwai 1048e9e02819STakashi Iwai static void setup_ump_event(struct snd_seq_ump_event *dest, 1049e9e02819STakashi Iwai const struct snd_seq_event *src) 1050e9e02819STakashi Iwai { 1051e9e02819STakashi Iwai memcpy(dest, src, sizeof(*src)); 1052e9e02819STakashi Iwai dest->type = 0; 1053e9e02819STakashi Iwai dest->flags |= SNDRV_SEQ_EVENT_UMP; 1054e9e02819STakashi Iwai dest->flags &= ~SNDRV_SEQ_EVENT_LENGTH_MASK; 1055e9e02819STakashi Iwai memset(dest->ump, 0, sizeof(dest->ump)); 1056e9e02819STakashi Iwai } 1057e9e02819STakashi Iwai 1058e9e02819STakashi Iwai /* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */ 1059e9e02819STakashi Iwai static int cvt_to_ump_midi1(struct snd_seq_client *dest, 1060e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 1061e9e02819STakashi Iwai struct snd_seq_event *event, 1062e9e02819STakashi Iwai int atomic, int hop) 1063e9e02819STakashi Iwai { 1064e9e02819STakashi Iwai const struct seq_ev_to_ump *encoder; 1065e9e02819STakashi Iwai struct snd_seq_ump_event ev_cvt; 1066e9e02819STakashi Iwai union snd_ump_midi1_msg data[4]; 1067e9e02819STakashi Iwai int i, n, err; 1068e9e02819STakashi Iwai 1069e9e02819STakashi Iwai encoder = find_ump_encoder(event->type); 1070e9e02819STakashi Iwai if (!encoder) 1071e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 1072e9e02819STakashi Iwai event, atomic, hop); 1073e9e02819STakashi Iwai 1074e9e02819STakashi Iwai data->raw = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE); 1075e9e02819STakashi Iwai n = encoder->midi1_encode(event, dest_port, data, encoder->status); 1076e9e02819STakashi Iwai if (!n) 1077e9e02819STakashi Iwai return 0; 1078e9e02819STakashi Iwai 1079e9e02819STakashi Iwai setup_ump_event(&ev_cvt, event); 1080e9e02819STakashi Iwai for (i = 0; i < n; i++) { 1081e9e02819STakashi Iwai ev_cvt.ump[0] = data[i].raw; 1082e9e02819STakashi Iwai err = __snd_seq_deliver_single_event(dest, dest_port, 1083e9e02819STakashi Iwai (struct snd_seq_event *)&ev_cvt, 1084e9e02819STakashi Iwai atomic, hop); 1085e9e02819STakashi Iwai if (err < 0) 1086e9e02819STakashi Iwai return err; 1087e9e02819STakashi Iwai } 1088e9e02819STakashi Iwai 1089e9e02819STakashi Iwai return 0; 1090e9e02819STakashi Iwai } 1091e9e02819STakashi Iwai 1092e9e02819STakashi Iwai /* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */ 1093e9e02819STakashi Iwai static int cvt_to_ump_midi2(struct snd_seq_client *dest, 1094e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 1095e9e02819STakashi Iwai struct snd_seq_event *event, 1096e9e02819STakashi Iwai int atomic, int hop) 1097e9e02819STakashi Iwai { 1098e9e02819STakashi Iwai const struct seq_ev_to_ump *encoder; 1099e9e02819STakashi Iwai struct snd_seq_ump_event ev_cvt; 1100e9e02819STakashi Iwai union snd_ump_midi2_msg data[2]; 1101e9e02819STakashi Iwai int i, n, err; 1102e9e02819STakashi Iwai 1103e9e02819STakashi Iwai encoder = find_ump_encoder(event->type); 1104e9e02819STakashi Iwai if (!encoder) 1105e9e02819STakashi Iwai return __snd_seq_deliver_single_event(dest, dest_port, 1106e9e02819STakashi Iwai event, atomic, hop); 1107e9e02819STakashi Iwai 1108e9e02819STakashi Iwai data->raw[0] = make_raw_ump(dest_port, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE); 1109e9e02819STakashi Iwai data->raw[1] = 0; 1110e9e02819STakashi Iwai n = encoder->midi2_encode(event, dest_port, data, encoder->status); 1111e9e02819STakashi Iwai if (!n) 1112e9e02819STakashi Iwai return 0; 1113e9e02819STakashi Iwai 1114e9e02819STakashi Iwai setup_ump_event(&ev_cvt, event); 1115e9e02819STakashi Iwai for (i = 0; i < n; i++) { 1116e9e02819STakashi Iwai memcpy(ev_cvt.ump, &data[i], sizeof(data[i])); 1117e9e02819STakashi Iwai err = __snd_seq_deliver_single_event(dest, dest_port, 1118e9e02819STakashi Iwai (struct snd_seq_event *)&ev_cvt, 1119e9e02819STakashi Iwai atomic, hop); 1120e9e02819STakashi Iwai if (err < 0) 1121e9e02819STakashi Iwai return err; 1122e9e02819STakashi Iwai } 1123e9e02819STakashi Iwai 1124e9e02819STakashi Iwai return 0; 1125e9e02819STakashi Iwai } 1126e9e02819STakashi Iwai 1127e9e02819STakashi Iwai /* Fill up a sysex7 UMP from the byte stream */ 1128e9e02819STakashi Iwai static void fill_sysex7_ump(struct snd_seq_client_port *dest_port, 1129e9e02819STakashi Iwai u32 *val, u8 status, u8 *buf, int len) 1130e9e02819STakashi Iwai { 1131e9e02819STakashi Iwai memset(val, 0, 8); 1132e9e02819STakashi Iwai memcpy((u8 *)val + 2, buf, len); 1133e9e02819STakashi Iwai #ifdef __LITTLE_ENDIAN 1134e9e02819STakashi Iwai swab32_array(val, 2); 1135e9e02819STakashi Iwai #endif 1136e9e02819STakashi Iwai val[0] |= ump_compose(UMP_MSG_TYPE_DATA, get_ump_group(dest_port), 1137e9e02819STakashi Iwai status, len); 1138e9e02819STakashi Iwai } 1139e9e02819STakashi Iwai 1140e9e02819STakashi Iwai /* Convert sysex var event to UMP sysex7 packets and deliver them */ 1141e9e02819STakashi Iwai static int cvt_sysex_to_ump(struct snd_seq_client *dest, 1142e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 1143e9e02819STakashi Iwai struct snd_seq_event *event, 1144e9e02819STakashi Iwai int atomic, int hop) 1145e9e02819STakashi Iwai { 1146e9e02819STakashi Iwai struct snd_seq_ump_event ev_cvt; 1147e9e02819STakashi Iwai unsigned char status; 1148e9e02819STakashi Iwai u8 buf[6], *xbuf; 1149e9e02819STakashi Iwai int offset = 0; 1150e9e02819STakashi Iwai int len, err; 1151e9e02819STakashi Iwai 1152e9e02819STakashi Iwai if (!snd_seq_ev_is_variable(event)) 1153e9e02819STakashi Iwai return 0; 1154e9e02819STakashi Iwai 1155e9e02819STakashi Iwai setup_ump_event(&ev_cvt, event); 1156e9e02819STakashi Iwai for (;;) { 1157e9e02819STakashi Iwai len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); 1158e9e02819STakashi Iwai if (len <= 0) 1159e9e02819STakashi Iwai break; 1160e9e02819STakashi Iwai if (WARN_ON(len > 6)) 1161e9e02819STakashi Iwai break; 1162e9e02819STakashi Iwai offset += len; 1163e9e02819STakashi Iwai xbuf = buf; 1164e9e02819STakashi Iwai if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { 1165e9e02819STakashi Iwai status = UMP_SYSEX_STATUS_START; 1166e9e02819STakashi Iwai xbuf++; 1167e9e02819STakashi Iwai len--; 1168e9e02819STakashi Iwai if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { 1169e9e02819STakashi Iwai status = UMP_SYSEX_STATUS_SINGLE; 1170e9e02819STakashi Iwai len--; 1171e9e02819STakashi Iwai } 1172e9e02819STakashi Iwai } else { 1173e9e02819STakashi Iwai if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { 1174e9e02819STakashi Iwai status = UMP_SYSEX_STATUS_END; 1175e9e02819STakashi Iwai len--; 1176e9e02819STakashi Iwai } else { 1177e9e02819STakashi Iwai status = UMP_SYSEX_STATUS_CONTINUE; 1178e9e02819STakashi Iwai } 1179e9e02819STakashi Iwai } 1180e9e02819STakashi Iwai fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); 1181e9e02819STakashi Iwai err = __snd_seq_deliver_single_event(dest, dest_port, 1182e9e02819STakashi Iwai (struct snd_seq_event *)&ev_cvt, 1183e9e02819STakashi Iwai atomic, hop); 1184e9e02819STakashi Iwai if (err < 0) 1185e9e02819STakashi Iwai return err; 1186e9e02819STakashi Iwai } 1187e9e02819STakashi Iwai return 0; 1188e9e02819STakashi Iwai } 1189e9e02819STakashi Iwai 1190e9e02819STakashi Iwai /* Convert to UMP packet and deliver */ 1191e9e02819STakashi Iwai int snd_seq_deliver_to_ump(struct snd_seq_client *source, 1192e9e02819STakashi Iwai struct snd_seq_client *dest, 1193e9e02819STakashi Iwai struct snd_seq_client_port *dest_port, 1194e9e02819STakashi Iwai struct snd_seq_event *event, 1195e9e02819STakashi Iwai int atomic, int hop) 1196e9e02819STakashi Iwai { 1197e9e02819STakashi Iwai if (event->type == SNDRV_SEQ_EVENT_SYSEX) 1198e9e02819STakashi Iwai return cvt_sysex_to_ump(dest, dest_port, event, atomic, hop); 1199e9e02819STakashi Iwai else if (snd_seq_client_is_midi2(dest)) 1200e9e02819STakashi Iwai return cvt_to_ump_midi2(dest, dest_port, event, atomic, hop); 1201e9e02819STakashi Iwai else 1202e9e02819STakashi Iwai return cvt_to_ump_midi1(dest, dest_port, event, atomic, hop); 1203e9e02819STakashi Iwai } 1204