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_MIDI2 5
int data_type;
bool raw;
bool rawfile;
const char *remote_name;
const char *media_type;
const char *media_category;
@ -125,7 +125,6 @@ struct data {
struct pw_properties *props;
const char *filename;
SNDFILE *file;
unsigned int bitrate;
unsigned int rate;
@ -147,6 +146,9 @@ struct data {
bool drained;
uint64_t clock_time;
struct {
SNDFILE *file;
} sndfile;
struct {
struct midi_file *file;
struct midi_file_info info;
@ -181,7 +183,12 @@ struct data {
#endif
struct {
FILE *file;
bool close;
} sysex;
struct {
FILE *file;
bool close;
} raw;
uint64_t sample_limit; /* 0 means unlimited */
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;
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;
}
@ -236,7 +243,7 @@ static int sf_playback_fill_s16(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn;
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;
}
@ -245,7 +252,7 @@ static int sf_playback_fill_s32(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn;
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;
}
@ -254,7 +261,7 @@ static int sf_playback_fill_f32(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn;
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;
}
@ -263,7 +270,7 @@ static int sf_playback_fill_f64(struct data *d, void *dest, unsigned int n_frame
sf_count_t rn;
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;
}
@ -550,7 +557,7 @@ static int sf_record_fill_x8(struct data *d, void *src, unsigned int n_frames, b
{
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;
}
@ -559,7 +566,7 @@ static int sf_record_fill_s16(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn;
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;
}
@ -568,7 +575,7 @@ static int sf_record_fill_s32(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn;
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;
}
@ -577,7 +584,7 @@ static int sf_record_fill_f32(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn;
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;
}
@ -586,7 +593,7 @@ static int sf_record_fill_f64(struct data *d, void *src, unsigned int n_frames,
sf_count_t rn;
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;
}
@ -1480,10 +1487,16 @@ static int setup_sysex(struct data *data)
if (data->mode == mode_record)
return -ENOTSUP;
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;
if (spa_streq(data->filename, "-")) {
data->sysex.file = stdin;
data->sysex.close = false;
} 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)
@ -1557,17 +1570,17 @@ static int setup_dsdfile(struct data *data)
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;
@ -1586,10 +1599,23 @@ static int setup_pipe(struct data *data)
data->spa_format = info->spa_format;
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)
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,
info->name, info->width, data->stride);
@ -1618,7 +1644,7 @@ static int fill_properties(struct data *data)
if (table[c] == NULL)
continue;
if ((s = sf_get_string(data->file, c)) == NULL ||
if ((s = sf_get_string(data->sndfile.file, c)) == NULL ||
*s == '\0')
continue;
@ -1627,14 +1653,14 @@ static int fill_properties(struct data *data)
}
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));
return -EIO;
}
spa_zero(fi);
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)
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);
}
data->file = sf_open(data->filename,
data->sndfile.file = sf_open(data->filename,
data->mode == mode_playback ? SFM_READ : SFM_WRITE,
&info);
if (!data->file) {
if (!data->sndfile.file) {
fprintf(stderr, "sndfile: failed to open audio file \"%s\": %s\n",
data->filename, sf_strerror(NULL));
if (data->verbose) {
@ -1853,7 +1879,7 @@ static int setup_sndfile(struct data *data)
if (data->channelmap.n_channels == 0) {
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,
sizeof(data->channelmap.position[0]) * data->channels)) {
data->channelmap.n_channels = data->channels;
@ -2097,7 +2123,7 @@ int main(int argc, char *argv[])
break;
case 'a':
data.raw = true;
data.rawfile = true;
break;
case 'M':
@ -2264,8 +2290,8 @@ int main(int argc, char *argv[])
}
pw_core_add_listener(data.core, &data.core_listener, &core_events, &data);
if (data.raw) {
ret = setup_pipe(&data);
if (data.rawfile) {
ret = setup_raw(&data);
} else {
switch (data.data_type) {
case TYPE_PCM:
@ -2500,8 +2526,8 @@ error_no_context:
error_no_props:
error_no_main_loop:
pw_properties_free(data.props);
if (data.file)
sf_close(data.file);
if (data.sndfile.file)
sf_close(data.sndfile.file);
if (data.midi.file)
midi_file_close(data.midi.file);
if (data.clip.file)
@ -2510,6 +2536,10 @@ error_no_main_loop:
dsf_file_close(data.dsf.file);
if (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
if (data.encoded.packet)
av_packet_free(&data.encoded.packet);