v0.52.0: volume normalization — every song plays at one loudness
Measured once per file with ffmpeg's ebur128 (cached on this machine), applied as a gain on the output volume; the next songs are measured ahead and an unmeasured one glides to its level. Toggle in Controls and Preferences → General.
This commit is contained in:
@@ -147,6 +147,17 @@ persistence) → GUI (Qt widgets that read the manager and connect to its signal
|
||||
each load, and on `refresh_volume()` (MainWindow calls that when the
|
||||
playing track is edited). `Player.volume()` stays the bare slider value.
|
||||
|
||||
- **Volume normalization** (Round 83, `loudness.py`, Controls → Normalize
|
||||
Volume / Preferences → General): each file's EBU R128 integrated loudness
|
||||
from the `ffmpeg` CLI's `ebur128` (~0.4 s a song), cached by path + size +
|
||||
mtime in `$XDG_CACHE_HOME/lintunes/loudness.json` (machine-local, never
|
||||
the synced dir). `Player` turns `TARGET_LUFS − measured` into a dB gain in
|
||||
`_output_volume` (`volume_with_gain`, linear amplitude through Qt's own
|
||||
volume curve, capped at full). The playing song is measured urgently and
|
||||
the next `LOOKAHEAD` ahead; an unmeasured one starts at the cache's median
|
||||
and **glides** (never jumps) to its own gain. No DSP, no tags: Qt's
|
||||
pipeline has no insert point, and none is needed.
|
||||
|
||||
- **`lintunes/player.py`** — `Player(QObject)` walks a queue through a swappable
|
||||
**`PlaybackSink`**. Player owns the queue, shuffle walk, per-track start/stop
|
||||
times and the play-count/scrobble bookkeeping; a sink owns only "make this file
|
||||
|
||||
Reference in New Issue
Block a user