mirror of
https://gitlab.freedesktop.org/pipewire/pipewire.git
synced 2025-10-29 05:40:27 -04:00
channelmix: add simple upmix method
Add a property to select the upmix method. PSD is enabled by default but a new simple upmixing algorithm is available that duplicates channels and avoids lowpass filter on the FC and disables widening. Fixes #861
This commit is contained in:
parent
cec8898740
commit
bc5b486cb9
8 changed files with 98 additions and 1 deletions
|
|
@ -246,6 +246,16 @@ channelmix_f32_2_3p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
|
|||
for (i = 0; i < n_dst; i++)
|
||||
memset(d[i], 0, n_samples * sizeof(float));
|
||||
}
|
||||
else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
|
||||
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;
|
||||
d[2][n] = c * v2;
|
||||
d[3][n] = c;
|
||||
}
|
||||
lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
|
||||
}
|
||||
else if (v0 == 1.0f && v1 == 1.0f) {
|
||||
for (n = 0; n < n_samples; n++) {
|
||||
float c = s[0][n] + s[1][n];
|
||||
|
|
@ -289,6 +299,18 @@ channelmix_f32_2_5p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
|
|||
for (i = 0; i < n_dst; i++)
|
||||
memset(d[i], 0, n_samples * sizeof(float));
|
||||
}
|
||||
else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
|
||||
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;
|
||||
d[2][n] = c * v2;
|
||||
d[3][n] = c;
|
||||
d[4][n] = s[0][n] * v4;
|
||||
d[5][n] = s[1][n] * v5;
|
||||
}
|
||||
lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
|
||||
}
|
||||
else if (v0 == 1.0f && v1 == 1.0f) {
|
||||
for (n = 0; n < n_samples; n++) {
|
||||
float c = s[0][n] + s[1][n];
|
||||
|
|
@ -347,6 +369,20 @@ channelmix_f32_2_7p1_c(struct channelmix *mix, void * SPA_RESTRICT dst[],
|
|||
for (i = 0; i < n_dst; i++)
|
||||
memset(d[i], 0, n_samples * sizeof(float));
|
||||
}
|
||||
else if (mix->upmix == CHANNELMIX_UPMIX_SIMPLE) {
|
||||
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;
|
||||
d[2][n] = c * v2;
|
||||
d[3][n] = c;
|
||||
d[4][n] = s[0][n] * v4;
|
||||
d[5][n] = s[1][n] * v5;
|
||||
d[6][n] = s[0][n] * v6;
|
||||
d[7][n] = s[1][n] * v7;
|
||||
}
|
||||
lr4_process(&mix->lr4[3], d[3], d[3], v3, n_samples);
|
||||
}
|
||||
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];
|
||||
|
|
|
|||
|
|
@ -210,7 +210,8 @@ static int make_matrix(struct channelmix *mix)
|
|||
unassigned = src_mask & ~dst_mask;
|
||||
keep = dst_mask & ~src_mask;
|
||||
|
||||
if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX))
|
||||
if (!SPA_FLAG_IS_SET(mix->options, CHANNELMIX_OPTION_UPMIX) ||
|
||||
mix->upmix == CHANNELMIX_UPMIX_NONE)
|
||||
keep = 0;
|
||||
|
||||
keep |= FRONT;
|
||||
|
|
|
|||
|
|
@ -26,6 +26,7 @@
|
|||
#include <stdio.h>
|
||||
|
||||
#include <spa/utils/defs.h>
|
||||
#include <spa/utils/string.h>
|
||||
#include <spa/param/audio/raw.h>
|
||||
|
||||
#undef SPA_LOG_TOPIC_DEFAULT
|
||||
|
|
@ -61,6 +62,10 @@ struct channelmix {
|
|||
#define CHANNELMIX_OPTION_NORMALIZE (1<<1) /**< normalize volumes */
|
||||
#define CHANNELMIX_OPTION_UPMIX (1<<2) /**< do simple upmixing */
|
||||
uint32_t options;
|
||||
#define CHANNELMIX_UPMIX_NONE (0) /**< disable upmixing */
|
||||
#define CHANNELMIX_UPMIX_SIMPLE (1) /**< simple upmixing */
|
||||
#define CHANNELMIX_UPMIX_PSD (2) /**< Passive Surround Decoding upmixing */
|
||||
uint32_t upmix;
|
||||
|
||||
struct spa_log *log;
|
||||
|
||||
|
|
@ -97,6 +102,26 @@ struct channelmix {
|
|||
|
||||
int channelmix_init(struct channelmix *mix);
|
||||
|
||||
static const struct channelmix_upmix_info {
|
||||
const char *label;
|
||||
const char *description;
|
||||
uint32_t upmix;
|
||||
} channelmix_upmix_info[] = {
|
||||
[CHANNELMIX_UPMIX_NONE] = { "none", "Disabled", CHANNELMIX_UPMIX_NONE },
|
||||
[CHANNELMIX_UPMIX_SIMPLE] = { "simple", "Simple upmixing", CHANNELMIX_UPMIX_SIMPLE },
|
||||
[CHANNELMIX_UPMIX_PSD] = { "psd", "Passive Surround Decoding", CHANNELMIX_UPMIX_PSD }
|
||||
};
|
||||
|
||||
static inline uint32_t channelmix_upmix_from_label(const char *label)
|
||||
{
|
||||
uint32_t i;
|
||||
for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) {
|
||||
if (spa_streq(channelmix_upmix_info[i].label, label))
|
||||
return channelmix_upmix_info[i].upmix;
|
||||
}
|
||||
return CHANNELMIX_UPMIX_NONE;
|
||||
}
|
||||
|
||||
#define channelmix_process(mix,...) (mix)->process(mix, __VA_ARGS__)
|
||||
#define channelmix_set_volume(mix,...) (mix)->set_volume(mix, __VA_ARGS__)
|
||||
#define channelmix_free(mix) (mix)->free(mix)
|
||||
|
|
|
|||
|
|
@ -546,6 +546,31 @@ static int impl_node_enum_params(void *object, int seq,
|
|||
this->mix.hilbert_taps, 0, MAX_TAPS),
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true));
|
||||
break;
|
||||
case 17:
|
||||
{
|
||||
struct spa_pod_frame f[2];
|
||||
uint32_t i;
|
||||
spa_pod_builder_push_object(&b, &f[0],
|
||||
SPA_TYPE_OBJECT_PropInfo, id);
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_INFO_name, SPA_POD_String("channelmix.upmix-method"),
|
||||
SPA_PROP_INFO_description, SPA_POD_String("Upmix Method to use"),
|
||||
SPA_PROP_INFO_type, SPA_POD_String(
|
||||
channelmix_upmix_info[this->mix.upmix].label),
|
||||
0);
|
||||
spa_pod_builder_prop(&b, SPA_PROP_INFO_labels, 0);
|
||||
spa_pod_builder_push_struct(&b, &f[1]);
|
||||
for (i = 0; i < SPA_N_ELEMENTS(channelmix_upmix_info); i++) {
|
||||
spa_pod_builder_string(&b, channelmix_upmix_info[i].label);
|
||||
spa_pod_builder_string(&b, channelmix_upmix_info[i].description);
|
||||
}
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
spa_pod_builder_add(&b,
|
||||
SPA_PROP_INFO_params, SPA_POD_Bool(true),
|
||||
0);
|
||||
param = spa_pod_builder_pop(&b, &f[0]);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return 0;
|
||||
}
|
||||
|
|
@ -605,6 +630,8 @@ static int impl_node_enum_params(void *object, int seq,
|
|||
spa_pod_builder_float(&b, this->mix.widen);
|
||||
spa_pod_builder_string(&b, "channelmix.hilbert-taps");
|
||||
spa_pod_builder_int(&b, this->mix.hilbert_taps);
|
||||
spa_pod_builder_string(&b, "channelmix.upmix-method");
|
||||
spa_pod_builder_string(&b, channelmix_upmix_info[this->mix.upmix].label);
|
||||
spa_pod_builder_pop(&b, &f[1]);
|
||||
param = spa_pod_builder_pop(&b, &f[0]);
|
||||
break;
|
||||
|
|
@ -648,6 +675,8 @@ static int channelmix_set_param(struct impl *this, const char *k, const char *s)
|
|||
spa_atof(s, &this->mix.widen);
|
||||
else if (spa_streq(k, "channelmix.hilbert-taps"))
|
||||
spa_atou32(s, &this->mix.hilbert_taps, 0);
|
||||
else if (spa_streq(k, "channelmix.upmix-method"))
|
||||
this->mix.upmix = channelmix_upmix_from_label(s);
|
||||
else
|
||||
return 0;
|
||||
return 1;
|
||||
|
|
@ -1625,6 +1654,7 @@ impl_init(const struct spa_handle_factory *factory,
|
|||
props_reset(&this->props);
|
||||
|
||||
this->mix.options = CHANNELMIX_OPTION_UPMIX;
|
||||
this->mix.upmix = CHANNELMIX_UPMIX_PSD;
|
||||
this->mix.log = this->log;
|
||||
this->mix.lfe_cutoff = 120.0f;
|
||||
this->mix.fc_cutoff = 6000.0f;
|
||||
|
|
|
|||
|
|
@ -84,6 +84,7 @@ stream.properties = {
|
|||
#channelmix.normalize = false
|
||||
#channelmix.mix-lfe = true
|
||||
#channelmix.upmix = true
|
||||
#channelmix.upmix-method = psd # none, simple
|
||||
#channelmix.lfe-cutoff = 120
|
||||
#channelmix.fc-cutoff = 6000
|
||||
#channelmix.rear-delay = 12.0
|
||||
|
|
|
|||
|
|
@ -74,6 +74,7 @@ stream.properties = {
|
|||
#channelmix.normalize = false
|
||||
#channelmix.mix-lfe = false
|
||||
#channelmix.upmix = true
|
||||
#channelmix.upmix-method = psd # none, simple
|
||||
#channelmix.lfe-cutoff = 120
|
||||
#channelmix.fc-cutoff = 6000
|
||||
#channelmix.rear-delay = 12.0
|
||||
|
|
|
|||
|
|
@ -205,6 +205,7 @@ context.objects = [
|
|||
#channelmix.normalize = false
|
||||
#channelmix.mix-lfe = false
|
||||
#channelmix.upmix = true
|
||||
#channelmix.upmix-method = psd # none, simple
|
||||
#channelmix.lfe-cutoff = 120
|
||||
#channelmix.fc-cutoff = 6000
|
||||
#channelmix.rear-delay = 12.0
|
||||
|
|
@ -264,6 +265,7 @@ context.objects = [
|
|||
#channelmix.normalize = false
|
||||
#channelmix.mix-lfe = false
|
||||
#channelmix.upmix = true
|
||||
#channelmix.upmix-method = psd # none, simple
|
||||
#channelmix.lfe-cutoff = 120
|
||||
#channelmix.fc-cutoff = 6000
|
||||
#channelmix.rear-delay = 12.0
|
||||
|
|
|
|||
|
|
@ -60,6 +60,7 @@ stream.properties = {
|
|||
#channelmix.normalize = false
|
||||
#channelmix.mix-lfe = false
|
||||
#channelmix.upmix = true
|
||||
#channelmix.upmix-method = psd # none, simple
|
||||
#channelmix.lfe-cutoff = 120
|
||||
#channelmix.fc-cutoff = 6000
|
||||
#channelmix.rear-delay = 12.0
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue