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