Commit 952b13c2 authored by Takashi Iwai's avatar Takashi Iwai

ALSA: seq: ump: Optimize conversions from SysEx to UMP

The current conversion from the legacy SysEx event to UMP SysEx packet
in the sequencer core has a couple of issues:

* The first packet trims the SysEx start byte (0xf0), hence it
  contains only 5 bytes instead of 6.  This isn't wrong, per
  specification, but it's strange not to fill 6 bytes.

* When the SysEx end marker (0xf7) is placed at the first byte of the
  next packet, it'll end up with an empty data just with the END
  status.  It can be rather folded into the previous packet with the
  END status.

This patch tries to address those issues.  The first packet may have 6
bytes even with the SysEx start, and an empty packet with the SysEx
end marker is omitted.

Fixes: e9e02819 ("ALSA: seq: Automatic conversion of UMP events")
Cc: <stable@vger.kernel.org>
Link: https://patch.msgid.link/20240726143455.3254-1-tiwai@suse.deSigned-off-by: default avatarTakashi Iwai <tiwai@suse.de>
parent 4f61c8fe
...@@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest, ...@@ -1192,44 +1192,53 @@ static int cvt_sysex_to_ump(struct snd_seq_client *dest,
{ {
struct snd_seq_ump_event ev_cvt; struct snd_seq_ump_event ev_cvt;
unsigned char status; unsigned char status;
u8 buf[6], *xbuf; u8 buf[8], *xbuf;
int offset = 0; int offset = 0;
int len, err; int len, err;
bool finished = false;
if (!snd_seq_ev_is_variable(event)) if (!snd_seq_ev_is_variable(event))
return 0; return 0;
setup_ump_event(&ev_cvt, event); setup_ump_event(&ev_cvt, event);
for (;;) { while (!finished) {
len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset); len = snd_seq_expand_var_event_at(event, sizeof(buf), buf, offset);
if (len <= 0) if (len <= 0)
break; break;
if (WARN_ON(len > 6)) if (WARN_ON(len > sizeof(buf)))
break; break;
offset += len;
xbuf = buf; xbuf = buf;
status = UMP_SYSEX_STATUS_CONTINUE;
/* truncate the sysex start-marker */
if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) { if (*xbuf == UMP_MIDI1_MSG_SYSEX_START) {
status = UMP_SYSEX_STATUS_START; status = UMP_SYSEX_STATUS_START;
xbuf++;
len--;
if (len > 0 && xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
status = UMP_SYSEX_STATUS_SINGLE;
len--; len--;
offset++;
xbuf++;
} }
} else {
if (xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) { /* if the last of this packet or the 1st byte of the next packet
* is the end-marker, finish the transfer with this packet
*/
if (len > 0 && len < 8 &&
xbuf[len - 1] == UMP_MIDI1_MSG_SYSEX_END) {
if (status == UMP_SYSEX_STATUS_START)
status = UMP_SYSEX_STATUS_SINGLE;
else
status = UMP_SYSEX_STATUS_END; status = UMP_SYSEX_STATUS_END;
len--; len--;
} else { finished = true;
status = UMP_SYSEX_STATUS_CONTINUE;
}
} }
len = min(len, 6);
fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len); fill_sysex7_ump(dest_port, ev_cvt.ump, status, xbuf, len);
err = __snd_seq_deliver_single_event(dest, dest_port, err = __snd_seq_deliver_single_event(dest, dest_port,
(struct snd_seq_event *)&ev_cvt, (struct snd_seq_event *)&ev_cvt,
atomic, hop); atomic, hop);
if (err < 0) if (err < 0)
return err; return err;
offset += len;
} }
return 0; return 0;
} }
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment