tools: add -M option to pw-cat and friends

It forces conversion to or from UMP. By default, the events will be
converted to UMP before injecting them into the graph.
This commit is contained in:
Wim Taymans 2025-08-19 17:47:29 +02:00
parent e35a8554f8
commit 00bb29de0f

View file

@ -142,6 +142,10 @@ struct data {
struct { struct {
struct midi_file *file; struct midi_file *file;
struct midi_file_info info; struct midi_file_info info;
#define MIDI_FORCE_NONE 0
#define MIDI_FORCE_UMP 1
#define MIDI_FORCE_MIDI1 2
int force_type;
} midi; } midi;
struct { struct {
struct dsf_file *file; struct dsf_file *file;
@ -1030,6 +1034,7 @@ static const struct option long_options[] = {
{ "volume", required_argument, NULL, OPT_VOLUME }, { "volume", required_argument, NULL, OPT_VOLUME },
{ "quality", required_argument, NULL, 'q' }, { "quality", required_argument, NULL, 'q' },
{ "raw", no_argument, NULL, 'a' }, { "raw", no_argument, NULL, 'a' },
{ "force-midi", required_argument, NULL, 'M' },
{ NULL, 0, NULL, 0 } { NULL, 0, NULL, 0 }
}; };
@ -1075,6 +1080,7 @@ static void show_usage(const char *name, bool is_error)
" --volume Stream volume 0-1.0 (default %.3f)\n" " --volume Stream volume 0-1.0 (default %.3f)\n"
" -q --quality Resampler quality (0 - 15) (default %d)\n" " -q --quality Resampler quality (0 - 15) (default %d)\n"
" -a, --raw RAW mode\n" " -a, --raw RAW mode\n"
" -M, --force-midi Force midi format, one of \"midi\" or \"ump\", (default ump)\n"
"\n"), "\n"),
DEFAULT_RATE, DEFAULT_RATE,
DEFAULT_CHANNELS, DEFAULT_CHANNELS,
@ -1116,6 +1122,8 @@ static int midi_play(struct data *d, void *src, unsigned int n_frames, bool *nul
while (1) { while (1) {
uint32_t frame; uint32_t frame;
struct midi_event ev; struct midi_event ev;
uint64_t state = 0;
size_t size;
res = midi_file_next_time(d->midi.file, &ev.sec); res = midi_file_next_time(d->midi.file, &ev.sec);
if (res <= 0) { if (res <= 0) {
@ -1137,30 +1145,46 @@ static int midi_play(struct data *d, void *src, unsigned int n_frames, bool *nul
if (d->verbose) if (d->verbose)
midi_file_dump_event(stderr, &ev); midi_file_dump_event(stderr, &ev);
if (ev.type == MIDI_EVENT_TYPE_MIDI1) { size = ev.size;
size_t size;
uint8_t *data;
uint64_t state = 0;
if (ev.data[0] == 0xff) if (ev.type == MIDI_EVENT_TYPE_MIDI1) {
if (size < 1 || ev.data[0] == 0xff)
continue; continue;
data = ev.data; if (d->midi.force_type == MIDI_FORCE_UMP) {
size = ev.size; uint8_t *data = ev.data;
while (size > 0) {
uint32_t ump[4];
int ump_size = spa_ump_from_midi(&data, &size,
ump, sizeof(ump), 0, &state);
if (ump_size <= 0)
break;
while (size > 0) { spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP);
uint32_t ump[4]; spa_pod_builder_bytes(&b, ump, ump_size);
int ump_size = spa_ump_from_midi(&data, &size, }
ump, sizeof(ump), 0, &state); } else {
if (ump_size <= 0) spa_pod_builder_control(&b, frame, SPA_CONTROL_Midi);
break; spa_pod_builder_bytes(&b, ev.data, ev.size);
spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ump, ump_size);
} }
} else if (ev.type == MIDI_EVENT_TYPE_UMP) { } else if (ev.type == MIDI_EVENT_TYPE_UMP) {
spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP); if (d->midi.force_type == MIDI_FORCE_MIDI1) {
spa_pod_builder_bytes(&b, ev.data, ev.size); const uint32_t *data = (const uint32_t*)ev.data;
while (size > 0) {
uint8_t ev[16];
int ev_size = spa_ump_to_midi(&data, &size,
ev, sizeof(ev), &state);
if (ev_size <= 0)
break;
spa_pod_builder_control(&b, frame, SPA_CONTROL_Midi);
spa_pod_builder_bytes(&b, ev, ev_size);
}
} else {
spa_pod_builder_control(&b, frame, SPA_CONTROL_UMP);
spa_pod_builder_bytes(&b, ev.data, ev.size);
}
} }
else else
continue; continue;
@ -1811,6 +1835,7 @@ int main(int argc, char *argv[])
/* negative means no volume adjustment */ /* negative means no volume adjustment */
data.volume = -1.0; data.volume = -1.0;
data.quality = -1; data.quality = -1;
data.midi.force_type = MIDI_FORCE_UMP;
data.props = pw_properties_new( data.props = pw_properties_new(
PW_KEY_APP_NAME, prog, PW_KEY_APP_NAME, prog,
PW_KEY_NODE_NAME, prog, PW_KEY_NODE_NAME, prog,
@ -1822,9 +1847,9 @@ int main(int argc, char *argv[])
} }
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION #ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
while ((c = getopt_long(argc, argv, "hvprmdosR:q:P:a", long_options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "hvprmdosR:q:P:aM:", long_options, NULL)) != -1) {
#else #else
while ((c = getopt_long(argc, argv, "hvprmdsR:q:P:a", long_options, NULL)) != -1) { while ((c = getopt_long(argc, argv, "hvprmdsR:q:P:aM:", long_options, NULL)) != -1) {
#endif #endif
switch (c) { switch (c) {
@ -1883,6 +1908,17 @@ int main(int argc, char *argv[])
data.raw = true; data.raw = true;
break; break;
case 'M':
if (spa_streq(optarg, "midi"))
data.midi.force_type = MIDI_FORCE_MIDI1;
else if (spa_streq(optarg, "ump"))
data.midi.force_type = MIDI_FORCE_UMP;
else {
fprintf(stderr, "error: bad force-midi %s\n", optarg);
goto error_usage;
}
break;
case OPT_MEDIA_TYPE: case OPT_MEDIA_TYPE:
data.media_type = optarg; data.media_type = optarg;
break; break;