#!/usr/bin/env bash
# Make every sound in ../Sounds LOUD and roughly even.
# Each file is brickwall-maximized toward TARGET_LUFS (boost only, never reduced),
# with the true peak held at PEAK_DB. This raises quiet-bodied / sharp-transient
# sounds (which already peak at 0 but feel soft) instead of just touching the peak.
# ffmpeg applies the gain + limiter -> WAV at the source sample rate; sox re-encodes
# to OGG Vorbis (this ffmpeg build has no libvorbis encoder). Originals are in git.
#
# Usage:  bash tools/normalize-sounds.sh
# Tunables (env): TARGET_LUFS (louder = closer to 0), MAX_BOOST dB, PEAK_DB, VORBIS_Q
set -euo pipefail

TARGET_LUFS="${TARGET_LUFS:--9}"
MAX_BOOST="${MAX_BOOST:-18}"
PEAK_DB="${PEAK_DB:--1}"
VORBIS_Q="${VORBIS_Q:-6}"

here="$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)"
sounds="$(cd "$here/.." && pwd)/Sounds"

command -v ffmpeg  >/dev/null 2>&1 || { echo "error: ffmpeg not found"  >&2; exit 1; }
command -v ffprobe >/dev/null 2>&1 || { echo "error: ffprobe not found" >&2; exit 1; }
command -v sox     >/dev/null 2>&1 || { echo "error: sox not found"     >&2; exit 1; }
command -v python3 >/dev/null 2>&1 || { echo "error: python3 not found" >&2; exit 1; }
[ -d "$sounds" ] || { echo "error: no Sounds dir at $sounds" >&2; exit 1; }

limit="$(python3 -c "print(round(10**(${PEAK_DB}/20.0),4))")"

shopt -s nullglob
if [ "$#" -gt 0 ]; then
  files=()
  for a in "$@"; do
    if [ -f "$a" ]; then files+=("$a")
    elif [ -f "$sounds/$a" ]; then files+=("$sounds/$a")
    else echo "warn: not found, skipping: $a" >&2; fi
  done
else
  files=("$sounds"/*.ogg)
fi
[ "${#files[@]}" -gt 0 ] || { echo "error: no input files" >&2; exit 1; }

echo "Maximizing ${#files[@]} files -> ~${TARGET_LUFS} LUFS (boost<=${MAX_BOOST}dB), peak ${PEAK_DB} dBFS"
fail=0
for f in "${files[@]}"; do
  name="$(basename "$f")"
  sr="$(ffprobe -v error -select_streams a:0 -show_entries stream=sample_rate -of csv=p=0 "$f" 2>/dev/null)"
  [ -n "$sr" ] || sr=44100

  i0="$(ffmpeg -hide_banner -nostats -i "$f" -af loudnorm=print_format=json -f null - 2>&1 \
        | awk -F'"' '/"input_i"/{print $4}')"

  gain="$(python3 -c "
import math
try:
    i = float('${i0}')
    if not math.isfinite(i): i = -23.0
except Exception:
    i = -23.0
g = ${TARGET_LUFS} - i
g = max(0.0, min(${MAX_BOOST}, g))
print(round(g, 3))
")"
  lin="$(python3 -c "print(round(10**(${gain}/20.0),4))")"

  wav="${f%.ogg}.__norm.wav"
  ogg="${f%.ogg}.__norm.ogg"
  if ffmpeg -hide_banner -nostats -y -i "$f" \
        -af "alimiter=level_in=${lin}:limit=${limit}:level_out=1,aresample=${sr}" \
        -c:a pcm_s16le "$wav" >/dev/null 2>&1 \
     && sox "$wav" -C "${VORBIS_Q}" "$ogg" >/dev/null 2>&1; then
    mv "$ogg" "$f"; rm -f "$wav"; echo "  ok   $name (+${gain} dB)"
  else
    rm -f "$wav" "$ogg"; echo "  FAIL $name"; fail=1
  fi
done

if [ "$fail" -eq 0 ]; then
  echo "All maximized."
else
  echo "Completed with errors." >&2
  exit 1
fi
