mirror of
https://github.com/kilyabin/psysonic.git
synced 2026-07-22 14:35:41 +00:00
refactor(audio): unify loudness/replay-gain prep via TrackGainInputs
audio_play and audio_chain_preload were both reading the same engine state (target_lufs, norm_mode, pre_analysis_db) and resolving the loudness cache, then feeding it into compute_gain — but with subtly different intermediate steps. audio_play split the resolve+post-resolve into two operations so it could log the cache value; chain_preload used the bundled `loudness_gain_db_or_startup` wrapper. Lift the shared logic into `resolve_track_gain_inputs(state, app, url, logical_id, js_loudness_gain_db) -> TrackGainInputs` in helpers.rs. The struct returns target_lufs, norm_mode, the cache-loudness value (for logging), and the post-resolve effective loudness for compute_gain. Both call sites now use the same helper; behaviour-preserving. Drops the now-unused `loudness_gain_db_or_startup` (audio_chain_preload was its only caller). audio/commands.rs: 676 → 642 LOC.
This commit is contained in:
@@ -152,32 +152,12 @@ pub async fn audio_play(
|
|||||||
return Ok(());
|
return Ok(());
|
||||||
}
|
}
|
||||||
|
|
||||||
let target_lufs = f32::from_bits(state.normalization_target_lufs.load(Ordering::Relaxed));
|
let gain_inputs = resolve_track_gain_inputs(&state, &app, &url, logical_trim.as_deref(), loudness_gain_db);
|
||||||
let cache_loudness = resolve_loudness_gain_from_cache(
|
|
||||||
&app,
|
|
||||||
&url,
|
|
||||||
target_lufs,
|
|
||||||
logical_trim.as_deref(),
|
|
||||||
);
|
|
||||||
let resolved_loudness_gain_db = cache_loudness;
|
|
||||||
let norm_mode = state.normalization_engine.load(Ordering::Relaxed);
|
|
||||||
let pre_analysis_db = loudness_pre_analysis_db_for_engine(&state);
|
|
||||||
let startup_loudness_gain_db = if norm_mode == 2 {
|
|
||||||
loudness_gain_db_after_resolve(
|
|
||||||
cache_loudness,
|
|
||||||
target_lufs,
|
|
||||||
pre_analysis_db,
|
|
||||||
false,
|
|
||||||
loudness_gain_db,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
cache_loudness
|
|
||||||
};
|
|
||||||
let (gain_linear, effective_volume) = compute_gain(
|
let (gain_linear, effective_volume) = compute_gain(
|
||||||
norm_mode,
|
gain_inputs.norm_mode,
|
||||||
replay_gain_db,
|
replay_gain_db,
|
||||||
replay_gain_peak,
|
replay_gain_peak,
|
||||||
startup_loudness_gain_db,
|
gain_inputs.effective_loudness_db,
|
||||||
pre_gain_db,
|
pre_gain_db,
|
||||||
fallback_db,
|
fallback_db,
|
||||||
volume,
|
volume,
|
||||||
@@ -186,22 +166,22 @@ pub async fn audio_play(
|
|||||||
crate::app_deprintln!(
|
crate::app_deprintln!(
|
||||||
"[normalization] audio_play track_id={:?} engine={} replay_gain_db={:?} replay_gain_peak={:?} loudness_gain_db={:?} gain_linear={:.4} current_gain_db={:?} target_lufs={:.2} volume={:.3} effective_volume={:.3}",
|
"[normalization] audio_play track_id={:?} engine={} replay_gain_db={:?} replay_gain_peak={:?} loudness_gain_db={:?} gain_linear={:.4} current_gain_db={:?} target_lufs={:.2} volume={:.3} effective_volume={:.3}",
|
||||||
playback_identity(&url),
|
playback_identity(&url),
|
||||||
normalization_engine_name(norm_mode),
|
normalization_engine_name(gain_inputs.norm_mode),
|
||||||
replay_gain_db,
|
replay_gain_db,
|
||||||
replay_gain_peak,
|
replay_gain_peak,
|
||||||
resolved_loudness_gain_db,
|
gain_inputs.cache_loudness_db,
|
||||||
gain_linear,
|
gain_linear,
|
||||||
current_gain_db,
|
current_gain_db,
|
||||||
target_lufs,
|
gain_inputs.target_lufs,
|
||||||
volume,
|
volume,
|
||||||
effective_volume
|
effective_volume
|
||||||
);
|
);
|
||||||
maybe_emit_normalization_state(
|
maybe_emit_normalization_state(
|
||||||
&app,
|
&app,
|
||||||
NormalizationStatePayload {
|
NormalizationStatePayload {
|
||||||
engine: normalization_engine_name(norm_mode).to_string(),
|
engine: normalization_engine_name(gain_inputs.norm_mode).to_string(),
|
||||||
current_gain_db,
|
current_gain_db,
|
||||||
target_lufs,
|
target_lufs: gain_inputs.target_lufs,
|
||||||
},
|
},
|
||||||
);
|
);
|
||||||
|
|
||||||
@@ -574,27 +554,12 @@ pub async fn audio_chain_preload(
|
|||||||
// current track ends, and `Sink::set_volume` affects the WHOLE Sink (incl.
|
// current track ends, and `Sink::set_volume` affects the WHOLE Sink (incl.
|
||||||
// the still-playing current source). Volume for the chained track is
|
// the still-playing current source). Volume for the chained track is
|
||||||
// applied at the gapless transition in `spawn_progress_task`, not here.
|
// applied at the gapless transition in `spawn_progress_task`, not here.
|
||||||
let target_lufs = f32::from_bits(state.normalization_target_lufs.load(Ordering::Relaxed));
|
let gain_inputs = resolve_track_gain_inputs(&state, &app, &url, logical_trim.as_deref(), loudness_gain_db);
|
||||||
let norm_mode = state.normalization_engine.load(Ordering::Relaxed);
|
|
||||||
let pre_analysis_db = loudness_pre_analysis_db_for_engine(&state);
|
|
||||||
let chain_loudness_db = if norm_mode == 2 {
|
|
||||||
loudness_gain_db_or_startup(
|
|
||||||
&app,
|
|
||||||
&url,
|
|
||||||
target_lufs,
|
|
||||||
logical_trim.as_deref(),
|
|
||||||
pre_analysis_db,
|
|
||||||
false,
|
|
||||||
loudness_gain_db,
|
|
||||||
)
|
|
||||||
} else {
|
|
||||||
resolve_loudness_gain_from_cache(&app, &url, target_lufs, logical_trim.as_deref())
|
|
||||||
};
|
|
||||||
let (gain_linear, _effective_volume) = compute_gain(
|
let (gain_linear, _effective_volume) = compute_gain(
|
||||||
norm_mode,
|
gain_inputs.norm_mode,
|
||||||
replay_gain_db,
|
replay_gain_db,
|
||||||
replay_gain_peak,
|
replay_gain_peak,
|
||||||
chain_loudness_db,
|
gain_inputs.effective_loudness_db,
|
||||||
pre_gain_db,
|
pre_gain_db,
|
||||||
fallback_db,
|
fallback_db,
|
||||||
volume,
|
volume,
|
||||||
|
|||||||
@@ -438,32 +438,54 @@ pub(crate) fn loudness_gain_db_after_resolve(
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// LUFS: DB-backed integrated LUFS only at bind time (`allow_js_when_uncached = false`);
|
/// Resolved gain inputs that both `audio_play` and `audio_chain_preload` need
|
||||||
/// after `analysis:loudness-partial`, `audio_update_replay_gain` passes `true` so finite
|
/// before calling [`compute_gain`]. Bundles the engine state reads + cache
|
||||||
/// JS gain applies until SQLite catches up. Must never return `None` or `compute_gain` uses unity.
|
/// resolution in one shot so the call sites don't drift apart on subtle
|
||||||
pub(crate) fn loudness_gain_db_or_startup(
|
/// behaviour (e.g. one accidentally skipping the post-resolve step for
|
||||||
|
/// LUFS mode).
|
||||||
|
#[derive(Debug, Clone, Copy)]
|
||||||
|
pub(crate) struct TrackGainInputs {
|
||||||
|
pub(crate) target_lufs: f32,
|
||||||
|
pub(crate) norm_mode: u32,
|
||||||
|
/// Pre-resolve cache value — kept around for logging in `audio_play`.
|
||||||
|
pub(crate) cache_loudness_db: Option<f32>,
|
||||||
|
/// Value to feed into `compute_gain` — for LUFS mode this is the
|
||||||
|
/// post-`loudness_gain_db_after_resolve` value, otherwise the raw cache
|
||||||
|
/// resolution (or `None` when not in normalisation mode).
|
||||||
|
pub(crate) effective_loudness_db: Option<f32>,
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Read engine state + resolve the loudness cache for a track that's about to
|
||||||
|
/// start playing. JS-supplied `loudness_gain_db` is **not** consulted at bind
|
||||||
|
/// time (only post-cache via `audio_update_replay_gain`).
|
||||||
|
pub(crate) fn resolve_track_gain_inputs(
|
||||||
|
state: &AudioEngine,
|
||||||
app: &AppHandle,
|
app: &AppHandle,
|
||||||
url: &str,
|
url: &str,
|
||||||
target_lufs: f32,
|
|
||||||
logical_track_id: Option<&str>,
|
logical_track_id: Option<&str>,
|
||||||
pre_analysis_attenuation_db: f32,
|
js_loudness_gain_db: Option<f32>,
|
||||||
allow_js_when_uncached: bool,
|
) -> TrackGainInputs {
|
||||||
js_gain_db: Option<f32>,
|
let target_lufs = f32::from_bits(state.normalization_target_lufs.load(Ordering::Relaxed));
|
||||||
) -> Option<f32> {
|
let norm_mode = state.normalization_engine.load(Ordering::Relaxed);
|
||||||
let resolved = resolve_loudness_gain_from_cache_impl(
|
let pre_analysis_db = loudness_pre_analysis_db_for_engine(state);
|
||||||
app,
|
let cache_loudness_db = resolve_loudness_gain_from_cache(app, url, target_lufs, logical_track_id);
|
||||||
url,
|
let effective_loudness_db = if norm_mode == 2 {
|
||||||
target_lufs,
|
|
||||||
logical_track_id,
|
|
||||||
ResolveLoudnessCacheOpts::default(),
|
|
||||||
);
|
|
||||||
loudness_gain_db_after_resolve(
|
loudness_gain_db_after_resolve(
|
||||||
resolved,
|
cache_loudness_db,
|
||||||
target_lufs,
|
target_lufs,
|
||||||
pre_analysis_attenuation_db,
|
pre_analysis_db,
|
||||||
allow_js_when_uncached,
|
false,
|
||||||
js_gain_db,
|
js_loudness_gain_db,
|
||||||
)
|
)
|
||||||
|
} else {
|
||||||
|
cache_loudness_db
|
||||||
|
};
|
||||||
|
TrackGainInputs {
|
||||||
|
target_lufs,
|
||||||
|
norm_mode,
|
||||||
|
cache_loudness_db,
|
||||||
|
effective_loudness_db,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
|
|||||||
Reference in New Issue
Block a user