diff --git a/spa/plugins/audiomixer/mix-ops-c.c b/spa/plugins/audiomixer/mix-ops-c.c index f2cfe5602..6c7c88e9b 100644 --- a/spa/plugins/audiomixer/mix-ops-c.c +++ b/spa/plugins/audiomixer/mix-ops-c.c @@ -30,6 +30,85 @@ #include "mix-ops.h" +void +mix_s8_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; + int8_t *d = dst; + + if (n_src == 0) + memset(dst, 0, n_samples * ops->n_channels * sizeof(int8_t)); + else if (dst != src[0]) + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(int8_t)); + + for (i = 1; i < n_src; i++) { + const int8_t *s = src[i]; + for (n = 0; n < n_samples * ops->n_channels; n++) + d[n] = S8_MIX(d[n], s[n]); + } +} + +void +mix_s16_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; + int16_t *d = dst; + + if (n_src == 0) + memset(dst, 0, n_samples * ops->n_channels * sizeof(int16_t)); + else if (dst != src[0]) + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(int16_t)); + + for (i = 1; i < n_src; i++) { + const int16_t *s = src[i]; + for (n = 0; n < n_samples * ops->n_channels; n++) + d[n] = S16_MIX(d[n], s[n]); + } +} + +void +mix_s24_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; + uint8_t *d = dst; + + if (n_src == 0) + memset(dst, 0, n_samples * ops->n_channels * sizeof(uint8_t) * 3); + else if (dst != src[0]) + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(uint8_t) * 3); + + for (i = 1; i < n_src; i++) { + const uint8_t *s = src[i]; + for (n = 0; n < n_samples * ops->n_channels; n++) { + write_s24(d, S24_MIX(read_s24(d), read_s24(s))); + d += 3; + s += 3; + } + } +} + +void +mix_s32_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; + int32_t *d = dst; + + if (n_src == 0) + memset(dst, 0, n_samples * ops->n_channels * sizeof(int32_t)); + else if (dst != src[0]) + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(int32_t)); + + for (i = 1; i < n_src; i++) { + const int32_t *s = src[i]; + for (n = 0; n < n_samples * ops->n_channels; n++) + d[n] = S32_MIX(d[n], s[n]); + } +} + void mix_f32_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRICT src[], uint32_t n_src, uint32_t n_samples) @@ -38,14 +117,14 @@ mix_f32_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRIC float *d = dst; if (n_src == 0) - memset(dst, 0, n_samples * sizeof(float)); + memset(dst, 0, n_samples * ops->n_channels * sizeof(float)); else if (dst != src[0]) - memcpy(dst, src[0], n_samples * sizeof(float)); + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(float)); for (i = 1; i < n_src; i++) { const float *s = src[i]; - for (n = 0; n < n_samples; n++) - d[n] += s[n]; + for (n = 0; n < n_samples * ops->n_channels; n++) + d[n] = F32_MIX(d[n], s[n]); } } @@ -57,13 +136,13 @@ mix_f64_c(struct mix_ops *ops, void * SPA_RESTRICT dst, const void * SPA_RESTRIC double *d = dst; if (n_src == 0) - memset(dst, 0, n_samples * sizeof(double)); + memset(dst, 0, n_samples * ops->n_channels * sizeof(double)); else if (dst != src[0]) - memcpy(dst, src[0], n_samples * sizeof(double)); + memcpy(dst, src[0], n_samples * ops->n_channels * sizeof(double)); for (i = 1; i < n_src; i++) { const double *s = src[i]; - for (n = 0; n < n_samples; n++) - d[n] += s[n]; + for (n = 0; n < n_samples * ops->n_channels; n++) + d[n] = F64_MIX(d[n], s[n]); } } diff --git a/spa/plugins/audiomixer/mix-ops.c b/spa/plugins/audiomixer/mix-ops.c index 3d1c0f8e5..c5281abaf 100644 --- a/spa/plugins/audiomixer/mix-ops.c +++ b/spa/plugins/audiomixer/mix-ops.c @@ -54,15 +54,32 @@ static struct mix_info mix_table[] = { SPA_AUDIO_FORMAT_F32, 1, SPA_CPU_FLAG_SSE, 4, mix_f32_sse }, { SPA_AUDIO_FORMAT_F32P, 1, SPA_CPU_FLAG_SSE, 4, mix_f32_sse }, #endif - { SPA_AUDIO_FORMAT_F32, 1, 0, 4, mix_f32_c }, - { SPA_AUDIO_FORMAT_F32P, 1, 0, 4, mix_f32_c }, + { SPA_AUDIO_FORMAT_F32, 0, 0, 4, mix_f32_c }, + { SPA_AUDIO_FORMAT_F32P, 0, 0, 4, mix_f32_c }, + /* f64 */ #if defined (HAVE_SSE2) { SPA_AUDIO_FORMAT_F64, 1, SPA_CPU_FLAG_SSE2, 8, mix_f64_sse2 }, { SPA_AUDIO_FORMAT_F64P, 1, SPA_CPU_FLAG_SSE2, 8, mix_f64_sse2 }, #endif - { SPA_AUDIO_FORMAT_F64, 1, 0, 8, mix_f64_c }, - { SPA_AUDIO_FORMAT_F64P, 1, 0, 8, mix_f64_c }, + { SPA_AUDIO_FORMAT_F64, 0, 0, 8, mix_f64_c }, + { SPA_AUDIO_FORMAT_F64P, 0, 0, 8, mix_f64_c }, + + /* s8 */ + { SPA_AUDIO_FORMAT_S8, 0, 0, 1, mix_s8_c }, + { SPA_AUDIO_FORMAT_S8P, 0, 0, 1, mix_s8_c }, + + /* s16 */ + { SPA_AUDIO_FORMAT_S16, 0, 0, 2, mix_s16_c }, + { SPA_AUDIO_FORMAT_S16P, 0, 0, 2, mix_s16_c }, + + /* s24 */ + { SPA_AUDIO_FORMAT_S24, 0, 0, 3, mix_s24_c }, + { SPA_AUDIO_FORMAT_S24P, 0, 0, 3, mix_s24_c }, + + /* s32 */ + { SPA_AUDIO_FORMAT_S32, 0, 0, 4, mix_s32_c }, + { SPA_AUDIO_FORMAT_S32P, 0, 0, 4, mix_s32_c }, }; #define MATCH_CHAN(a,b) ((a) == 0 || (a) == (b)) diff --git a/spa/plugins/audiomixer/mix-ops.h b/spa/plugins/audiomixer/mix-ops.h index 0c878eeca..000f13392 100644 --- a/spa/plugins/audiomixer/mix-ops.h +++ b/spa/plugins/audiomixer/mix-ops.h @@ -24,6 +24,50 @@ #include +static inline int32_t read_s24(const void *src) +{ + const int8_t *s = src; +#if __BYTE_ORDER == __LITTLE_ENDIAN + return (((int32_t)s[2] << 16) | ((uint32_t)(uint8_t)s[1] << 8) | (uint32_t)(uint8_t)s[0]); +#else + return (((int32_t)s[0] << 16) | ((uint32_t)(uint8_t)s[1] << 8) | (uint32_t)(uint8_t)s[2]); +#endif +} + +static inline void write_s24(void *dst, int32_t val) +{ + uint8_t *d = dst; +#if __BYTE_ORDER == __LITTLE_ENDIAN + d[0] = (uint8_t) (val); + d[1] = (uint8_t) (val >> 8); + d[2] = (uint8_t) (val >> 16); +#else + d[0] = (uint8_t) (val >> 16); + d[1] = (uint8_t) (val >> 8); + d[2] = (uint8_t) (val); +#endif +} + +#define S8_MIN -127 +#define S8_MAX 127 +#define S8_MIX(a, b) (int8_t)(SPA_CLAMP((int16_t)(a) + (int16_t)(b), S8_MIN, S8_MAX)) + +#define S16_MIN -32767 +#define S16_MAX 32767 +#define S16_MIX(a, b) (int16_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S16_MIN, S16_MAX)) + +#define S24_MIN -8388607 +#define S24_MAX 8388607 +#define S24_MIX(a, b) (int32_t)(SPA_CLAMP((int32_t)(a) + (int32_t)(b), S24_MIN, S24_MAX)) + +#define S32_MIN -2147483647 +#define S32_MAX 2147483647 +#define S32_MIX(a, b) (int32_t)(SPA_CLAMP((int64_t)(a) + (int64_t)(b), S32_MIN, S32_MAX)) + +#define F32_MIX(a, b) (float)((float)(a) + (float)(b)) + +#define F64_MIX(a, b) (double)((double)(a) + (double)(b)) + struct mix_ops { uint32_t fmt; uint32_t n_channels; @@ -50,6 +94,10 @@ void mix_##name##_##arch(struct mix_ops *ops, void * SPA_RESTRICT dst, \ const void * SPA_RESTRICT src[], uint32_t n_src, \ uint32_t n_samples) \ +DEFINE_FUNCTION(s8, c); +DEFINE_FUNCTION(s16, c); +DEFINE_FUNCTION(s24, c); +DEFINE_FUNCTION(s32, c); DEFINE_FUNCTION(f32, c); DEFINE_FUNCTION(f64, c);