diff --git a/spa/plugins/audiomixer/meson.build b/spa/plugins/audiomixer/meson.build index 9e1d12d59..12a8d9e61 100644 --- a/spa/plugins/audiomixer/meson.build +++ b/spa/plugins/audiomixer/meson.build @@ -1,6 +1,5 @@ audiomixer_sources = [ 'audiomixer.c', - 'mix-ops.c', 'mixer-dsp.c', 'plugin.c' ] @@ -47,11 +46,52 @@ if have_avx and have_fma simd_dependencies += audiomixer_avx endif -audiomixerlib = shared_library('spa-audiomixer', +audiomixer_lib = static_library('audiomixer', + ['mix-ops.c' ], + c_args : [ simd_cargs, '-O3'], + link_with : simd_dependencies, + include_directories : [configinc], + dependencies : [ spa_dep ], + install : false + ) +audiomixer_dep = declare_dependency(link_with: audiomixer_lib) + +spa_audiomixer_lib = shared_library('spa-audiomixer', audiomixer_sources, c_args : simd_cargs, link_with : simd_dependencies, - dependencies : [ spa_dep, mathlib ], + dependencies : [ spa_dep, mathlib, audiomixer_dep ], install : true, install_dir : spa_plugindir / 'audiomixer' ) +spa_audiomixer_dep = declare_dependency(link_with: spa_audiomixer_lib) + +test_apps = [ + 'test-mix-ops', + ] + +foreach a : test_apps + test(a, + executable(a, a + '.c', + dependencies : [ spa_dep, dl_lib, pthread_lib, mathlib, audiomixer_dep ], + include_directories : [ configinc ], + link_with : [ test_lib ], + install_rpath : spa_plugindir / 'audiomixer', + c_args : [ simd_cargs ], + install : installed_tests_enabled, + install_dir : installed_tests_execdir / 'audiomixer'), + env : [ + 'SPA_PLUGIN_DIR=@0@'.format(spa_dep.get_variable('plugindir')), + ]) + + if installed_tests_enabled + test_conf = configuration_data() + test_conf.set('exec', installed_tests_execdir / 'audiomixer' / a) + configure_file( + input: installed_tests_template, + output: a + '.test', + install_dir: installed_tests_metadir / 'audiomixer', + configuration: test_conf + ) + endif +endforeach diff --git a/spa/plugins/audiomixer/mix-ops-c.c b/spa/plugins/audiomixer/mix-ops-c.c index 56c238ea2..1cafd208d 100644 --- a/spa/plugins/audiomixer/mix-ops-c.c +++ b/spa/plugins/audiomixer/mix-ops-c.c @@ -30,34 +30,39 @@ #include "mix-ops.h" -#define MAKE_FUNC(name,type,func) \ +#define MAKE_FUNC(name,type,atype,accum,clamp,zero) \ void mix_ ##name## _c(struct mix_ops *ops, \ void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], \ uint32_t n_src, uint32_t n_samples) \ { \ uint32_t i, n; \ type *d = dst; \ + const type **s = (const type **)src; \ n_samples *= ops->n_channels; \ - if (n_src == 0) \ + if (n_src == 0 && zero) \ memset(dst, 0, n_samples * sizeof(type)); \ - else if (dst != src[0]) \ - spa_memcpy(dst, src[0], n_samples * sizeof(type)); \ - for (i = 1; i < n_src; i++) { \ - const type *s = src[i]; \ - for (n = 0; n < n_samples; n++) \ - d[n] = func (d[n], s[n]); \ + else if (n_src == 1) { \ + if (dst != src[0]) \ + spa_memcpy(dst, src[0], n_samples * sizeof(type)); \ + } else { \ + for (n = 0; n < n_samples; n++) { \ + atype ac = 0; \ + for (i = 0; i < n_src; i++) \ + ac = accum (ac, s[i][n]); \ + d[n] = clamp (ac); \ + } \ } \ } -MAKE_FUNC(s8, int8_t, S8_MIX); -MAKE_FUNC(u8, uint8_t, U8_MIX); -MAKE_FUNC(s16, int16_t, S16_MIX); -MAKE_FUNC(u16, uint16_t, U16_MIX); -MAKE_FUNC(s24, int24_t, S24_MIX); -MAKE_FUNC(u24, uint24_t, U24_MIX); -MAKE_FUNC(s32, int32_t, S32_MIX); -MAKE_FUNC(u32, uint32_t, U32_MIX); -MAKE_FUNC(s24_32, int32_t, S24_32_MIX); -MAKE_FUNC(u24_32, uint32_t, U24_32_MIX); -MAKE_FUNC(f32, float, F32_MIX); -MAKE_FUNC(f64, double, F64_MIX); +MAKE_FUNC(s8, int8_t, int16_t, S8_ACCUM, S8_CLAMP, true); +MAKE_FUNC(u8, uint8_t, int16_t, U8_ACCUM, U8_CLAMP, false); +MAKE_FUNC(s16, int16_t, int32_t, S16_ACCUM, S16_CLAMP, true); +MAKE_FUNC(u16, uint16_t, int16_t, U16_ACCUM, U16_CLAMP, false); +MAKE_FUNC(s24, int24_t, int32_t, S24_ACCUM, S24_CLAMP, false); +MAKE_FUNC(u24, uint24_t, int32_t, U24_ACCUM, U24_CLAMP, false); +MAKE_FUNC(s32, int32_t, int64_t, S32_ACCUM, S32_CLAMP, true); +MAKE_FUNC(u32, uint32_t, int64_t, U32_ACCUM, U32_CLAMP, false); +MAKE_FUNC(s24_32, int32_t, int32_t, S24_32_ACCUM, S24_32_CLAMP, true); +MAKE_FUNC(u24_32, uint32_t, int32_t, U24_32_ACCUM, U24_32_CLAMP, false); +MAKE_FUNC(f32, float, float, F32_ACCUM, F32_CLAMP, true); +MAKE_FUNC(f64, double, double, F64_ACCUM, F64_CLAMP, true); diff --git a/spa/plugins/audiomixer/mix-ops.h b/spa/plugins/audiomixer/mix-ops.h index ab6c62725..11e88dcdf 100644 --- a/spa/plugins/audiomixer/mix-ops.h +++ b/spa/plugins/audiomixer/mix-ops.h @@ -75,36 +75,47 @@ static inline int24_t s32_to_s24(int32_t src) } -#define S8_MIN -128 -#define S8_MAX 127 -#define S8_MIX(a,b) (int8_t)(SPA_CLAMP((int16_t)(a) + (int16_t)(b), S8_MIN, S8_MAX)) -#define U8_OFFS 128 -#define U8_MIX(a,b) (uint8_t)((int16_t)S8_MIX((int16_t)(a) - U8_OFFS, (int16_t)(b) - U8_OFFS) + U8_OFFS) +#define S8_MIN -128 +#define S8_MAX 127 +#define S8_ACCUM(a,b) ((a) + (int16_t)(b)) +#define S8_CLAMP(a) (int8_t)(SPA_CLAMP((a), S8_MIN, S8_MAX)) +#define U8_OFFS 128 +#define U8_ACCUM(a,b) ((a) + ((int16_t)(b) - U8_OFFS)) +#define U8_CLAMP(a) (uint8_t)(SPA_CLAMP((a), S8_MIN, S8_MAX) + U8_OFFS) -#define S16_MIN -32768 -#define S16_MAX 32767 -#define S16_MIX(a,b) (int16_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S16_MIN, S16_MAX)) -#define U16_OFFS 32768 -#define U16_MIX(a,b) (uint16_t)((int32_t)S16_MIX((int32_t)(a) - U16_OFFS, (int32_t)(b) - U16_OFFS) + U16_OFFS) +#define S16_MIN -32768 +#define S16_MAX 32767 +#define S16_ACCUM(a,b) ((a) + (int32_t)(b)) +#define S16_CLAMP(a) (int16_t)(SPA_CLAMP((a), S16_MIN, S16_MAX)) +#define U16_OFFS 32768 +#define U16_ACCUM(a,b) ((a) + ((int32_t)(b) - U16_OFFS)) +#define U16_CLAMP(a) (uint16_t)(SPA_CLAMP((a), S16_MIN, S16_MAX) + U16_OFFS) -#define S24_MIN -8388608 -#define S24_MAX 8388607 -#define S24_MIX_32(a,b) (int32_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S24_MIN, S24_MAX)) -#define S24_MIX(a,b) s32_to_s24(S24_MIX_32(s24_to_s32(a), s24_to_s32(b))) -#define U24_OFFS 8388608 -#define U24_MIX(a,b) u32_to_u24(S24_MIX_32((int32_t)u24_to_u32(a) - U24_OFFS, (int32_t)u24_to_u32(b) - U24_OFFS) + U24_OFFS) +#define S24_32_MIN -8388608 +#define S24_32_MAX 8388607 +#define S24_32_ACCUM(a,b) ((a) + (int32_t)(b)) +#define S24_32_CLAMP(a) (int32_t)(SPA_CLAMP((a), S24_32_MIN, S24_32_MAX)) +#define U24_32_OFFS 8388608 +#define U24_32_ACCUM(a,b) ((a) + ((int32_t)(b) - U24_32_OFFS)) +#define U24_32_CLAMP(a) (uint32_t)(SPA_CLAMP((a), S24_32_MIN, S24_32_MAX) + U24_32_OFFS) -#define S32_MIN -2147483648 -#define S32_MAX 2147483647 -#define S32_MIX(a,b) (int32_t)(SPA_CLAMP((int64_t)(a) + (int64_t)(b), S32_MIN, S32_MAX)) -#define U32_OFFS 2147483648 -#define U32_MIX(a,b) (uint32_t)((int64_t)S32_MIX((int64_t)(a) - U32_OFFS, (int64_t)(b) - U32_OFFS) + U32_OFFS) +#define S24_ACCUM(a,b) S24_32_ACCUM(a, s24_to_s32(b)) +#define S24_CLAMP(a) s32_to_s24(S24_32_CLAMP(a)) +#define U24_ACCUM(a,b) U24_32_ACCUM(a, u24_to_u32(b)) +#define U24_CLAMP(a) u32_to_u24(U24_32_CLAMP(a)) -#define S24_32_MIX(a,b) (int32_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S24_MIN, S24_MAX)) -#define U24_32_MIX(a,b) (uint32_t)((int32_t)S24_32_MIX((int32_t)(a) - U24_OFFS, (int32_t)(b) - U24_OFFS) + U24_OFFS) +#define S32_MIN -2147483648 +#define S32_MAX 2147483647 +#define S32_ACCUM(a,b) ((a) + (int64_t)(b)) +#define S32_CLAMP(a) (int32_t)(SPA_CLAMP((a), S32_MIN, S32_MAX)) +#define U32_OFFS 2147483648 +#define U32_ACCUM(a,b) ((a) + ((int64_t)(b) - U32_OFFS)) +#define U32_CLAMP(a) (uint32_t)(SPA_CLAMP((a), S32_MIN, S32_MAX) + U32_OFFS) -#define F32_MIX(a, b) (float)((float)(a) + (float)(b)) -#define F64_MIX(a, b) (double)((double)(a) + (double)(b)) +#define F32_ACCUM(a,b) ((a) + (b)) +#define F32_CLAMP(a) (a) +#define F64_ACCUM(a,b) ((a) + (b)) +#define F64_CLAMP(a) (a) struct mix_ops { uint32_t fmt; diff --git a/spa/plugins/audiomixer/test-mix-ops.c b/spa/plugins/audiomixer/test-mix-ops.c new file mode 100644 index 000000000..0d71de832 --- /dev/null +++ b/spa/plugins/audiomixer/test-mix-ops.c @@ -0,0 +1,272 @@ +/* Spa + * + * Copyright © 2022 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 "config.h" + +#include +#include +#include +#include +#include +#include + +#include + +#include "test-helper.h" +#include "mix-ops.c" + +static uint32_t cpu_flags; + +#define N_SAMPLES 1024 + +static uint8_t samp_out[N_SAMPLES * 8]; + +static void compare_mem(int i, int j, const void *m1, const void *m2, size_t size) +{ + int res = memcmp(m1, m2, size); + if (res != 0) { + fprintf(stderr, "%d %d %zd:\n", i, j, size); + spa_debug_mem(0, m1, size); + spa_debug_mem(0, m2, size); + } + spa_assert_se(res == 0); +} + +static int run_test(const char *name, const void *src[], uint32_t n_src, const void *dst, + size_t dst_size, uint32_t n_samples, mix_func_t mix) +{ + struct mix_ops ops; + + ops.fmt = SPA_AUDIO_FORMAT_F32; + ops.n_channels = 1; + ops.cpu_flags = cpu_flags; + mix_ops_init(&ops); + + fprintf(stderr, "%s\n", name); + + mix(&ops, (void *)samp_out, src, n_src, n_samples); + compare_mem(0, 0, samp_out, dst, dst_size); + return 0; +} + +static void test_s8(void) +{ + int8_t out[] = { 0x00, 0x00, 0x00, 0x00 }; + int8_t in_1[] = { 0x00, 0x00, 0x00, 0x00 }; + int8_t in_2[] = { 0x7f, 0x80, 0x40, 0xc0 }; + int8_t in_3[] = { 0x40, 0xc0, 0xc0, 0x40 }; + int8_t in_4[] = { 0xc0, 0x40, 0x40, 0xc0 }; + int8_t out_4[] = { 0x7f, 0x80, 0x40, 0xc0 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_s8_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s8_c); + run_test("test_s8_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s8_c); + run_test("test_s8_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s8_c); +} + +static void test_u8(void) +{ + uint8_t out[] = { 0x80, 0x80, 0x80, 0x80 }; + uint8_t in_1[] = { 0x80, 0x80, 0x80, 0x80 }; + uint8_t in_2[] = { 0xff, 0x00, 0xc0, 0x40 }; + uint8_t in_3[] = { 0xc0, 0x40, 0x40, 0xc0 }; + uint8_t in_4[] = { 0x40, 0xc0, 0xc0, 0x40 }; + uint8_t out_4[] = { 0xff, 0x00, 0xc0, 0x40 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_u8_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u8_c); + run_test("test_u8_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u8_c); + run_test("test_u8_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u8_c); +} + +static void test_s16(void) +{ + int16_t out[] = { 0x0000, 0x0000, 0x0000, 0x0000 }; + int16_t in_1[] = { 0x0000, 0x0000, 0x0000, 0x0000 }; + int16_t in_2[] = { 0x7fff, 0x8000, 0x4000, 0xc000 }; + int16_t in_3[] = { 0x4000, 0xc000, 0xc000, 0x4000 }; + int16_t in_4[] = { 0xc000, 0x4000, 0x4000, 0xc000 }; + int16_t out_4[] = { 0x7fff, 0x8000, 0x4000, 0xc000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_s16_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s16_c); + run_test("test_s16_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s16_c); + run_test("test_s16_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s16_c); +} + +static void test_u16(void) +{ + uint16_t out[] = { 0x8000, 0x8000, 0x8000, 0x8000 }; + uint16_t in_1[] = { 0x8000, 0x8000, 0x8000 , 0x8000}; + uint16_t in_2[] = { 0xffff, 0x0000, 0xc000, 0x4000 }; + uint16_t in_3[] = { 0xc000, 0x4000, 0x4000, 0xc000 }; + uint16_t in_4[] = { 0x4000, 0xc000, 0xc000, 0x4000 }; + uint16_t out_4[] = { 0xffff, 0x0000, 0xc000, 0x4000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_u16_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u16_c); + run_test("test_u16_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u16_c); + run_test("test_u16_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u16_c); +} + +static void test_s24(void) +{ + int24_t out[] = { S32_TO_S24(0x000000), S32_TO_S24(0x000000), S32_TO_S24(0x000000) }; + int24_t in_1[] = { S32_TO_S24(0x000000), S32_TO_S24(0x000000), S32_TO_S24(0x000000) }; + int24_t in_2[] = { S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000), S32_TO_S24(0x400000) }; + int24_t in_3[] = { S32_TO_S24(0x400000), S32_TO_S24(0xffc00000), S32_TO_S24(0xffc00000) }; + int24_t in_4[] = { S32_TO_S24(0xffc00000), S32_TO_S24(0x400000), S32_TO_S24(0x400000) }; + int24_t out_4[] = { S32_TO_S24(0x7fffff), S32_TO_S24(0xff800000), S32_TO_S24(0x400000) }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_s24_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s24_c); + run_test("test_s24_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s24_c); + run_test("test_s24_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s24_c); +} + +static void test_u24(void) +{ + uint24_t out[] = { U32_TO_U24(0x800000), U32_TO_U24(0x800000), U32_TO_U24(0x800000) }; + uint24_t in_1[] = { U32_TO_U24(0x800000), U32_TO_U24(0x800000), U32_TO_U24(0x800000) }; + uint24_t in_2[] = { U32_TO_U24(0xffffffff), U32_TO_U24(0x000000), U32_TO_U24(0xffc00000) }; + uint24_t in_3[] = { U32_TO_U24(0xffc00000), U32_TO_U24(0x400000), U32_TO_U24(0x400000) }; + uint24_t in_4[] = { U32_TO_U24(0x400000), U32_TO_U24(0xffc00000), U32_TO_U24(0xffc00000) }; + uint24_t out_4[] = { U32_TO_U24(0xffffffff), U32_TO_U24(0x000000), U32_TO_U24(0xffc00000) }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_u24_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u24_c); + run_test("test_u24_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u24_c); + run_test("test_u24_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u24_c); +} + +static void test_s32(void) +{ + int32_t out[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int32_t in_1[] = { 0x00000000, 0x00000000, 0x00000000, 0x00000000 }; + int32_t in_2[] = { 0x7fffffff, 0x80000000, 0x40000000, 0xc0000000 }; + int32_t in_3[] = { 0x40000000, 0xc0000000, 0xc0000000, 0x40000000 }; + int32_t in_4[] = { 0xc0000000, 0x40000000, 0x40000000, 0xc0000000 }; + int32_t out_4[] = { 0x7fffffff, 0x80000000, 0x40000000, 0xc0000000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_s32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s32_c); + run_test("test_s32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s32_c); + run_test("test_s32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s32_c); +} + +static void test_u32(void) +{ + uint32_t out[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + uint32_t in_1[] = { 0x80000000, 0x80000000, 0x80000000, 0x80000000 }; + uint32_t in_2[] = { 0xffffffff, 0x00000000, 0xc0000000, 0x40000000 }; + uint32_t in_3[] = { 0xc0000000, 0x40000000, 0x40000000, 0xc0000000 }; + uint32_t in_4[] = { 0x40000000, 0xc0000000, 0xc0000000, 0x40000000 }; + uint32_t out_4[] = { 0xffffffff, 0x00000000, 0xc0000000, 0x40000000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_u32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u32_c); + run_test("test_u32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u32_c); + run_test("test_u32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u32_c); +} + +static void test_s24_32(void) +{ + int32_t out[] = { 0x000000, 0x000000, 0x000000, 0x000000 }; + int32_t in_1[] = { 0x000000, 0x000000, 0x000000, 0x000000 }; + int32_t in_2[] = { 0x7fffff, 0xff800000, 0x400000, 0xffc00000 }; + int32_t in_3[] = { 0x400000, 0xffc00000, 0xffc00000, 0x400000 }; + int32_t in_4[] = { 0xffc00000, 0x400000, 0x400000, 0xffc00000 }; + int32_t out_4[] = { 0x7fffff, 0xff800000, 0x400000, 0xffc00000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_s24_32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_s24_32_c); + run_test("test_s24_32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_s24_32_c); + run_test("test_s24_32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_s24_32_c); +} + +static void test_u24_32(void) +{ + uint32_t out[] = { 0x800000, 0x800000, 0x800000, 0x800000 }; + uint32_t in_1[] = { 0x800000, 0x800000, 0x800000, 0x800000 }; + uint32_t in_2[] = { 0xffffff, 0x000000, 0xc00000, 0x400000 }; + uint32_t in_3[] = { 0xc00000, 0x400000, 0x400000, 0xc00000 }; + uint32_t in_4[] = { 0x400000, 0xc00000, 0xc00000, 0x400000 }; + uint32_t out_4[] = { 0xffffff, 0x000000, 0xc00000, 0x400000 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_u24_32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_u24_32_c); + run_test("test_u24_32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_u24_32_c); + run_test("test_u24_32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_u24_32_c); +} + +static void test_f32(void) +{ + float out[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float in_1[] = { 0.0f, 0.0f, 0.0f, 0.0f }; + float in_2[] = { 1.0f, -1.0f, 0.5f, -0.5f }; + float in_3[] = { 0.5f, -0.5f, -0.5f, 0.5f }; + float in_4[] = { -0.5f, 1.0f, 0.5f, -0.5f }; + float out_4[] = { 1.0f, -0.5f, 0.5f, -0.5f }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_f32_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_f32_c); + run_test("test_f32_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_f32_c); + run_test("test_f32_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_f32_c); +} + +static void test_f64(void) +{ + double out[] = { 0.0, 0.0, 0.0, 0.0 }; + double in_1[] = { 0.0, 0.0, 0.0, 0.0 }; + double in_2[] = { 1.0, -1.0, 0.5, -0.5 }; + double in_3[] = { 0.5, -0.5, -0.5, 0.5 }; + double in_4[] = { -0.5, 1.0, 0.5, -0.5 }; + double out_4[] = { 1.0, -0.5, 0.5, -0.5 }; + const void *src[6] = { in_1, in_2, in_3, in_4 }; + + run_test("test_f64_0", NULL, 0, out, sizeof(out), SPA_N_ELEMENTS(out), mix_f64_c); + run_test("test_f64_1", src, 1, in_1, sizeof(in_1), SPA_N_ELEMENTS(in_1), mix_f64_c); + run_test("test_f64_4", src, 4, out_4, sizeof(out_4), SPA_N_ELEMENTS(out_4), mix_f64_c); +} + +int main(int argc, char *argv[]) +{ + cpu_flags = get_cpu_flags(); + printf("got get CPU flags %d\n", cpu_flags); + + test_s8(); + test_u8(); + test_s16(); + test_u16(); + test_s24(); + test_u24(); + test_s32(); + test_u32(); + test_s24_32(); + test_u24_32(); + test_f32(); + test_f64(); + + return 0; +}