From 61431dcbc0a0f59ee3c5e25892b88b8b3ff469fa Mon Sep 17 00:00:00 2001 From: Wim Taymans Date: Thu, 14 May 2026 11:19:02 +0200 Subject: [PATCH] audioconvert: add dither noise even on empty input When we are asked to add noise bits, don't call the clear function. Make the passthrough and clear-on-empty flags available with a new flag field to make it more extensible. Fixes #5260 --- spa/plugins/audioconvert/audioconvert.c | 18 +++++++++--------- spa/plugins/audioconvert/fmt-ops.c | 3 ++- spa/plugins/audioconvert/fmt-ops.h | 7 ++++++- 3 files changed, 17 insertions(+), 11 deletions(-) diff --git a/spa/plugins/audioconvert/audioconvert.c b/spa/plugins/audioconvert/audioconvert.c index 032af578d..a34974429 100644 --- a/spa/plugins/audioconvert/audioconvert.c +++ b/spa/plugins/audioconvert/audioconvert.c @@ -2176,8 +2176,8 @@ static int setup_in_convert(struct impl *this) if ((res = convert_init(&in->conv)) < 0) return res; - spa_log_debug(this->log, "%p: got converter features %08x:%08x passthrough:%d remap:%d %s", this, - this->cpu_flags, in->conv.func_cpu_flags, in->conv.is_passthrough, + spa_log_debug(this->log, "%p: got converter features %08x:%08x flags:%08x remap:%d %s", this, + this->cpu_flags, in->conv.func_cpu_flags, in->conv.flags, remap, in->conv.func_name); return 0; @@ -2478,9 +2478,9 @@ static int setup_out_convert(struct impl *this) return res; spa_log_debug(this->log, "%p: got converter features %08x:%08x quant:%d:%d" - " passthrough:%d remap:%d %s", this, + " flags:%08x remap:%d %s", this, this->cpu_flags, out->conv.func_cpu_flags, out->conv.method, - out->conv.noise_bits, out->conv.is_passthrough, remap, out->conv.func_name); + out->conv.noise_bits, out->conv.flags, remap, out->conv.func_name); return 0; } @@ -3643,7 +3643,7 @@ static void run_src_convert_stage(struct stage *s, struct stage_context *c) } else { dst = c->datas[s->out_idx]; } - if (c->empty && dir->conv.clear) + if (c->empty && dir->conv.clear && convert_is_clear_on_empty(&dir->conv)) convert_clear(&dir->conv, dst, c->n_samples); else convert_process(&dir->conv, dst, (const void**)c->datas[s->in_idx], c->n_samples); @@ -3757,7 +3757,7 @@ static void run_dst_convert_stage(struct stage *s, struct stage_context *c) struct dir *dir = &impl->dir[SPA_DIRECTION_OUTPUT]; void *remap_datas[MAX_PORTS], **src; - spa_log_trace_fp(impl->log, "%p: output convert %d", impl, c->n_samples); + spa_log_trace_fp(impl->log, "%p: output convert %d %d", impl, c->n_samples, c->empty); if (dir->need_remap) { uint32_t i; for (i = 0; i < dir->conv.n_channels; i++) { @@ -3768,7 +3768,7 @@ static void run_dst_convert_stage(struct stage *s, struct stage_context *c) } else { src = c->datas[s->in_idx]; } - if (c->empty && dir->conv.clear) + if (c->empty && dir->conv.clear && convert_is_clear_on_empty(&dir->conv)) convert_clear(&dir->conv, c->datas[s->out_idx], c->n_samples); else convert_process(&dir->conv, c->datas[s->out_idx], (const void **)src, c->n_samples); @@ -3805,11 +3805,11 @@ static void recalc_stages(struct impl *this, struct stage_context *ctx) /* set bits for things we need to do */ dir = &this->dir[SPA_DIRECTION_INPUT]; - SPA_FLAG_UPDATE(ctx->bits, SRC_CONVERT_BIT, !dir->conv.is_passthrough); + SPA_FLAG_UPDATE(ctx->bits, SRC_CONVERT_BIT, !convert_is_passthrough(&dir->conv)); in_need_remap = dir->need_remap; dir = &this->dir[SPA_DIRECTION_OUTPUT]; - SPA_FLAG_UPDATE(ctx->bits, DST_CONVERT_BIT, !dir->conv.is_passthrough); + SPA_FLAG_UPDATE(ctx->bits, DST_CONVERT_BIT, !convert_is_passthrough(&dir->conv)); out_need_remap = dir->need_remap; this->resample_passthrough = resample_is_passthrough(this); diff --git a/spa/plugins/audioconvert/fmt-ops.c b/spa/plugins/audioconvert/fmt-ops.c index 734b2d36c..4b21134da 100644 --- a/spa/plugins/audioconvert/fmt-ops.c +++ b/spa/plugins/audioconvert/fmt-ops.c @@ -640,7 +640,8 @@ int convert_init(struct convert *conv) for (i = 0; i < RANDOM_SIZE; i++) conv->random[i] = random(); - conv->is_passthrough = conv->src_fmt == conv->dst_fmt; + SPA_FLAG_UPDATE(conv->flags, CONVERT_FLAG_CLEAR_ON_EMPTY, conv->noise_bits == 0); + SPA_FLAG_UPDATE(conv->flags, CONVERT_FLAG_PASSTHROUGH, conv->src_fmt == conv->dst_fmt); conv->func_cpu_flags = info->cpu_flags; conv->update_noise = ninfo->noise; conv->process = info->process; diff --git a/spa/plugins/audioconvert/fmt-ops.h b/spa/plugins/audioconvert/fmt-ops.h index 24b4b1aaf..03ca6a909 100644 --- a/spa/plugins/audioconvert/fmt-ops.h +++ b/spa/plugins/audioconvert/fmt-ops.h @@ -222,7 +222,9 @@ struct convert { uint32_t func_cpu_flags; const char *func_name; - unsigned int is_passthrough:1; +#define CONVERT_FLAG_PASSTHROUGH (1u<<0) +#define CONVERT_FLAG_CLEAR_ON_EMPTY (1u<<1) + uint32_t flags; float scale; uint32_t *random; @@ -283,6 +285,9 @@ static inline uint32_t dither_method_from_label(const char *label) #define convert_clear(conv,...) (conv)->clear(conv, __VA_ARGS__) #define convert_free(conv) (conv)->free(conv) +#define convert_is_passthrough(conv) SPA_FLAG_IS_SET((conv)->flags, CONVERT_FLAG_PASSTHROUGH) +#define convert_is_clear_on_empty(conv) SPA_FLAG_IS_SET((conv)->flags, CONVERT_FLAG_CLEAR_ON_EMPTY) + #define DEFINE_NOISE_FUNCTION(name,arch) \ void conv_noise_##name##_##arch(struct convert *conv, float *noise, \ uint32_t n_samples)