v0.2 - drop fingerprinting, add LUFS cart normalisation, playlist save/load, editable history with TXT+CSV export

This commit is contained in:
2026-05-08 17:19:11 +10:00
parent 0c8900ac36
commit 95f74d813f
19 changed files with 679 additions and 483 deletions
+22
View File
@@ -6,8 +6,10 @@ import jack
import threading
import subprocess
import os
import pyloudnorm as pyln
LUFS_TARGET = -14.0
SOUNDFILE_FORMATS = {'.wav', '.flac', '.ogg', '.aiff', '.aif'}
FFMPEG_FORMATS = {'.mp3', '.m4a', '.mp4', '.opus', '.aac', '.wma'}
@@ -52,6 +54,18 @@ def load_audio(filepath: str, target_sr: int) -> np.ndarray:
return data
def normalize_lufs(audio: np.ndarray, sr: int,
target: float = LUFS_TARGET) -> np.ndarray:
meter = pyln.Meter(sr)
loudness = meter.integrated_loudness(audio.T)
if np.isinf(loudness):
return audio
gain_db = target - loudness
gain_linear = 10 ** (gain_db / 20.0)
normalized = audio * gain_linear
return np.clip(normalized, -1.0, 1.0)
class Track:
def __init__(self, filepath: str, audio: np.ndarray, sr: int):
self.filepath = filepath
@@ -260,6 +274,14 @@ class AudioEngine:
self.decks[deck_key].load(track)
threading.Thread(target=_load, daemon=True).start()
def load_cart_track(self, cart_key: str, filepath: str):
def _load():
audio = load_audio(filepath, self.sr)
audio = normalize_lufs(audio, self.sr)
track = Track(filepath, audio, self.sr)
self.decks[cart_key].load(track)
threading.Thread(target=_load, daemon=True).start()
def load_queue(self, deck_key: str, filepath: str):
def _load():
audio = load_audio(filepath, self.sr)