tools: support filenames in raw mode

The raw mode -a only supported reading raw data from stdin/stdout and
simply ignored the filename. Make it use the filename to determine
where to read from instead.

Support stdin/stdout for sysex mode as well and close the file when we
are done.

Fixes #5012
This commit is contained in:
Wim Taymans 2025-12-04 10:10:54 +01:00
parent b68698a086
commit e30ee9c846

View file

@ -113,7 +113,7 @@ struct data {
#define TYPE_SYSEX 4 #define TYPE_SYSEX 4
#define TYPE_MIDI2 5 #define TYPE_MIDI2 5
int data_type; int data_type;
bool raw; bool rawfile;
const char *remote_name; const char *remote_name;
const char *media_type; const char *media_type;
const char *media_category; const char *media_category;
@ -125,7 +125,6 @@ struct data {
struct pw_properties *props; struct pw_properties *props;
const char *filename; const char *filename;
SNDFILE *file;
unsigned int bitrate; unsigned int bitrate;
unsigned int rate; unsigned int rate;
@ -147,6 +146,9 @@ struct data {
bool drained; bool drained;
uint64_t clock_time; uint64_t clock_time;
struct {
SNDFILE *file;
} sndfile;
struct { struct {
struct midi_file *file; struct midi_file *file;
struct midi_file_info info; struct midi_file_info info;
@ -181,7 +183,12 @@ struct data {
#endif #endif
struct { struct {
FILE *file; FILE *file;
bool close;
} sysex; } sysex;
struct {
FILE *file;
bool close;
} raw;
uint64_t sample_limit; /* 0 means unlimited */ uint64_t sample_limit; /* 0 means unlimited */
uint64_t samples_processed; uint64_t samples_processed;
@ -227,7 +234,7 @@ static int sf_playback_fill_x8(struct data *d, void *dest, unsigned int n_frames
{ {
sf_count_t rn; sf_count_t rn;
rn = sf_read_raw(d->file, dest, n_frames * d->stride); rn = sf_read_raw(d->sndfile.file, dest, n_frames * d->stride);
return (int)rn / d->stride; return (int)rn / d->stride;
} }
@ -236,7 +243,7 @@ static int sf_playback_fill_s16(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn; sf_count_t rn;
assert(sizeof(short) == sizeof(int16_t)); assert(sizeof(short) == sizeof(int16_t));
rn = sf_readf_short(d->file, dest, n_frames); rn = sf_readf_short(d->sndfile.file, dest, n_frames);
return (int)rn; return (int)rn;
} }
@ -245,7 +252,7 @@ static int sf_playback_fill_s32(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn; sf_count_t rn;
assert(sizeof(int) == sizeof(int32_t)); assert(sizeof(int) == sizeof(int32_t));
rn = sf_readf_int(d->file, dest, n_frames); rn = sf_readf_int(d->sndfile.file, dest, n_frames);
return (int)rn; return (int)rn;
} }
@ -254,7 +261,7 @@ static int sf_playback_fill_f32(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn; sf_count_t rn;
assert(sizeof(float) == 4); assert(sizeof(float) == 4);
rn = sf_readf_float(d->file, dest, n_frames); rn = sf_readf_float(d->sndfile.file, dest, n_frames);
return (int)rn; return (int)rn;
} }
@ -263,7 +270,7 @@ static int sf_playback_fill_f64(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn; sf_count_t rn;
assert(sizeof(double) == 8); assert(sizeof(double) == 8);
rn = sf_readf_double(d->file, dest, n_frames); rn = sf_readf_double(d->sndfile.file, dest, n_frames);
return (int)rn; return (int)rn;
} }
@ -550,7 +557,7 @@ static int sf_record_fill_x8(struct data *d, void *src, unsigned int n_frames, b
{ {
sf_count_t rn; sf_count_t rn;
rn = sf_write_raw(d->file, src, n_frames * d->stride); rn = sf_write_raw(d->sndfile.file, src, n_frames * d->stride);
return (int)rn / d->stride; return (int)rn / d->stride;
} }
@ -559,7 +566,7 @@ static int sf_record_fill_s16(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn; sf_count_t rn;
assert(sizeof(short) == sizeof(int16_t)); assert(sizeof(short) == sizeof(int16_t));
rn = sf_writef_short(d->file, src, n_frames); rn = sf_writef_short(d->sndfile.file, src, n_frames);
return (int)rn; return (int)rn;
} }
@ -568,7 +575,7 @@ static int sf_record_fill_s32(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn; sf_count_t rn;
assert(sizeof(int) == sizeof(int32_t)); assert(sizeof(int) == sizeof(int32_t));
rn = sf_writef_int(d->file, src, n_frames); rn = sf_writef_int(d->sndfile.file, src, n_frames);
return (int)rn; return (int)rn;
} }
@ -577,7 +584,7 @@ static int sf_record_fill_f32(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn; sf_count_t rn;
assert(sizeof(float) == 4); assert(sizeof(float) == 4);
rn = sf_writef_float(d->file, src, n_frames); rn = sf_writef_float(d->sndfile.file, src, n_frames);
return (int)rn; return (int)rn;
} }
@ -586,7 +593,7 @@ static int sf_record_fill_f64(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn; sf_count_t rn;
assert(sizeof(double) == 8); assert(sizeof(double) == 8);
rn = sf_writef_double(d->file, src, n_frames); rn = sf_writef_double(d->sndfile.file, src, n_frames);
return (int)rn; return (int)rn;
} }
@ -1480,10 +1487,16 @@ static int setup_sysex(struct data *data)
if (data->mode == mode_record) if (data->mode == mode_record)
return -ENOTSUP; return -ENOTSUP;
data->sysex.file = fopen(data->filename, "r"); if (spa_streq(data->filename, "-")) {
if (data->sysex.file == NULL) { data->sysex.file = stdin;
fprintf(stderr, "sysex: can't read file '%s': %m\n", data->filename); data->sysex.close = false;
return -errno; } else {
data->sysex.file = fopen(data->filename, "r");
if (data->sysex.file == NULL) {
fprintf(stderr, "sysex: can't read file '%s': %m\n", data->filename);
return -errno;
}
data->sysex.close = false;
} }
if (data->verbose) if (data->verbose)
@ -1557,17 +1570,17 @@ static int setup_dsdfile(struct data *data)
return 0; return 0;
} }
static int stdout_record(struct data *d, void *src, unsigned int n_frames, bool *null_frame) static int raw_record(struct data *d, void *src, unsigned int n_frames, bool *null_frame)
{ {
return fwrite(src, d->stride, n_frames, stdout); return fwrite(src, d->stride, n_frames, d->raw.file);
} }
static int stdin_play(struct data *d, void *src, unsigned int n_frames, bool *null_frame) static int raw_play(struct data *d, void *src, unsigned int n_frames, bool *null_frame)
{ {
return fread(src, d->stride, n_frames, stdin); return fread(src, d->stride, n_frames, d->raw.file);
} }
static int setup_pipe(struct data *data) static int setup_raw(struct data *data)
{ {
const struct format_info *info; const struct format_info *info;
@ -1586,10 +1599,23 @@ static int setup_pipe(struct data *data)
data->spa_format = info->spa_format; data->spa_format = info->spa_format;
data->stride = info->width * data->channels; data->stride = info->width * data->channels;
data->fill = data->mode == mode_playback ? stdin_play : stdout_record; data->fill = data->mode == mode_playback ? raw_play : raw_record;
if (spa_streq(data->filename, "-")) {
data->raw.file = data->mode == mode_playback ? stdin : stdout;
data->raw.close = false;
} else {
data->raw.file = fopen(data->filename,
data->mode == mode_playback ? "r" : "w");
if (data->raw.file == NULL) {
fprintf(stderr, "raw: can't open file '%s': %m\n", data->filename);
return -errno;
}
data->raw.close = true;
}
if (data->verbose) if (data->verbose)
fprintf(stderr, "PIPE: rate=%u channels=%u fmt=%s samplesize=%u stride=%u\n", fprintf(stderr, "raw: rate=%u channels=%u fmt=%s samplesize=%u stride=%u\n",
data->rate, data->channels, data->rate, data->channels,
info->name, info->width, data->stride); info->name, info->width, data->stride);
@ -1618,7 +1644,7 @@ static int fill_properties(struct data *data)
if (table[c] == NULL) if (table[c] == NULL)
continue; continue;
if ((s = sf_get_string(data->file, c)) == NULL || if ((s = sf_get_string(data->sndfile.file, c)) == NULL ||
*s == '\0') *s == '\0')
continue; continue;
@ -1627,14 +1653,14 @@ static int fill_properties(struct data *data)
} }
spa_zero(sfi); spa_zero(sfi);
if ((res = sf_command(data->file, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) { if ((res = sf_command(data->sndfile.file, SFC_GET_CURRENT_SF_INFO, &sfi, sizeof(sfi)))) {
pw_log_error("sndfile: %s", sf_error_number(res)); pw_log_error("sndfile: %s", sf_error_number(res));
return -EIO; return -EIO;
} }
spa_zero(fi); spa_zero(fi);
fi.format = sfi.format; fi.format = sfi.format;
if (sf_command(data->file, SFC_GET_FORMAT_INFO, &fi, sizeof(fi)) == 0 && fi.name) if (sf_command(data->sndfile.file, SFC_GET_FORMAT_INFO, &fi, sizeof(fi)) == 0 && fi.name)
if (pw_properties_get(data->props, PW_KEY_MEDIA_FORMAT) == NULL) if (pw_properties_get(data->props, PW_KEY_MEDIA_FORMAT) == NULL)
pw_properties_set(data->props, PW_KEY_MEDIA_FORMAT, fi.name); pw_properties_set(data->props, PW_KEY_MEDIA_FORMAT, fi.name);
@ -1811,10 +1837,10 @@ static int setup_sndfile(struct data *data)
format_from_filename(&info, data->filename); format_from_filename(&info, data->filename);
} }
data->file = sf_open(data->filename, data->sndfile.file = sf_open(data->filename,
data->mode == mode_playback ? SFM_READ : SFM_WRITE, data->mode == mode_playback ? SFM_READ : SFM_WRITE,
&info); &info);
if (!data->file) { if (!data->sndfile.file) {
fprintf(stderr, "sndfile: failed to open audio file \"%s\": %s\n", fprintf(stderr, "sndfile: failed to open audio file \"%s\": %s\n",
data->filename, sf_strerror(NULL)); data->filename, sf_strerror(NULL));
if (data->verbose) { if (data->verbose) {
@ -1853,7 +1879,7 @@ static int setup_sndfile(struct data *data)
if (data->channelmap.n_channels == 0) { if (data->channelmap.n_channels == 0) {
bool def = false; bool def = false;
if (sf_command(data->file, SFC_GET_CHANNEL_MAP_INFO, if (sf_command(data->sndfile.file, SFC_GET_CHANNEL_MAP_INFO,
data->channelmap.position, data->channelmap.position,
sizeof(data->channelmap.position[0]) * data->channels)) { sizeof(data->channelmap.position[0]) * data->channels)) {
data->channelmap.n_channels = data->channels; data->channelmap.n_channels = data->channels;
@ -2097,7 +2123,7 @@ int main(int argc, char *argv[])
break; break;
case 'a': case 'a':
data.raw = true; data.rawfile = true;
break; break;
case 'M': case 'M':
@ -2264,8 +2290,8 @@ int main(int argc, char *argv[])
} }
pw_core_add_listener(data.core, &data.core_listener, &core_events, &data); pw_core_add_listener(data.core, &data.core_listener, &core_events, &data);
if (data.raw) { if (data.rawfile) {
ret = setup_pipe(&data); ret = setup_raw(&data);
} else { } else {
switch (data.data_type) { switch (data.data_type) {
case TYPE_PCM: case TYPE_PCM:
@ -2500,8 +2526,8 @@ error_no_context:
error_no_props: error_no_props:
error_no_main_loop: error_no_main_loop:
pw_properties_free(data.props); pw_properties_free(data.props);
if (data.file) if (data.sndfile.file)
sf_close(data.file); sf_close(data.sndfile.file);
if (data.midi.file) if (data.midi.file)
midi_file_close(data.midi.file); midi_file_close(data.midi.file);
if (data.clip.file) if (data.clip.file)
@ -2510,6 +2536,10 @@ error_no_main_loop:
dsf_file_close(data.dsf.file); dsf_file_close(data.dsf.file);
if (data.dff.file) if (data.dff.file)
dff_file_close(data.dff.file); dff_file_close(data.dff.file);
if (data.sysex.file && data.sysex.close)
fclose(data.sysex.file);
if (data.raw.file && data.raw.close)
fclose(data.raw.file);
#ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION #ifdef HAVE_PW_CAT_FFMPEG_INTEGRATION
if (data.encoded.packet) if (data.encoded.packet)
av_packet_free(&data.encoded.packet); av_packet_free(&data.encoded.packet);