From 6ee3d0102b51798c7f8001948e202a0b3758cd9a Mon Sep 17 00:00:00 2001
From: Simon Arlott <sa.me.uk>
Date: Sat, 27 May 2023 20:13:53 +0100
Subject: [PATCH] decoder/mad: Fix decode of LAME peak value

6d91b5c7b21926137c63561e313afd1fb72274f8 ("fix double promotions") changed
how LAME peak values are decoded, producing large incorrect values that
cause some MP3 files to play silently.

Restore the original decode from MAD fixed-point format to double and
document what it's doing.

Fixes #1823
---
 NEWS                                     |  2 ++
 src/decoder/plugins/MadDecoderPlugin.cxx | 16 +++++++++++++++-
 2 files changed, 17 insertions(+), 1 deletion(-)

diff --git a/NEWS b/NEWS
index b82032c82..fec18ffb4 100644
--- a/NEWS
+++ b/NEWS
@@ -1,4 +1,6 @@
 ver 0.23.14 (not yet released)
+* decoder
+  - mad: fix calculation of LAME peak values
 
 ver 0.23.13 (2023/05/22)
 * input
diff --git a/src/decoder/plugins/MadDecoderPlugin.cxx b/src/decoder/plugins/MadDecoderPlugin.cxx
index 7e34c25b1..d861e2e6e 100644
--- a/src/decoder/plugins/MadDecoderPlugin.cxx
+++ b/src/decoder/plugins/MadDecoderPlugin.cxx
@@ -562,7 +562,21 @@ parse_lame(struct lame *lame, struct mad_bitptr *ptr, int *bitlen) noexcept
 
 	mad_bit_skip(ptr, 16);
 
-	lame->peak = MAD_F(mad_bit_read(ptr, 32) << 5); /* peak */
+	/* The lame peak value is a float multiplied by 2^23 and stored as an
+	 * unsigned integer (it is always positive). MAD's fixed-point format uses
+	 * 28 bits for the fractional part, so shift the 23 bit fraction up before
+	 * converting to a float.
+	 */
+	unsigned long peak_int = mad_bit_read(ptr, 32);
+
+#define LAME_PEAK_FRACBITS 23
+#if MAD_F_FRACBITS > LAME_PEAK_FRACBITS
+	peak_int <<= (MAD_F_FRACBITS - LAME_PEAK_FRACBITS);
+#elif LAME_PEAK_FRACBITS > MAD_F_FRACBITS
+	peak_int >>= (LAME_PEAK_FRACBITS - MAD_F_FRACBITS);
+#endif
+
+	lame->peak = mad_f_todouble(peak_int); /* peak */
 	FmtDebug(mad_domain, "LAME peak found: {}", lame->peak);
 
 	lame->track_gain = 0;