fix(audio): stabilize loudness normalization and streaming startup behavior

Improve normalization consistency by separating cache refresh for non-playing tracks, hardening track-id cache lookups, and keeping UI gain state aligned with actual playback. Also reduce startup stalls by preferring non-seekable streaming when format hints are missing and by tuning ALSA/analysis paths to avoid underrun-prone churn.
This commit is contained in:
Maxim Isaev
2026-04-25 22:09:38 +03:00
parent 93b724fc65
commit 86704473ed
14 changed files with 2092 additions and 37 deletions
+22
View File
@@ -258,6 +258,9 @@ export default function QueuePanel() {
const contextMenu = usePlayerStore(s => s.contextMenu);
const playbackSource = usePlayerStore(s => s.currentPlaybackSource);
const normalizationNowDb = usePlayerStore(s => s.normalizationNowDb);
const normalizationTargetLufs = usePlayerStore(s => s.normalizationTargetLufs);
const normalizationEngineLive = usePlayerStore(s => s.normalizationEngineLive);
const crossfadeEnabled = useAuthStore(s => s.crossfadeEnabled);
const crossfadeSecs = useAuthStore(s => s.crossfadeSecs);
@@ -267,6 +270,8 @@ export default function QueuePanel() {
const setCrossfadeSecs = useAuthStore(s => s.setCrossfadeSecs);
const setGaplessEnabled = useAuthStore(s => s.setGaplessEnabled);
const setInfiniteQueueEnabled = useAuthStore(s => s.setInfiniteQueueEnabled);
const normalizationEngine = useAuthStore(s => s.normalizationEngine);
const replayGainMode = useAuthStore(s => s.replayGainMode);
const activeTab = useLyricsStore(s => s.activeTab);
const setTab = useLyricsStore(s => s.setTab);
@@ -478,6 +483,14 @@ export default function QueuePanel() {
const rgParts = formatQueueReplayGainParts(currentTrack, t);
const baseLine = baseParts.join(' · ');
const rgLine = rgParts.join(' · ');
const liveGainLabel = normalizationNowDb != null
? `${normalizationNowDb >= 0 ? '+' : ''}${normalizationNowDb.toFixed(2)} dB`
: '—';
const targetLabel = normalizationEngineLive === 'loudness'
? (normalizationTargetLufs != null ? `${normalizationTargetLufs} LUFS` : '-16 LUFS')
: normalizationEngineLive === 'replaygain'
? `ReplayGain (${replayGainMode})`
: t('queue.normOff', { defaultValue: 'Off' });
if (!baseLine && !rgLine && !playbackSource) return null;
const showRgLine = expandReplayGain && !!rgLine;
return (
@@ -522,6 +535,15 @@ export default function QueuePanel() {
{' · '}{rgLine}
</span>
)}
{(normalizationEngine === 'loudness' || normalizationEngineLive === 'loudness') && (
<span className="queue-current-tech-rg">
<span className="queue-current-tech-rg-label">{t('queue.normNow', { defaultValue: 'Now' })}</span>
{' · '}{liveGainLabel}
{' · '}
<span className="queue-current-tech-rg-label">{t('queue.normTarget', { defaultValue: 'Target' })}</span>
{' · '}{targetLabel}
</span>
)}
</div>
</div>
);