master
John Lauer Preserve BQ independent routing, narration and native copper-retention evidence a4b7711 1mo ago
import json,subprocess,re,hashlib
from pathlib import Path
P=Path(__file__).resolve().parent;V=P.parent/'video';cues=json.loads((P/'script.json').read_text());duration=143.333333
args=[];filters=[];timings=[]
for i,c in enumerate(cues):
 f=P/c['file'];d=float(subprocess.check_output(['ffprobe','-v','error','-show_entries','format=duration','-of','default=nw=1:nk=1',str(f)]));tempo=max(1,d/(c['end']-c['start']-.15));assert tempo<1.10
 args+=['-i',str(f)];filters.append(f'[{i}:a]atempo={tempo},aresample=48000,adelay={round(c["start"]*1000)}:all=1[a{i}]');timings.append({**c,'sourceDuration':d,'tempo':tempo,'actualEnd':c['start']+d/tempo})
filters.append(''.join(f'[a{i}]' for i in range(len(cues)))+f'amix=inputs={len(cues)}:normalize=0,apad=whole_len=6880000,atrim=end_sample=6880000,asetpts=N/SR/TB[mix]')
raw=P/'narration-mix.wav'
subprocess.run(['ffmpeg','-v','error',*args,'-filter_complex',';'.join(filters),'-map','[mix]','-c:a','pcm_s24le','-y',str(raw)],check=True)
r=subprocess.run(['ffmpeg','-hide_banner','-i',str(raw),'-af','loudnorm=I=-16:TP=-1.5:LRA=7:print_format=json','-f','null','-'],capture_output=True,text=True,check=True);m=json.loads(r.stderr[r.stderr.rfind('{'):]);(P/'loudness-first-pass.json').write_text(json.dumps(m,indent=2))
filt=f'loudnorm=I=-16:TP=-1.5:LRA=7:measured_I={m["input_i"]}:measured_TP={m["input_tp"]}:measured_LRA={m["input_lra"]}:measured_thresh={m["input_thresh"]}:offset={m["target_offset"]}:linear=true:print_format=json'
normalized=P/'narration-master.wav';subprocess.run(['ffmpeg','-v','error','-i',str(raw),'-af',filt,'-ar','48000','-ac','2','-c:a','pcm_s24le','-y',str(normalized)],check=True)
out=V/'fusion-bq25792-astra-3x-narrated.mp4'
subprocess.run(['ffmpeg','-v','error','-i',str(V/'fusion-bq25792-astra-3x.mp4'),'-i',str(normalized),'-map','0:v:0','-map','1:a:0','-c:v','copy','-c:a','aac','-b:a','192k','-ar','48000','-metadata','comment=AI-generated narration: Andrew Neural via Adom TTS. Independently calculated routing; edited playback.','-movflags','+faststart','-y',str(out)],check=True)
subprocess.run(['ffmpeg','-v','error','-i',str(out),'-f','null','-'],check=True)
r=subprocess.run(['ffmpeg','-hide_banner','-i',str(out),'-vn','-af','loudnorm=I=-16:TP=-1.5:LRA=7:print_format=json','-f','null','-'],capture_output=True,text=True,check=True);measured=json.loads(r.stderr[r.stderr.rfind('{'):]);assert float(measured['input_tp'])<0
probe=json.loads(subprocess.check_output(['ffprobe','-v','error','-show_streams','-show_format','-of','json',str(out)]));assert len(probe['streams'])==2
(P/'verification.json').write_text(json.dumps({'voice':'en-US-AndrewNeural','synthesis':'Adom TTS / Microsoft Edge TTS','cues':timings,'measuredLoudness':measured,'fullDecode':'passed','video':'Copied without re-encoding','probe':probe,'sha256':hashlib.sha256(out.read_bytes()).hexdigest()},indent=2));print(out);print(measured)