diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/ReplayGainControls.kt b/app/src/main/kotlin/com/subtracks/ui/settings/ReplayGainControls.kt index 833fef72..534ae664 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/ReplayGainControls.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/ReplayGainControls.kt @@ -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, diff --git a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt index 7df3d06b..b82ab683 100644 --- a/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt +++ b/app/src/main/kotlin/com/subtracks/ui/settings/SettingsScreen.kt @@ -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 = { diff --git a/app/src/main/res/values/strings.xml b/app/src/main/res/values/strings.xml index b266bccf..439d8c73 100644 --- a/app/src/main/res/values/strings.xml +++ b/app/src/main/res/values/strings.xml @@ -77,7 +77,10 @@ Album gain Off Track gain + Lower preamp + Raise preamp Adjust level on top of the replay gain + Reset Preamp %1$s dB Normalise loudness using the gain from the server diff --git a/app/src/test/kotlin/com/subtracks/ui/settings/ReplayGainControlsTest.kt b/app/src/test/kotlin/com/subtracks/ui/settings/ReplayGainControlsTest.kt index b6a5032d..5b08e816 100644 --- a/app/src/test/kotlin/com/subtracks/ui/settings/ReplayGainControlsTest.kt +++ b/app/src/test/kotlin/com/subtracks/ui/settings/ReplayGainControlsTest.kt @@ -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)