audiomixer: rewrite the mixer functions

Let the mixer functions accumulate the intermediate results into a
larger size variable and then clamp to the final precission. This avoids
distortions because of intermediate clamping.

Although the access pattern of the reads are no longer sequential, the
writes are sequential and we don't need to read intermediate values.
Together with the avoided clamping this is probably faster overall.

Add a unit test for the various cases.
This commit is contained in:
Wim Taymans 2022-07-09 18:11:13 +02:00
parent 3ffb9f4b26
commit 371b5a1836
4 changed files with 376 additions and 48 deletions

View file

@ -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);