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