simplify get_factor (#942)

Simplify `get_factor`
This commit is contained in:
Jason Gray 2022-01-27 00:40:59 -06:00 committed by GitHub
parent 55ced49c2d
commit 03e71f6e0a
No known key found for this signature in database
GPG key ID: 4AEE18F83AFDEB23
2 changed files with 46 additions and 13 deletions

View file

@ -29,6 +29,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- [main] Don't panic when parsing options. Instead list valid values and exit.
- [main] `--alsa-mixer-device` and `--alsa-mixer-index` now fallback to the card and index specified in `--device`.
- [core] Removed unsafe code (breaking)
- [playback] Adhere to ReplayGain spec when calculating gain normalisation factor.
### Removed
- [playback] `alsamixer`: previously deprecated option `mixer-card` has been removed.

View file

@ -31,6 +31,7 @@ use crate::{MS_PER_PAGE, NUM_CHANNELS, PAGES_PER_MS, SAMPLES_PER_SECOND};
const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS: u32 = 30000;
pub const DB_VOLTAGE_RATIO: f64 = 20.0;
pub const PCM_AT_0DBFS: f64 = 1.0;
pub struct Player {
commands: Option<mpsc::UnboundedSender<PlayerCommand>>,
@ -251,26 +252,57 @@ impl NormalisationData {
(data.track_gain_db, data.track_peak)
};
let normalisation_power = gain_db + config.normalisation_pregain_db;
let mut normalisation_factor = db_to_ratio(normalisation_power);
// As per the ReplayGain 1.0 & 2.0 (proposed) spec:
// https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Clipping_prevention
// https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Clipping_prevention
let normalisation_factor = if config.normalisation_method == NormalisationMethod::Basic {
// For Basic Normalisation, factor = min(ratio of (ReplayGain + PreGain), 1.0 / peak level).
// https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Peak_amplitude
// https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Peak_amplitude
// We then limit that to 1.0 as not to exceed dBFS (0.0 dB).
let factor = f64::min(
db_to_ratio(gain_db + config.normalisation_pregain_db),
PCM_AT_0DBFS / gain_peak,
);
if normalisation_power + ratio_to_db(gain_peak) > config.normalisation_threshold_dbfs {
let limited_normalisation_factor =
db_to_ratio(config.normalisation_threshold_dbfs) / gain_peak;
let limited_normalisation_power = ratio_to_db(limited_normalisation_factor);
if factor > PCM_AT_0DBFS {
info!(
"Lowering gain by {:.2} dB for the duration of this track to avoid potentially exceeding dBFS.",
ratio_to_db(factor)
);
if config.normalisation_method == NormalisationMethod::Basic {
warn!("Limiting gain to {:.2} dB for the duration of this track to stay under normalisation threshold.", limited_normalisation_power);
normalisation_factor = limited_normalisation_factor;
PCM_AT_0DBFS
} else {
factor
}
} else {
// For Dynamic Normalisation it's up to the player to decide,
// factor = ratio of (ReplayGain + PreGain).
// We then let the dynamic limiter handle gain reduction.
let factor = db_to_ratio(gain_db + config.normalisation_pregain_db);
let threshold_ratio = db_to_ratio(config.normalisation_threshold_dbfs);
if factor > PCM_AT_0DBFS {
let factor_db = gain_db + config.normalisation_pregain_db;
let limiting_db = factor_db + config.normalisation_threshold_dbfs.abs();
warn!(
"This track will at its peak be subject to {:.2} dB of dynamic limiting.",
normalisation_power - limited_normalisation_power
"This track may exceed dBFS by {:.2} dB and be subject to {:.2} dB of dynamic limiting at it's peak.",
factor_db, limiting_db
);
} else if factor > threshold_ratio {
let limiting_db = gain_db
+ config.normalisation_pregain_db
+ config.normalisation_threshold_dbfs.abs();
info!(
"This track may be subject to {:.2} dB of dynamic limiting at it's peak.",
limiting_db
);
}
warn!("Please lower pregain to avoid.");
}
factor
};
debug!("Normalisation Data: {:?}", data);
debug!(