From 5dd0a12875a60ad77e4b2b099ee74b2e38873945 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Tue, 1 Mar 2022 10:28:11 +0100 Subject: [PATCH] channelmix: add option for stereo widen When generating FC, add an option to subtract some of the generated FC from the FL and FR channel to move the sound more to the center. See #861 --- spa/plugins/audioconvert/channelmix-ops-c.c | 32 +++++++++++++-------- spa/plugins/audioconvert/channelmix-ops.h | 1 + spa/plugins/audioconvert/channelmix.c | 13 +++++++++ src/daemon/client-rt.conf.in | 1 + src/daemon/client.conf.in | 1 + src/daemon/minimal.conf.in | 2 ++ src/daemon/pipewire-pulse.conf.in | 1 + 7 files changed, 39 insertions(+), 12 deletions(-) diff --git a/spa/plugins/audioconvert/channelmix-ops-c.c b/spa/plugins/audioconvert/channelmix-ops-c.c index c0d12d541..8d4a02a0a 100644 --- a/spa/plugins/audioconvert/channelmix-ops-c.c +++ b/spa/plugins/audioconvert/channelmix-ops-c.c @@ -249,8 +249,9 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else if (v0 == 1.0f && v1 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; - d[0][n] = s[0][n]; - d[1][n] = s[1][n]; + float w = c * mix->widen; + d[0][n] = s[0][n] - w; + d[1][n] = s[1][n] - w; d[2][n] = c; } lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); @@ -259,8 +260,9 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; - d[0][n] = s[0][n] * v0; - d[1][n] = s[1][n] * v1; + float w = c * mix->widen; + d[0][n] = (s[0][n] - w) * v0; + d[1][n] = (s[1][n] - w) * v1; d[2][n] = c; } lr4_process(&mix->lr4[3], d[3], d[2], v3, n_samples); @@ -290,9 +292,10 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else if (v0 == 1.0f && v1 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; + float w = c * mix->widen; float m = s[0][n] - s[1][n]; - d[0][n] = s[0][n]; - d[1][n] = s[1][n]; + d[0][n] = s[0][n] - w; + d[1][n] = s[1][n] - w; d[3][n] = c; d[5][n] = m; } @@ -307,9 +310,10 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; + float w = c * mix->widen; float m = s[0][n] - s[1][n]; - d[0][n] = s[0][n] * v0; - d[1][n] = s[1][n] * v1; + d[0][n] = (s[0][n] - w) * v0; + d[1][n] = (s[1][n] - w) * v1; d[3][n] = c; d[5][n] = m; } @@ -346,10 +350,13 @@ channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else if (v0 == 1.0f && v1 == 1.0f && v4 == 1.0f && v5 == 1.0f) { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; + float w = c * mix->widen; float m = s[0][n] - s[1][n]; - d[0][n] = d[4][n] = s[0][n]; - d[1][n] = d[5][n] = s[1][n]; + d[0][n] = s[0][n] - w; + d[1][n] = s[1][n] - w; d[3][n] = c; + d[4][n] = s[0][n]; + d[5][n] = s[1][n]; d[7][n] = m; } lr4_process(&mix->lr4[2], d[2], d[3], v2, n_samples); @@ -363,9 +370,10 @@ channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[], else { for (n = 0; n < n_samples; n++) { float c = s[0][n] + s[1][n]; + float w = c * mix->widen; float m = s[0][n] - s[1][n]; - d[0][n] = s[0][n] * v0; - d[1][n] = s[1][n] * v1; + d[0][n] = (s[0][n] - w) * v0; + d[1][n] = (s[1][n] - w) * v1; d[3][n] = c; d[4][n] = s[0][n] * v4; d[5][n] = s[1][n] * v5; diff --git a/spa/plugins/audioconvert/channelmix-ops.h b/spa/plugins/audioconvert/channelmix-ops.h index 8500f401c..89a9172e6 100644 --- a/spa/plugins/audioconvert/channelmix-ops.h +++ b/spa/plugins/audioconvert/channelmix-ops.h @@ -72,6 +72,7 @@ struct channelmix { float freq; /* sample frequency */ float lfe_cutoff; /* in Hz, 0 is disabled */ float rear_delay; /* in ms, 0 is disabled */ + float widen; /* stereo widen. 0 is disabled */ struct lr4 lr4[SPA_AUDIO_MAX_CHANNELS]; float buffer[2][BUFFER_SIZE]; diff --git a/spa/plugins/audioconvert/channelmix.c b/spa/plugins/audioconvert/channelmix.c index 2857e7cf2..4f5539fb2 100644 --- a/spa/plugins/audioconvert/channelmix.c +++ b/spa/plugins/audioconvert/channelmix.c @@ -518,6 +518,15 @@ static int impl_node_enum_params(void *object, int seq, this->mix.rear_delay, 0.0, 1000.0), SPA_PROP_INFO_params, SPA_POD_Bool(true)); break; + case 14: + param = spa_pod_builder_add_object(&b, + SPA_TYPE_OBJECT_PropInfo, id, + SPA_PROP_INFO_name, SPA_POD_String("channelmix.stereo-widen"), + SPA_PROP_INFO_description, SPA_POD_String("Stereo widen"), + SPA_PROP_INFO_type, SPA_POD_CHOICE_RANGE_Float( + this->mix.widen, 0.0, 1.0), + SPA_PROP_INFO_params, SPA_POD_Bool(true)); + break; default: return 0; } @@ -571,6 +580,8 @@ static int impl_node_enum_params(void *object, int seq, spa_pod_builder_float(&b, this->mix.lfe_cutoff); spa_pod_builder_string(&b, "channelmix.rear-delay"); spa_pod_builder_float(&b, this->mix.rear_delay); + spa_pod_builder_string(&b, "channelmix.stereo-widen"); + spa_pod_builder_float(&b, this->mix.widen); spa_pod_builder_pop(&b, &f[1]); param = spa_pod_builder_pop(&b, &f[0]); break; @@ -608,6 +619,8 @@ static int channelmix_set_param(struct impl *this, const char *k, const char *s) spa_atof(s, &this->mix.lfe_cutoff); else if (spa_streq(k, "channelmix.rear-delay")) spa_atof(s, &this->mix.rear_delay); + else if (spa_streq(k, "channelmix.stereo-widen")) + spa_atof(s, &this->mix.widen); else return 0; return 1; diff --git a/src/daemon/client-rt.conf.in b/src/daemon/client-rt.conf.in index 24caae996..80b061252 100644 --- a/src/daemon/client-rt.conf.in +++ b/src/daemon/client-rt.conf.in @@ -86,4 +86,5 @@ stream.properties = { #channelmix.upmix = false #channelmix.lfe-cutoff = 0 #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.0 } diff --git a/src/daemon/client.conf.in b/src/daemon/client.conf.in index 69b6cb3f6..ce08f56be 100644 --- a/src/daemon/client.conf.in +++ b/src/daemon/client.conf.in @@ -76,4 +76,5 @@ stream.properties = { #channelmix.upmix = false #channelmix.lfe-cutoff = 0 #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.0 } diff --git a/src/daemon/minimal.conf.in b/src/daemon/minimal.conf.in index c43596894..2a077b1ad 100644 --- a/src/daemon/minimal.conf.in +++ b/src/daemon/minimal.conf.in @@ -207,6 +207,7 @@ context.objects = [ #channelmix.upmix = false #channelmix.lfe-cutoff = 0 #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.0 channelmix.disable = true #node.param.Props = { # params = [ @@ -263,6 +264,7 @@ context.objects = [ #channelmix.upmix = false #channelmix.lfe-cutoff = 0 #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.0 channelmix.disable = true #node.param.Props = { # params = [ diff --git a/src/daemon/pipewire-pulse.conf.in b/src/daemon/pipewire-pulse.conf.in index 89501ff0f..8145365a0 100644 --- a/src/daemon/pipewire-pulse.conf.in +++ b/src/daemon/pipewire-pulse.conf.in @@ -86,6 +86,7 @@ stream.properties = { #channelmix.upmix = false #channelmix.lfe-cutoff = 0 #channelmix.rear-delay = 12.0 + #channelmix.stereo-widen = 0.0 } # client/stream specific properties