#!/usr/bin/env python3
"""Generate original equal-peak examples and measure them with local FFmpeg.
Usage: python3 scripts/seo/generate-loudness-example.py --out /tmp/hearably-loudness
No downloaded audio, speech, user recordings, network access or paid services.
"""
import argparse, array, hashlib, io, json, math, pathlib, re, subprocess, sys, wave
parser=argparse.ArgumentParser();parser.add_argument('--out',required=True,type=pathlib.Path)
out=parser.parse_args().out;out.mkdir(parents=True,exist_ok=True)
rate=48000;duration=10;count=rate*duration
version=subprocess.check_output(['ffmpeg','-version'],text=True).splitlines()[0]
results=[]
for name in ['steady','pulsed']:
 values=array.array('h')
 for n in range(count):
  t=n/rate;fade=min(1,t/.02,(duration-t)/.02)
  phase=t%0.5
  if name=='steady':envelope=1
  elif phase<.10:envelope=1
  elif phase<.11:envelope=.25+.75*(1+math.cos(math.pi*(phase-.10)/.01))/2
  elif phase<.49:envelope=.25
  else:envelope=.25+.75*(1-math.cos(math.pi*(phase-.49)/.01))/2
  values.append(round(4096*math.sin(2*math.pi*480*t)*fade*envelope))
 peak=max(abs(x)for x in values)/32768
 rms=math.sqrt(sum((x/32768)**2 for x in values)/count)
 if sys.byteorder!='little':values.byteswap()
 buffer=io.BytesIO()
 with wave.open(buffer,'wb')as wav:
  wav.setnchannels(1);wav.setsampwidth(2);wav.setframerate(rate);wav.writeframes(values.tobytes())
 data=buffer.getvalue();path=out/(name+'.wav')
 if path.exists()and path.read_bytes()!=data:raise SystemExit(f'Refusing to overwrite a different file: {path}')
 path.write_bytes(data)
 command=['ffmpeg','-hide_banner','-nostats','-i',path.name,'-af','ebur128=peak=true','-f','null','-']
 run=subprocess.run(command,cwd=out,text=True,capture_output=True,check=True)
 summary=run.stderr.rsplit('Summary:',1)[1]
 integrated=float(re.search(r'\bI:\s*([-\d.]+) LUFS',summary)[1])
 true_peak=float(re.search(r'True peak:\s*Peak:\s*([-\d.]+) dBFS',summary)[1])
 (out/(name+'-measurement.txt')).write_text('FFmpeg command: '+' '.join(command)+'\n'+run.stderr)
 results.append({'file':path.name,'sha256':hashlib.sha256(data).hexdigest(),'bytes':len(data),'durationSeconds':duration,'sampleRateHz':rate,'channels':1,'encoding':'16-bit PCM WAV','samplePeakDbFS':round(20*math.log10(peak),3),'rmsDbFS':round(20*math.log10(rms),3),'integratedLUFS':integrated,'truePeakDbTP':true_peak,'meterCommand':command})
assert results[0]['samplePeakDbFS']==results[1]['samplePeakDbFS']
assert results[0]['integratedLUFS']>results[1]['integratedLUFS']+3
report={'title':'Hearably equal-peak loudness example','methodVersion':1,'createdDate':'2026-09-19','provenance':'Original synthesized 480 Hz signals generated by Hearably; no third-party recordings.','generator':'https://hearably.app/audio/loudness-lab/generate-loudness-example.py','meter':version,'meterMethod':'FFmpeg ebur128 integrated loudness with true-peak estimation; default gating; whole mono file. Summary readings rounded by FFmpeg to 0.1.','signals':'Steady tone versus repeating 0.5 s envelope: 0.10 s full, 0.38 s quarter amplitude, two 0.01 s cosine transitions. Both have 0.02 s edge fades. Peak PCM amplitude 4096/32768.','limitations':['Synthetic measurement illustration; not an extension, streaming-platform or listening-device benchmark.','Mono measurement; playback routes, channel mapping and device volume affect what listeners hear.','Measured with the named FFmpeg implementation, not independently certified as a BS.1770-5 conformance test.'],'files':results}
(out/'generate-loudness-example.py').write_text(pathlib.Path(__file__).read_text())
(out/'measurements.json').write_text(json.dumps(report,indent=2)+'\n');print(json.dumps(results,indent=2))
