diff --git a/pipewire-jack/src/pipewire-jack.c b/pipewire-jack/src/pipewire-jack.c index d513d6403..c8b4a149d 100644 --- a/pipewire-jack/src/pipewire-jack.c +++ b/pipewire-jack/src/pipewire-jack.c @@ -1610,7 +1610,6 @@ static inline int midi_event_write(void *port_buffer, static void convert_to_event(struct mix_info **mix, uint32_t n_mix, void *midi, bool fix, uint32_t type) { - uint64_t state = 0; uint32_t i; int res = 0; bool in_sysex = false; @@ -1621,6 +1620,7 @@ static void convert_to_event(struct mix_info **mix, uint32_t n_mix, void *midi, struct spa_pod_control *control; size_t size; uint8_t *data; + uint64_t state = 0; for (i = 0; i < n_mix; i++) { struct mix_info *m = mix[i]; @@ -1664,34 +1664,36 @@ static void convert_to_event(struct mix_info **mix, uint32_t n_mix, void *midi, } case SPA_CONTROL_UMP: { - uint8_t ev[32]; - bool was_sysex = in_sysex; - if (type == TYPE_ID_MIDI) { - uint32_t *d = (uint32_t*)data; - int ev_size = spa_ump_to_midi(d, size, ev, sizeof(ev)); - if (ev_size <= 0) - break; + uint8_t ev[32]; + const uint32_t *d = (uint32_t*)data; - size = ev_size; - data = ev; + while (size > 0) { + bool was_sysex = in_sysex; + int ev_size = spa_ump_to_midi(&d, &size, ev, sizeof(ev), &state); + if (ev_size <= 0) + break; - if (!in_sysex && ev[0] == 0xf0) - in_sysex = true; - if (in_sysex && ev[ev_size-1] == 0xf7) - in_sysex = false; + if (!in_sysex && ev[0] == 0xf0) + in_sysex = true; + if (in_sysex && ev[ev_size-1] == 0xf7) + in_sysex = false; - } else if (type != TYPE_ID_UMP) - break; + if (was_sysex) + res = midi_event_append(midi, ev, ev_size); + else + res = midi_event_write(midi, control->offset, ev, ev_size, fix); + if (res < 0) + break; - if (was_sysex) - res = midi_event_append(midi, data, size); - else + } + } else if (type == TYPE_ID_UMP) { res = midi_event_write(midi, control->offset, data, size, fix); - + } if (res < 0) pw_log_warn("midi %p: can't write event: %s", midi, spa_strerror(res)); + break; } } if (spa_pod_parser_get_control_body(&next->parser, diff --git a/spa/include/spa/control/ump-utils.h b/spa/include/spa/control/ump-utils.h index 4525cef76..52738897f 100644 --- a/spa/include/spa/control/ump-utils.h +++ b/spa/include/spa/control/ump-utils.h @@ -48,72 +48,98 @@ SPA_API_CONTROL_UMP_UTILS size_t spa_ump_message_size(uint8_t message_type) return ump_sizes[message_type & 0xf]; } -SPA_API_CONTROL_UMP_UTILS int spa_ump_to_midi(const uint32_t *ump, size_t ump_size, - uint8_t *midi, size_t midi_maxsize) +SPA_API_CONTROL_UMP_UTILS int spa_ump_to_midi(const uint32_t **ump, size_t *ump_size, + uint8_t *midi, size_t midi_maxsize, uint64_t *state) { int size = 0; + uint32_t to_consume = 0; + const uint32_t *u = *ump; - if (ump_size < 4) - return 0; + if (*ump_size < 4 || + (to_consume = (spa_ump_message_size(u[0]>>28) * 4)) > *ump_size) { + to_consume = *ump_size; + goto done; + } if (midi_maxsize < 8) return -ENOSPC; - switch (ump[0] >> 28) { + switch (u[0] >> 28) { case 0x1: /* System Real Time and System Common Messages (except System Exclusive) */ - midi[size++] = (ump[0] >> 16) & 0xff; + midi[size++] = (u[0] >> 16) & 0xff; if (midi[0] >= 0xf1 && midi[0] <= 0xf3) { - midi[size++] = (ump[0] >> 8) & 0x7f; + midi[size++] = (u[0] >> 8) & 0x7f; if (midi[0] == 0xf2) - midi[size++] = ump[0] & 0x7f; + midi[size++] = u[0] & 0x7f; } break; case 0x2: /* MIDI 1.0 Channel Voice Messages */ - midi[size++] = (ump[0] >> 16); - midi[size++] = (ump[0] >> 8); + midi[size++] = (u[0] >> 16); + midi[size++] = (u[0] >> 8); if (midi[0] < 0xc0 || midi[0] > 0xdf) - midi[size++] = (ump[0]); + midi[size++] = (u[0]); break; case 0x3: /* Data Messages (including System Exclusive) */ { uint8_t status, i, bytes; - if (ump_size < 8) - return 0; - - status = (ump[0] >> 20) & 0xf; - bytes = SPA_CLAMP((ump[0] >> 16) & 0xf, 0u, 6u); + status = (u[0] >> 20) & 0xf; + bytes = SPA_CLAMP((u[0] >> 16) & 0xf, 0u, 6u); if (status == 0 || status == 1) midi[size++] = 0xf0; for (i = 0 ; i < bytes; i++) - /* ump[0] >> 8 | ump[0] | ump[1] >> 24 | ump[1] >>16 ... */ - midi[size++] = ump[(i+2)/4] >> ((5-i)%4 * 8); + /* u[0] >> 8 | u[0] | u[1] >> 24 | u[1] >>16 ... */ + midi[size++] = u[(i+2)/4] >> ((5-i)%4 * 8); if (status == 0 || status == 3) midi[size++] = 0xf7; break; } case 0x4: /* MIDI 2.0 Channel Voice Messages */ - if (ump_size < 8) - return 0; - midi[size++] = (ump[0] >> 16) | 0x80; - switch (midi[0] & 0xf0) { + { + uint8_t status = (u[0] >> 16) | 0x80; + switch (status & 0xf0) { case 0xc0: - midi[size++] = (ump[1] >> 24); + /* program/bank change */ + if (!(u[0] & 1)) + *state = 2; + if (*state == 0) { + midi[size++] = (status & 0xf) | 0xb0; + midi[size++] = 0; + midi[size++] = (u[1] >> 8); + to_consume = 0; + *state = 1; + } + else if (*state == 1) { + midi[size++] = (status & 0xf) | 0xb0; + midi[size++] = 32; + midi[size++] = u[1]; + to_consume = 0; + *state = 2; + } + else if (*state == 2) { + midi[size++] = status; + midi[size++] = (u[1] >> 24); + *state = 0; + } break; default: - midi[size++] = (ump[0] >> 8) & 0x7f; + midi[size++] = status; + midi[size++] = (u[0] >> 8) & 0x7f; SPA_FALLTHROUGH; case 0xd0: - midi[size++] = (ump[1] >> 25); + midi[size++] = (u[1] >> 25); break; } break; - + } case 0x0: /* Utility Messages */ case 0x5: /* Data Messages */ default: - return 0; + break; } +done: + (*ump_size) -= to_consume; + (*ump) = SPA_PTROFF(*ump, to_consume, uint32_t); return size; } diff --git a/spa/plugins/alsa/alsa-seq.c b/spa/plugins/alsa/alsa-seq.c index efd1d3f24..8a4ba369c 100644 --- a/spa/plugins/alsa/alsa-seq.c +++ b/spa/plugins/alsa/alsa-seq.c @@ -880,34 +880,41 @@ static int process_write(struct seq_state *state) snd_seq_event_t ev; uint8_t data[MAX_EVENT_SIZE]; int size; + uint64_t st = 0; - if ((size = spa_ump_to_midi((uint32_t *)body, body_size, data, sizeof(data))) <= 0) - continue; + while (body_size > 0) { + if ((size = spa_ump_to_midi((const uint32_t **)&body, &body_size, + data, sizeof(data), &st)) <= 0) + break; - if (first) - snd_seq_ev_clear(&ev); + if (first) + snd_seq_ev_clear(&ev); - if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) < 0) { - spa_log_warn(state->log, "failed to encode event: %s", snd_strerror(size)); - snd_midi_event_reset_encode(stream->codec); + if ((size = snd_midi_event_encode(stream->codec, data, size, &ev)) < 0) { + spa_log_warn(state->log, "failed to encode event: %s", + snd_strerror(size)); + snd_midi_event_reset_encode(stream->codec); + first = true; + continue; + } + first = false; + if (ev.type == SND_SEQ_EVENT_NONE) + /* this can happen when the event is not complete yet, like + * a sysex message and we need to encode some more data. */ + continue; + + snd_seq_ev_set_source(&ev, state->event.addr.port); + snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); + snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); + + debug_event(state, "send", &ev); + + if ((err = snd_seq_event_output(state->event.hndl, &ev)) < 0) { + spa_log_warn(state->log, "failed to output event: %s", + snd_strerror(err)); + } first = true; - continue; } - first = false; - if (ev.type == SND_SEQ_EVENT_NONE) - /* this can happen when the event is not complete yet, like - * a sysex message and we need to encode some more data. */ - continue; - - snd_seq_ev_set_source(&ev, state->event.addr.port); - snd_seq_ev_set_dest(&ev, port->addr.client, port->addr.port); - snd_seq_ev_schedule_real(&ev, state->event.queue_id, 0, &out_rt); - - if ((err = snd_seq_event_output(state->event.hndl, &ev)) < 0) { - spa_log_warn(state->log, "failed to output event: %s", - snd_strerror(err)); - } - first = true; } } } diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 5c411efcf..adb4b92bb 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -1824,18 +1824,20 @@ static int apply_props(struct impl *this, const struct spa_pod *param) static int apply_midi(struct impl *this, const struct spa_pod *value) { struct props *p = &this->props; - uint8_t data[8]; - int size; + uint8_t ev[8]; + int ev_size; + const uint32_t *body = SPA_POD_BODY_CONST(value); + size_t size = SPA_POD_BODY_SIZE(value); + uint64_t state = 0; - size = spa_ump_to_midi(SPA_POD_BODY(value), SPA_POD_BODY_SIZE(value), - data, sizeof(data)); - if (size < 3) + ev_size = spa_ump_to_midi(&body, &size, ev, sizeof(ev), &state); + if (ev_size < 3) return -EINVAL; - if ((data[0] & 0xf0) != 0xb0 || data[1] != 7) + if ((ev[0] & 0xf0) != 0xb0 || ev[1] != 7) return 0; - p->volume = data[2] / 127.0f; + p->volume = ev[2] / 127.0f; set_volume(this); return 1; } diff --git a/spa/plugins/bluez5/midi-node.c b/spa/plugins/bluez5/midi-node.c index b2acb40f4..7146d6f8a 100644 --- a/spa/plugins/bluez5/midi-node.c +++ b/spa/plugins/bluez5/midi-node.c @@ -788,30 +788,35 @@ static int write_data(struct impl *this, struct spa_data *d) while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { int size; uint8_t event[32]; + const uint32_t *ump = c_body; + size_t ump_size = c.value.size; + uint64_t state = 0; if (c.type != SPA_CONTROL_UMP) continue; time = SPA_MAX(time, this->current_time + c.offset * SPA_NSEC_PER_SEC / this->rate); - size = spa_ump_to_midi(c_body, c.value.size, event, sizeof(event)); - if (size <= 0) - continue; + while (ump_size > 0) { + size = spa_ump_to_midi(&ump, &ump_size, event, sizeof(event), &state); + if (size <= 0) + break; - spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this, - (size > 0) ? event[0] : 0, time); + spa_log_trace(this->log, "%p: output event:0x%x time:%"PRIu64, this, + (size > 0) ? event[0] : 0, time); - do { - res = spa_bt_midi_writer_write(&this->writer, - time, event, size); - if (res < 0) { - return res; - } else if (res) { - int res2; - if ((res2 = flush_packet(this)) < 0) - return res2; - } - } while (res); + do { + res = spa_bt_midi_writer_write(&this->writer, + time, event, size); + if (res < 0) { + return res; + } else if (res) { + int res2; + if ((res2 = flush_packet(this)) < 0) + return res2; + } + } while (res); + } } if ((res = flush_packet(this)) < 0) diff --git a/spa/plugins/control/mixer.c b/spa/plugins/control/mixer.c index ccf0df54a..d71a1e16d 100644 --- a/spa/plugins/control/mixer.c +++ b/spa/plugins/control/mixer.c @@ -826,11 +826,15 @@ static int impl_node_process(void *object) case SPA_CONTROL_UMP: { uint8_t ev[8]; - int ev_size = spa_ump_to_midi((uint32_t*)body, size, ev, sizeof(ev)); - if (ev_size <= 0) - break; - spa_pod_builder_control(&builder, control->offset, SPA_CONTROL_Midi); - spa_pod_builder_bytes(&builder, ev, ev_size); + const uint32_t *ump = (const uint32_t*)body; + uint64_t state = 0; + while (size > 0) { + int ev_size = spa_ump_to_midi(&ump, &size, ev, sizeof(ev), &state); + if (ev_size <= 0) + break; + spa_pod_builder_control(&builder, control->offset, SPA_CONTROL_Midi); + spa_pod_builder_bytes(&builder, ev, ev_size); + } break; } } diff --git a/src/modules/module-ffado-driver.c b/src/modules/module-ffado-driver.c index 0cd2a75ff..8c94edcdd 100644 --- a/src/modules/module-ffado-driver.c +++ b/src/modules/module-ffado-driver.c @@ -345,27 +345,32 @@ static void midi_to_ffado(struct port *p, float *src, uint32_t n_samples) while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { uint8_t data[16]; int j, size; + size_t c_size = c.value.size; + uint64_t state = 0; if (c.type != SPA_CONTROL_UMP) continue; - size = spa_ump_to_midi(c_body, c.value.size, data, sizeof(data)); - if (size <= 0) - continue; - if (index < c.offset) index = SPA_ROUND_UP_N(c.offset, 8); - 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]; + + while (c_size > 0) { + size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state); + if (size <= 0) + break; + + 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 - unhandled++; + dst[index] = 0x01000000 | (uint32_t) data[j]; + index += 8; } - else - dst[index] = 0x01000000 | (uint32_t) data[j]; - index += 8; } } if (unhandled > 0) diff --git a/src/modules/module-jack-tunnel.c b/src/modules/module-jack-tunnel.c index e64535938..226caf6fe 100644 --- a/src/modules/module-jack-tunnel.c +++ b/src/modules/module-jack-tunnel.c @@ -273,29 +273,34 @@ static void midi_to_jack(struct impl *impl, float *dst, float *src, uint32_t n_s while (spa_pod_parser_get_control_body(&parser, &c, &c_body) >= 0) { int size; + size_t c_size = c.value.size; + uint64_t state = 0; if (c.type != SPA_CONTROL_UMP) continue; - size = spa_ump_to_midi(c_body, c.value.size, &tmp[tmp_size], sizeof(tmp) - tmp_size); - if (size <= 0) - continue; + while (c_size > 0) { + size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, + &tmp[tmp_size], sizeof(tmp) - tmp_size, &state); + if (size <= 0) + break; - if (impl->fix_midi) - fix_midi_event(&tmp[tmp_size], size); + if (impl->fix_midi) + fix_midi_event(&tmp[tmp_size], size); - if (!in_sysex && tmp[tmp_size] == 0xf0) - in_sysex = true; + if (!in_sysex && tmp[tmp_size] == 0xf0) + in_sysex = true; - tmp_size += size; - if (in_sysex && tmp[tmp_size-1] == 0xf7) - in_sysex = false; + 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 (!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; + } } } } diff --git a/src/modules/module-netjack2/peer.c b/src/modules/module-netjack2/peer.c index d2251e705..37f7854db 100644 --- a/src/modules/module-netjack2/peer.c +++ b/src/modules/module-netjack2/peer.c @@ -333,32 +333,36 @@ static void midi_to_netjack2(struct netjack2_peer *peer, int size; uint8_t data[16]; bool was_sysex = in_sysex; + size_t c_size = c.value.size; + uint64_t state = 0; if (c.type != SPA_CONTROL_UMP) continue; - size = spa_ump_to_midi(c_body, c.value.size, data, sizeof(data)); - if (size <= 0) - continue; + while (c_size > 0) { + size = spa_ump_to_midi((const uint32_t**)&c_body, &c_size, data, sizeof(data), &state); + if (size <= 0) + break; - if (c.offset >= n_samples) { - buf->lost_events++; - continue; + 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 (!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 (buf->write_pos > 0) memmove(SPA_PTROFF(buf, sizeof(*buf) + buf->event_count * sizeof(struct nj2_midi_event), void), diff --git a/src/modules/module-rtp/midi.c b/src/modules/module-rtp/midi.c index 77e348233..498c6e6a9 100644 --- a/src/modules/module-rtp/midi.c +++ b/src/modules/module-rtp/midi.c @@ -437,57 +437,61 @@ static void rtp_midi_flush_packets(struct impl *impl, while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) { uint32_t delta, offset; uint8_t event[16]; - size_t size; + int size; + size_t c_size = c.value.size; + uint64_t state = 0; if (c.type != SPA_CONTROL_UMP) continue; - size = spa_ump_to_midi(c_body, c.value.size, event, sizeof(event)); - if (size <= 0) - continue; + while (c_size > 0) { + 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; + offset = c.offset * impl->rate / rate; - if (len > 0 && (len + size > max_size || - offset - base > impl->psamples)) { - /* flush packet when we have one and when it's either - * too large or has too much data. */ - if (len < 16) { - midi_header.b = 0; - 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); + if (len > 0 && (len + size > max_size || + offset - base > impl->psamples)) { + /* flush packet when we have one and when it's either + * too large or has too much data. */ + if (len < 16) { + midi_header.b = 0; + 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; } - iov[2].iov_len = len; + 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); - 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 (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 { - delta = offset - prev_offset; - prev_offset = offset; - len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, event, size); + memcpy(&impl->buffer[len], event, size); + len += size; + } else { + delta = offset - prev_offset; + prev_offset = offset; + len += write_event(&impl->buffer[len], BUFFER_SIZE - len, delta, event, size); + } } } if (len > 0) { diff --git a/src/modules/module-vban/midi.c b/src/modules/module-vban/midi.c index 4fbd39532..f460bd274 100644 --- a/src/modules/module-vban/midi.c +++ b/src/modules/module-vban/midi.c @@ -239,27 +239,32 @@ static void vban_midi_flush_packets(struct impl *impl, while (spa_pod_parser_get_control_body(parser, &c, &c_body) >= 0) { int size; uint8_t event[16]; + uint64_t state = 0; + size_t c_size = c.value.size; if (c.type != SPA_CONTROL_UMP) continue; - size = spa_ump_to_midi(c_body, c.value.size, event, sizeof(event)); - if (size <= 0) - continue; + while (c_size > 0) { + size = spa_ump_to_midi((const uint32_t**)&c_body, + &c_size, event, sizeof(event), &state); + if (size <= 0) + break; - if (len == 0) { - /* start new packet */ - header.n_frames++; - } else if (len + size > impl->mtu) { - /* flush packet when we have one and when it's too large */ - iov[1].iov_len = len; + if (len == 0) { + /* start new packet */ + header.n_frames++; + } 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; + 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], event, size); - len += size; } if (len > 0) { /* flush last packet */ diff --git a/src/tools/midifile.c b/src/tools/midifile.c index d7503da92..0aee51638 100644 --- a/src/tools/midifile.c +++ b/src/tools/midifile.c @@ -496,41 +496,46 @@ int midi_file_write_event(struct midi_file *mf, const struct midi_event *event) { struct midi_track *tr; uint32_t tick; - void *data; + void *data, *ev_data; size_t size; - int res; + int res, ev_size; uint8_t ev[32]; + uint64_t state = 0; spa_return_val_if_fail(event != NULL, -EINVAL); spa_return_val_if_fail(mf != NULL, -EINVAL); spa_return_val_if_fail(event->track == 0, -EINVAL); spa_return_val_if_fail(event->size > 1, -EINVAL); - switch (event->type) { - case MIDI_EVENT_TYPE_MIDI1: - data = event->data; - size = event->size; - break; - case MIDI_EVENT_TYPE_UMP: - data = ev; - size = spa_ump_to_midi((uint32_t*)event->data, event->size, ev, sizeof(ev)); - if (size == 0) - return 0; - break; - default: - return -EINVAL; - } + data = event->data; + size = event->size; tr = &mf->tracks[event->track]; - tick = (uint32_t)(event->sec * (1000000.0 * mf->info.division) / (double)mf->tempo); - CHECK_RES(write_varlen(mf, tr, tick - tr->tick)); - tr->tick = tick; + while (size > 0) { + switch (event->type) { + case MIDI_EVENT_TYPE_MIDI1: + ev_data = data; + ev_size = size; + size = 0; + break; + case MIDI_EVENT_TYPE_UMP: + ev_size = spa_ump_to_midi((const uint32_t**)&data, &size, ev, sizeof(ev), &state); + if (ev_size <= 0) + return ev_size; + ev_data = ev; + break; + default: + return -EINVAL; + } - CHECK_RES(write_n(mf->file, data, size)); - tr->size += size; + CHECK_RES(write_varlen(mf, tr, tick - tr->tick)); + tr->tick = tick; + CHECK_RES(write_n(mf->file, ev_data, ev_size)); + tr->size += ev_size; + } return 0; } diff --git a/test/test-spa-control.c b/test/test-spa-control.c index d493b2934..97589efd7 100644 --- a/test/test-spa-control.c +++ b/test/test-spa-control.c @@ -123,6 +123,7 @@ static int do_ump_to_midi_test(char *ump, char *midi) size_t m_size, u_size, m_offs = 0; uint8_t *m_data = alloca(strlen(midi) / 2); uint32_t *u_data = alloca(strlen(ump) / 2); + uint64_t state = 0; u_size = parse_ump(ump, u_data, sizeof(u_data)); m_size = parse_midi(midi, m_data, sizeof(m_data)); @@ -133,8 +134,9 @@ static int do_ump_to_midi_test(char *ump, char *midi) while (u_size > 0) { uint8_t midi[32]; fprintf(stdout, "%zd %08x\n", u_size, *u_data); - int midi_size = spa_ump_to_midi(u_data, u_size, - midi, sizeof(midi)); + + int midi_size = spa_ump_to_midi((const uint32_t**)&u_data, &u_size, + midi, sizeof(midi), &state); if (midi_size <= 0) return midi_size; @@ -145,8 +147,6 @@ static int do_ump_to_midi_test(char *ump, char *midi) fprintf(stdout, "%08x %08x\n", m_data[m_offs], midi[i]); spa_assert(m_data[m_offs++] == midi[i]); } - u_size -= spa_ump_message_size(*u_data >> 28) * 4; - u_data += spa_ump_message_size(*u_data >> 28); } return 0; } @@ -160,6 +160,11 @@ PWTEST(control_ump_to_midi) spa_assert(do_ump_to_midi_test("30160102 03040506 30260708 09101112 30311300 00000000", "f0 01 02 03 04 05 06 07 08 09 10 11 12 13 f7") >= 0); + + spa_assert(do_ump_to_midi_test("40cf0000 11000000", "cf 11") >= 0); + + spa_assert(do_ump_to_midi_test("40cf0001 11002233", "bf 00 22 bf 20 33 cf 11") >= 0); + return PWTEST_PASS; }