mirror of
https://gitlab.freedesktop.org/pipewire/pipewire
synced 2024-10-15 20:32:38 +00:00
channelmix: Improve unknown channel layout handling
Clamp position to valid range. so that AUX becomes UNKNOWN. If we have one mono source channel and unknown destination, copy it to all destination channels. If we have one mono destination channel and unknown source layout, average all channels. Otherwise, pair source and dest channels. See #538
This commit is contained in:
parent
376436fc2c
commit
6b0abd2057
|
@ -177,9 +177,20 @@ static int make_matrix(struct channelmix *mix)
|
|||
dst_mask = _MASK(FC);
|
||||
|
||||
if (src_mask == 0 || dst_mask == 0) {
|
||||
if (src_mask == _MASK(FC) && mix->src_chan == 1) {
|
||||
/* one mono src goes everywhere */
|
||||
for (i = 0; i < NUM_CHAN; i++)
|
||||
matrix[i][0]= 1.0f;
|
||||
} else if (dst_mask == _MASK(FC) && mix->dst_chan == 1) {
|
||||
/* one mono dst get average of everything */
|
||||
for (i = 0; i < NUM_CHAN; i++)
|
||||
matrix[0][i]= 1.0f / mix->src_chan;
|
||||
} else {
|
||||
/* just pair channels */
|
||||
for (i = 0; i < NUM_CHAN; i++)
|
||||
matrix[i][i]= 1.0f;
|
||||
}
|
||||
src_mask = dst_mask = ~0LU;
|
||||
for (i = 0; i < NUM_CHAN; i++)
|
||||
matrix[i][i]= 1.0f;
|
||||
goto done;
|
||||
} else {
|
||||
for (i = 0; i < NUM_CHAN; i++) {
|
||||
|
|
|
@ -236,7 +236,7 @@ static int setup_convert(struct impl *this,
|
|||
const struct spa_audio_info *info)
|
||||
{
|
||||
const struct spa_audio_info *src_info, *dst_info;
|
||||
uint32_t i, src_chan, dst_chan;
|
||||
uint32_t i, src_chan, dst_chan, p;
|
||||
uint64_t src_mask, dst_mask;
|
||||
int res;
|
||||
|
||||
|
@ -251,10 +251,14 @@ static int setup_convert(struct impl *this,
|
|||
src_chan = src_info->info.raw.channels;
|
||||
dst_chan = dst_info->info.raw.channels;
|
||||
|
||||
for (i = 0, src_mask = 0; i < src_chan; i++)
|
||||
src_mask |= 1UL << src_info->info.raw.position[i];
|
||||
for (i = 0, dst_mask = 0; i < dst_chan; i++)
|
||||
dst_mask |= 1UL << dst_info->info.raw.position[i];
|
||||
for (i = 0, src_mask = 0; i < src_chan; i++) {
|
||||
p = src_info->info.raw.position[i];
|
||||
src_mask |= 1ULL << (p < 64 ? p : 0);
|
||||
}
|
||||
for (i = 0, dst_mask = 0; i < dst_chan; i++) {
|
||||
p = dst_info->info.raw.position[i];
|
||||
dst_mask |= 1ULL << (p < 64 ? p : 0);
|
||||
}
|
||||
|
||||
if (src_mask & 1 || src_chan == 1)
|
||||
src_mask = default_mask(src_chan);
|
||||
|
|
|
@ -34,15 +34,19 @@
|
|||
|
||||
SPA_LOG_IMPL(logger);
|
||||
|
||||
#define MATRIX(...) (float[]) { __VA_ARGS__ }
|
||||
|
||||
#include "channelmix-ops.c"
|
||||
static void dump_matrix(struct channelmix *mix)
|
||||
static void dump_matrix(struct channelmix *mix, float *coeff)
|
||||
{
|
||||
uint32_t i, j;
|
||||
|
||||
for (i = 0; i < mix->dst_chan; i++) {
|
||||
for (j = 0; j < mix->src_chan; j++) {
|
||||
float v = mix->matrix_orig[i][j];
|
||||
spa_log_debug(mix->log, "%d %d: %f", i, j, v);
|
||||
spa_log_debug(mix->log, "%d %d: %f <-> %f", i, j, v, *coeff);
|
||||
spa_assert(fabs(v - *coeff) < 0.000001);
|
||||
coeff++;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -61,61 +65,138 @@ static void test_mix(uint32_t src_chan, uint32_t src_mask, uint32_t dst_chan, ui
|
|||
mix.log = &logger.log;
|
||||
|
||||
channelmix_init(&mix);
|
||||
dump_matrix(&mix);
|
||||
dump_matrix(&mix, coeff);
|
||||
}
|
||||
|
||||
static void test_1_N(void)
|
||||
{
|
||||
test_mix(1, _M(MONO), 2, _M(FL)|_M(FR), (float[]) { 1.0, 1.0 });
|
||||
test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE), (float[]) { 1.0, 1.0, 0.0 });
|
||||
test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), (float[]) { 1.0, 1.0, 1.0, 1.0 });
|
||||
test_mix(1, _M(MONO), 2, _M(FL)|_M(FR),
|
||||
MATRIX(0.707107, 0.707107));
|
||||
test_mix(1, _M(MONO), 3, _M(FL)|_M(FR)|_M(LFE),
|
||||
MATRIX(0.707107, 0.707107, 0.0));
|
||||
test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
|
||||
MATRIX(0.0, 0.0, 1.0, 0.0));
|
||||
test_mix(1, _M(MONO), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
|
||||
MATRIX(0.707107, 0.707107, 0.0, 0.0));
|
||||
test_mix(1, _M(MONO), 12, 0,
|
||||
MATRIX(1.0, 1.0, 1.0, 1.0, 1.0, 1.0,
|
||||
1.0, 1.0, 1.0, 1.0, 1.0, 1.0));
|
||||
}
|
||||
|
||||
static void test_N_1(void)
|
||||
{
|
||||
test_mix(1, _M(MONO), 1, _M(MONO), (float[]) { 1.0 });
|
||||
test_mix(1, _M(MONO), 1, _M(FC), (float[]) { 1.0 });
|
||||
test_mix(1, _M(FC), 1, _M(MONO), (float[]) { 1.0 });
|
||||
test_mix(1, _M(FC), 1, _M(FC), (float[]) { 1.0 });
|
||||
test_mix(2, _M(FL)|_M(FR), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(1, _M(MONO), 1, _M(MONO),
|
||||
MATRIX(1.0));
|
||||
test_mix(1, _M(MONO), 1, _M(FC),
|
||||
MATRIX(1.0));
|
||||
test_mix(1, _M(FC), 1, _M(MONO),
|
||||
MATRIX(1.0));
|
||||
test_mix(1, _M(FC), 1, _M(FC),
|
||||
MATRIX(1.0));
|
||||
test_mix(2, _M(FL)|_M(FR), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107));
|
||||
test_mix(12, 0, 1, _M(MONO),
|
||||
MATRIX(0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.083333,
|
||||
0.083333, 0.083333, 0.083333, 0.083333, 0.083333, 0.0833333));
|
||||
}
|
||||
|
||||
static void test_3p1_N(void)
|
||||
{
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 3, _M(FL)|_M(FR)|_M(LFE), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107, 1.0, 0.0));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0 ));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 3, _M(FL)|_M(FR)|_M(LFE),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0 ));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
|
||||
MATRIX(1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0,));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0,));
|
||||
}
|
||||
|
||||
static void test_4_N(void)
|
||||
{
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 3, _M(FL)|_M(FR)|_M(LFE), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), (float[]) { 0.5, 0.5 });
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107, 0.5, 0.5));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107, 0.5, 0.5));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.0, 0.707107));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.0, 0.707107));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 3, _M(FL)|_M(FR)|_M(LFE),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.0, 0.707107,
|
||||
0.0, 0.0, 0.0, 0.0));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
|
||||
MATRIX(1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0));
|
||||
test_mix(4, _M(FL)|_M(FR)|_M(RL)|_M(RR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.0, 0.707107,
|
||||
0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0));
|
||||
}
|
||||
|
||||
static void test_5p1_N(void)
|
||||
{
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 3, _M(FL)|_M(FR)|_M(LFE), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 5, _M(FL)|_M(FR)|_M(FC)|_M(SL)|_M(SR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 3, _M(FL)|_M(FR)|_M(LFE),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107,
|
||||
0.0, 0.0, 0.0, 1.0, 0.0, 0.0));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(LFE)|_M(FC),
|
||||
MATRIX(1.0, 0.0, 0.0, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0, 0.0, 0.707107,
|
||||
0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0, 0.0, 0.0));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 4, _M(FL)|_M(FR)|_M(RL)|_M(RR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 5, _M(FL)|_M(FR)|_M(FC)|_M(SL)|_M(SR),
|
||||
MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
|
||||
test_mix(6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR), 6, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR),
|
||||
MATRIX(1.0, 0.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 1.0, 0.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 1.0, 0.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 1.0, 0.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 1.0, 0.0,
|
||||
0.0, 0.0, 0.0, 0.0, 0.0, 1.0));
|
||||
}
|
||||
|
||||
static void test_7p1_N(void)
|
||||
{
|
||||
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 1, _M(MONO), (float[]) { 0.5, 0.5 });
|
||||
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR), (float[]) { 0.5, 0.5 });
|
||||
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 1, _M(MONO),
|
||||
MATRIX(0.707107, 0.707107, 1.0, 0.0, 0.5, 0.5, 0.5, 0.5));
|
||||
test_mix(8, _M(FL)|_M(FR)|_M(LFE)|_M(FC)|_M(SL)|_M(SR)|_M(RL)|_M(RR), 2, _M(FL)|_M(FR),
|
||||
MATRIX(1.0, 0.0, 0.707107, 0.0, 0.707107, 0.0, 0.707107, 0.0,
|
||||
0.0, 1.0, 0.707107, 0.0, 0.0, 0.707107, 0.0, 0.707107));
|
||||
}
|
||||
|
||||
int main(int argc, char *argv[])
|
||||
|
|
Loading…
Reference in a new issue