Skip to content

Commit

Permalink
Player: optionally use album gain for loudness normalisation
Browse files Browse the repository at this point in the history
  • Loading branch information
Stefan Keller committed Oct 20, 2023
1 parent 3c52fce commit 01df6e1
Show file tree
Hide file tree
Showing 5 changed files with 22 additions and 6 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -62,13 +62,19 @@ public static NormalizationData read(@NotNull InputStream in) throws IOException
return new NormalizationData(buffer.getFloat(), buffer.getFloat(), buffer.getFloat(), buffer.getFloat());
}

public float getFactor(float normalisationPregain) {
float normalisationFactor = (float) Math.pow(10, (track_gain_db + normalisationPregain) / 20);
public float getFactor(float normalisationPregain, boolean useAlbumGain) {
float gain = useAlbumGain? album_gain_db : track_gain_db;
LOGGER.trace("Using gain: {}", gain);
float normalisationFactor = (float) Math.pow(10, (gain + normalisationPregain) / 20);
if (normalisationFactor * track_peak > 1) {
LOGGER.warn("Reducing normalisation factor to prevent clipping. Please add negative pregain to avoid.");
normalisationFactor = 1 / track_peak;
}

return normalisationFactor;
}

public float getFactor(float normalisationPregain) {
return getFactor(normalisationPregain, false);
}
}
Original file line number Diff line number Diff line change
Expand Up @@ -439,6 +439,7 @@ public PlayerConfiguration toPlayer() {
.setAutoplayEnabled(config.get("player.autoplayEnabled"))
.setCrossfadeDuration(config.get("player.crossfadeDuration"))
.setEnableNormalisation(config.get("player.enableNormalisation"))
.setUseAlbumGain(config.get("player.useAlbumGain"))
.setInitialVolume(config.get("player.initialVolume"))
.setLogAvailableMixers(config.get("player.logAvailableMixers"))
.setMetadataPipe(metadataPipe())
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ public final class PlayerConfiguration {
// Audio
public final AudioQuality preferredQuality;
public final boolean enableNormalisation;
public final boolean useAlbumGain;
public final float normalisationPregain;
public final boolean autoplayEnabled;
public final int crossfadeDuration;
Expand All @@ -52,11 +53,12 @@ public final class PlayerConfiguration {
// Local files
public final File localFilesPath;

private PlayerConfiguration(AudioQuality preferredQuality, boolean enableNormalisation, float normalisationPregain, boolean autoplayEnabled, int crossfadeDuration, boolean preloadEnabled,
private PlayerConfiguration(AudioQuality preferredQuality, boolean enableNormalisation, boolean useAlbumGain, float normalisationPregain, boolean autoplayEnabled, int crossfadeDuration, boolean preloadEnabled,
AudioOutput output, String outputClass, Object[] outputClassParams, File outputPipe, File metadataPipe, String[] mixerSearchKeywords, boolean logAvailableMixers, int releaseLineDelay,
int initialVolume, int volumeSteps, boolean bypassSinkVolume, File localFilesPath) {
this.preferredQuality = preferredQuality;
this.enableNormalisation = enableNormalisation;
this.useAlbumGain = useAlbumGain;
this.normalisationPregain = normalisationPregain;
this.autoplayEnabled = autoplayEnabled;
this.crossfadeDuration = crossfadeDuration;
Expand All @@ -83,6 +85,7 @@ public final static class Builder {
// Audio
private AudioQuality preferredQuality = AudioQuality.NORMAL;
private boolean enableNormalisation = true;
private boolean useAlbumGain = false;
private float normalisationPregain = 3.0f;
private boolean autoplayEnabled = true;
private int crossfadeDuration = 0;
Expand Down Expand Up @@ -119,6 +122,11 @@ public Builder setEnableNormalisation(boolean enableNormalisation) {
return this;
}

public Builder setUseAlbumGain(boolean useAlbumGain) {
this.useAlbumGain = useAlbumGain;
return this;
}

public Builder setNormalisationPregain(float normalisationPregain) {
this.normalisationPregain = normalisationPregain;
return this;
Expand Down Expand Up @@ -207,7 +215,7 @@ public Builder setLocalFilesPath(File localFilesPath) {

@Contract(value = " -> new", pure = true)
public @NotNull PlayerConfiguration build() {
return new PlayerConfiguration(preferredQuality, enableNormalisation, normalisationPregain, autoplayEnabled, crossfadeDuration, preloadEnabled,
return new PlayerConfiguration(preferredQuality, enableNormalisation, useAlbumGain, normalisationPregain, autoplayEnabled, crossfadeDuration, preloadEnabled,
output, outputClass, outputClassParams, outputPipe, metadataPipe, mixerSearchKeywords, logAvailableMixers, releaseLineDelay,
initialVolume, volumeSteps, bypassSinkVolume, localFilesPath);
}
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -135,7 +135,7 @@ private void load(boolean preload) throws IOException, Decoder.DecoderException,

float normalizationFactor;
if (stream.normalizationData == null || !conf.enableNormalisation) normalizationFactor = 1;
else normalizationFactor = stream.normalizationData.getFactor(conf.normalisationPregain);
else normalizationFactor = stream.normalizationData.getFactor(conf.normalisationPregain, conf.useAlbumGain);

Iterator<Decoder> iter = Decoders.initDecoder(stream.in.codec(), stream.in.stream(), normalizationFactor, metadata.duration());
while (iter.hasNext()) {
Expand Down
3 changes: 2 additions & 1 deletion player/src/main/resources/default.toml
Original file line number Diff line number Diff line change
Expand Up @@ -37,6 +37,7 @@ manualCorrection = 0 # Manual time correction in millis
autoplayEnabled = true # Autoplay similar songs when your music ends
preferredAudioQuality = "NORMAL" # Preferred audio quality (NORMAL, HIGH, VERY_HIGH)
enableNormalisation = true # Whether to apply the Spotify loudness normalisation
useAlbumGain = false # Whether to apply album gain (instead of track gain) for normalisation
normalisationPregain = +3.0 # Normalisation pregain in decibels (loud at +6, normal at +3, quiet at -5)
initialVolume = 65536 # Initial volume (0-65536)
volumeSteps = 64 # Number of volume notches
Expand Down Expand Up @@ -83,4 +84,4 @@ onPanicState = ""
onConnectionDropped = ""
onConnectionEstablished = ""
onStartedLoading = ""
onFinishedLoading = ""
onFinishedLoading = ""

0 comments on commit 01df6e1

Please sign in to comment.