mirror of
https://github.com/austinried/subtracks.git
synced 2026-11-15 00:42:54 +01:00
playback: only attenuate a gain with no peak
A peak is the only headroom check the gain code has. When the server sends a gain without one (Navidrome does this for Opus R128 gains, which carry no peak tags by design), a positive gain was applied unchecked and the 16-bit sink saturated. Cap a peakless gain at unity instead: attenuation still applies, but a boost needs a peak to prove it fits. The cap is unchanged when a peak is present. Update the tests that expected a peakless boost, and cover the positive preamp that can no longer lift a peakless track and the attenuation that still applies.
This commit is contained in:
@@ -53,7 +53,9 @@ class ReplayGainControllerTest {
|
||||
fun theLatestItemLeavesItsGainApplied() {
|
||||
controller.setSettings(ReplayGainSettings(ReplayGainMode.Track, 0f))
|
||||
|
||||
controller.applyItem(item("a", trackGain = 6.0206f))
|
||||
controller.applyItem(item("a", trackGain = 6.0206f, trackPeak = 0.5f))
|
||||
assertEquals(2f, applied.last(), TOLERANCE)
|
||||
|
||||
controller.applyItem(item("b", trackGain = -6.0206f))
|
||||
|
||||
assertEquals(0.5f, applied.last(), TOLERANCE)
|
||||
@@ -62,6 +64,7 @@ class ReplayGainControllerTest {
|
||||
private fun item(
|
||||
id: String,
|
||||
trackGain: Float?,
|
||||
trackPeak: Float? = null,
|
||||
) = queueMediaItem(
|
||||
QueueItem(
|
||||
id = id,
|
||||
@@ -69,7 +72,7 @@ class ReplayGainControllerTest {
|
||||
artist = null,
|
||||
album = null,
|
||||
coverArtId = null,
|
||||
replayGain = ReplayGain(trackGain = trackGain),
|
||||
replayGain = ReplayGain(trackGain = trackGain, trackPeak = trackPeak),
|
||||
),
|
||||
local = null,
|
||||
stream = "http://server/$id",
|
||||
|
||||
@@ -128,7 +128,7 @@ class ReplayGainProcessorTest {
|
||||
processor.queueInput(sixteenBit(1000))
|
||||
assertEquals(listOf(500), readShorts(processor.getOutput()))
|
||||
|
||||
processor.flush(streamMetadata(item("b", trackGain = 6.0206f)))
|
||||
processor.flush(streamMetadata(item("b", trackGain = 6.0206f, trackPeak = 0.5f)))
|
||||
processor.queueInput(sixteenBit(1000))
|
||||
assertEquals(listOf(2000), readShorts(processor.getOutput()))
|
||||
}
|
||||
@@ -146,6 +146,7 @@ class ReplayGainProcessorTest {
|
||||
private fun item(
|
||||
id: String,
|
||||
trackGain: Float,
|
||||
trackPeak: Float? = null,
|
||||
): MediaItem =
|
||||
queueMediaItem(
|
||||
QueueItem(
|
||||
@@ -154,7 +155,7 @@ class ReplayGainProcessorTest {
|
||||
artist = null,
|
||||
album = null,
|
||||
coverArtId = null,
|
||||
replayGain = ReplayGain(trackGain = trackGain),
|
||||
replayGain = ReplayGain(trackGain = trackGain, trackPeak = trackPeak),
|
||||
),
|
||||
local = null,
|
||||
stream = "http://server/$id",
|
||||
|
||||
@@ -76,11 +76,35 @@ class ReplayGainTest {
|
||||
|
||||
@Test
|
||||
fun thePreampShiftsTheAppliedGain() {
|
||||
assertEquals(
|
||||
0.5f,
|
||||
replayGainLinearGain(
|
||||
ReplayGain(trackGain = -12.0412f),
|
||||
ReplayGainSettings(ReplayGainMode.Track, 6.0206f),
|
||||
),
|
||||
TOLERANCE,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aPositivePreampCannotBoostWithoutAPeak() {
|
||||
assertEquals(
|
||||
1f,
|
||||
replayGainLinearGain(
|
||||
ReplayGain(trackGain = -6.0206f),
|
||||
ReplayGainSettings(ReplayGainMode.Track, 6.0206f),
|
||||
ReplayGainSettings(ReplayGainMode.Track, 12f),
|
||||
),
|
||||
TOLERANCE,
|
||||
)
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aMissingPeakStillAppliesAnAttenuation() {
|
||||
assertEquals(
|
||||
0.31622776f,
|
||||
replayGainLinearGain(
|
||||
ReplayGain(trackGain = -10f),
|
||||
ReplayGainSettings(ReplayGainMode.Track, 0f),
|
||||
),
|
||||
TOLERANCE,
|
||||
)
|
||||
@@ -111,12 +135,11 @@ class ReplayGainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aMissingOrZeroPeakDoesNotCap() {
|
||||
fun aMissingOrZeroPeakAllowsNoBoost() {
|
||||
val settings = ReplayGainSettings(ReplayGainMode.Track, 0f)
|
||||
val expected = 3.9810717f
|
||||
|
||||
assertEquals(expected, replayGainLinearGain(ReplayGain(trackGain = 12f), settings), TOLERANCE)
|
||||
assertEquals(expected, replayGainLinearGain(ReplayGain(trackGain = 12f, trackPeak = 0f), settings), TOLERANCE)
|
||||
assertEquals(1f, replayGainLinearGain(ReplayGain(trackGain = 12f), settings), TOLERANCE)
|
||||
assertEquals(1f, replayGainLinearGain(ReplayGain(trackGain = 12f, trackPeak = 0f), settings), TOLERANCE)
|
||||
}
|
||||
|
||||
@Test
|
||||
@@ -144,9 +167,9 @@ class ReplayGainTest {
|
||||
}
|
||||
|
||||
@Test
|
||||
fun aNonFinitePeakDoesNotCap() {
|
||||
fun aNonFinitePeakAllowsNoBoost() {
|
||||
assertEquals(
|
||||
3.9810717f,
|
||||
1f,
|
||||
replayGainLinearGain(
|
||||
ReplayGain(trackGain = 12f, trackPeak = Float.POSITIVE_INFINITY),
|
||||
ReplayGainSettings(ReplayGainMode.Track, 0f),
|
||||
|
||||
Reference in New Issue
Block a user