@@ -31,6 +31,7 @@ use crate::{MS_PER_PAGE, NUM_CHANNELS, PAGES_PER_MS, SAMPLES_PER_SECOND};
3131
3232const PRELOAD_NEXT_TRACK_BEFORE_END_DURATION_MS : u32 = 30000 ;
3333pub const DB_VOLTAGE_RATIO : f64 = 20.0 ;
34+ pub const PCM_AT_0DBFS : f64 = 1.0 ;
3435
3536pub struct Player {
3637 commands : Option < mpsc:: UnboundedSender < PlayerCommand > > ,
@@ -251,26 +252,57 @@ impl NormalisationData {
251252 ( data. track_gain_db , data. track_peak )
252253 } ;
253254
254- let normalisation_power = gain_db + config. normalisation_pregain_db ;
255- let mut normalisation_factor = db_to_ratio ( normalisation_power) ;
255+ // As per the ReplayGain 1.0 & 2.0 (proposed) spec:
256+ // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Clipping_prevention
257+ // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Clipping_prevention
258+ let normalisation_factor = if config. normalisation_method == NormalisationMethod :: Basic {
259+ // For Basic Normalisation, factor = min(ratio of (ReplayGain + PreGain), 1.0 / peak level).
260+ // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_1.0_specification#Peak_amplitude
261+ // https://wiki.hydrogenaud.io/index.php?title=ReplayGain_2.0_specification#Peak_amplitude
262+ // We then limit that to 1.0 as not to exceed dBFS (0.0 dB).
263+ let factor = f64:: min (
264+ db_to_ratio ( gain_db + config. normalisation_pregain_db ) ,
265+ PCM_AT_0DBFS / gain_peak,
266+ ) ;
256267
257- if normalisation_power + ratio_to_db ( gain_peak) > config. normalisation_threshold_dbfs {
258- let limited_normalisation_factor =
259- db_to_ratio ( config. normalisation_threshold_dbfs ) / gain_peak;
260- let limited_normalisation_power = ratio_to_db ( limited_normalisation_factor) ;
268+ if factor > PCM_AT_0DBFS {
269+ info ! (
270+ "Lowering gain by {:.2} dB for the duration of this track to avoid potentially exceeding dBFS." ,
271+ ratio_to_db( factor)
272+ ) ;
261273
262- if config. normalisation_method == NormalisationMethod :: Basic {
263- warn ! ( "Limiting gain to {:.2} dB for the duration of this track to stay under normalisation threshold." , limited_normalisation_power) ;
264- normalisation_factor = limited_normalisation_factor;
274+ PCM_AT_0DBFS
265275 } else {
276+ factor
277+ }
278+ } else {
279+ // For Dynamic Normalisation it's up to the player to decide,
280+ // factor = ratio of (ReplayGain + PreGain).
281+ // We then let the dynamic limiter handle gain reduction.
282+ let factor = db_to_ratio ( gain_db + config. normalisation_pregain_db ) ;
283+ let threshold_ratio = db_to_ratio ( config. normalisation_threshold_dbfs ) ;
284+
285+ if factor > PCM_AT_0DBFS {
286+ let factor_db = gain_db + config. normalisation_pregain_db ;
287+ let limiting_db = factor_db + config. normalisation_threshold_dbfs . abs ( ) ;
288+
266289 warn ! (
267- "This track will at its peak be subject to {:.2} dB of dynamic limiting." ,
268- normalisation_power - limited_normalisation_power
290+ "This track may exceed dBFS by {:.2} dB and be subject to {:.2} dB of dynamic limiting at it's peak." ,
291+ factor_db, limiting_db
292+ ) ;
293+ } else if factor > threshold_ratio {
294+ let limiting_db = gain_db
295+ + config. normalisation_pregain_db
296+ + config. normalisation_threshold_dbfs . abs ( ) ;
297+
298+ info ! (
299+ "This track may be subject to {:.2} dB of dynamic limiting at it's peak." ,
300+ limiting_db
269301 ) ;
270302 }
271303
272- warn ! ( "Please lower pregain to avoid." ) ;
273- }
304+ factor
305+ } ;
274306
275307 debug ! ( "Normalisation Data: {:?}" , data) ;
276308 debug ! (
0 commit comments