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