diff --git a/spa/plugins/audioconvert/channelmix-ops.c b/spa/plugins/audioconvert/channelmix-ops.c index 5ec08a7f8..138fb5b3d 100644 --- a/spa/plugins/audioconvert/channelmix-ops.c +++ b/spa/plugins/audioconvert/channelmix-ops.c @@ -166,14 +166,14 @@ static int make_matrix(struct channelmix *mix) float clev = SQRT1_2; float slev = SQRT1_2; float llev = 0.5f; - float max = 0.0f; + float max; spa_log_debug(mix->log, "src-mask:%08"PRIx64" dst-mask:%08"PRIx64, src_mask, dst_mask); - if ((src_mask & _MASK(MONO)) == _MASK(MONO)) + if ((src_mask & _MASK(MONO)) == _MASK(MONO)) src_mask = _MASK(FC); - if ((dst_mask & _MASK(MONO)) == _MASK(MONO)) + if ((dst_mask & _MASK(MONO)) == _MASK(MONO)) dst_mask = _MASK(FC); for (i = 0; i < NUM_CHAN; i++) { @@ -330,6 +330,7 @@ static int make_matrix(struct channelmix *mix) } } + max = 0.0f; for (ic = 0, i = 0; i < NUM_CHAN; i++) { float sum = 0.0f; if ((dst_mask & (1UL << (i + 2))) == 0) diff --git a/spa/plugins/audioconvert/meson.build b/spa/plugins/audioconvert/meson.build index 9013c348a..b843afe94 100644 --- a/spa/plugins/audioconvert/meson.build +++ b/spa/plugins/audioconvert/meson.build @@ -94,6 +94,7 @@ test_lib = static_library('test_lib', test_apps = [ 'test-audioadapter', 'test-audioconvert', + 'test-channelmix', 'test-fmt-ops', 'test-resample', ] diff --git a/spa/plugins/audioconvert/test-channelmix.c b/spa/plugins/audioconvert/test-channelmix.c new file mode 100644 index 000000000..87b2934a3 --- /dev/null +++ b/spa/plugins/audioconvert/test-channelmix.c @@ -0,0 +1,133 @@ +/* Spa + * + * Copyright © 2019 Wim Taymans + * + * Permission is hereby granted, free of charge, to any person obtaining a + * copy of this software and associated documentation files (the "Software"), + * to deal in the Software without restriction, including without limitation + * the rights to use, copy, modify, merge, publish, distribute, sublicense, + * and/or sell copies of the Software, and to permit persons to whom the + * Software is furnished to do so, subject to the following conditions: + * + * The above copyright notice and this permission notice (including the next + * paragraph) shall be included in all copies or substantial portions of the + * Software. + * + * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR + * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, + * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL + * THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER + * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING + * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER + * DEALINGS IN THE SOFTWARE. + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + +SPA_LOG_IMPL(logger); + +#include "channelmix-ops.c" +static void dump_matrix(struct channelmix *mix) +{ + 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); + } + } +} + +static void test_mix(uint32_t src_chan, uint32_t src_mask, uint32_t dst_chan, uint32_t dst_mask, float *coeff) +{ + struct channelmix mix; + + spa_log_debug(&logger.log, "start %d->%d (%08x -> %08x)", src_chan, dst_chan, src_mask, dst_mask); + + spa_zero(mix); + mix.src_chan = src_chan; + mix.dst_chan = dst_chan; + mix.src_mask = src_mask; + mix.dst_mask = dst_mask; + mix.log = &logger.log; + + channelmix_init(&mix); + dump_matrix(&mix); +} + +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 }); +} + +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 }); +} + +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 }); +} + +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 }); +} + +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 }); +} + +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 }); +} + +int main(int argc, char *argv[]) +{ + logger.log.level = SPA_LOG_LEVEL_TRACE; + + test_1_N(); + test_N_1(); + test_3p1_N(); + test_4_N(); + test_5p1_N(); + test_7p1_N(); + + return 0; +}