- UI SFX v3: procedurally synthesized one-shots (Tools/synth_ui_sfx.py) wired to buttons, rewards, errors and red dots via UiSfx, gated by the SFX setting. - Five formal enemies (Hornlet, Dashlet, Shellhorn, HornCaptain, GreatHorn): Hunyuan 50k -> 2000-tri XPbr, DGXA TokenRig, Idle/Walk/Attack, nested per type in PrototypeArena; PrototypeBattle.Enemy gains presentation-only Moving/Strikes. - Formal partners for all ten pets in the arena and portraits, including new VineSprite, ThunderLeopard and TideWhale. - Pipeline fixes: reject local TokenRig fallback, drop loose mesh islands, configurable Unity run_script timeout, companion static stage. - Also includes concurrent work from another tool in this working tree (FlameLion, enemy combat FX, challenge mode, home explorer, server updates). - Resources registered in Doc/ResDesc_*.md; verified on isolated :18081. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
34 lines
1.9 KiB
Python
34 lines
1.9 KiB
Python
"""Validate delivered one-shots and their TangoFlux source/recipe provenance."""
|
|
import hashlib
|
|
import json
|
|
from pathlib import Path
|
|
import numpy as np
|
|
from scipy.io import wavfile
|
|
|
|
ROOT=Path(__file__).resolve().parents[1]
|
|
DESIGN=ROOT/'Doc/Design/Sound/EnemyCombat'
|
|
|
|
def main():
|
|
generation=json.loads((DESIGN/'generation.json').read_text(encoding='utf-8'))
|
|
rows=[]
|
|
for item in generation['items']:
|
|
path=ROOT/item['output']; source=ROOT/item['source']
|
|
assert hashlib.sha256(path.read_bytes()).hexdigest()==item['outputSha256']
|
|
assert hashlib.sha256(source.read_bytes()).hexdigest()==item['sourceSha256']
|
|
assert item['job']['status']=='succeeded'
|
|
assert item['requestHash']==hashlib.sha256(json.dumps(item['request'],sort_keys=True).encode()).hexdigest()
|
|
rate,samples=wavfile.read(path);x=samples.astype(float)/32768
|
|
assert rate==44100 and x.ndim==2 and x.shape[1]==2 and samples.dtype==np.int16
|
|
assert .1<len(x)/rate<1 and np.isfinite(x).all()
|
|
assert np.max(np.abs(x))<.95 and np.max(np.abs(x[:4410]))>.05
|
|
assert np.max(np.abs(x[-10:]))<.003
|
|
rms=float(20*np.log10(np.sqrt(np.mean(x*x))))
|
|
assert rms>-36
|
|
rows.append(dict(id=item['id'],seconds=len(x)/rate,peakDb=float(20*np.log10(np.max(np.abs(x)))),rmsDb=rms,clippedSamples=int(np.sum(np.abs(x)>=.999)),hashesMatch=True))
|
|
assert len(rows)==8
|
|
report=dict(status='pass',clips=rows,checks='source/output/request hashes; succeeded job; PCM16 44.1kHz stereo; short duration; prompt onset; fade tail; finite samples; zero clipping',subjectiveListening='not_asserted_by_automated_QA',previewOrder=[item['id'] for item in generation['items']])
|
|
(DESIGN/'audio_validation.json').write_text(json.dumps(report,indent=2),encoding='utf-8')
|
|
print('PASS eight TangoFlux one-shots: provenance, format, onset, level, fade and zero clipping')
|
|
|
|
if __name__=='__main__':main()
|