1 // SPDX-License-Identifier: GPL-2.0-or-later
3 * ALSA sequencer event conversion between UMP and legacy clients
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"
15 * Upgrade / downgrade value bits
17 static u8
downscale_32_to_7bit(u32 src
)
22 static u16
downscale_32_to_14bit(u32 src
)
27 static u8
downscale_16_to_7bit(u16 src
)
32 static u16
upscale_7_to_16bit(u8 src
)
40 return val
| (repeat
<< 3) | (repeat
>> 3);
43 static u32
upscale_7_to_32bit(u8 src
)
51 return val
| (repeat
<< 19) | (repeat
<< 13) |
52 (repeat
<< 7) | (repeat
<< 1) | (repeat
>> 5);
55 static u32
upscale_14_to_32bit(u16 src
)
62 repeat
= src
& 0x1fff;
63 return val
| (repeat
<< 5) | (repeat
>> 8);
66 static unsigned char get_ump_group(struct snd_seq_client_port
*port
)
68 return port
->ump_group
? (port
->ump_group
- 1) : 0;
71 /* create a UMP header */
72 #define make_raw_ump(port, type) \
73 ump_compose(type, get_ump_group(port), 0, 0)
76 * UMP -> MIDI1 sequencer event
81 /* encode note event */
82 static void ump_midi1_to_note_ev(const union snd_ump_midi1_msg
*val
,
83 struct snd_seq_event
*ev
)
85 ev
->data
.note
.channel
= val
->note
.channel
;
86 ev
->data
.note
.note
= val
->note
.note
;
87 ev
->data
.note
.velocity
= val
->note
.velocity
;
90 /* encode one parameter controls */
91 static void ump_midi1_to_ctrl_ev(const union snd_ump_midi1_msg
*val
,
92 struct snd_seq_event
*ev
)
94 ev
->data
.control
.channel
= val
->caf
.channel
;
95 ev
->data
.control
.value
= val
->caf
.data
;
98 /* encode pitch wheel change */
99 static void ump_midi1_to_pitchbend_ev(const union snd_ump_midi1_msg
*val
,
100 struct snd_seq_event
*ev
)
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;
107 /* encode midi control change */
108 static void ump_midi1_to_cc_ev(const union snd_ump_midi1_msg
*val
,
109 struct snd_seq_event
*ev
)
111 ev
->data
.control
.channel
= val
->cc
.channel
;
112 ev
->data
.control
.param
= val
->cc
.index
;
113 ev
->data
.control
.value
= val
->cc
.data
;
116 /* Encoding MIDI 1.0 UMP packet */
117 struct seq_ump_midi1_to_ev
{
119 void (*encode
)(const union snd_ump_midi1_msg
*val
, struct snd_seq_event
*ev
);
122 /* Encoders for MIDI1 status 0x80-0xe0 */
123 static 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 */
133 static int cvt_ump_midi1_to_event(const union snd_ump_midi1_msg
*val
,
134 struct snd_seq_event
*ev
)
136 unsigned char status
= val
->note
.status
;
138 if (status
< 0x8 || status
> 0xe)
139 return 0; /* invalid - skip */
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
);
147 /* MIDI System message */
149 /* encode one parameter value*/
150 static void ump_system_to_one_param_ev(const union snd_ump_midi1_msg
*val
,
151 struct snd_seq_event
*ev
)
153 ev
->data
.control
.value
= val
->system
.parm1
;
156 /* encode song position */
157 static void ump_system_to_songpos_ev(const union snd_ump_midi1_msg
*val
,
158 struct snd_seq_event
*ev
)
160 ev
->data
.control
.value
= (val
->system
.parm1
<< 7) | val
->system
.parm2
;
163 /* Encoders for 0xf0 - 0xff */
164 static 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 */
183 static int cvt_ump_system_to_event(const union snd_ump_midi1_msg
*val
,
184 struct snd_seq_event
*ev
)
186 unsigned char status
= val
->system
.status
;
188 if ((status
& 0xf0) != UMP_MIDI1_MSG_REALTIME
)
189 return 0; /* invalid status - skip */
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
)
195 if (system_msg_encoders
[status
].encode
)
196 system_msg_encoders
[status
].encode(val
, ev
);
202 /* encode note event */
203 static int ump_midi2_to_note_ev(const union snd_ump_midi2_msg
*val
,
204 struct snd_seq_event
*ev
)
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
212 if (ev
->type
== SNDRV_SEQ_EVENT_NOTEON
&&
213 !ev
->data
.note
.velocity
)
214 ev
->data
.note
.velocity
= 1;
218 /* encode pitch wheel change */
219 static int ump_midi2_to_pitchbend_ev(const union snd_ump_midi2_msg
*val
,
220 struct snd_seq_event
*ev
)
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;
228 /* encode midi control change */
229 static int ump_midi2_to_cc_ev(const union snd_ump_midi2_msg
*val
,
230 struct snd_seq_event
*ev
)
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
);
238 /* encode midi program change */
239 static int ump_midi2_to_pgm_ev(const union snd_ump_midi2_msg
*val
,
240 struct snd_seq_event
*ev
)
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
;
251 ev
->type
= SNDRV_SEQ_EVENT_PGMCHANGE
;
254 ev
->data
.control
.value
= val
->pg
.program
;
258 /* encode one parameter controls */
259 static int ump_midi2_to_ctrl_ev(const union snd_ump_midi2_msg
*val
,
260 struct snd_seq_event
*ev
)
262 ev
->data
.control
.channel
= val
->caf
.channel
;
263 ev
->data
.control
.value
= downscale_32_to_7bit(val
->caf
.data
);
267 /* encode RPN/NRPN */
268 static int ump_midi2_to_rpn_ev(const union snd_ump_midi2_msg
*val
,
269 struct snd_seq_event
*ev
)
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
);
277 /* Encoding MIDI 2.0 UMP Packet */
278 struct seq_ump_midi2_to_ev
{
280 int (*encode
)(const union snd_ump_midi2_msg
*val
, struct snd_seq_event
*ev
);
283 /* Encoders for MIDI2 status 0x00-0xf0 */
284 static 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 */
303 static int cvt_ump_midi2_to_event(const union snd_ump_midi2_msg
*val
,
304 struct snd_seq_event
*ev
)
306 unsigned char status
= val
->note
.status
;
308 ev
->type
= midi2_msg_encoders
[status
].seq_type
;
309 if (ev
->type
== SNDRV_SEQ_EVENT_NONE
)
311 ev
->flags
= SNDRV_SEQ_EVENT_LENGTH_FIXED
;
312 return midi2_msg_encoders
[status
].encode(val
, ev
);
315 /* parse and compose for a sysex var-length event */
316 static int cvt_ump_sysex7_to_event(const u32
*data
, unsigned char *buf
,
317 struct snd_seq_event
*ev
)
319 unsigned char status
;
325 status
= ump_sysex_message_status(val
);
326 bytes
= ump_sysex_message_length(val
);
330 if (status
== UMP_SYSEX_STATUS_SINGLE
||
331 status
== UMP_SYSEX_STATUS_START
) {
332 buf
[0] = UMP_MIDI1_MSG_SYSEX_START
;
337 buf
[size
++] = (val
>> 8) & 0x7f;
339 buf
[size
++] = val
& 0x7f;
342 buf
[size
++] = (val
>> 24) & 0x7f;
344 buf
[size
++] = (val
>> 16) & 0x7f;
346 buf
[size
++] = (val
>> 8) & 0x7f;
348 buf
[size
++] = val
& 0x7f;
350 if (status
== UMP_SYSEX_STATUS_SINGLE
||
351 status
== UMP_SYSEX_STATUS_END
)
352 buf
[size
++] = UMP_MIDI1_MSG_SYSEX_END
;
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
;
361 /* convert UMP packet from MIDI 1.0 to MIDI 2.0 and deliver it */
362 static 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
,
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
;
373 memset(&ev_cvt
.ump
, 0, sizeof(ev_cvt
.ump
));
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
);
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
);
389 case UMP_MSG_STATUS_CC
:
390 midi2
->cc
.index
= midi1
->cc
.index
;
391 midi2
->cc
.data
= upscale_7_to_32bit(midi1
->cc
.data
);
393 case UMP_MSG_STATUS_PROGRAM
:
394 midi2
->pg
.program
= midi1
->pg
.program
;
396 case UMP_MSG_STATUS_CHANNEL_PRESSURE
:
397 midi2
->caf
.data
= upscale_7_to_32bit(midi1
->caf
.data
);
399 case UMP_MSG_STATUS_PITCH_BEND
:
400 midi2
->pb
.data
= upscale_14_to_32bit((midi1
->pb
.data_msb
<< 7) |
407 return __snd_seq_deliver_single_event(dest
, dest_port
,
408 (struct snd_seq_event
*)&ev_cvt
,
412 /* convert UMP packet from MIDI 2.0 to MIDI 1.0 and deliver it */
413 static 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
,
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
;
425 memset(&ev_cvt
.ump
, 0, sizeof(ev_cvt
.ump
));
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
<< 4) {
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
);
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
);
441 case UMP_MSG_STATUS_CC
:
442 midi1
->cc
.index
= midi2
->cc
.index
;
443 midi1
->cc
.data
= downscale_32_to_7bit(midi2
->cc
.data
);
445 case UMP_MSG_STATUS_PROGRAM
:
446 midi1
->pg
.program
= midi2
->pg
.program
;
448 case UMP_MSG_STATUS_CHANNEL_PRESSURE
:
449 midi1
->caf
.data
= downscale_32_to_7bit(midi2
->caf
.data
);
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;
460 return __snd_seq_deliver_single_event(dest
, dest_port
,
461 (struct snd_seq_event
*)&ev_cvt
,
465 /* convert UMP to a legacy ALSA seq event and deliver it */
466 static int cvt_ump_to_any(struct snd_seq_client
*dest
,
467 struct snd_seq_client_port
*dest_port
,
468 struct snd_seq_event
*event
,
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
;
479 ev_cvt
[0] = ev_cvt
[1] = *event
;
480 ev_cvt
[0].flags
= flags
;
481 ev_cvt
[1].flags
= flags
;
483 case UMP_MSG_TYPE_SYSTEM
:
484 len
= cvt_ump_system_to_event((union snd_ump_midi1_msg
*)ump_ev
->ump
,
487 case UMP_MSG_TYPE_MIDI1_CHANNEL_VOICE
:
488 len
= cvt_ump_midi1_to_event((union snd_ump_midi1_msg
*)ump_ev
->ump
,
491 case UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE
:
492 len
= cvt_ump_midi2_to_event((union snd_ump_midi2_msg
*)ump_ev
->ump
,
495 case UMP_MSG_TYPE_DATA
:
496 len
= cvt_ump_sysex7_to_event(ump_ev
->ump
, sysex_buf
, ev_cvt
);
502 for (i
= 0; i
< len
; i
++) {
503 err
= __snd_seq_deliver_single_event(dest
, dest_port
,
504 &ev_cvt
[i
], atomic
, hop
);
512 /* Replace UMP group field with the destination and deliver */
513 static 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
,
518 struct snd_seq_ump_event ev
= *ump_ev
;
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);
525 return __snd_seq_deliver_single_event(dest
, dest_port
,
526 (struct snd_seq_event
*)&ev
,
530 /* apply the UMP event filter; return true to skip the event */
531 static bool ump_event_filtered(struct snd_seq_client
*dest
,
532 const struct snd_seq_ump_event
*ev
)
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));
543 /* Convert from UMP packet and deliver */
544 int 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
,
550 struct snd_seq_ump_event
*ump_ev
= (struct snd_seq_ump_event
*)event
;
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]);
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
,
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
,
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
);
575 return __snd_seq_deliver_single_event(dest
, dest_port
,
579 return cvt_ump_to_any(dest
, dest_port
, event
, type
, atomic
, hop
);
583 * MIDI1 sequencer event -> UMP conversion
586 /* Conversion to UMP MIDI 1.0 */
588 /* convert note on/off event to MIDI 1.0 UMP */
589 static 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
)
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;
603 /* convert CC event to MIDI 1.0 UMP */
604 static 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
)
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
;
616 /* convert one-parameter control event to MIDI 1.0 UMP */
617 static 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
)
622 data
->caf
.status
= status
;
623 data
->caf
.channel
= event
->data
.control
.channel
& 0x0f;
624 data
->caf
.data
= event
->data
.control
.value
& 0x7f;
628 /* convert pitchbend event to MIDI 1.0 UMP */
629 static 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
)
634 int val
= event
->data
.control
.value
+ 8192;
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;
644 /* convert 14bit control event to MIDI 1.0 UMP; split to two events */
645 static 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
)
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;
656 data
[1].cc
.index
= event
->data
.control
.param
| 0x20;
657 data
[1].cc
.data
= event
->data
.control
.value
& 0x7f;
661 data
->cc
.data
= event
->data
.control
.value
& 0x7f;
665 /* convert RPN/NRPN event to MIDI 1.0 UMP; split to four events */
666 static 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
)
671 bool is_rpn
= (status
== UMP_MSG_STATUS_RPN
);
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];
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;
688 /* convert system / RT message to UMP */
689 static 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
)
694 data
->system
.status
= status
;
698 /* convert system / RT message with 1 parameter to UMP */
699 static 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
)
704 data
->system
.status
= status
;
705 data
->system
.parm1
= event
->data
.control
.value
& 0x7f;
709 /* convert system / RT message with two parameters to UMP */
710 static 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
)
715 data
->system
.status
= status
;
716 data
->system
.parm1
= (event
->data
.control
.value
>> 7) & 0x7f;
717 data
->system
.parm2
= event
->data
.control
.value
& 0x7f;
721 /* Conversion to UMP MIDI 2.0 */
723 /* convert note on/off event to MIDI 2.0 UMP */
724 static 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
)
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);
738 /* convert PAF event to MIDI 2.0 UMP */
739 static 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
)
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);
751 /* set up the MIDI2 RPN/NRPN packet data from the parsed info */
752 static void fill_rpn(struct snd_seq_ump_midi2_bank
*cc
,
753 union snd_ump_midi2_msg
*data
)
756 data
->rpn
.status
= UMP_MSG_STATUS_RPN
;
757 data
->rpn
.bank
= cc
->cc_rpn_msb
;
758 data
->rpn
.index
= cc
->cc_rpn_lsb
;
760 cc
->cc_rpn_msb
= cc
->cc_rpn_lsb
= 0;
762 data
->rpn
.status
= UMP_MSG_STATUS_NRPN
;
763 data
->rpn
.bank
= cc
->cc_nrpn_msb
;
764 data
->rpn
.index
= cc
->cc_nrpn_lsb
;
766 cc
->cc_nrpn_msb
= cc
->cc_nrpn_lsb
= 0;
768 data
->rpn
.data
= upscale_14_to_32bit((cc
->cc_data_msb
<< 7) |
770 cc
->cc_data_msb
= cc
->cc_data_lsb
= 0;
773 /* convert CC event to MIDI 2.0 UMP */
774 static 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
)
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
];
784 /* process special CC's (bank/rpn/nrpn) */
788 cc
->cc_rpn_msb
= val
;
792 cc
->cc_rpn_lsb
= val
;
794 case UMP_CC_NRPN_MSB
:
796 cc
->cc_nrpn_msb
= val
;
798 case UMP_CC_NRPN_LSB
:
800 cc
->cc_nrpn_lsb
= val
;
803 cc
->cc_data_msb
= val
;
805 case UMP_CC_BANK_SELECT
:
807 cc
->cc_bank_msb
= val
;
809 case UMP_CC_BANK_SELECT_LSB
:
811 cc
->cc_bank_lsb
= val
;
813 case UMP_CC_DATA_LSB
:
814 cc
->cc_data_lsb
= val
;
815 if (!(cc
->rpn_set
|| cc
->nrpn_set
))
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);
828 /* convert one-parameter control event to MIDI 2.0 UMP */
829 static 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
)
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);
840 /* convert program change event to MIDI 2.0 UMP */
841 static 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
)
846 unsigned char channel
= event
->data
.control
.channel
& 0x0f;
847 struct snd_seq_ump_midi2_bank
*cc
= &dest_port
->midi2_bank
[channel
];
849 data
->pg
.status
= status
;
850 data
->pg
.channel
= channel
;
851 data
->pg
.program
= event
->data
.control
.value
& 0x7f;
853 data
->pg
.bank_valid
= 1;
854 data
->pg
.bank_msb
= cc
->cc_bank_msb
;
855 data
->pg
.bank_lsb
= cc
->cc_bank_lsb
;
857 cc
->cc_bank_msb
= cc
->cc_bank_lsb
= 0;
862 /* convert pitchbend event to MIDI 2.0 UMP */
863 static 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
)
868 int val
= event
->data
.control
.value
+ 8192;
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
);
877 /* convert 14bit control event to MIDI 2.0 UMP; split to two events */
878 static 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
)
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
;
888 msb
= (event
->data
.control
.value
>> 7) & 0x7f;
889 lsb
= event
->data
.control
.value
& 0x7f;
890 /* process special CC's (bank/rpn/nrpn) */
892 case UMP_CC_BANK_SELECT
:
893 cc
->cc_bank_msb
= msb
;
895 case UMP_CC_BANK_SELECT_LSB
:
897 cc
->cc_bank_lsb
= lsb
;
900 cc
->cc_rpn_msb
= msb
;
904 cc
->cc_rpn_lsb
= lsb
;
906 case UMP_CC_NRPN_MSB
:
907 cc
->cc_nrpn_msb
= msb
;
909 case UMP_CC_NRPN_LSB
:
911 cc
->cc_nrpn_lsb
= lsb
;
914 cc
->cc_data_msb
= msb
;
916 case UMP_CC_DATA_LSB
:
917 cc
->cc_data_lsb
= lsb
;
918 if (!(cc
->rpn_set
|| cc
->nrpn_set
))
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
);
930 data
[1].cc
.index
= event
->data
.control
.param
| 0x20;
931 data
[1].cc
.data
= upscale_7_to_32bit(lsb
);
935 data
->cc
.data
= upscale_7_to_32bit(lsb
);
939 /* convert RPN/NRPN event to MIDI 2.0 UMP */
940 static 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
)
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);
953 /* convert system / RT message to UMP */
954 static 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
)
959 return system_ev_to_ump_midi1(event
, dest_port
,
960 (union snd_ump_midi1_msg
*)data
,
964 /* convert system / RT message with 1 parameter to UMP */
965 static 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
)
970 return system_1p_ev_to_ump_midi1(event
, dest_port
,
971 (union snd_ump_midi1_msg
*)data
,
975 /* convert system / RT message with two parameters to UMP */
976 static 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
)
981 return system_1p_ev_to_ump_midi1(event
, dest_port
,
982 (union snd_ump_midi1_msg
*)data
,
986 struct seq_ev_to_ump
{
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
);
999 static 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
},
1040 static const struct seq_ev_to_ump
*find_ump_encoder(int type
)
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
];
1051 static void setup_ump_event(struct snd_seq_ump_event
*dest
,
1052 const struct snd_seq_event
*src
)
1054 memcpy(dest
, src
, sizeof(*src
));
1056 dest
->flags
|= SNDRV_SEQ_EVENT_UMP
;
1057 dest
->flags
&= ~SNDRV_SEQ_EVENT_LENGTH_MASK
;
1058 memset(dest
->ump
, 0, sizeof(dest
->ump
));
1061 /* Convert ALSA seq event to UMP MIDI 1.0 and deliver it */
1062 static 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
)
1067 const struct seq_ev_to_ump
*encoder
;
1068 struct snd_seq_ump_event ev_cvt
;
1069 union snd_ump_midi1_msg data
[4];
1072 encoder
= find_ump_encoder(event
->type
);
1074 return __snd_seq_deliver_single_event(dest
, dest_port
,
1075 event
, atomic
, hop
);
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
);
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
,
1095 /* Convert ALSA seq event to UMP MIDI 2.0 and deliver it */
1096 static 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
)
1101 const struct seq_ev_to_ump
*encoder
;
1102 struct snd_seq_ump_event ev_cvt
;
1103 union snd_ump_midi2_msg data
[2];
1106 encoder
= find_ump_encoder(event
->type
);
1108 return __snd_seq_deliver_single_event(dest
, dest_port
,
1109 event
, atomic
, hop
);
1111 data
->raw
[0] = make_raw_ump(dest_port
, UMP_MSG_TYPE_MIDI2_CHANNEL_VOICE
);
1113 n
= encoder
->midi2_encode(event
, dest_port
, data
, encoder
->status
);
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
,
1130 /* Fill up a sysex7 UMP from the byte stream */
1131 static void fill_sysex7_ump(struct snd_seq_client_port
*dest_port
,
1132 u32
*val
, u8 status
, u8
*buf
, int len
)
1135 memcpy((u8
*)val
+ 2, buf
, len
);
1136 #ifdef __LITTLE_ENDIAN
1137 swab32_array(val
, 2);
1139 val
[0] |= ump_compose(UMP_MSG_TYPE_DATA
, get_ump_group(dest_port
),
1143 /* Convert sysex var event to UMP sysex7 packets and deliver them */
1144 static 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
)
1149 struct snd_seq_ump_event ev_cvt
;
1150 unsigned char status
;
1155 if (!snd_seq_ev_is_variable(event
))
1158 setup_ump_event(&ev_cvt
, event
);
1160 len
= snd_seq_expand_var_event_at(event
, sizeof(buf
), buf
, offset
);
1163 if (WARN_ON(len
> 6))
1167 if (*xbuf
== UMP_MIDI1_MSG_SYSEX_START
) {
1168 status
= UMP_SYSEX_STATUS_START
;
1171 if (len
> 0 && xbuf
[len
- 1] == UMP_MIDI1_MSG_SYSEX_END
) {
1172 status
= UMP_SYSEX_STATUS_SINGLE
;
1176 if (xbuf
[len
- 1] == UMP_MIDI1_MSG_SYSEX_END
) {
1177 status
= UMP_SYSEX_STATUS_END
;
1180 status
= UMP_SYSEX_STATUS_CONTINUE
;
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
,
1193 /* Convert to UMP packet and deliver */
1194 int 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
)
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
);
1207 return cvt_to_ump_midi1(dest
, dest_port
, event
, atomic
, hop
);