ITU-R BS.1770 LUFS + true-peak + crest + LRA analyzer with batch CLI, Markdown report, and optional email send
Project description
sacrifunk-loudness
ITU-R BS.1770 LUFS + true-peak + crest analyzer with a Click CLI, Markdown report renderer, and optional SMTP email send. Drop a folder of WAV bounces at it and get back a JSON dump, a human-readable Markdown report, or an email straight to your inbox.
Why
Streaming-music mastering targets -14 LUFS ±0.5 and True Peak ≤ -1.0 dBTP (Sacrifunk's locked targets — same as Spotify/Apple/Tidal norms). Every bounce out of Logic Pro needs to clear those thresholds before it ships to CD Baby. This tool runs the standard analysis in one command and tells you which tracks pass and which need a second pass.
Install
pip install sacrifunk-loudness
Python 3.10+. Pulls in numpy, scipy, pyloudnorm, and click.
Usage
Single file
sacrifunk-loudness analyze Bounces/Darko_master.wav
Default output is JSON on stdout, summary on stderr.
Folder (recursive)
sacrifunk-loudness analyze Bounces/ --md report.md --json report.json
Custom targets (e.g. broadcast / podcast)
sacrifunk-loudness analyze Bounces/ \
--target -16 \
--tolerance 1.0 \
--tp-limit -2 \
--crest-min 10 --crest-max 22
Markdown from a saved JSON
sacrifunk-loudness report report.json --output report.md
Email a report
export SMTP_HOST=smtp.gmail.com
export SMTP_USER=info@sacrifunk.com
export SMTP_PASS='app-password-here'
export SMTP_FROM='Ahmed <info@sacrifunk.com>'
sacrifunk-loudness send report.md --to ae@example.com --subject "Genesis 3 — Blues Bang final master"
DSP
| Metric | Method |
|---|---|
| Integrated loudness (LUFS) | pyloudnorm.Meter — ITU-R BS.1770-4 K-weighted gating |
| True peak (dBTP) | 4× polyphase upsampling via scipy.signal.resample_poly, then 20·log10(max(abs(x))) |
| Sample peak (dBFS) | 20·log10(max(abs(x))) on raw samples |
| Crest factor (dB) | sample_peak_dBFS − 20·log10(RMS) |
Mono input is duplicated to stereo before measurement. Int16/Int24/Int32/uint8 WAVs are normalized to [-1, 1] float64.
Sacrifunk defaults
The default AnalysisTargets matches Sacrifunk mastering canon (locked April 22, 2026):
- LUFS target
-14.0 ±0.5 - True peak
≤ -1.0 dBTP - Crest factor
14–18 dB
Override any of these via CLI flags or by passing an AnalysisTargets to analyze_file() / analyze_folder() programmatically.
Library use
from sacrifunk_loudness import analyze_file, analyze_folder, render_markdown, SACRIFUNK_TARGETS
result = analyze_file("Bounces/Darko_master.wav")
print(result.lufs, result.true_peak_dbtp, result.verdict)
results = analyze_folder("Bounces/", SACRIFUNK_TARGETS, recursive=True)
md = render_markdown(results)
SMTP env vars
| Var | Required | Default | Notes |
|---|---|---|---|
SMTP_HOST |
yes | — | e.g. smtp.gmail.com |
SMTP_USER |
yes | — | full email address |
SMTP_PASS |
yes | — | app password, not your Google login |
SMTP_FROM |
no | SMTP_USER |
From: header |
SMTP_PORT |
no | 587 |
use 465 for SSL providers |
SMTP_SECURITY |
no | starttls |
starttls / ssl / none |
Never pass credentials on the command line. send reads them from the environment only.
Development
pip install -e ".[dev]"
pytest -v
Tests use synthetic 1 kHz sine WAVs scaled to known LUFS levels via pyloudnorm — no Sacrifunk workspace dependency.
Roadmap
- LRA (Loudness Range, EBU R128 gated) — currently summary only.
- AAC / FLAC / AIFF input via
soundfilefallback (today: WAV only viascipy.io.wavfile). - HTML report alongside Markdown.
--watchmode (chokidar-style folder watch).- Optional Telegram digest output for mobile workflows.
The Sacrifunk production stack already runs the analyzer via an n8n cron at _logic_pro_bounce_watch (30s scheduler, Telegram digest to @Sacrifunkbot). A planned follow-up swaps runtime/scripts/wav_quick_analyze.py to a thin from sacrifunk_loudness.analyzer import analyze_file wrapper.
License
MIT — see LICENSE.
Project details
Release history Release notifications | RSS feed
Download files
Download the file for your platform. If you're not sure which to choose, learn more about installing packages.
Source Distribution
Built Distribution
Filter files by name, interpreter, ABI, and platform.
If you're not sure about the file name format, learn more about wheel file names.
Copy a direct link to the current filters
File details
Details for the file sacrifunk_loudness-0.1.0.tar.gz.
File metadata
- Download URL: sacrifunk_loudness-0.1.0.tar.gz
- Upload date:
- Size: 15.1 kB
- Tags: Source
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1f0e7ca54969d043368592baacdf5c1a1544bdb8cee72014819dbf46b51a9832
|
|
| MD5 |
851e1598b2e7fd41506e2fb37e348314
|
|
| BLAKE2b-256 |
d3c56007cd33ec2ead2663675e909271d3064c59b08801bd2859566ae42121a4
|
File details
Details for the file sacrifunk_loudness-0.1.0-py3-none-any.whl.
File metadata
- Download URL: sacrifunk_loudness-0.1.0-py3-none-any.whl
- Upload date:
- Size: 14.7 kB
- Tags: Python 3
- Uploaded using Trusted Publishing? No
- Uploaded via: twine/6.2.0 CPython/3.14.3
File hashes
| Algorithm | Hash digest | |
|---|---|---|
| SHA256 |
1961b13d314ec6ef4e60b035055af4aaf31aafabccde31fffcfa8383d10dcbbd
|
|
| MD5 |
86ed8981f12c809d41d6a699c49e397c
|
|
| BLAKE2b-256 |
8051884a0f8711a8affcd29edc43832f018e7d7e8ddb7529ada0f977b72e393e
|