Files
SonicForgeStudio/tests/test_loudness.py
T

44 lines
1.3 KiB
Python

"""D1: EBU R128 loudness + true peak metrics (app/core/loudness.py)."""
import numpy as np
from app.core import loudness
def _sine(dbfs, sr=44100, sec=3.0, freq=1000.0):
t = np.arange(int(sr * sec)) / sr
x = (10 ** (dbfs / 20.0)) * np.sin(2 * np.pi * freq * t)
return np.stack([x, x])
def test_sine_minus20_lufs():
# 1 kHz sine @ -20 dBFS: RMS -23.01 dB + K-weight +0.44 dB - 0.691 offset
# => ~ -23.3 LUFS (0 dBFS sine ~ -3.7 LUFS per EBU R128).
audio = _sine(-20.0)
lufs = loudness.integrated_lufs(audio, 44100)
assert -24.5 < lufs < -22.0, lufs
tp = loudness.true_peak_db(audio, 44100)
assert abs(tp - (-20.0)) < 0.2, tp
def test_true_peak_inter_sample_overshoot():
# Square-ish: sample peak 0 dBFS, oversampled true peak > 0 dBTP.
sr = 44100
x = np.repeat([1.0, 1.0, -1.0, -1.0], int(sr * 0.125))
audio = np.stack([x, x])
assert loudness.true_peak_db(audio, sr) > 0.05
def test_silence_inf():
audio = np.zeros((2, 44100))
assert loudness.integrated_lufs(audio, 44100) == -np.inf
assert loudness.true_peak_db(audio, 44100) == -np.inf
def test_mono_and_stereo_same():
sr = 44100
t = np.arange(sr * 2) / sr
x = 0.2 * np.sin(2 * np.pi * 440 * t)
mono = loudness.integrated_lufs(x, sr)
stereo = loudness.integrated_lufs(np.stack([x, x]), sr)
assert abs(mono - stereo) < 1e-6