From 68f883ff7764906a41f4e7c6be8fb3036fd4a4d6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 11 Jul 2022 17:19:28 +0200 Subject: [PATCH] audioconvert: fix dither scale Rectangular dither should be [-0.5, 0.5] Triangular dither should be [-1.0, 1.0] Noise should add extra bits. --- spa/plugins/audioconvert/fmt-ops-c.c | 1 + spa/plugins/audioconvert/fmt-ops-sse2.c | 4 +++- spa/plugins/audioconvert/fmt-ops.c | 5 ++++- spa/plugins/audioconvert/test-fmt-ops.c | 16 +++++++++++++++- 4 files changed, 23 insertions(+), 3 deletions(-) diff --git a/spa/plugins/audioconvert/fmt-ops-c.c b/spa/plugins/audioconvert/fmt-ops-c.c index f37a41523..45bbf8ee9 100644 --- a/spa/plugins/audioconvert/fmt-ops-c.c +++ b/spa/plugins/audioconvert/fmt-ops-c.c @@ -237,6 +237,7 @@ static inline void update_dither_c(struct convert *conv, uint32_t n_samples) uint32_t *state = &conv->random[0]; if (conv->method < DITHER_METHOD_TRIANGULAR) { + scale *= 0.5f; for (n = 0; n < n_samples; n++) dither[n] = lcnoise(state) * scale; } else { diff --git a/spa/plugins/audioconvert/fmt-ops-sse2.c b/spa/plugins/audioconvert/fmt-ops-sse2.c index accff00b3..23806b8eb 100644 --- a/spa/plugins/audioconvert/fmt-ops-sse2.c +++ b/spa/plugins/audioconvert/fmt-ops-sse2.c @@ -585,11 +585,12 @@ static inline void update_dither_sse2(struct convert *conv, uint32_t n_samples) { uint32_t n; const uint32_t *r = SPA_PTR_ALIGN(conv->random, 16, uint32_t); + __m128 out[1]; float *dither = SPA_PTR_ALIGN(conv->dither, 16, float); - __m128 scale = _mm_set1_ps(conv->scale), out[1]; __m128i in[2]; if (conv->method < DITHER_METHOD_TRIANGULAR) { + __m128 scale = _mm_set1_ps(conv->scale * 0.5f); for (n = 0; n < n_samples; n += 4) { in[0] = _MM_XORSHIFT_EPI32(r); out[0] = _mm_cvtepi32_ps(_MM_XORSHIFT_EPI32(r)); @@ -597,6 +598,7 @@ static inline void update_dither_sse2(struct convert *conv, uint32_t n_samples) _mm_store_ps(&dither[n], out[0]); } } else { + __m128 scale = _mm_set1_ps(conv->scale); for (n = 0; n < n_samples; n += 4) { in[0] = _mm_add_epi32( _MM_XORSHIFT_EPI32(r), _MM_XORSHIFT_EPI32(r)); out[0] = _mm_cvtepi32_ps(in[0]); diff --git a/spa/plugins/audioconvert/fmt-ops.c b/spa/plugins/audioconvert/fmt-ops.c index f6e324708..0e4f57c17 100644 --- a/spa/plugins/audioconvert/fmt-ops.c +++ b/spa/plugins/audioconvert/fmt-ops.c @@ -394,7 +394,10 @@ int convert_init(struct convert *conv) const struct conv_info *info; uint32_t i, dither_flags; - conv->scale = 1.0f / (float)(INT32_MAX >> conv->noise); + conv->scale = 1.0f / (float)(INT32_MAX); + + if (conv->noise > 0) + conv->scale *= (1 << (conv->noise + 1)); /* disable dither if not needed */ if (!need_dither(conv->dst_fmt)) diff --git a/spa/plugins/audioconvert/test-fmt-ops.c b/spa/plugins/audioconvert/test-fmt-ops.c index a271805ba..1880e16a1 100644 --- a/spa/plugins/audioconvert/test-fmt-ops.c +++ b/spa/plugins/audioconvert/test-fmt-ops.c @@ -632,6 +632,7 @@ static void run_test_noise(uint32_t fmt, uint32_t noise, uint32_t flags) const void *ip[N_CHANNELS]; void *op[N_CHANNELS]; uint32_t i, range; + bool all_zero; spa_zero(conv); @@ -653,35 +654,47 @@ static void run_test_noise(uint32_t fmt, uint32_t noise, uint32_t flags) range = (1 << conv.noise) - 1; + all_zero = true; for (i = 0; i < conv.n_channels * N_SAMPLES; i++) { switch (fmt) { case SPA_AUDIO_FORMAT_S8: { int8_t *d = (int8_t *)samp_out; + if (d[i] != 0) + all_zero = false; spa_assert_se(SPA_ABS(d[i] - 0) <= (int8_t)range); break; } case SPA_AUDIO_FORMAT_U8: { uint8_t *d = (uint8_t *)samp_out; + if (d[i] != 0x80) + all_zero = false; spa_assert_se((int8_t)SPA_ABS(d[i] - 0x80) <= (int8_t)(range<<1)); break; } case SPA_AUDIO_FORMAT_S16: { int16_t *d = (int16_t *)samp_out; + if (d[i] != 0) + all_zero = false; spa_assert_se(SPA_ABS(d[i] - 0) <= (int16_t)range); break; } case SPA_AUDIO_FORMAT_S24: { int24_t *d = (int24_t *)samp_out; - spa_assert_se(SPA_ABS(s24_to_s32(d[i]) - 0) <= (int32_t)range); + int32_t t = s24_to_s32(d[i]); + if (t != 0) + all_zero = false; + spa_assert_se(SPA_ABS(t - 0) <= (int32_t)range); break; } case SPA_AUDIO_FORMAT_S32: { int32_t *d = (int32_t *)samp_out; + if (d[i] != 0) + all_zero = false; spa_assert_se(SPA_ABS(d[i] - 0) <= (int32_t)(range << 8)); break; } @@ -690,6 +703,7 @@ static void run_test_noise(uint32_t fmt, uint32_t noise, uint32_t flags) break; } } + spa_assert_se(all_zero == false); convert_free(&conv); }