From e35972ea8284e2644d4813d8628dbca895d32aea Mon Sep 17 00:00:00 2001 From: TuxSH <1922548+TuxSH@users.noreply.github.com> Date: Wed, 11 Feb 2026 02:41:03 +0100 Subject: [PATCH] rosalina: fix volume slider override value calculation Below 50%, the volume slider moves the dB value twice as fast. When linearly interpolating the value in dB (lerp in log-scale), we need to account for that fact to match how the MCU firmware handles the actual volume slider. --- sysmodules/rosalina/source/menus/sysconfig.c | 26 ++++++++++++++++++-- 1 file changed, 24 insertions(+), 2 deletions(-) diff --git a/sysmodules/rosalina/source/menus/sysconfig.c b/sysmodules/rosalina/source/menus/sysconfig.c index 6f2dec52..47ee0c51 100644 --- a/sysmodules/rosalina/source/menus/sysconfig.c +++ b/sysmodules/rosalina/source/menus/sysconfig.c @@ -420,8 +420,30 @@ static Result SysConfigMenu_ApplyVolumeOverride(void) s8 i2s2Volume; if (currVolumeSliderOverride >= 0) { - i2s1Volume = -128 + (((float)currVolumeSliderOverride/100.f) * 108); - i2s2Volume = i2s1Volume; + // Considering I found this table inside MCU fw bin (at around offset 0x1200 in the raw bin): + // 127, 126, 125, ... 56 + // which corresponds to round(127 - 71 * (i/63)) modulo some rounding error, it is certain + // that the MCU writes to "Page 0/Register 117: VOL/MICDET-Pin Gain" using linear interpolation + // to map the slider position (0..63) to the raw gain values, using 127 ("reserved") as "mute". + // Indeed, the value used in all calibration data for shutter volume is -10 dB, which maps to 56. + + // However, if you look at the definition of reg 0,117 closely, you will notice that the mapping + // to the 7-bit value is piecewise, with half the resolution (double the slope) for values mapping + // to -28 dB or lower, which means that the slider increases volume twice as fast below 50% position. + + // LERP like MCU does, round to nearest integer + u8 rawPinGain = 127 - (71 * currVolumeSliderOverride + 50) / 100; + s8 volume; + + if (rawPinGain <= 90) + volume = 36 - rawPinGain; + else if (rawPinGain >= 91 && rawPinGain <= 126) + volume = 126 - 2 * rawPinGain; + else + volume = -128; // mute + + i2s1Volume = volume; + i2s2Volume = volume; } else {