#!/usr/bin/env python3
"""
Normalize WAV files to a target LUFS, but never exceed a true peak ceiling.
If the TP ceiling is the binding constraint, backs off the LUFS target rather
than falling back to dynamic normalization. Always applies linear (static) gain.
"""

import subprocess, json, sys, os, glob, shutil

TARGET_LUFS = -14.0
TP_CEILING  = -1.0       # dBTP
OUT_DIR     = "normalized"
SAMPLE_RATE = 44100
CODEC       = "pcm_s16le"

def measure(path):
    cmd = [
        "ffmpeg", "-i", path,
        "-af", "loudnorm=print_format=json",
        "-f", "null", "-"
    ]
    result = subprocess.run(cmd, capture_output=True, text=True)
    # loudnorm prints JSON to stderr
    stderr = result.stderr
    start = stderr.rfind('{')
    end   = stderr.rfind('}') + 1
    data  = json.loads(stderr[start:end])
    return float(data["input_i"]), float(data["input_tp"])

def normalize(path, out_path, gain_db):
    cmd = [
        "ffmpeg", "-y", "-i", path,
        "-af", f"volume={gain_db:.4f}dB",
        "-ar", str(SAMPLE_RATE),
        "-c:a", CODEC,
        out_path
    ]
    subprocess.run(cmd, check=True)

def process(path):
    input_i, input_tp = measure(path)

    gain_for_lufs = TARGET_LUFS - input_i
    gain_for_tp   = TP_CEILING  - input_tp
    safe_gain     = min(gain_for_lufs, gain_for_tp)
    actual_lufs   = input_i + safe_gain

    binding = "TP ceiling" if gain_for_tp < gain_for_lufs else "LUFS target"
    print(f"{os.path.basename(path)}")
    print(f"  measured:  {input_i:.1f} LUFS, {input_tp:.1f} dBTP")
    print(f"  gain:      {safe_gain:+.2f} dB  (limited by {binding})")
    print(f"  output:    {actual_lufs:.1f} LUFS  (target was {TARGET_LUFS})")

    fname    = os.path.basename(path)
    out_path = os.path.join(OUT_DIR, fname)
    normalize(path, out_path, safe_gain)
    print(f"  -> {out_path}\n")

os.makedirs(OUT_DIR, exist_ok=True)
files = glob.glob(sys.argv[1]) if len(sys.argv) > 1 else glob.glob("*.wav")

if not files:
    print("No files found.")
    sys.exit(1)

for f in sorted(files):
    process(f)


