mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-11-25 06:59:57 -05:00
filter-graph: improve latency reporting of convolver
The latency of the convolver depends on the IR used. It's 0 for /dirac, len/2 for /hilbert and let's assume it is 0 for file IRs. Fixes #4980
This commit is contained in:
parent
33c7d9cba5
commit
ed2889cecf
2 changed files with 33 additions and 20 deletions
|
|
@ -718,7 +718,9 @@ struct finfo {
|
||||||
SNDFILE *fs;
|
SNDFILE *fs;
|
||||||
#endif
|
#endif
|
||||||
int channels;
|
int channels;
|
||||||
int frames;
|
int def_frames;
|
||||||
|
int max_frames;
|
||||||
|
float latency; /* latency relative to number of samples */
|
||||||
uint32_t rate;
|
uint32_t rate;
|
||||||
const char *error;
|
const char *error;
|
||||||
};
|
};
|
||||||
|
|
@ -729,14 +731,18 @@ static int finfo_open(const char *filename, struct finfo *info, int rate)
|
||||||
if (spa_strstartswith(filename, "/hilbert")) {
|
if (spa_strstartswith(filename, "/hilbert")) {
|
||||||
info->channels = 1;
|
info->channels = 1;
|
||||||
info->rate = rate;
|
info->rate = rate;
|
||||||
info->frames = 64;
|
info->def_frames = 64;
|
||||||
|
info->max_frames = INT_MAX;
|
||||||
info->type = TYPE_HILBERT;
|
info->type = TYPE_HILBERT;
|
||||||
|
info->latency = 0.5f;
|
||||||
}
|
}
|
||||||
else if (spa_strstartswith(filename, "/dirac")) {
|
else if (spa_strstartswith(filename, "/dirac")) {
|
||||||
info->channels = 1;
|
info->channels = 1;
|
||||||
info->frames = 1;
|
info->def_frames = 1;
|
||||||
|
info->max_frames = 1;
|
||||||
info->rate = rate;
|
info->rate = rate;
|
||||||
info->type = TYPE_DIRAC;
|
info->type = TYPE_DIRAC;
|
||||||
|
info->latency = 0.0f;
|
||||||
}
|
}
|
||||||
else if (spa_strstartswith(filename, "/ir:")) {
|
else if (spa_strstartswith(filename, "/ir:")) {
|
||||||
struct spa_json it[1];
|
struct spa_json it[1];
|
||||||
|
|
@ -744,14 +750,16 @@ static int finfo_open(const char *filename, struct finfo *info, int rate)
|
||||||
int rate;
|
int rate;
|
||||||
info->channels = 1;
|
info->channels = 1;
|
||||||
info->type = TYPE_IR;
|
info->type = TYPE_IR;
|
||||||
info->frames = 0;
|
info->def_frames = 0;
|
||||||
if (spa_json_begin_array_relax(&it[0], filename+4, strlen(filename+4)) <= 0)
|
if (spa_json_begin_array_relax(&it[0], filename+4, strlen(filename+4)) <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
if (spa_json_get_int(&it[0], &rate) <= 0)
|
if (spa_json_get_int(&it[0], &rate) <= 0)
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
info->rate = rate;
|
info->rate = rate;
|
||||||
while (spa_json_get_float(&it[0], &v) > 0)
|
while (spa_json_get_float(&it[0], &v) > 0)
|
||||||
info->frames++;
|
info->def_frames++;
|
||||||
|
info->max_frames = info->def_frames;
|
||||||
|
info->latency = 0.0f;
|
||||||
} else {
|
} else {
|
||||||
#ifdef HAVE_SNDFILE
|
#ifdef HAVE_SNDFILE
|
||||||
info->fs = sf_open(filename, SFM_READ, &info->info);
|
info->fs = sf_open(filename, SFM_READ, &info->info);
|
||||||
|
|
@ -760,9 +768,11 @@ static int finfo_open(const char *filename, struct finfo *info, int rate)
|
||||||
return -ENOENT;
|
return -ENOENT;
|
||||||
}
|
}
|
||||||
info->channels = info->info.channels;
|
info->channels = info->info.channels;
|
||||||
info->frames = info->info.frames;
|
info->def_frames = info->info.frames;
|
||||||
|
info->max_frames = info->def_frames;
|
||||||
info->rate = info->info.samplerate;
|
info->rate = info->info.samplerate;
|
||||||
info->type = TYPE_SNDFILE;
|
info->type = TYPE_SNDFILE;
|
||||||
|
info->latency = 0.0f;
|
||||||
#else
|
#else
|
||||||
info->error = "compiled without sndfile support, can't load samples";
|
info->error = "compiled without sndfile support, can't load samples";
|
||||||
return -ENOTSUP;
|
return -ENOTSUP;
|
||||||
|
|
@ -772,15 +782,15 @@ static int finfo_open(const char *filename, struct finfo *info, int rate)
|
||||||
}
|
}
|
||||||
|
|
||||||
static float *finfo_read_samples(struct plugin *pl, struct finfo *info, float gain, int delay,
|
static float *finfo_read_samples(struct plugin *pl, struct finfo *info, float gain, int delay,
|
||||||
int offset, int length, int channel, long unsigned *rate, int *n_samples)
|
int offset, int length, int channel, long unsigned *rate, int *n_samples, int *latency)
|
||||||
{
|
{
|
||||||
float *samples, v;
|
float *samples, v;
|
||||||
int i, n, h;
|
int i, n, h;
|
||||||
|
|
||||||
if (length <= 0)
|
if (length <= 0)
|
||||||
length = info->frames;
|
length = info->def_frames;
|
||||||
else
|
else
|
||||||
length = SPA_MIN(length, info->frames);
|
length = SPA_MIN(length, info->max_frames);
|
||||||
|
|
||||||
length -= SPA_MIN(offset, length);
|
length -= SPA_MIN(offset, length);
|
||||||
|
|
||||||
|
|
@ -837,6 +847,7 @@ static float *finfo_read_samples(struct plugin *pl, struct finfo *info, float ga
|
||||||
}
|
}
|
||||||
*n_samples = n;
|
*n_samples = n;
|
||||||
*rate = info->rate;
|
*rate = info->rate;
|
||||||
|
*latency = (int) (n * info->latency);
|
||||||
return samples;
|
return samples;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -850,7 +861,7 @@ static void finfo_close(struct finfo *info)
|
||||||
}
|
}
|
||||||
|
|
||||||
static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset,
|
static float *read_closest(struct plugin *pl, char **filenames, float gain, float delay_sec, int offset,
|
||||||
int length, int channel, long unsigned *rate, int *n_samples)
|
int length, int channel, long unsigned *rate, int *n_samples, int *latency)
|
||||||
{
|
{
|
||||||
struct finfo finfo[MAX_RATES];
|
struct finfo finfo[MAX_RATES];
|
||||||
int res, diff = INT_MAX;
|
int res, diff = INT_MAX;
|
||||||
|
|
@ -874,7 +885,7 @@ static float *read_closest(struct plugin *pl, char **filenames, float gain, floa
|
||||||
spa_log_info(pl->log, "loading best rate:%u %s", finfo[best].rate, filenames[best]);
|
spa_log_info(pl->log, "loading best rate:%u %s", finfo[best].rate, filenames[best]);
|
||||||
samples = finfo_read_samples(pl, &finfo[best], gain,
|
samples = finfo_read_samples(pl, &finfo[best], gain,
|
||||||
(int) (delay_sec * finfo[best].rate), offset, length,
|
(int) (delay_sec * finfo[best].rate), offset, length,
|
||||||
channel, rate, n_samples);
|
channel, rate, n_samples, latency);
|
||||||
} else {
|
} else {
|
||||||
char buf[PATH_MAX];
|
char buf[PATH_MAX];
|
||||||
spa_log_error(pl->log, "Can't open any sample file (CWD %s):",
|
spa_log_error(pl->log, "Can't open any sample file (CWD %s):",
|
||||||
|
|
@ -984,7 +995,7 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
|
||||||
char key[256];
|
char key[256];
|
||||||
char *filenames[MAX_RATES] = { 0 };
|
char *filenames[MAX_RATES] = { 0 };
|
||||||
int blocksize = 0, tailsize = 0;
|
int blocksize = 0, tailsize = 0;
|
||||||
int resample_quality = RESAMPLE_DEFAULT_QUALITY;
|
int resample_quality = RESAMPLE_DEFAULT_QUALITY, def_latency;
|
||||||
float gain = 1.0f, delay = 0.0f, latency = -1.0f;
|
float gain = 1.0f, delay = 0.0f, latency = -1.0f;
|
||||||
unsigned long rate;
|
unsigned long rate;
|
||||||
|
|
||||||
|
|
@ -1092,7 +1103,7 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
|
||||||
|
|
||||||
rate = SampleRate;
|
rate = SampleRate;
|
||||||
samples = read_closest(pl, filenames, gain, delay, offset,
|
samples = read_closest(pl, filenames, gain, delay, offset,
|
||||||
length, channel, &rate, &n_samples);
|
length, channel, &rate, &n_samples, &def_latency);
|
||||||
if (samples != NULL && rate != SampleRate)
|
if (samples != NULL && rate != SampleRate)
|
||||||
samples = resample_buffer(pl, samples, &n_samples,
|
samples = resample_buffer(pl, samples, &n_samples,
|
||||||
rate, SampleRate, resample_quality);
|
rate, SampleRate, resample_quality);
|
||||||
|
|
@ -1111,8 +1122,8 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
|
||||||
if (tailsize <= 0)
|
if (tailsize <= 0)
|
||||||
tailsize = SPA_CLAMP(4096, blocksize, 32768);
|
tailsize = SPA_CLAMP(4096, blocksize, 32768);
|
||||||
|
|
||||||
spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f", n_samples,
|
spa_log_info(pl->log, "using n_samples:%u %d:%d blocksize delay:%f def-latency:%d", n_samples,
|
||||||
blocksize, tailsize, delay);
|
blocksize, tailsize, delay, def_latency);
|
||||||
|
|
||||||
impl = calloc(1, sizeof(*impl));
|
impl = calloc(1, sizeof(*impl));
|
||||||
if (impl == NULL)
|
if (impl == NULL)
|
||||||
|
|
@ -1128,7 +1139,7 @@ static void * convolver_instantiate(const struct spa_fga_plugin *plugin, const s
|
||||||
goto error;
|
goto error;
|
||||||
|
|
||||||
if (latency < 0.0f)
|
if (latency < 0.0f)
|
||||||
impl->latency = n_samples;
|
impl->latency = def_latency;
|
||||||
else
|
else
|
||||||
impl->latency = latency * impl->rate;
|
impl->latency = latency * impl->rate;
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -401,11 +401,13 @@ extern struct spa_handle_factory spa_filter_graph_factory;
|
||||||
* - `filename` The IR to load or create. Possible values are:
|
* - `filename` The IR to load or create. Possible values are:
|
||||||
* - `/hilbert` creates a [hilbert function](https://en.wikipedia.org/wiki/Hilbert_transform)
|
* - `/hilbert` creates a [hilbert function](https://en.wikipedia.org/wiki/Hilbert_transform)
|
||||||
* that can be used to phase shift the signal by +/-90 degrees. The
|
* that can be used to phase shift the signal by +/-90 degrees. The
|
||||||
* `length` will be used as the number of coefficients.
|
* `length` will be used as the number of coefficients. The default latency
|
||||||
|
* if the length/2.
|
||||||
* - `/dirac` creates a [Dirac function](https://en.wikipedia.org/wiki/Dirac_delta_function) that
|
* - `/dirac` creates a [Dirac function](https://en.wikipedia.org/wiki/Dirac_delta_function) that
|
||||||
* can be used as gain.
|
* can be used as gain. The default latency is 0.
|
||||||
* - A filename to load as the IR. This needs to be a file format supported
|
* - A filename to load as the IR. This needs to be a file format supported
|
||||||
* by sndfile or be an inline IR with "/ir:<rate>,<value1>,<value2>".
|
* by sndfile or be an inline IR with "/ir:<rate>,<value1>,<value2>". The default
|
||||||
|
* latency of file IRs is 0.
|
||||||
* - [ filename, ... ] an array of filenames. The file with the closest samplerate match
|
* - [ filename, ... ] an array of filenames. The file with the closest samplerate match
|
||||||
* with the graph samplerate will be used.
|
* with the graph samplerate will be used.
|
||||||
* - `offset` The sample offset in the file as the start of the IR.
|
* - `offset` The sample offset in the file as the start of the IR.
|
||||||
|
|
@ -414,7 +416,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
|
||||||
* - `resample_quality` The resample quality in case the IR does not match the graph
|
* - `resample_quality` The resample quality in case the IR does not match the graph
|
||||||
* samplerate.
|
* samplerate.
|
||||||
* - `latency` The extra latency in seconds to report. When left unspecified (or < 0.0)
|
* - `latency` The extra latency in seconds to report. When left unspecified (or < 0.0)
|
||||||
* the convolver latency will be the length of the IR.
|
* the default IR latency will be used, the the filename argument.
|
||||||
*
|
*
|
||||||
* ### Delay
|
* ### Delay
|
||||||
*
|
*
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue