midi: don't convert Midi in nodes

Avoid doing conversions in the nodes between Midi formats, just assume
the imput is what we expect and output what we naturally produce.

For ALSA this means we produce and consume Midi1 or Midi2 depending on the
configurtation.

All of the other modules (ffado, RTP, netjack and VBAN) really only
produce and consume MIDI1.

Set the default MIDI format to MIDI1 in ALSA.

Whith this change, almost everything now produces and consumes MIDI1
again (previously the buffer format was forced to MIDI2).

The problem is that MIDI2 to and from MIDI1 conversion has problems in
some cases in PipeWire and ALSA and breaks compatibility with some
hardware.

The idea is to let elements produce their prefered format and that the
control mixer also negotiates and converts to the node prefered format.
There is then a mix of MIDI2 and MIDI1 on ports but with the control
port adapting, this should not be a problem.

There is one remaining problem to make this work, the port format is
taken from the node port and not the mixer port, which would then expose
the prefered format on the port and force negotiation to it with the
peer instead of in the mixer.

See #5183
This commit is contained in:
Wim Taymans 2026-03-24 14:02:46 +01:00
parent 67070762d0
commit ea28343166
9 changed files with 177 additions and 293 deletions

View file

@ -1448,8 +1448,9 @@ static size_t convert_from_event(void *midi, void *buffer, size_t size, uint32_t
switch (type) { switch (type) {
case TYPE_ID_MIDI: case TYPE_ID_MIDI:
event_type = SPA_CONTROL_Midi;
break;
case TYPE_ID_OSC: case TYPE_ID_OSC:
/* we handle MIDI as OSC, check below */
event_type = SPA_CONTROL_OSC; event_type = SPA_CONTROL_OSC;
break; break;
case TYPE_ID_UMP: case TYPE_ID_UMP:
@ -1466,27 +1467,15 @@ static size_t convert_from_event(void *midi, void *buffer, size_t size, uint32_t
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
jack_midi_event_t ev; jack_midi_event_t ev;
jack_midi_event_get(&ev, midi, i); jack_midi_event_get(&ev, midi, i);
uint32_t ev_type;
if (type != TYPE_ID_MIDI || is_osc(&ev)) { if (type == TYPE_ID_MIDI && is_osc(&ev))
/* no midi port or it's OSC */ ev_type = SPA_CONTROL_OSC;
spa_pod_builder_control(&b, ev.time, event_type); else
spa_pod_builder_bytes(&b, ev.buffer, ev.size); ev_type = event_type;
} else {
/* midi port and it's not OSC, convert to UMP */
uint8_t *data = ev.buffer;
size_t size = ev.size;
uint64_t state = 0;
while (size > 0) { spa_pod_builder_control(&b, ev.time, ev_type);
uint32_t ump[4]; spa_pod_builder_bytes(&b, ev.buffer, ev.size);
int ump_size = spa_ump_from_midi(&data, &size,
ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
spa_pod_builder_control(&b, ev.time, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
}
} }
spa_pod_builder_pop(&b, &f); spa_pod_builder_pop(&b, &f);
return b.state.offset; return b.state.offset;

View file

@ -501,6 +501,7 @@ impl_node_port_enum_params(void *object, int seq,
struct seq_state *this = object; struct seq_state *this = object;
struct seq_port *port; struct seq_port *port;
struct spa_pod *param; struct spa_pod *param;
struct spa_pod_frame f[1];
struct spa_pod_builder b = { 0 }; struct spa_pod_builder b = { 0 };
uint8_t buffer[1024]; uint8_t buffer[1024];
struct spa_result_node_params result; struct spa_result_node_params result;
@ -524,10 +525,18 @@ impl_node_port_enum_params(void *object, int seq,
case SPA_PARAM_EnumFormat: case SPA_PARAM_EnumFormat:
if (result.index > 0) if (result.index > 0)
return 0; return 0;
param = spa_pod_builder_add_object(&b, spa_pod_builder_push_object(&b, &f[0],
SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(&b,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
0);
if (port->control_types != 0) {
spa_pod_builder_add(&b,
SPA_FORMAT_CONTROL_types, SPA_POD_Int(port->control_types),
0);
}
param = spa_pod_builder_pop(&b, &f[0]);
break; break;
case SPA_PARAM_Format: case SPA_PARAM_Format:
@ -535,10 +544,18 @@ impl_node_port_enum_params(void *object, int seq,
return -EIO; return -EIO;
if (result.index > 0) if (result.index > 0)
return 0; return 0;
param = spa_pod_builder_add_object(&b, spa_pod_builder_push_object(&b, &f[0],
SPA_TYPE_OBJECT_Format, SPA_PARAM_Format, SPA_TYPE_OBJECT_Format, SPA_PARAM_EnumFormat);
spa_pod_builder_add(&b,
SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application), SPA_FORMAT_mediaType, SPA_POD_Id(SPA_MEDIA_TYPE_application),
SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control)); SPA_FORMAT_mediaSubtype, SPA_POD_Id(SPA_MEDIA_SUBTYPE_control),
0);
if (port->control_types != 0) {
spa_pod_builder_add(&b,
SPA_FORMAT_CONTROL_types, SPA_POD_Int(port->control_types),
0);
}
param = spa_pod_builder_pop(&b, &f[0]);
break; break;
case SPA_PARAM_Buffers: case SPA_PARAM_Buffers:
@ -955,7 +972,7 @@ impl_init(const struct spa_handle_factory *factory,
this->quantum_limit = 8192; this->quantum_limit = 8192;
this->min_pool_size = 500; this->min_pool_size = 500;
this->max_pool_size = 2000; this->max_pool_size = 2000;
this->ump = true; this->ump = false;
for (i = 0; info && i < info->n_items; i++) { for (i = 0; info && i < info->n_items; i++) {
const char *k = info->items[i].key; const char *k = info->items[i].key;

View file

@ -620,9 +620,8 @@ static int process_read(struct seq_state *state)
{ {
struct seq_stream *stream = &state->streams[SPA_DIRECTION_OUTPUT]; struct seq_stream *stream = &state->streams[SPA_DIRECTION_OUTPUT];
const bool ump = state->ump; const bool ump = state->ump;
uint32_t *data; void *data;
uint8_t midi1_data[MAX_EVENT_SIZE]; uint8_t midi1_data[MAX_EVENT_SIZE];
uint32_t ump_data[MAX_EVENT_SIZE];
long size; long size;
int res = -1; int res = -1;
struct seq_port *port; struct seq_port *port;
@ -633,9 +632,6 @@ static int process_read(struct seq_state *state)
uint64_t ev_time, diff; uint64_t ev_time, diff;
uint32_t offset; uint32_t offset;
void *event; void *event;
uint8_t *midi1_ptr;
size_t midi1_size = 0;
uint64_t ump_state = 0;
snd_seq_event_type_t SPA_UNUSED type; snd_seq_event_type_t SPA_UNUSED type;
if (ump) { if (ump) {
@ -702,7 +698,7 @@ static int process_read(struct seq_state *state)
#ifdef HAVE_ALSA_UMP #ifdef HAVE_ALSA_UMP
snd_seq_ump_event_t *ev = event; snd_seq_ump_event_t *ev = event;
data = (uint32_t*)&ev->ump[0]; data = &ev->ump[0];
size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump[0])) * 4; size = spa_ump_message_size(snd_ump_msg_hdr_type(ev->ump[0])) * 4;
#else #else
spa_assert_not_reached(); spa_assert_not_reached();
@ -715,34 +711,21 @@ static int process_read(struct seq_state *state)
spa_log_warn(state->log, "decode failed: %s", snd_strerror(size)); spa_log_warn(state->log, "decode failed: %s", snd_strerror(size));
continue; continue;
} }
data = midi1_data;
midi1_ptr = midi1_data;
midi1_size = size;
} }
do { spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d",
if (!ump) { type, ev_time, offset, size, addr->client, addr->port);
data = ump_data;
size = spa_ump_from_midi(&midi1_ptr, &midi1_size,
ump_data, sizeof(ump_data), 0, &ump_state);
if (size <= 0)
break;
}
spa_log_trace_fp(state->log, "event %d time:%"PRIu64" offset:%d size:%ld port:%d.%d", spa_pod_builder_control(&port->builder, offset, ump ? SPA_CONTROL_UMP : SPA_CONTROL_Midi );
type, ev_time, offset, size, addr->client, addr->port); spa_pod_builder_bytes(&port->builder, data, size);
spa_pod_builder_control(&port->builder, offset, SPA_CONTROL_UMP); /* make sure we can fit at least one control event of max size otherwise
spa_pod_builder_bytes(&port->builder, data, size); * we keep the event in the queue and try to copy it in the next cycle */
if (port->builder.state.offset +
/* make sure we can fit at least one control event of max size otherwise sizeof(struct spa_pod_control) +
* we keep the event in the queue and try to copy it in the next cycle */ MAX_EVENT_SIZE > port->buffer->buf->datas[0].maxsize)
if (port->builder.state.offset + goto done;
sizeof(struct spa_pod_control) +
MAX_EVENT_SIZE > port->buffer->buf->datas[0].maxsize)
goto done;
} while (!ump);
} }
done: done:
@ -819,7 +802,6 @@ static int process_write(struct seq_state *state)
const void *c_body; const void *c_body;
uint64_t out_time; uint64_t out_time;
snd_seq_real_time_t out_rt; snd_seq_real_time_t out_rt;
bool first = true;
if (io->status != SPA_STATUS_HAVE_DATA || if (io->status != SPA_STATUS_HAVE_DATA ||
io->buffer_id >= port->n_buffers) io->buffer_id >= port->n_buffers)
@ -844,9 +826,6 @@ static int process_write(struct seq_state *state)
size_t body_size; size_t body_size;
uint8_t *body; uint8_t *body;
if (c.type != SPA_CONTROL_UMP)
continue;
body = (uint8_t*)c_body; body = (uint8_t*)c_body;
body_size = c.value.size; body_size = c.value.size;
@ -861,6 +840,9 @@ static int process_write(struct seq_state *state)
#ifdef HAVE_ALSA_UMP #ifdef HAVE_ALSA_UMP
snd_seq_ump_event_t ev; snd_seq_ump_event_t ev;
if (c.type != SPA_CONTROL_UMP)
continue;
snd_seq_ump_ev_clear(&ev); snd_seq_ump_ev_clear(&ev);
snd_seq_ev_set_ump_data(&ev, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size)); snd_seq_ev_set_ump_data(&ev, body, SPA_MIN(sizeof(ev.ump), (size_t)body_size));
snd_seq_ev_set_source(&ev, state->event.addr.port); snd_seq_ev_set_source(&ev, state->event.addr.port);
@ -878,26 +860,26 @@ static int process_write(struct seq_state *state)
#endif #endif
} else { } else {
snd_seq_event_t ev; snd_seq_event_t ev;
uint8_t data[MAX_EVENT_SIZE]; int size = 0;
int size; long s;
uint64_t st = 0;
if (c.type != SPA_CONTROL_Midi)
continue;
while (body_size > 0) { while (body_size > 0) {
if ((size = spa_ump_to_midi((const uint32_t **)&body, &body_size, if (size == 0)
data, sizeof(data), &st)) <= 0)
break;
if (first)
snd_seq_ev_clear(&ev); snd_seq_ev_clear(&ev);
if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) < 0) { if ((s = snd_midi_event_encode(stream->codec, body, body_size, &ev)) < 0) {
spa_log_warn(state->log, "failed to encode event: %s", spa_log_warn(state->log, "failed to encode event: %s",
snd_strerror(size)); snd_strerror(size));
snd_midi_event_reset_encode(stream->codec); snd_midi_event_reset_encode(stream->codec);
first = true; size = 0;
continue; continue;
} }
first = false; body += s;
body_size -= s;
size += s;
if (ev.type == SND_SEQ_EVENT_NONE) if (ev.type == SND_SEQ_EVENT_NONE)
/* this can happen when the event is not complete yet, like /* this can happen when the event is not complete yet, like
* a sysex message and we need to encode some more data. */ * a sysex message and we need to encode some more data. */
@ -913,7 +895,7 @@ static int process_write(struct seq_state *state)
spa_log_warn(state->log, "failed to output event: %s", spa_log_warn(state->log, "failed to output event: %s",
snd_strerror(err)); snd_strerror(err));
} }
first = true; size = 0;
} }
} }
} }

