mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2026-04-23 06:47:02 -04:00
filter-graph: use convolver2 for sofa
We don't need 2 convolvers anymore, we can use the same convolver with 2 outputs with the left and right ir. Add latency option to the sofa plugin. I believe the latency of the SOFA filters is by default 0, so use that.
This commit is contained in:
parent
9cae4ce7e7
commit
c6ae30593c
2 changed files with 45 additions and 44 deletions
|
|
@ -34,11 +34,11 @@ struct spatializer_impl {
|
|||
int n_samples, blocksize, tailsize;
|
||||
float gain;
|
||||
float *tmp[2];
|
||||
float latency;
|
||||
|
||||
struct MYSOFA_EASY *sofa;
|
||||
unsigned int interpolate:1;
|
||||
struct convolver *l_conv[3];
|
||||
struct convolver *r_conv[3];
|
||||
struct convolver *conv[3];
|
||||
};
|
||||
|
||||
static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const struct spa_fga_descriptor * Descriptor,
|
||||
|
|
@ -73,6 +73,7 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
|
|||
impl->dsp = pl->dsp;
|
||||
impl->log = pl->log;
|
||||
impl->gain = 1.0f;
|
||||
impl->latency = 0.0f;
|
||||
|
||||
while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) {
|
||||
if (spa_streq(key, "blocksize")) {
|
||||
|
|
@ -103,6 +104,16 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
|
|||
goto error;
|
||||
}
|
||||
}
|
||||
else if (spa_streq(key, "latency")) {
|
||||
if (spa_json_parse_float(val, len, &impl->latency) <= 0) {
|
||||
spa_log_error(impl->log, "spatializer:latency requires a number");
|
||||
errno = EINVAL;
|
||||
goto error;
|
||||
}
|
||||
}
|
||||
else {
|
||||
spa_log_warn(pl->log, "spatializer: ignoring config key: '%s'", key);
|
||||
}
|
||||
}
|
||||
if (!filename[0]) {
|
||||
spa_log_error(impl->log, "spatializer:filename was not given");
|
||||
|
|
@ -201,6 +212,7 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const
|
|||
impl->tmp[0] = calloc(impl->plugin->quantum_limit, sizeof(float));
|
||||
impl->tmp[1] = calloc(impl->plugin->quantum_limit, sizeof(float));
|
||||
impl->rate = SampleRate;
|
||||
|
||||
return impl;
|
||||
error:
|
||||
if (impl->sofa)
|
||||
|
|
@ -215,14 +227,12 @@ do_switch(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
|
|||
{
|
||||
struct spatializer_impl *impl = user_data;
|
||||
|
||||
if (impl->l_conv[0] == NULL) {
|
||||
SPA_SWAP(impl->l_conv[0], impl->l_conv[2]);
|
||||
SPA_SWAP(impl->r_conv[0], impl->r_conv[2]);
|
||||
if (impl->conv[0] == NULL) {
|
||||
SPA_SWAP(impl->conv[0], impl->conv[2]);
|
||||
} else {
|
||||
SPA_SWAP(impl->l_conv[1], impl->l_conv[2]);
|
||||
SPA_SWAP(impl->r_conv[1], impl->r_conv[2]);
|
||||
SPA_SWAP(impl->conv[1], impl->conv[2]);
|
||||
}
|
||||
impl->interpolate = impl->l_conv[0] && impl->l_conv[1];
|
||||
impl->interpolate = impl->conv[0] && impl->conv[1];
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -235,6 +245,7 @@ static void spatializer_reload(void * Instance)
|
|||
float left_delay;
|
||||
float right_delay;
|
||||
float coords[3];
|
||||
struct convolver_ir ir[2];
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++)
|
||||
coords[i] = impl->port[3 + i][0];
|
||||
|
|
@ -257,10 +268,8 @@ static void spatializer_reload(void * Instance)
|
|||
if ((left_delay != 0.0f || right_delay != 0.0f) && (!isnan(left_delay) || !isnan(right_delay)))
|
||||
spa_log_warn(impl->log, "delay dropped l: %f, r: %f", left_delay, right_delay);
|
||||
|
||||
if (impl->l_conv[2])
|
||||
convolver_free(impl->l_conv[2]);
|
||||
if (impl->r_conv[2])
|
||||
convolver_free(impl->r_conv[2]);
|
||||
if (impl->conv[2])
|
||||
convolver_free(impl->conv[2]);
|
||||
|
||||
if (impl->gain != 1.0f) {
|
||||
for (int i = 0; i < impl->n_samples; i++) {
|
||||
|
|
@ -268,24 +277,25 @@ static void spatializer_reload(void * Instance)
|
|||
right_ir[i] *= impl->gain;
|
||||
}
|
||||
}
|
||||
ir[0].ir = left_ir;
|
||||
ir[0].len = impl->n_samples;
|
||||
ir[1].ir = right_ir;
|
||||
ir[1].len = impl->n_samples;
|
||||
|
||||
impl->l_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize,
|
||||
left_ir, impl->n_samples);
|
||||
impl->r_conv[2] = convolver_new(impl->dsp, impl->blocksize, impl->tailsize,
|
||||
right_ir, impl->n_samples);
|
||||
impl->conv[2] = convolver_new_many(impl->dsp, impl->blocksize, impl->tailsize, ir, 2);
|
||||
|
||||
free(left_ir);
|
||||
free(right_ir);
|
||||
|
||||
if (impl->l_conv[2] == NULL || impl->r_conv[2] == NULL) {
|
||||
spa_log_error(impl->log, "reloading left or right convolver failed");
|
||||
if (impl->conv[2] == NULL) {
|
||||
spa_log_error(impl->log, "reloading convolver failed");
|
||||
return;
|
||||
}
|
||||
spa_loop_locked(impl->plugin->data_loop, do_switch, 1, NULL, 0, impl);
|
||||
}
|
||||
|
||||
struct free_data {
|
||||
void *item[2];
|
||||
void *item[1];
|
||||
};
|
||||
|
||||
static int
|
||||
|
|
@ -295,8 +305,6 @@ do_free(struct spa_loop *loop, bool async, uint32_t seq, const void *data,
|
|||
const struct free_data *fd = data;
|
||||
if (fd->item[0])
|
||||
convolver_free(fd->item[0]);
|
||||
if (fd->item[1])
|
||||
convolver_free(fd->item[1]);
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
|
@ -309,29 +317,24 @@ static void spatializer_run(void * Instance, unsigned long SampleCount)
|
|||
struct free_data free_data;
|
||||
float *l = impl->tmp[0], *r = impl->tmp[1];
|
||||
|
||||
convolver_run(impl->l_conv[0], impl->port[2], impl->port[0], len);
|
||||
convolver_run(impl->l_conv[1], impl->port[2], l, len);
|
||||
convolver_run(impl->r_conv[0], impl->port[2], impl->port[1], len);
|
||||
convolver_run(impl->r_conv[1], impl->port[2], r, len);
|
||||
convolver_run_many(impl->conv[0], impl->port[2], &impl->port[0], len);
|
||||
convolver_run_many(impl->conv[1], impl->port[2], impl->tmp, len);
|
||||
|
||||
for (uint32_t i = 0; i < SampleCount; i++) {
|
||||
float t = (float)i / SampleCount;
|
||||
impl->port[0][i] = impl->port[0][i] * (1.0f - t) + l[i] * t;
|
||||
impl->port[1][i] = impl->port[1][i] * (1.0f - t) + r[i] * t;
|
||||
}
|
||||
free_data.item[0] = impl->l_conv[0];
|
||||
free_data.item[1] = impl->r_conv[0];
|
||||
impl->l_conv[0] = impl->l_conv[1];
|
||||
impl->r_conv[0] = impl->r_conv[1];
|
||||
impl->l_conv[1] = impl->r_conv[1] = NULL;
|
||||
free_data.item[0] = impl->conv[0];
|
||||
impl->conv[0] = impl->conv[1];
|
||||
impl->conv[1] = NULL;
|
||||
impl->interpolate = false;
|
||||
|
||||
spa_loop_invoke(impl->plugin->main_loop, do_free, 1, &free_data, sizeof(free_data), false, impl);
|
||||
} else if (impl->l_conv[0] && impl->r_conv[0]) {
|
||||
convolver_run(impl->l_conv[0], impl->port[2], impl->port[0], SampleCount);
|
||||
convolver_run(impl->r_conv[0], impl->port[2], impl->port[1], SampleCount);
|
||||
} else if (impl->conv[0]) {
|
||||
convolver_run_many(impl->conv[0], impl->port[2], &impl->port[0], SampleCount);
|
||||
}
|
||||
impl->port[6][0] = impl->n_samples;
|
||||
impl->port[6][0] = impl->latency;
|
||||
}
|
||||
|
||||
static void spatializer_connect_port(void * Instance, unsigned long Port,
|
||||
|
|
@ -346,10 +349,8 @@ static void spatializer_cleanup(void * Instance)
|
|||
struct spatializer_impl *impl = Instance;
|
||||
|
||||
for (uint8_t i = 0; i < 3; i++) {
|
||||
if (impl->l_conv[i])
|
||||
convolver_free(impl->l_conv[i]);
|
||||
if (impl->r_conv[i])
|
||||
convolver_free(impl->r_conv[i]);
|
||||
if (impl->conv[i])
|
||||
convolver_free(impl->conv[i]);
|
||||
}
|
||||
if (impl->sofa)
|
||||
mysofa_close_cached(impl->sofa);
|
||||
|
|
@ -367,16 +368,14 @@ static void spatializer_control_changed(void * Instance)
|
|||
static void spatializer_activate(void * Instance)
|
||||
{
|
||||
struct spatializer_impl *impl = Instance;
|
||||
impl->port[6][0] = impl->n_samples;
|
||||
impl->port[6][0] = impl->latency;
|
||||
}
|
||||
|
||||
static void spatializer_deactivate(void * Instance)
|
||||
{
|
||||
struct spatializer_impl *impl = Instance;
|
||||
if (impl->l_conv[0])
|
||||
convolver_reset(impl->l_conv[0]);
|
||||
if (impl->r_conv[0])
|
||||
convolver_reset(impl->r_conv[0]);
|
||||
if (impl->conv[0])
|
||||
convolver_reset(impl->conv[0]);
|
||||
impl->interpolate = false;
|
||||
}
|
||||
|
||||
|
|
|
|||
|
|
@ -761,6 +761,7 @@ extern struct spa_handle_factory spa_filter_graph_factory;
|
|||
* tailsize = ...
|
||||
* filename = ...
|
||||
* gain = ...
|
||||
* latency = ...
|
||||
* }
|
||||
* control = {
|
||||
* "Azimuth" = ...
|
||||
|
|
@ -780,7 +781,8 @@ extern struct spa_handle_factory spa_filter_graph_factory;
|
|||
* - `tailsize` specifies the size of the tail blocks to use in the FFT.
|
||||
* - `filename` The SOFA file to load. SOFA files usually end in the .sofa extension
|
||||
* and contain the HRTF for the various spatial positions.
|
||||
* - `gain` the overall gain to apply to the IR file.
|
||||
* - `gain` the overall gain to apply to the IR file, default 1.0.
|
||||
* - `latency` the latency introduced by the filter, default 0
|
||||
*
|
||||
* - `Azimuth` controls the azimuth, this is the direction the sound is coming from
|
||||
* in degrees between 0 and 360. 0 is straight ahead. 90 is left, 180
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue