#!/usr/bin/env python3 """Levels (and a spectrogram) of a game audio capture — smoke runs write DIR/audio.wav through OpenAL Soft's wave backend (audio spec §8). The game is killed at the end of a run, so the WAV header sizes may be unfinished: data is read to end of file. Usage: scripts/audio_report.py WAV [--png OUT.png] [--start S] [--end S] prints one line per second: RMS and peak in dBFS (mono mix) --png: spectrogram of [start, end] via ffmpeg (skipped if ffmpeg is missing) """ import argparse import array import math import shutil import struct import subprocess import sys import tempfile from pathlib import Path def read_wav(path): """Returns (rate, channels, samples as list of ints, interleaved). 16-bit PCM only.""" data = Path(path).read_bytes() if data[:4] != b"RIFF" or data[8:12] != b"WAVE": raise ValueError("not a RIFF/WAVE file") pos, rate, channels, bits = 12, None, None, None while pos + 8 <= len(data): cid, size = data[pos:pos + 4], struct.unpack("