View file

@ -82,6 +82,8 @@ struct seq_port {
struct spa_pod_builder builder; struct spa_pod_builder builder;
struct spa_pod_frame frame; struct spa_pod_frame frame;
uint32_t control_types;
struct spa_audio_info current_format; struct spa_audio_info current_format;
unsigned int have_format:1; unsigned int have_format:1;
unsigned int active:1; unsigned int active:1;

View file

@ -345,34 +345,26 @@ static void midi_to_ffado(struct port *p, float *src, uint32_t n_samples)
p->event_pos = 0; p->event_pos = 0;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
uint8_t data[16]; uint32_t j, size = c.value.size;
int j, size; const uint8_t *data = c_body;
size_t c_size = c.value.size;
uint64_t state = 0;
if (c.type != SPA_CONTROL_UMP) if (c.type != SPA_CONTROL_Midi)
continue; continue;
if (index < c.offset) if (index < c.offset)
index = SPA_ROUND_UP_N(c.offset, 8); index = SPA_ROUND_UP_N(c.offset, 8);
while (c_size > 0) { for (j = 0; j < size; j++) {
size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state); if (index >= n_samples) {
if (size <= 0) /* keep events that don't fit for the next cycle */
break; if (p->event_pos < sizeof(p->event_buffer))
p->event_buffer[p->event_pos++] = data[j];
for (j = 0; j < size; j++) {
if (index >= n_samples) {
/* keep events that don't fit for the next cycle */
if (p->event_pos < sizeof(p->event_buffer))
p->event_buffer[p->event_pos++] = data[j];
else
unhandled++;
}
else else
dst[index] = 0x01000000 | (uint32_t) data[j]; unhandled++;
index += 8;
} }
else
dst[index] = 0x01000000 | (uint32_t) data[j];
index += 8;
} }
} }
if (unhandled > 0) if (unhandled > 0)
@ -497,16 +489,8 @@ static void ffado_to_midi(struct port *p, float *dst, uint32_t *src, uint32_t si
continue; continue;
if (process_byte(p, i, data & 0xff, &frame, &bytes, &size)) { if (process_byte(p, i, data & 0xff, &frame, &bytes, &size)) {
uint64_t state = 0; spa_pod_builder_control(&b, frame, SPA_CONTROL_Midi);
while (size > 0) { spa_pod_builder_bytes(&b, bytes, size);
uint32_t ev[4];
int ev_size = spa_ump_from_midi(&bytes, &size, ev, sizeof(ev), 0, &state);
if (ev_size <= 0)
break;
spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ev, ev_size);
}
} }
} }
spa_pod_builder_pop(&b, &f); spa_pod_builder_pop(&b, &f);

