settings: make the preamp easier to set exactly

The slider alone is awkward for the two things people actually do with a
preamp: zero it, and nudge it by a known amount.

- Minus and plus buttons flank the slider, stepping one grid notch (0.5
  dB) and disabling at the ends.
- A Reset button sits under it, beside the current value, disabled when
  the value is already zero.
- Both go through the same snapping the slider does, so a button cannot
  land off the grid.
This commit is contained in:
austinried
2026-10-16 13:07:11 +00:00
parent 0b4e1d18bc
commit 31859b66b6
4 changed files with 57 additions and 7 deletions
@@ -17,6 +17,13 @@ internal val REPLAY_GAIN_PREAMP_STEPS =
// storing it.
internal fun snapReplayGainPreampDb(value: Float): Float = (value / REPLAY_GAIN_PREAMP_STEP_DB).roundToInt() * REPLAY_GAIN_PREAMP_STEP_DB
internal fun stepReplayGainPreampDb(
value: Float,
steps: Int,
): Float =
snapReplayGainPreampDb(value + steps * REPLAY_GAIN_PREAMP_STEP_DB)
.coerceIn(MIN_REPLAY_GAIN_PREAMP_DB, MAX_REPLAY_GAIN_PREAMP_DB)
internal fun replayGainModeLabel(
resources: Resources,
mode: ReplayGainMode,
@@ -28,6 +28,7 @@ import androidx.compose.material.icons.rounded.Edit
import androidx.compose.material.icons.rounded.Favorite
import androidx.compose.material.icons.rounded.Info
import androidx.compose.material.icons.rounded.Language
import androidx.compose.material.icons.rounded.Remove
import androidx.compose.material.icons.rounded.Share
import androidx.compose.material3.AlertDialog
import androidx.compose.material3.Button
@@ -779,13 +780,44 @@ private fun ReplayGainPreampDialog(
style = MaterialTheme.typography.titleSmall,
color = MaterialTheme.colorScheme.primary,
)
Slider(
value = draft,
onValueChange = { draft = snapReplayGainPreampDb(it) },
valueRange = MIN_REPLAY_GAIN_PREAMP_DB..MAX_REPLAY_GAIN_PREAMP_DB,
steps = REPLAY_GAIN_PREAMP_STEPS,
)
Text(replayGainPreampLabel(resources, draft))
Row(verticalAlignment = Alignment.CenterVertically) {
IconButton(
onClick = { draft = stepReplayGainPreampDb(draft, -1) },
enabled = draft > MIN_REPLAY_GAIN_PREAMP_DB,
) {
Icon(
Icons.Rounded.Remove,
contentDescription = stringResource(R.string.settings_replay_gain_preamp_decrease),
)
}
Slider(
value = draft,
onValueChange = { draft = snapReplayGainPreampDb(it) },
valueRange = MIN_REPLAY_GAIN_PREAMP_DB..MAX_REPLAY_GAIN_PREAMP_DB,
steps = REPLAY_GAIN_PREAMP_STEPS,
modifier = Modifier.weight(1f),
)
IconButton(
onClick = { draft = stepReplayGainPreampDb(draft, 1) },
enabled = draft < MAX_REPLAY_GAIN_PREAMP_DB,
) {
Icon(
Icons.Rounded.Add,
contentDescription = stringResource(R.string.settings_replay_gain_preamp_increase),
)
}
}
Row(
verticalAlignment = Alignment.CenterVertically,
modifier = Modifier.fillMaxWidth(),
) {
Text(replayGainPreampLabel(resources, draft))
Spacer(Modifier.weight(1f))
TextButton(
onClick = { draft = 0f },
enabled = draft != 0f,
) { Text(stringResource(R.string.settings_replay_gain_preamp_reset)) }
}
}
},
confirmButton = {
+3
View File
@@ -77,7 +77,10 @@
<string name="settings_replay_gain_mode_album">Album gain</string>
<string name="settings_replay_gain_mode_off">Off</string>
<string name="settings_replay_gain_mode_track">Track gain</string>
<string name="settings_replay_gain_preamp_decrease">Lower preamp</string>
<string name="settings_replay_gain_preamp_increase">Raise preamp</string>
<string name="settings_replay_gain_preamp_prompt">Adjust level on top of the replay gain</string>
<string name="settings_replay_gain_preamp_reset">Reset</string>
<string name="settings_replay_gain_preamp_title">Preamp</string>
<string name="settings_replay_gain_preamp_value">%1$s dB</string>
<string name="settings_replay_gain_prompt">Normalise loudness using the gain from the server</string>
@@ -34,6 +34,14 @@ class ReplayGainControlsTest {
assertEquals(59, REPLAY_GAIN_PREAMP_STEPS)
}
@Test
fun thePreampStepsAlongTheGridAndStopsAtTheEnds() {
assertEquals(-1.5f, stepReplayGainPreampDb(-1f, -1), 0f)
assertEquals(-0.5f, stepReplayGainPreampDb(-1f, 1), 0f)
assertEquals(MIN_REPLAY_GAIN_PREAMP_DB, stepReplayGainPreampDb(MIN_REPLAY_GAIN_PREAMP_DB, -1), 0f)
assertEquals(MAX_REPLAY_GAIN_PREAMP_DB, stepReplayGainPreampDb(MAX_REPLAY_GAIN_PREAMP_DB, 1), 0f)
}
@Test
fun thePreampSnapsBackOntoTheHalfDecibelGrid() {
assertEquals(0f, snapReplayGainPreampDb(-0f), 0f)