From 8667af5cd7ca2d57bc2ece016878ab0afce1f193 Mon Sep 17 00:00:00 2001 From: Michael Giacomelli Date: Tue, 6 Oct 2026 10:46:37 -0400 Subject: [PATCH] atrac3: fix gain compensation at adjacent gain points applyVariableGain() applied the constant gain before a gain point in a do-while loop, so at least eight samples of it, even when there are none: when the point is at the start of the block or follows straight after the previous one. Every later gain point in the block was then eight samples late. This came in with the loop unrolling of 51a8be1a0f. Use a while loop, as ffmpeg does. Checked with perfsim (Sansa e200v1 build) against ffmpeg's decode. Over the whole of atrac3_lp2_132.oma the SNR goes from 45 to 51 dB and the worst frame from 14 to 21 dB; the right channel of a joint stereo RM file goes from 37 to 54 dB. What is left is a noise floor near -72 dBFS in every frame, from the 2 fractional bits the decoder works with. Co-Authored-By: Claude Opus 5.5 --- lib/rbcodec/codecs/libatrac/atrac3.c | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/lib/rbcodec/codecs/libatrac/atrac3.c b/lib/rbcodec/codecs/libatrac/atrac3.c index ea3b02fc86..fc7d03e621 100644 --- a/lib/rbcodec/codecs/libatrac/atrac3.c +++ b/lib/rbcodec/codecs/libatrac/atrac3.c @@ -717,8 +717,10 @@ static int applyVariableGain (int32_t *pIn, int32_t *pPrev, int32_t *pOut, { int32_t i = start; - /* Apply fix gains until end index is reached */ - do { + /* Apply fix gains until end index is reached. There is nothing to do + * here when the gain point is where the previous one ended, or at the + * start of the block. */ + while (i < end) { pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; @@ -727,7 +729,7 @@ static int applyVariableGain (int32_t *pIn, int32_t *pPrev, int32_t *pOut, pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++; - } while (i < end); + } /* Interpolation is done over next eight samples */ pOut[i] = fixmul16((fixmul16(pIn[i], gain1) + pPrev[i]), gain2); i++;