mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-05-22 12:18:12 +02:00
pw-cat: split SysEx over multiple packets
Use the same method as RTP Midi to split long SysEx messages into chunks that we can then put into buffers and reassemble again later.
This commit is contained in:
parent
4e389940e8
commit
87a2ae2f15
2 changed files with 65 additions and 4 deletions
|
|
@ -69,6 +69,33 @@ and consumers must be enabled explicitly. UMP in producers is supported
|
|||
still and will be converted to Midi1 by all consumers that did not explicitly
|
||||
enable UMP support.
|
||||
|
||||
## SysEx
|
||||
|
||||
SysEx messages in Midi1 can be of unlimited length. They start with an
|
||||
F0 byte and end with a F7 byte. Because of the buffer data length limitations,
|
||||
it might be necessary to split a MIDI1 SysEx message accross multiple
|
||||
buffers.
|
||||
|
||||
The stategy to implement this is specified in RFC 6295 (RTP Midi) section
|
||||
3.2. Long SysEx messages can be split up into parts by using the following
|
||||
start/end bytes combinations:
|
||||
|
||||
|-----------------------------------------------------------|
|
||||
| Sublist Position | Head Status Octet | Tail Status Octet |
|
||||
|-----------------------------------------------------------|
|
||||
| first | 0xF0 | 0xF0 |
|
||||
|-----------------------------------------------------------|
|
||||
| middle | 0xF7 | 0xF0 |
|
||||
|-----------------------------------------------------------|
|
||||
| last | 0xF7 | 0xF7 |
|
||||
|-----------------------------------------------------------|
|
||||
| cancel | 0xF7 | 0xF4 |
|
||||
-----------------------------------------------------------
|
||||
|
||||
Nodes that require a complete SysEx message must be able to assemble the
|
||||
complete message from the parts before processing the message.
|
||||
|
||||
|
||||
## The PipeWire Daemon
|
||||
|
||||
Nothing special is implemented for MIDI. Negotiation of formats
|
||||
|
|
|
|||
|
|
@ -185,6 +185,7 @@ struct data {
|
|||
struct {
|
||||
FILE *file;
|
||||
bool close;
|
||||
bool first;
|
||||
} sysex;
|
||||
struct {
|
||||
FILE *file;
|
||||
|
|
@ -1552,16 +1553,48 @@ static int sysex_play(struct data *d, void *dst, unsigned int n_frames, bool *nu
|
|||
struct spa_pod_builder b;
|
||||
struct spa_pod_frame f;
|
||||
size_t size, to_read = n_frames - 64;
|
||||
uint8_t bytes[to_read];
|
||||
uint8_t data[to_read+2], *bytes;
|
||||
|
||||
bytes = &data[1];
|
||||
size = fread(bytes, 1, to_read, d->sysex.file);
|
||||
|
||||
if (size != to_read) {
|
||||
if (ferror(d->sysex.file))
|
||||
return -EIO;
|
||||
}
|
||||
if (feof(d->sysex.file)) {
|
||||
if (size == 0)
|
||||
return 0;
|
||||
if (bytes[size-1] != 0xf7) {
|
||||
bytes[size] = 0xf7;
|
||||
size += 1;
|
||||
}
|
||||
} else {
|
||||
if (bytes[size-1] != 0xf0) {
|
||||
bytes[size] = 0xf0;
|
||||
size += 1;
|
||||
}
|
||||
}
|
||||
if (d->sysex.first) {
|
||||
if (bytes[0] != 0xf0) {
|
||||
bytes = &data[0];
|
||||
bytes[0] = 0xf0;
|
||||
size += 1;
|
||||
}
|
||||
d->sysex.first = false;
|
||||
} else {
|
||||
if (bytes[0] != 0xf7) {
|
||||
bytes = &data[0];
|
||||
bytes[0] = 0xf7;
|
||||
size += 1;
|
||||
}
|
||||
}
|
||||
|
||||
spa_zero(b);
|
||||
spa_pod_builder_init(&b, dst, n_frames);
|
||||
|
||||
spa_pod_builder_push_sequence(&b, &f, 0);
|
||||
spa_pod_builder_control(&b, 0, SPA_CONTROL_Midi);
|
||||
|
||||
size = fread(bytes, 1, to_read, d->sysex.file);
|
||||
|
||||
spa_pod_builder_bytes(&b, bytes, size);
|
||||
spa_pod_builder_pop(&b, &f);
|
||||
|
||||
|
|
@ -1590,6 +1623,7 @@ static int setup_sysex(struct data *data)
|
|||
|
||||
data->fill = sysex_play;
|
||||
data->stride = 1;
|
||||
data->sysex.first = true;
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
|
|||
Loading…
Add table
Reference in a new issue