From 3c80f0fb3efc46a9690bdf3f4750df04020311dc Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 2 Feb 2026 16:21:03 +0100 Subject: [PATCH] filter-graph: add gain option to sofa So that we can apply the gain to the IR. This is more efficient than doing a volume after the convolution. See #5098 --- spa/plugins/filter-graph/plugin_sofa.c | 20 ++++++++- src/daemon/filter-chain/spatializer-7.1.conf | 43 ++++++++++++-------- src/modules/module-filter-chain.c | 8 ++-- 3 files changed, 50 insertions(+), 21 deletions(-) diff --git a/spa/plugins/filter-graph/plugin_sofa.c b/spa/plugins/filter-graph/plugin_sofa.c index 14005dabd..2e3a1ea3b 100644 --- a/spa/plugins/filter-graph/plugin_sofa.c +++ b/spa/plugins/filter-graph/plugin_sofa.c @@ -32,6 +32,7 @@ struct spatializer_impl { unsigned long rate; float *port[7]; int n_samples, blocksize, tailsize; + float gain; float *tmp[2]; struct MYSOFA_EASY *sofa; @@ -71,6 +72,7 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const impl->plugin = pl; impl->dsp = pl->dsp; impl->log = pl->log; + impl->gain = 1.0f; while ((len = spa_json_object_next(&it[0], key, sizeof(key), &val)) > 0) { if (spa_streq(key, "blocksize")) { @@ -94,6 +96,13 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const goto error; } } + else if (spa_streq(key, "gain")) { + if (spa_json_parse_float(val, len, &impl->gain) <= 0) { + spa_log_error(impl->log, "spatializer:gain requires a number"); + errno = EINVAL; + goto error; + } + } } if (!filename[0]) { spa_log_error(impl->log, "spatializer:filename was not given"); @@ -186,8 +195,8 @@ static void * spatializer_instantiate(const struct spa_fga_plugin *plugin, const if (impl->tailsize <= 0) impl->tailsize = SPA_CLAMP(4096, impl->blocksize, 32768); - spa_log_info(impl->log, "using n_samples:%u %d:%d blocksize sofa:%s", impl->n_samples, - impl->blocksize, impl->tailsize, filename); + spa_log_info(impl->log, "using n_samples:%u %d:%d blocksize gain:%f sofa:%s", impl->n_samples, + impl->blocksize, impl->tailsize, impl->gain, filename); impl->tmp[0] = calloc(impl->plugin->quantum_limit, sizeof(float)); impl->tmp[1] = calloc(impl->plugin->quantum_limit, sizeof(float)); @@ -253,6 +262,13 @@ static void spatializer_reload(void * Instance) if (impl->r_conv[2]) convolver_free(impl->r_conv[2]); + if (impl->gain != 1.0f) { + for (int i = 0; i < impl->n_samples; i++) { + left_ir[i] *= impl->gain; + right_ir[i] *= impl->gain; + } + } + 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, diff --git a/src/daemon/filter-chain/spatializer-7.1.conf b/src/daemon/filter-chain/spatializer-7.1.conf index 931e80975..bb19d5443 100644 --- a/src/daemon/filter-chain/spatializer-7.1.conf +++ b/src/daemon/filter-chain/spatializer-7.1.conf @@ -19,6 +19,8 @@ context.modules = [ name = spFL config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + # The gain depends on the .sofa file in use + gain = 0.5 } control = { "Azimuth" = 30.0 @@ -32,6 +34,7 @@ context.modules = [ name = spFR config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 330.0 @@ -45,6 +48,7 @@ context.modules = [ name = spFC config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 0.0 @@ -58,6 +62,7 @@ context.modules = [ name = spRL config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 150.0 @@ -71,6 +76,7 @@ context.modules = [ name = spRR config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 210.0 @@ -84,6 +90,7 @@ context.modules = [ name = spSL config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 90.0 @@ -97,6 +104,7 @@ context.modules = [ name = spSR config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 270.0 @@ -110,6 +118,7 @@ context.modules = [ name = spLFE config = { filename = "~/.config/hrtf-sofa/hrtf b_nh724.sofa" + gain = 0.5 } control = { "Azimuth" = 0.0 @@ -120,26 +129,28 @@ context.modules = [ { type = builtin label = mixer name = mixL control = { - "Gain 1" = 0.5 - "Gain 2" = 0.5 - "Gain 3" = 0.5 - "Gain 4" = 0.5 - "Gain 5" = 0.5 - "Gain 6" = 0.5 - "Gain 7" = 0.5 - "Gain 8" = 0.5 + # Set individual left mixer gain if needed + #"Gain 1" = 1.0 + #"Gain 2" = 1.0 + #"Gain 3" = 1.0 + #"Gain 4" = 1.0 + #"Gain 5" = 1.0 + #"Gain 6" = 1.0 + #"Gain 7" = 1.0 + #"Gain 8" = 1.0 } } { type = builtin label = mixer name = mixR control = { - "Gain 1" = 0.5 - "Gain 2" = 0.5 - "Gain 3" = 0.5 - "Gain 4" = 0.5 - "Gain 5" = 0.5 - "Gain 6" = 0.5 - "Gain 7" = 0.5 - "Gain 8" = 0.5 + # Set individual right mixer gain if needed + #"Gain 1" = 1.0 + #"Gain 2" = 1.0 + #"Gain 3" = 1.0 + #"Gain 4" = 1.0 + #"Gain 5" = 1.0 + #"Gain 6" = 1.0 + #"Gain 7" = 1.0 + #"Gain 8" = 1.0 } } ] diff --git a/src/modules/module-filter-chain.c b/src/modules/module-filter-chain.c index 6453baeee..64a92c5ac 100644 --- a/src/modules/module-filter-chain.c +++ b/src/modules/module-filter-chain.c @@ -717,6 +717,7 @@ extern struct spa_handle_factory spa_filter_graph_factory; * blocksize = ... * tailsize = ... * filename = ... + * gain = ... * } * control = { * "Azimuth" = ... @@ -733,9 +734,10 @@ extern struct spa_handle_factory spa_filter_graph_factory; * - `blocksize` specifies the size of the blocks to use in the FFT. It is a value * between 64 and 256. When not specified, this value is * computed automatically from the number of samples in the file. - * - `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. + * - `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. * * - `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