@@ -214,21 +214,21 @@ pub fn coefficient_to_duration(coefficient: f64) -> Duration {
214214
215215#[ derive( Clone , Copy , Debug ) ]
216216pub struct NormalisationData {
217- track_gain_db : f32 ,
218- track_peak : f32 ,
219- album_gain_db : f32 ,
220- album_peak : f32 ,
217+ track_gain_db : f64 ,
218+ track_peak : f64 ,
219+ album_gain_db : f64 ,
220+ album_peak : f64 ,
221221}
222222
223223impl NormalisationData {
224224 fn parse_from_file < T : Read + Seek > ( mut file : T ) -> io:: Result < NormalisationData > {
225225 const SPOTIFY_NORMALIZATION_HEADER_START_OFFSET : u64 = 144 ;
226226 file. seek ( SeekFrom :: Start ( SPOTIFY_NORMALIZATION_HEADER_START_OFFSET ) ) ?;
227227
228- let track_gain_db = file. read_f32 :: < LittleEndian > ( ) ?;
229- let track_peak = file. read_f32 :: < LittleEndian > ( ) ?;
230- let album_gain_db = file. read_f32 :: < LittleEndian > ( ) ?;
231- let album_peak = file. read_f32 :: < LittleEndian > ( ) ?;
228+ let track_gain_db = file. read_f32 :: < LittleEndian > ( ) ? as f64 ;
229+ let track_peak = file. read_f32 :: < LittleEndian > ( ) ? as f64 ;
230+ let album_gain_db = file. read_f32 :: < LittleEndian > ( ) ? as f64 ;
231+ let album_peak = file. read_f32 :: < LittleEndian > ( ) ? as f64 ;
232232
233233 let r = NormalisationData {
234234 track_gain_db,
@@ -246,17 +246,17 @@ impl NormalisationData {
246246 }
247247
248248 let ( gain_db, gain_peak) = if config. normalisation_type == NormalisationType :: Album {
249- ( data. album_gain_db as f64 , data. album_peak as f64 )
249+ ( data. album_gain_db , data. album_peak )
250250 } else {
251- ( data. track_gain_db as f64 , data. track_peak as f64 )
251+ ( data. track_gain_db , data. track_peak )
252252 } ;
253253
254- let normalisation_power = gain_db + config. normalisation_pregain_db as f64 ;
254+ let normalisation_power = gain_db + config. normalisation_pregain_db ;
255255 let mut normalisation_factor = db_to_ratio ( normalisation_power) ;
256256
257257 if normalisation_power + ratio_to_db ( gain_peak) > config. normalisation_threshold_dbfs {
258258 let limited_normalisation_factor =
259- db_to_ratio ( config. normalisation_threshold_dbfs as f64 ) / gain_peak;
259+ db_to_ratio ( config. normalisation_threshold_dbfs ) / gain_peak;
260260 let limited_normalisation_power = ratio_to_db ( limited_normalisation_factor) ;
261261
262262 if config. normalisation_method == NormalisationMethod :: Basic {
@@ -279,7 +279,7 @@ impl NormalisationData {
279279 normalisation_factor * 100.0
280280 ) ;
281281
282- normalisation_factor as f64
282+ normalisation_factor
283283 }
284284}
285285
@@ -1305,54 +1305,60 @@ impl PlayerInternal {
13051305 // Engineering Society, 60, 399-408.
13061306 if self . config . normalisation_method == NormalisationMethod :: Dynamic
13071307 {
1308- // steps 1 + 2: half-wave rectification and conversion into dB
1309- let abs_sample_db = ratio_to_db ( sample. abs ( ) ) ;
1310-
1311- // Some tracks have samples that are precisely 0.0, but ratio_to_db(0.0)
1312- // returns -inf and gets the peak detector stuck.
1313- if !abs_sample_db. is_normal ( ) {
1314- continue ;
1315- }
1316-
1317- // step 3: gain computer with soft knee
1318- let biased_sample = abs_sample_db - threshold_db;
1319- let limited_sample = if 2.0 * biased_sample < -knee_db {
1320- abs_sample_db
1321- } else if 2.0 * biased_sample. abs ( ) <= knee_db {
1322- abs_sample_db
1323- - ( biased_sample + knee_db / 2.0 ) . powi ( 2 )
1324- / ( 2.0 * knee_db)
1308+ // Some tracks have samples that are precisely 0.0. That's silence
1309+ // and we know we don't need to limit that, in which we can spare
1310+ // the CPU cycles.
1311+ //
1312+ // Also, calling `ratio_to_db(0.0)` returns `inf` and would get the
1313+ // peak detector stuck. Also catch the unlikely case where a sample
1314+ // is decoded as `NaN` or some other non-normal value.
1315+ let limiter_db = if sample. is_normal ( ) {
1316+ // step 1-2: half-wave rectification and conversion into dB
1317+ let abs_sample_db = ratio_to_db ( sample. abs ( ) ) ;
1318+
1319+ // step 3-4: gain computer with soft knee and subtractor
1320+ let bias_db = abs_sample_db - threshold_db;
1321+ let knee_boundary_db = bias_db * 2.0 ;
1322+
1323+ if knee_boundary_db < -knee_db {
1324+ 0.0
1325+ } else if knee_boundary_db. abs ( ) <= knee_db {
1326+ abs_sample_db
1327+ - ( abs_sample_db
1328+ - ( bias_db + knee_db / 2.0 ) . powi ( 2 )
1329+ / ( 2.0 * knee_db) )
1330+ } else {
1331+ abs_sample_db - threshold_db
1332+ }
13251333 } else {
1326- threshold_db as f64
1334+ 0.0
13271335 } ;
13281336
1329- // step 4: subtractor
1330- let limiter_input = abs_sample_db - limited_sample;
1331-
1332- // Spare the CPU unless the limiter is active or we are riding a peak.
1333- if !( limiter_input > 0.0
1337+ // Spare the CPU unless (1) the limiter is engaged, (2) we
1338+ // were in attack or (3) we were in release, and that attack/
1339+ // release wasn't finished yet.
1340+ if limiter_db > 0.0
13341341 || self . normalisation_integrator > 0.0
1335- || self . normalisation_peak > 0.0 )
1342+ || self . normalisation_peak > 0.0
13361343 {
1337- continue ;
1344+ // step 5: smooth, decoupled peak detector
1345+ self . normalisation_integrator = f64:: max (
1346+ limiter_db,
1347+ release_cf * self . normalisation_integrator
1348+ + ( 1.0 - release_cf) * limiter_db,
1349+ ) ;
1350+ self . normalisation_peak = attack_cf
1351+ * self . normalisation_peak
1352+ + ( 1.0 - attack_cf) * self . normalisation_integrator ;
1353+
1354+ // step 6: make-up gain applied later (volume attenuation)
1355+ // Applying the standard normalisation factor here won't work,
1356+ // because there are tracks with peaks as high as 6 dB above
1357+ // the default threshold, so that would clip.
1358+
1359+ // steps 7-8: conversion into level and multiplication into gain stage
1360+ * sample *= db_to_ratio ( -self . normalisation_peak ) ;
13381361 }
1339-
1340- // step 5: smooth, decoupled peak detector
1341- self . normalisation_integrator = f64:: max (
1342- limiter_input,
1343- release_cf * self . normalisation_integrator
1344- + ( 1.0 - release_cf) * limiter_input,
1345- ) ;
1346- self . normalisation_peak = attack_cf * self . normalisation_peak
1347- + ( 1.0 - attack_cf) * self . normalisation_integrator ;
1348-
1349- // step 6: make-up gain applied later (volume attenuation)
1350- // Applying the standard normalisation factor here won't work,
1351- // because there are tracks with peaks as high as 6 dB above
1352- // the default threshold, so that would clip.
1353-
1354- // steps 7-8: conversion into level and multiplication into gain stage
1355- * sample *= db_to_ratio ( -self . normalisation_peak ) ;
13561362 }
13571363 }
13581364 }
0 commit comments