diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index 51f843c4e..70260e07d 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -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++) { diff --git a/spa/plugins/audioconvert/channelmix.c b/spa/plugins/audioconvert/channelmix.c index 30c94ef67..c837c350f 100644 --- a/spa/plugins/audioconvert/channelmix.c +++ b/spa/plugins/audioconvert/channelmix.c @@ -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); diff --git a/spa/plugins/audioconvert/test-channelmix.c b/spa/plugins/audioconvert/test-channelmix.c index 87b2934a3..fa279cd1d 100644 --- a/spa/plugins/audioconvert/test-channelmix.c +++ b/spa/plugins/audioconvert/test-channelmix.c @@ -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[])