From ada39f3048464bb499c2b37f64679255ff0057d6 Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Mon, 18 Jul 2022 11:39:24 +0200 Subject: [PATCH] audioconvert: improve noise bits Make a new noise method called PATTERN and use it to add a slow (every 1024 samples) repeating pattern of -1, 0. Only use this method when we don't already use triangular dither. See #2540 --- spa/plugins/audioconvert/fmt-ops-c.c | 34 +++++++++++++++---------- spa/plugins/audioconvert/fmt-ops-sse2.c | 8 +++++- spa/plugins/audioconvert/fmt-ops.c | 20 +++++++++++---- spa/plugins/audioconvert/fmt-ops.h | 1 + 4 files changed, 43 insertions(+), 20 deletions(-) diff --git a/spa/plugins/audioconvert/fmt-ops-c.c b/spa/plugins/audioconvert/fmt-ops-c.c index e79e12137..f3d91d035 100644 --- a/spa/plugins/audioconvert/fmt-ops-c.c +++ b/spa/plugins/audioconvert/fmt-ops-c.c @@ -33,7 +33,7 @@ #include "fmt-ops.h" #include "law.h" -#define MAKE_COPY(size) \ +#define MAKE_COPY(size) \ void conv_copy ##size## d_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -55,7 +55,7 @@ MAKE_COPY(24); MAKE_COPY(32); MAKE_COPY(64); -#define MAKE_D_TO_D(sname,stype,dname,dtype,func) \ +#define MAKE_D_TO_D(sname,stype,dname,dtype,func) \ void conv_ ##sname## d_to_ ##dname## d_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -65,11 +65,11 @@ void conv_ ##sname## d_to_ ##dname## d_c(struct convert *conv, \ const stype *s = src[i]; \ dtype *d = dst[i]; \ for (j = 0; j < n_samples; j++) \ - d[j] = func (s[j]); \ + d[j] = func (s[j]); \ } \ } -#define MAKE_I_TO_I(sname,stype,dname,dtype,func) \ +#define MAKE_I_TO_I(sname,stype,dname,dtype,func) \ void conv_ ##sname## _to_ ##dname## _c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -79,10 +79,10 @@ void conv_ ##sname## _to_ ##dname## _c(struct convert *conv, \ dtype *d = dst[0]; \ n_samples *= conv->n_channels; \ for (j = 0; j < n_samples; j++) \ - d[j] = func (s[j]); \ + d[j] = func (s[j]); \ } -#define MAKE_I_TO_D(sname,stype,dname,dtype,func) \ +#define MAKE_I_TO_D(sname,stype,dname,dtype,func) \ void conv_ ##sname## _to_ ##dname## d_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -92,11 +92,11 @@ void conv_ ##sname## _to_ ##dname## d_c(struct convert *conv, \ uint32_t i, j, n_channels = conv->n_channels; \ for (j = 0; j < n_samples; j++) { \ for (i = 0; i < n_channels; i++) \ - d[i][j] = func (*s++); \ + d[i][j] = func (*s++); \ } \ } -#define MAKE_D_TO_I(sname,stype,dname,dtype,func) \ +#define MAKE_D_TO_I(sname,stype,dname,dtype,func) \ void conv_ ##sname## d_to_ ##dname## _c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -106,7 +106,7 @@ void conv_ ##sname## d_to_ ##dname## _c(struct convert *conv, \ uint32_t i, j, n_channels = conv->n_channels; \ for (j = 0; j < n_samples; j++) { \ for (i = 0; i < n_channels; i++) \ - *d++ = func (s[i][j]); \ + *d++ = func (s[i][j]); \ } \ } @@ -255,10 +255,16 @@ static inline void update_noise_c(struct convert *conv, uint32_t n_samples) } *prev = old; break; + case NOISE_METHOD_PATTERN: + old = *prev; + for (n = 0; n < n_samples; n++) + noise[n] = conv->scale * (1-((old++>>10)&1)); + *prev = old; + break; } } -#define MAKE_D_noise(dname,dtype,func) \ +#define MAKE_D_noise(dname,dtype,func) \ void conv_f32d_to_ ##dname## d_noise_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -277,7 +283,7 @@ void conv_f32d_to_ ##dname## d_noise_c(struct convert *conv, \ } \ } -#define MAKE_I_noise(dname,dtype,func) \ +#define MAKE_I_noise(dname,dtype,func) \ void conv_f32d_to_ ##dname## _noise_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -316,7 +322,7 @@ MAKE_I_noise(s24_32s, int32_t, F32_TO_S24_32S_D); #define SHAPER(type,s,scale,offs,sh,min,max,d) \ ({ \ type t; \ - float v = s * scale + offs; \ + float v = s * scale + offs; \ for (n = 0; n < n_ns; n++) \ v += sh->e[idx + n] * ns[n]; \ t = FTOI(type, v, 1.0f, 0.0f, d, min, max); \ @@ -330,7 +336,7 @@ MAKE_I_noise(s24_32s, int32_t, F32_TO_S24_32S_D); #define F32_TO_S16_SH(s,sh,d) SHAPER(int16_t, s, S16_SCALE, 0, sh, S16_MIN, S16_MAX, d) #define F32_TO_S16S_SH(s,sh,d) bswap_16(F32_TO_S16_SH(s,sh,d)) -#define MAKE_D_shaped(dname,dtype,func) \ +#define MAKE_D_shaped(dname,dtype,func) \ void conv_f32d_to_ ##dname## d_shaped_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ @@ -353,7 +359,7 @@ void conv_f32d_to_ ##dname## d_shaped_c(struct convert *conv, \ } \ } -#define MAKE_I_shaped(dname,dtype,func) \ +#define MAKE_I_shaped(dname,dtype,func) \ void conv_f32d_to_ ##dname## _shaped_c(struct convert *conv, \ void * SPA_RESTRICT dst[], const void * SPA_RESTRICT src[], \ uint32_t n_samples) \ diff --git a/spa/plugins/audioconvert/fmt-ops-sse2.c b/spa/plugins/audioconvert/fmt-ops-sse2.c index bf5197d56..917bfa0dc 100644 --- a/spa/plugins/audioconvert/fmt-ops-sse2.c +++ b/spa/plugins/audioconvert/fmt-ops-sse2.c @@ -581,7 +581,7 @@ static inline void update_noise_sse2(struct convert *conv, uint32_t n_samples) { uint32_t n; const uint32_t *r = SPA_PTR_ALIGN(conv->random, 16, uint32_t); - const int32_t *p = SPA_PTR_ALIGN(conv->prev, 16, int32_t); + int32_t *p = SPA_PTR_ALIGN(conv->prev, 16, int32_t), op; __m128 scale = _mm_set1_ps(conv->scale); __m128 out[1]; float *noise = SPA_PTR_ALIGN(conv->noise, 16, float); @@ -616,6 +616,12 @@ static inline void update_noise_sse2(struct convert *conv, uint32_t n_samples) } _mm_store_si128((__m128i*)p, old[0]); break; + case NOISE_METHOD_PATTERN: + op = *p; + for (n = 0; n < n_samples; n++) + noise[n] = conv->scale * (1-((op++>>10)&1)); + *p = op; + break; } } diff --git a/spa/plugins/audioconvert/fmt-ops.c b/spa/plugins/audioconvert/fmt-ops.c index 4a09fa7e1..443d59eec 100644 --- a/spa/plugins/audioconvert/fmt-ops.c +++ b/spa/plugins/audioconvert/fmt-ops.c @@ -453,9 +453,6 @@ int convert_init(struct convert *conv) conv->scale = 1.0f / (float)(INT32_MAX); - if (conv->noise_bits > 0) - conv->scale *= (1 << (conv->noise_bits + 1)); - /* disable dither if not needed */ if (!need_dither(conv->dst_fmt)) conv->method = DITHER_METHOD_NONE; @@ -465,8 +462,21 @@ int convert_init(struct convert *conv) return -EINVAL; conv->noise_method = dinfo->noise_method; - if (conv->noise_bits && conv->noise_method == NOISE_METHOD_NONE) - conv->noise_method = NOISE_METHOD_RECTANGULAR; + if (conv->noise_bits > 0) { + switch (conv->noise_method) { + case NOISE_METHOD_NONE: + conv->noise_method = NOISE_METHOD_PATTERN; + conv->scale = -1.0f * (1 << (conv->noise_bits-1)); + break; + case NOISE_METHOD_RECTANGULAR: + conv->noise_method = NOISE_METHOD_TRIANGULAR; + SPA_FALLTHROUGH; + case NOISE_METHOD_TRIANGULAR: + case NOISE_METHOD_TRIANGULAR_HF: + conv->scale *= (1 << (conv->noise_bits-1)); + break; + } + } if (conv->noise_method < NOISE_METHOD_TRIANGULAR) conv->scale *= 0.5f; diff --git a/spa/plugins/audioconvert/fmt-ops.h b/spa/plugins/audioconvert/fmt-ops.h index f223f5b2f..68d34b517 100644 --- a/spa/plugins/audioconvert/fmt-ops.h +++ b/spa/plugins/audioconvert/fmt-ops.h @@ -233,6 +233,7 @@ struct convert { #define NOISE_METHOD_RECTANGULAR 1 #define NOISE_METHOD_TRIANGULAR 2 #define NOISE_METHOD_TRIANGULAR_HF 3 +#define NOISE_METHOD_PATTERN 4 uint32_t noise_method; float *noise; uint32_t noise_size;