View file

@ -243,13 +243,16 @@ static inline void do_volume(float *dst, const float *src, struct volume *vol, u
} }
} }
static inline void fix_midi_event(uint8_t *data, size_t size) static inline bool fix_midi_event(const uint8_t *data, size_t size, uint8_t dst[3])
{ {
/* fixup NoteOn with vel 0 */ /* fixup NoteOn with vel 0 */
if (size > 2 && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) { if (size > 2 && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
data[0] = 0x80 + (data[0] & 0x0F); dst[0] = 0x80 + (data[0] & 0x0F);
data[2] = 0x40; dst[1] = data[1];
dst[2] = 0x40;
return true;
} }
return false;
} }
static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_samples) static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_samples)
@ -260,9 +263,6 @@ static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_s
struct spa_pod_control c; struct spa_pod_control c;
const void *seq_body, *c_body; const void *seq_body, *c_body;
int res; int res;
bool in_sysex = false;
uint8_t tmp[n_samples * 4];
size_t tmp_size = 0;
jack.midi_clear_buffer(dst); jack.midi_clear_buffer(dst);
if (src == NULL) if (src == NULL)
@ -274,36 +274,20 @@ static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_s
return; return;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
int size; uint32_t size = c.value.size;
size_t c_size = c.value.size; const uint8_t *data = c_body;
uint64_t state = 0; uint8_t tmp[3];
if (c.type != SPA_CONTROL_UMP) if (c.type != SPA_CONTROL_Midi)
continue; continue;
while (c_size > 0) { if (impl->fix_midi && fix_midi_event(data, size, tmp)) {
size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data = tmp;
&tmp[tmp_size], sizeof(tmp) - tmp_size, &state); size = 3;
if (size <= 0)
break;
if (impl->fix_midi)
fix_midi_event(&tmp[tmp_size], size);
if (!in_sysex && tmp[tmp_size] == 0xf0)
in_sysex = true;
tmp_size += size;
if (in_sysex && tmp[tmp_size-1] == 0xf7)
in_sysex = false;
if (!in_sysex) {
if ((res = jack.midi_event_write(dst, c.offset, tmp, tmp_size)) < 0)
pw_log_warn("midi %p: can't write event: %s", dst,
spa_strerror(res));
tmp_size = 0;
}
} }
if ((res = jack.midi_event_write(dst, c.offset, data, size)) < 0)
pw_log_warn("midi %p: can't write event: %s", dst,
spa_strerror(res));
} }
} }
@ -319,19 +303,11 @@ static void jack_to_midi(float *dst, float *src, uint32_t size)
spa_pod_builder_push_sequence(&b, &f, 0); spa_pod_builder_push_sequence(&b, &f, 0);
for (i = 0; i < count; i++) { for (i = 0; i < count; i++) {
jack_midi_event_t ev; jack_midi_event_t ev;
uint64_t state = 0;
jack.midi_event_get(&ev, src, i); jack.midi_event_get(&ev, src, i);
while (ev.size > 0) { spa_pod_builder_control(&b, ev.time, SPA_CONTROL_Midi);
uint32_t ump[4]; spa_pod_builder_bytes(&b, ev.buffer, ev.size);
int ump_size = spa_ump_from_midi(&ev.buffer, &ev.size, ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
spa_pod_builder_control(&b, ev.time, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
} }
spa_pod_builder_pop(&b, &f); spa_pod_builder_pop(&b, &f);
} }

View file

@ -235,13 +235,16 @@ struct data_info {
bool filled; bool filled;
}; };
static inline void fix_midi_event(uint8_t *data, size_t size) static inline bool fix_midi_event(const uint8_t *data, size_t size, uint8_t tmp[3])
{ {
/* fixup NoteOn with vel 0 */ /* fixup NoteOn with vel 0 */
if (size > 2 && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) { if (size > 2 && (data[0] & 0xF0) == 0x90 && data[2] == 0x00) {
data[0] = 0x80 + (data[0] & 0x0F); tmp[0] = 0x80 + (data[0] & 0x0F);
data[2] = 0x40; tmp[1] = data[1];
tmp[2] = 0x40;
return true;
} }
return false;
} }
static inline void *n2j_midi_buffer_reserve(struct nj2_midi_buffer *buf, static inline void *n2j_midi_buffer_reserve(struct nj2_midi_buffer *buf,
@ -273,7 +276,7 @@ static inline void *n2j_midi_buffer_reserve(struct nj2_midi_buffer *buf,
} }
static inline void n2j_midi_buffer_write(struct nj2_midi_buffer *buf, static inline void n2j_midi_buffer_write(struct nj2_midi_buffer *buf,
uint32_t offset, void *data, uint32_t size) uint32_t offset, const void *data, uint32_t size)
{ {
void *ptr = n2j_midi_buffer_reserve(buf, offset, size); void *ptr = n2j_midi_buffer_reserve(buf, offset, size);
if (ptr != NULL) if (ptr != NULL)
@ -314,7 +317,6 @@ static void midi_to_netjack2(struct netjack2_peer *peer,
struct spa_pod_sequence seq; struct spa_pod_sequence seq;
struct spa_pod_control c; struct spa_pod_control c;
const void *seq_body, *c_body; const void *seq_body, *c_body;
bool in_sysex = false;
buf->magic = MIDI_BUFFER_MAGIC; buf->magic = MIDI_BUFFER_MAGIC;
buf->buffer_size = peer->params.period_size * sizeof(float); buf->buffer_size = peer->params.period_size * sizeof(float);
@ -332,39 +334,22 @@ static void midi_to_netjack2(struct netjack2_peer *peer,
return; return;
while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) {
int size; uint32_t size = c.value.size;
uint8_t data[16]; const uint8_t *data = c_body;
bool was_sysex = in_sysex; uint8_t tmp[3];
size_t c_size = c.value.size;
uint64_t state = 0;
if (c.type != SPA_CONTROL_UMP) if (c.type != SPA_CONTROL_Midi)
continue; continue;
while (c_size > 0) { if (c.offset >= n_samples) {
size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state); buf->lost_events++;
if (size <= 0) continue;
break;
if (c.offset >= n_samples) {
buf->lost_events++;
continue;
}
if (!in_sysex && data[0] == 0xf0)
in_sysex = true;
if (!in_sysex && peer->fix_midi)
fix_midi_event(data, size);
if (in_sysex && data[size-1] == 0xf7)
in_sysex = false;
if (was_sysex)
n2j_midi_buffer_append(buf, data, size);
else
n2j_midi_buffer_write(buf, c.offset, data, size);
} }
if (peer->fix_midi && fix_midi_event(data, size, tmp)) {
data = tmp;
size = 3;
}
n2j_midi_buffer_write(buf, c.offset, data, size);
} }
if (buf->write_pos > 0) if (buf->write_pos > 0)
memmove(SPA_PTROFF(buf, sizeof(*buf) + buf->event_count * sizeof(struct nj2_midi_event), void), memmove(SPA_PTROFF(buf, sizeof(*buf) + buf->event_count * sizeof(struct nj2_midi_event), void),
@ -395,8 +380,6 @@ static inline void netjack2_to_midi(float *dst, uint32_t size, struct nj2_midi_b
for (i = 0; i < buf->event_count; i++) { for (i = 0; i < buf->event_count; i++) {
struct nj2_midi_event *ev = &buf->event[i]; struct nj2_midi_event *ev = &buf->event[i];
uint8_t *data; uint8_t *data;
size_t s;
uint64_t state = 0;
if (ev->size <= MIDI_INLINE_MAX) if (ev->size <= MIDI_INLINE_MAX)
data = ev->buffer; data = ev->buffer;
@ -405,17 +388,8 @@ static inline void netjack2_to_midi(float *dst, uint32_t size, struct nj2_midi_b
else else
continue; continue;
s = ev->size; spa_pod_builder_control(&b, ev->time, SPA_CONTROL_Midi);
while (s > 0) { spa_pod_builder_bytes(&b, data, ev->size);
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&data, &s, ump, sizeof(ump), 0, &state);
if (ump_size <= 0) {
pw_log_warn("invalid MIDI received: %s", spa_strerror(ump_size));
break;
}
spa_pod_builder_control(&b, ev->time, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
} }
spa_pod_builder_pop(&b, &f); spa_pod_builder_pop(&b, &f);
} }

View file

@ -271,9 +271,6 @@ static int rtp_midi_receive_midi(struct impl *impl, uint8_t *packet, uint32_t ti
while (offs < end) { while (offs < end) {
uint32_t delta; uint32_t delta;
int size; int size;
uint64_t state = 0;
uint8_t *d;
size_t s;
if (first && !hdr.z) if (first && !hdr.z)
delta = 0; delta = 0;
@ -294,17 +291,9 @@ static int rtp_midi_receive_midi(struct impl *impl, uint8_t *packet, uint32_t ti
return -EINVAL; return -EINVAL;
} }
d = &packet[offs]; spa_pod_builder_control(&b, timestamp, SPA_CONTROL_Midi);
s = size; spa_pod_builder_bytes(&b, &packet[offs], size);
while (s > 0) {
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&d, &s, ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
spa_pod_builder_control(&b, timestamp, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
offs += size; offs += size;
first = false; first = false;
} }
@ -378,7 +367,7 @@ unexpected_ssrc:
return -EINVAL; return -EINVAL;
} }
static int write_event(uint8_t *p, uint32_t buffer_size, uint32_t value, void *ev, uint32_t size) static int write_event(uint8_t *p, uint32_t buffer_size, uint32_t value, const void *ev, uint32_t size)
{ {
uint64_t buffer; uint64_t buffer;
uint8_t b; uint8_t b;
@ -437,62 +426,54 @@ static void rtp_midi_flush_packets(struct impl *impl,
while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) { while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) {
uint32_t delta, offset; uint32_t delta, offset;
uint8_t event[16]; uint32_t size = c.value.size;
int size; const uint8_t *data = c_body;
size_t c_size = c.value.size;
uint64_t state = 0;
if (c.type != SPA_CONTROL_UMP) if (c.type != SPA_CONTROL_Midi)
continue; continue;
while (c_size > 0) { offset = c.offset * impl->rate / rate;
size = spa_ump_to_midi((const uint32_t **)&c_body, &c_size, event, sizeof(event), &state);
if (size <= 0)
break;
offset = c.offset * impl->rate / rate; if (len > 0 && (len + size > max_size ||
offset - base > impl->psamples)) {
if (len > 0 && (len + size > max_size || /* flush packet when we have one and when it's either
offset - base > impl->psamples)) { * too large or has too much data. */
/* flush packet when we have one and when it's either if (len < 16) {
* too large or has too much data. */ midi_header.b = 0;
if (len < 16) { midi_header.len = len;
midi_header.b = 0; iov[1].iov_len = sizeof(midi_header) - 1;
midi_header.len = len;
iov[1].iov_len = sizeof(midi_header) - 1;
} else {
midi_header.b = 1;
midi_header.len = (len >> 8) & 0xf;
midi_header.len_b = len & 0xff;
iov[1].iov_len = sizeof(midi_header);
}
iov[2].iov_len = len;
pw_log_trace("sending %d timestamp:%d %u %u",
len, timestamp + base,
offset, impl->psamples);
rtp_stream_emit_send_packet(impl, iov, 3);
impl->seq++;
len = 0;
}
if ((unsigned int)size > BUFFER_SIZE || len > BUFFER_SIZE - size) {
pw_log_error("Buffer overflow prevented!");
return; // FIXME: what to do instead?
}
if (len == 0) {
/* start new packet */
base = prev_offset = offset;
header.sequence_number = htons(impl->seq);
header.timestamp = htonl(impl->ts_offset + timestamp + base);
memcpy(&impl->buffer[len], event, size);
len += size;
} else { } else {
delta = offset - prev_offset; midi_header.b = 1;
prev_offset = offset; midi_header.len = (len >> 8) & 0xf;
len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, event, size); midi_header.len_b = len & 0xff;
iov[1].iov_len = sizeof(midi_header);
} }
iov[2].iov_len = len;
pw_log_trace("sending %d timestamp:%d %u %u",
len, timestamp + base,
offset, impl->psamples);
rtp_stream_emit_send_packet(impl, iov, 3);
impl->seq++;
len = 0;
}
if ((unsigned int)size > BUFFER_SIZE || len > BUFFER_SIZE - size) {
pw_log_error("Buffer overflow prevented!");
return; // FIXME: what to do instead?
}
if (len == 0) {
/* start new packet */
base = prev_offset = offset;
header.sequence_number = htons(impl->seq);
header.timestamp = htonl(impl->ts_offset + timestamp + base);
memcpy(&impl->buffer[len], data, size);
len += size;
} else {
delta = offset - prev_offset;
prev_offset = offset;
len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, data, size);
} }
} }
if (len > 0) { if (len > 0) {

View file

@ -163,9 +163,6 @@ static int vban_midi_receive_midi(struct impl *impl, uint8_t *packet,
while (offs < plen) { while (offs < plen) {
int size; int size;
uint8_t *midi_data;
size_t midi_size;
uint64_t midi_state = 0;
size = get_midi_size(&packet[offs], plen - offs); size = get_midi_size(&packet[offs], plen - offs);
if (size <= 0 || offs + size > plen) { if (size <= 0 || offs + size > plen) {
@ -174,18 +171,9 @@ static int vban_midi_receive_midi(struct impl *impl, uint8_t *packet,
break; break;
} }
midi_data = &packet[offs]; spa_pod_builder_control(&b, timestamp, SPA_CONTROL_Midi);
midi_size = size; spa_pod_builder_bytes(&b, &packet[offs], size);
while (midi_size > 0) {
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&midi_data, &midi_size,
ump, sizeof(ump), 0, &midi_state);
if (ump_size <= 0)
break;
spa_pod_builder_control(&b, timestamp, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
}
offs += size; offs += size;
} }
spa_pod_builder_pop(&b, &f[0]); spa_pod_builder_pop(&b, &f[0]);
@ -237,34 +225,25 @@ static void vban_midi_flush_packets(struct impl *impl,
len = 0; len = 0;
while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) { while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) {
int size; uint32_t size = c.value.size;
uint8_t event[16]; const void *data = c_body;
uint64_t state = 0;
size_t c_size = c.value.size;
if (c.type != SPA_CONTROL_UMP) if (c.type != SPA_CONTROL_Midi)
continue; continue;
while (c_size > 0) { if (len == 0) {
size = spa_ump_to_midi((const uint32_t**)&c_body, /* start new packet */
&c_size, event, sizeof(event), &state); header.n_frames++;
if (size <= 0) } else if (len + size > impl->mtu) {
break; /* flush packet when we have one and when it's too large */
iov[1].iov_len = len;
if (len == 0) { pw_log_debug("sending %d", len);
/* start new packet */ vban_stream_emit_send_packet(impl, iov, 2);
header.n_frames++; len = 0;
} else if (len + size > impl->mtu) {
/* flush packet when we have one and when it's too large */
iov[1].iov_len = len;
pw_log_debug("sending %d", len);
vban_stream_emit_send_packet(impl, iov, 2);
len = 0;
}
memcpy(&impl->buffer[len], event, size);
len += size;
} }
memcpy(&impl->buffer[len], data, size);
len += size;
} }
if (len > 0) { if (len > 0) {
/* flush last packet */ /* flush last packet */